Debugging |
To debug the Shockwave 3D§ scenegraph, use the S3DDebugInfo class. This class can dump most of the information you will need to determine if you are exporting the correct data. After creating and initializing an S3DdebugInfo object, these calls will dump the following information to disk:
S3DdebugInfo.WriteNodePalette( m_pNodePalette );
S3DdebugInfo.WriteLightPalette( m_pLightPalette );
S3DdebugInfo.WriteModelPalette( m_pModelPalette );
S3DdebugInfo.WriteShaderPalette( m_pShaderPalette );
S3DdebugInfo.WriteMaterialPalette( m_pMaterialPalette );
S3DdebugInfo.WriteTexturePalette( m_pTexturePalette );
S3DdebugInfo.WriteMotionPalette( m_pMotionPalette );
The output generated by the S3DdebugInfo class is controlled by a file called SW3D_Exp.ini, which is included with this SDK. Examine this file and the source to this class for details on how to use it. You may need to modify the location in which the exporter looks for this file by modifying the S3DDebugInfo::Init() method.
When debugging the skeletal animation code, refer to Shockwave 3D Data Out for information on how to see the relative positions of the skeletons and meshes.
To find the bounding volume of an object, or get the world bounding volume, use the S3DSceneGraphUtils::FindWorldBoundingSphere() method, which shows how to iterate through a palette. Because objects in Shockwave 3D are stored at zero resolution until they are rendered, you must first bring the model to full resolution by calling the IFXModelResource::SetMRMLevel() method with a value of 1.0f.
Once a model is at full resolution, you can force it to determine its bounding volume by calling the IFXModelData::SetBoundVolumeUpdatesEnabled() and IFXModelData::RebuildBound() methods. After you have done this, ask the IFXNode that points to the IFXModelResource containing this IFXModelData to get the bounding volume of the model and all of its children by calling the IFXNode::ResolveBoundingHierarchy() and IFXNode::GetBoundingSphere() methods. If the IFXNode is the root of the scene, this will give you the world bounding volume (the S3DSceneGraphUtils::FindWorldBoundingSphere() method implements this code). You can get the bounding sphere of a single model by calling the IFXModelData::GetBound() method (the S3DDebugInfo::Write(IFXModelResource *) method illustrates this data).
Call the IFXModelResource::SetMRMLevel() method with a value of 0.0f, or the original value, after obtaining the bounding sphere data.
Shockwave 3D classes make use of a COM-like implementation to ensure that pointers stay valid as long as an object is still in use. Calls to methods such as QueryInterface(), SetResourcePtr(), SetParent(), GetPalette(), and the IFXCreateComponent() function all result in a reference being added to an object. When you are done with an object, be sure to release the reference to it with a call to the IFXRelease() macro. When the number of references on an object drops to zero, the object will delete itself.
The exporter should call IFXRelease() on all the Shockwave 3D IFXPalette objects (which will also undo references to objects created when the SetResourcePtr() method is called), the IFXSceneGraph object, and the IFXCoreServices object, each in reverse order from the way they were allocated. The destructor for the S3DSceneGraphUtils class, whose use is recommended, will take care of this step. The last step is to call the IFXPluginDisposeOfGlobals() function. If everything has been done properly, the application should be using no more memory than it did before you created the IFXCoreServices object. If it does, you need to look for objects that were not freed, including those created but which you forgot to release.
Remember that references are created when one object is assigned to another object and when an interface is queried on an object. Release interfaces as soon as you are finished with them, and release all the palettes. At this point you should only have to track down a few leaks. If you use a tool like BoundsChecker§, note that a failure to release the IFXScenegraph object is a sure sign that a lower-level object, like a light or a palette, wasn't released because it was still referenced by something else.
To help figure out the number of references used by any given object, add one of the following two functions to your project and use it to query an object's reference count.
template<class T>
long GetObjRefCnt(T* in_T)
{
if(in_T)
{
IFXUnknown *pUnknown = NULL;
// Note: QueryInterface does an AddRef()
if(IFXFAILURE(in_T->QueryInterface(IID_IFXUnknown,(void**)&pUnknown)))
{return 0;
}
return pUnknown->Release(); // Returns number 	
}
return 0;
}
or
// Objects will cast to
IFXUnknown transparently
// As they all should
inherit directly from it.
long GetObjRefCnt2(IFXUnknown* in_pUnk)
{
if(in_pUnk)
{
in_pUnk->AddRef();
return in_pUnk->Release(); // Returns number
}
return 0;
}
§See asterisked (*) statement at Legal Information © 2001 Intel Corporation.