importexport/FBXExtension/mbcustomdataplugin.cxx

importexport/FBXExtension/mbcustomdataplugin.cxx
/***************************************************************************************
Autodesk(R) Open Reality(R) Samples
(C) 2009 Autodesk, Inc. and/or its licensors
All rights reserved.
AUTODESK SOFTWARE LICENSE AGREEMENT
Autodesk, Inc. licenses this Software to you only upon the condition that
you accept all of the terms contained in the Software License Agreement ("Agreement")
that is embedded in or that is delivered with this Software. By selecting
the "I ACCEPT" button at the end of the Agreement or by copying, installing,
uploading, accessing or using all or any portion of the Software you agree
to enter into the Agreement. A contract is then formed between Autodesk and
either you personally, if you acquire the Software for yourself, or the company
or other legal entity for which you are acquiring the software.
AUTODESK, INC., MAKES NO WARRANTY, EITHER EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR
PURPOSE REGARDING THESE MATERIALS, AND MAKES SUCH MATERIALS AVAILABLE SOLELY ON AN
"AS-IS" BASIS.
IN NO EVENT SHALL AUTODESK, INC., BE LIABLE TO ANYONE FOR SPECIAL, COLLATERAL,
INCIDENTAL, OR CONSEQUENTIAL DAMAGES IN CONNECTION WITH OR ARISING OUT OF PURCHASE
OR USE OF THESE MATERIALS. THE SOLE AND EXCLUSIVE LIABILITY TO AUTODESK, INC.,
REGARDLESS OF THE FORM OF ACTION, SHALL NOT EXCEED THE PURCHASE PRICE OF THE
MATERIALS DESCRIBED HEREIN.
Autodesk, Inc., reserves the right to revise and improve its products as it sees fit.
Autodesk and Open Reality are registered trademarks or trademarks of Autodesk, Inc.,
in the U.S.A. and/or other countries. All other brand names, product names, or
trademarks belong to their respective holders.
GOVERNMENT USE
Use, duplication, or disclosure by the U.S. Government is subject to restrictions as
set forth in FAR 12.212 (Commercial Computer Software-Restricted Rights) and
DFAR 227.7202 (Rights in Technical Data and Computer Software), as applicable.
Manufacturer is Autodesk, Inc., 10 Duke Street, Montreal, Quebec, Canada, H3C 2L7.
***************************************************************************************/
#include "mbextension.h"
#include "IOPlugin/MyOwnWriter.h"
#include "IOPlugin/MyOwnReader.h"
#include "IOPlugin/MyOwnIOPlugin.h"
#include <fbxsdk/fbxsdk_nsbegin.h>
#define MY_CUSTOM_CLASS_NAME "MyCustomClass"
#define MY_CUSTOM_CLASS_TYPE "MyCustomType"
#define MY_CUSTOM_CLASS_SUBTYPE "MyCustomSubType"
static FbxManager* gFbxManager = NULL;
class MyCustomObject : public FbxObject
{
FBXSDK_OBJECT_DECLARE( MyCustomObject, FbxObject );
protected:
};
FBXSDK_OBJECT_IMPLEMENT( MyCustomObject );
class MBCustomDataPlugin : public FbxPlugin
{
FBXSDK_PLUGIN_DECLARE( MBCustomDataPlugin );
protected:
explicit MBCustomDataPlugin( const FbxPluginDef& pDefinition, FbxModule pLibHandle ) : FbxPlugin( pDefinition, pLibHandle )
{
}
// Implement kfbxmodules::KFbxPlugin
virtual bool SpecificInitialize()
{
// Register MyCustomObject class with the plug-in's manager
gFbxManager = GetData().mSDKManager;
gFbxManager->RegisterFbxClass( MY_CUSTOM_CLASS_NAME, FBX_TYPE(MyCustomObject ), FBX_TYPE( FbxObject ), MY_CUSTOM_CLASS_TYPE, MY_CUSTOM_CLASS_SUBTYPE );
int FirstPluginID, RegistredCount;
gFbxManager->GetIOPluginRegistry()->RegisterReader(CreateMyOwnReader, GetMyOwnReaderInfo, FirstPluginID, RegistredCount, FillOwnReaderIOSettings, true /* override any existing format */);
gFbxManager->GetIOPluginRegistry()->RegisterWriter(CreateMyOwnWriter, GetMyOwnWriterInfo, FirstPluginID, RegistredCount, FillOwnWriterIOSettings, true /* override any existing format */);
return true;
}
virtual bool SpecificTerminate()
{
// Unregister MyCustomObject class with the plug-in's manager
gFbxManager->UnregisterFbxClass( FBX_TYPE( MyCustomObject ) );
return true;
}
};
FBXSDK_PLUGIN_IMPLEMENT( MBCustomDataPlugin );
extern "C"
{
// The DLL is owner of the plug-in
static MBCustomDataPlugin* sPlugin = NULL;
// This function will be called when an application will request the plug-in
EXPORT_DLL void FBXPluginRegistration( FbxPluginContainer& pContainer, FbxModule pLibHandle )
{
if ( sPlugin == NULL )
{
// Create the plug-in definition which contains the information about the plug-in
FbxPluginDef sPluginDef;
sPluginDef.mName = "MBCustomDataPlugin";
sPluginDef.mVersion = "1.0";
// Create an instance of the plug-in. The DLL has the ownership of the plug-in
sPlugin = MBCustomDataPlugin::Create( sPluginDef, pLibHandle );
// Register the plug-in
pContainer.Register( *sPlugin );
}
}
FBX_MB_EXTENSION_DECLARE();
}
bool MBExt_ExportHandled( FBComponent* pFBComponent )
{
/* Called for each MotionBuilder object that *is going to* be translated into fbx common data.
The purpose of this function is to tell the plug-in if we are going to handle the creation
of this MB object in this extension plug-in or if we let the application work as usual.
So returning TRUE means the corresponding fbx object for this particular MB object won't
be created, and we'll have to create it ourselves, so we say "we handle it". Otherwise,
returning FALSE will simply result in the usual behavior, which means the plug-in will
translate the MB object into the corresponding fbx object, if it knows how-to, of course.
*/
if ( !pFBComponent->Is( FBCamera::TypeInfo ) && pFBComponent->Is( FBModelCube::TypeInfo ) )
{
if ( FBString( pFBComponent->Name ) == FBString( "MyCubeToNotExport" ) )
{
// Let's do a translation on that MB cube
( ( FBModelCube* )pFBComponent )->Translation = FBVector3d( 150.0, 100.0, 0.0 );
// We decided to NOT CREATE an Fbx object for that "MyCubeToNotExport" found in the MB Scene.
return true;
}
else if ( FBString( pFBComponent->Name ) == FBString( "MyCubeToNotImport" ) )
{
// Let's do a translation on that MB cube
( ( FBModelCube* )pFBComponent )->Translation = FBVector3d( -150.0, 100.0, 0.0 );
}
}
return false;
}
void MBExt_ExportBegin( FbxScene* pFbxScene )
{
// Called before we export anything into the fbx scene.
// We could choose to create our custom data now or wait at the end of the export
// depending if that custom data replaces objects in the fbx scene hierarchy.
// For that example, let's create 3 simple cube in our MB scene.
FBModelCube* lMyCube1 = new FBModelCube("MyCubeToNotExport");
FBModelCube* lMyCube2 = new FBModelCube("MyCubeToNotImport");
FBModelCube* lMyCube3 = new FBModelCube("MyCubeToTestWith");
lMyCube1->Show = true;
lMyCube2->Show = true;
lMyCube3->Show = true;
lMyCube1->Scaling = FBVector3d(50.0, 50.0, 50.0);
lMyCube2->Scaling = FBVector3d(50.0, 50.0, 50.0);
lMyCube3->Scaling = FBVector3d(50.0, 50.0, 50.0);
lMyCube1->Translation = FBVector3d(0.0, 100.0, 0.0);
lMyCube2->Translation = FBVector3d(0.0, 100.0, 0.0);
lMyCube3->Translation = FBVector3d(0.0, 100.0, 0.0);
}
bool MBExt_ExportProcess( FbxObject*& pOutputFbxObject, FBComponent* pInputObject, FbxScene* pFbxScene)
{
//Called during the export process of all objects:
//
//Right after the FbxNode is created but before the FbxNodeAttribute.
//The purpose of this function is to intercept the default creation of the FBX object based on the MB
//object and replace it with this extension plugin version. If this function returns TRUE it will mean that
//all the required manipulation has been performed here and no further processing is required by the exporter.
//Inversely, if we return FALSE, we let the exporter process the data as usual.
//
//The proper implementation of this function requires to check what is the inputObject type
//and based on his type, we either need to :
//
// - create the corresponding FbxObject type (this is typically a custom Fbx class) when the content
// of pOutputFbxObject is NULL
//
//or
//
// - create and add the appropriate FBX data to the existing pOutputFbxObject.
//
//Notes:
// 1) This callback is never called if the MBExt_ExportHandled callback returned TRUE
// 2) In case 2 above, this callback is responsible for maintaining the integrity of the
// received FbxObject and all its existing connections.
//
const char* lOutput = "NULL";
const char* lInput = "NULL";
if(pOutputFbxObject)
{
lOutput = pOutputFbxObject->GetName();
}
if(pInputObject)
{
lInput = pInputObject->GetFullName();
}
FBTrace("FBXExtension::MBExt_ExportProcess output = %s, input = %s\n", lOutput, lInput );
return false;
}
void MBExt_ExportTranslated(FbxObject* pFbxObject, FBComponent* pFBComponent)
{
/*Called after the MB scene has been translated into an fbx scene, for each
object that was convertible. In other words, objects unknown or unsupported
by the FbxSdk won't be called in this function.
The purpose of this function is to tell the extension plug-in what is the corresponding
fbx object for that particular MB object. This is especially useful when connections
need to be preserved between application and extension plug-in fbx objects. */
// Here's a simple example that count polygons and vertices for the "MyCubeToTestWith"
// with the MotionBuilder and Fbx object created.
FBMesh* lFBMesh = NULL;
FbxMesh* lFbxMesh = NULL;
// MotionBuilder Object
if ( !pFBComponent->Is( FBCamera::TypeInfo ) && pFBComponent->Is( FBModelCube::TypeInfo ) )
{
if ( FBString( pFBComponent->Name ) == FBString( "MyCubeToNotExport" ) )
{
// You will never enter here because we handled the "MyCubeToNotExport" in MBExt_ExportHandled(...)
// So no object "MyCubeToNotExport" has been translated to an fbx object.
}
else if ( FBString( pFBComponent->Name ) == FBString( "MyCubeToTestWith" ) )
{
lFBMesh = ( ( FBModelCube* )pFBComponent )->TessellatedMesh;
}
}
// FBX Object
if ( pFbxObject->Is<FbxNode>() )
{
FbxNode* lFbxNode = FbxCast<FbxNode>( pFbxObject );
FbxNodeAttribute* lNodeAttribute = lFbxNode->GetNodeAttribute();
if ( lNodeAttribute->Is<FbxMesh>() )
{
if ( FbxString(lNodeAttribute->GetName() ) == FbxString( "MyCubeToNotExport" ) )
{
// You will never enter here because we handled the "MyCubeToNotExport" in MBExt_ExportHandled(...)
// So no object "MyCubeToNotExport" has been translated to an fbx object.
}
else if ( FbxString(lNodeAttribute->GetName() ) == FbxString( "MyCubeToTestWith" ) )
{
lFbxMesh = FbxCast<FbxMesh>( lNodeAttribute );
}
}
}
if ( lFBMesh && lFbxMesh )
{
if ( lFBMesh->PolygonCount() == lFbxMesh->GetPolygonCount() && lFBMesh->VertexCount() == lFbxMesh->GetPolygonVertexCount() )
{
// Of course the MB and Fbx object have the same number of polygons and vertices.
}
}
}
void MBExt_ExportEnd( FbxScene* pFbxScene )
{
// Called after the scene has been fully translated into fbx. This is the last function called
// before the extension plug-in is done with the export process. Any clean-up or last minute
// modification to the scene must be done now.
// Make sure our custom object class was correctly registred
FbxClassId MyCustomDataClassId = gFbxManager->FindClass( MY_CUSTOM_CLASS_NAME );
if( !MyCustomDataClassId.IsValid() ) return;
// Browse through the MotionBuilder Scene
int lCnt = FBGetComponentArray().GetCount();
for( int i=0; i<lCnt; i++ )
{
FBComponent* lComp = FBGetComponentArray().operator[](i);
if ( !lComp->Is( FBCamera::TypeInfo ) && lComp->Is( FBModelCube::TypeInfo ) )
{
if ( FBString( lComp->Name ) == FBString( "MyCubeToNotExport" ) )
{
// Create the custom object to hold the custom data
MyCustomObject* MyCustomObjectInstance = MyCustomObject::Create( pFbxScene, "My Custom Object Instance" );
FBMesh* lFBMesh = ( ( FBModelCube* )lComp )->TessellatedMesh;
// Fill our custom Fbx object with the vertex count of the object "MyCubeToNotExport"
// that we decided to not export earlier.
float Value = lFBMesh->VertexCount();
FbxString PropertyName = "MyCustomData";
FbxProperty NewProperty = FbxProperty::Create( MyCustomObjectInstance, FbxFloatDT, PropertyName.Buffer() );
if ( NewProperty.IsValid() ) NewProperty.Set( Value );
}
}
}
}
bool MBExt_ImportHandled( FbxObject* pFbxObject )
{
// This is called by the importer every time it's about to translate the FBX object
// into an MB object. If the extension plugin should handle the creation, then
// it needs to answer TRUE to this call.
if ( pFbxObject->Is<FbxNode>() )
{
FbxNode* lFbxNode = FbxCast<FbxNode>( pFbxObject );
FbxNodeAttribute* lNodeAttribute = lFbxNode->GetNodeAttribute();
if ( lNodeAttribute->Is<FbxMesh>() )
{
if ( FbxString(lNodeAttribute->GetName() ) == FbxString( "MyCubeToNotImport" ) )
{
// Let's not import that fbx object
return true;
}
}
}
return false;
}
void MBExt_ImportBegin( FbxScene* pFbxScene )
{
// This is called at the beginning of the import process,
// allowing us to act on the FBX scene before it's loaded from the file.
FBTrace("%s\n", "FBXExtension::MBExt_ImportBegin" );
}
bool MBExt_ImportProcess( FBComponent*& pOutputObject, FbxObject* pInputFbxObject, bool pIsAnInstance, bool pMerge)
{
//This is called by the importer every time it is about to create a MB object:
//
//The purpose of this function is to intercept the default creation of the MBobject (from the FBX object)
//and replace it with this extension plugin version. If this function returns TRUE it will mean that
//all the required manipulation has been performed here and no further processing is required by the importer.
//Inversely, if we return FALSE, we let the importer process the data as usual.
//
const char* lOutput = "NULL";
const char* lInput = "NULL";
if(pOutputObject)
{
lOutput = pOutputObject->GetFullName();
}
if(pInputFbxObject)
{
lInput = pInputFbxObject->GetName();
}
FBTrace("FBXExtension::MBExt_ImportProcess output = %s, input = %s\n", lOutput, lInput );
return false;
}
void MBExt_ImportTranslated( FbxObject* pFbxObject, FBComponent* pFBComponent )
{
// This is called every time an FBX object got converted into an MB object
// while we are traversing the scene during the translation process.
}
void MBExt_ImportEnd( FbxScene* pFbxScene )
{
// This is called at the very end of the import.
// In this example, we will try to retrieve our custom data to see if it's there
bool Result = false;
// Make sure our custom object class was correctly registered
FbxClassId MyCustomDataClassId = gFbxManager->FindClass( MY_CUSTOM_CLASS_NAME );
if ( !MyCustomDataClassId.IsValid() ) return;
// Search through the FBX scene to find our custom objects
int Iter, Count = pFbxScene->GetSrcObjectCount<MyCustomObject>( );
for ( Iter = 0; Iter < Count; ++Iter )
{
MyCustomObject* MyCustomObjectInstance = FbxCast<MyCustomObject>( pFbxScene->GetSrcObject<MyCustomObject>( 0 ) );
if ( MyCustomObjectInstance )
{
if ( MyCustomObjectInstance->FindProperty( "MyCustomData" ).IsValid() )
{
// We successfully retrieved our custom data.
// Here we could loop to find all the properties that we wrote, its limitless...
// We can also alternate the MB scene, its all available!
Result = true;
}
}
}
FBTrace("%s\n", "FBXExtension::MBExt_ImportEnd" );
}
#include <fbxsdk/fbxsdk_nsend.h>