Exporter Code Samples


  • CBExporter.hpp

    #ifndef included_CBExporter
    #define included_CBExporter
    #pragma once
    
    #include 
    #include 
    
    #include 
    
    #include "CBExportMesh.hpp"
    #include "CBExportNode.hpp"
    #include "CBExportSkinnedMesh.hpp"
    #include "CBStringHelper.hpp"
    #include "CBMaterialManager.hpp"
    #include "CBSkeletalBoneManager.hpp"
    
    namespace cbengine {
    
    	std::set		g_processedNodeSet;
    
    	// Helper Function Declarations
    	void ExtractAllNodeMeshDataFromScene( const std::string& exportFileName, IGameScene& maxScene, std::vector& nodeVector );
    	void ProcessNode( IGameScene& maxScene, IGameNode* nodeToProcess, CBExportNode* parentNode, std::vector& nodeVector );
    
    	void ExtractTransformationMatrices( IGameScene& maxScene, IGameNode* nodeToExtract, CBExportNode* cbNodeToExtract );
    	void ExtractAnimationTransformData( IGameScene& maxScene, IGameNode* nodeToExtract, CBExportNode* cbNodeToExtract );
    	void ExtractNonSkinnedMesh( CBExportMesh*& exportMesh, const std::string& nodeName, IGameScene& maxScene, IGameMesh* gameMesh, IGameNode* nodeToProcess );
    	void ExtractSkinnedMesh( CBExportSkinnedMesh*& exportMesh, const std::string& nodeName, IGameScene& maxScene, IGameMesh* gameMesh, IGameNode* nodeToProcess );
    	void DetectIfNodesAreBoneNodesAndMarkThem( std::vector& nodeVector );
    	void ConnectVertexAndBoneData( std::vector& nodeVector );
    
    	bool IsMeshASkinnedMesh( IGameMesh* gameMesh );
    
    	void ReleaseAndCleanUpIGameData( std::vector& nodeVector );
    	void ReleaseAndCleanUpMaterialData();
    	void ReleaseAndCleanUpBoneData();
    	void ReleaseAndCleanUpExportNodeData( std::vector& nodeVector );
    
    
    	// Helper Function Definitions
    	inline void ExtractAllNodeMeshDataFromScene( IGameScene& maxScene, std::vector& nodeVector ) {
    
    		size_t numNodesInScene = maxScene.GetTopLevelNodeCount();
    		for ( size_t i = 0; i < numNodesInScene; ++i ) {
    
    			IGameNode* gameNode = maxScene.GetTopLevelNode( static_cast(i) );	
    			ProcessNode( maxScene, gameNode, nullptr, nodeVector );
    
    		} // end for
    
    		DetectIfNodesAreBoneNodesAndMarkThem( nodeVector );
    		ConnectVertexAndBoneData( nodeVector );
    
    	} // end exportFunction
    
    
    	inline void ProcessNode( IGameScene& maxScene, IGameNode* nodeToProcess, CBExportNode* parentNode, std::vector& nodeVector ) {
    
    		static int nodeIndex = 0;
    
    		// Handle case where Node or Object is a nullptr :: Return and process another node if so
    		if ( nodeToProcess == nullptr ) {
    			return;
    		}
    
    		IGameObject* gameObject = nodeToProcess->GetIGameObject();
    		if ( gameObject == nullptr ) {
    			return;
    		}
    		
    		std::string nodeName;
    		cbengine::convertWideCharToString( nodeToProcess->GetName(), nodeName );
    
    		IGameObject::ObjectTypes objectType = gameObject->GetIGameType();
    
    		if ( objectType == IGameObject::IGAME_MESH ) {
    		
    			IGameMesh* gameMesh = static_cast( gameObject );
    			if ( gameMesh != nullptr ) {
    				
    				bool isSkinnedMesh = IsMeshASkinnedMesh( gameMesh );
    
    				if ( isSkinnedMesh ) {
    
    					CBExportSkinnedMesh* exportSkinnedMesh = nullptr;
    					ExtractSkinnedMesh( exportSkinnedMesh, nodeName, maxScene, gameMesh, nodeToProcess );
    
    					exportSkinnedMesh->setParentNode( parentNode );
    					exportSkinnedMesh->setNodeIndex( nodeIndex );
    					exportSkinnedMesh->setIGameNode( nodeToProcess );
    					nodeVector.push_back( exportSkinnedMesh );
    
    					++nodeIndex;
    
    					int childCount = nodeToProcess->GetChildCount();
    					for ( int i = 0; i < childCount; ++i ) {
    
    						IGameNode* childNode = nodeToProcess->GetNodeChild( i );
    						ProcessNode( maxScene, childNode, exportSkinnedMesh, nodeVector );
    					}
    
    				} else {
    
    					CBExportMesh* exportMesh = nullptr;
    					ExtractNonSkinnedMesh( exportMesh, nodeName, maxScene, gameMesh, nodeToProcess );
    
    					exportMesh->setParentNode( parentNode );
    					exportMesh->setNodeIndex( nodeIndex );
    					exportMesh->setIGameNode( nodeToProcess );
    					nodeVector.push_back( exportMesh );
    
    					++nodeIndex;
    
    					int childCount = nodeToProcess->GetChildCount();
    					for ( int i = 0; i < childCount; ++i ) {
    
    						IGameNode* childNode = nodeToProcess->GetNodeChild( i );
    						ProcessNode( maxScene, childNode, exportMesh, nodeVector );
    					}
    
    				}
    
    			} else {
    				return;
    			}
    
    		} else {
    
    			// For now until we cover more nodes
    			CBExportNode* exportNode = new CBExportNode;
    			ExtractTransformationMatrices( maxScene, nodeToProcess , exportNode );
    			ExtractAnimationTransformData( maxScene, nodeToProcess, exportNode );
    
    			exportNode->setNodeName( nodeName );
    			exportNode->setParentNode( parentNode );
    			exportNode->setNodeIndex( nodeIndex );
    			exportNode->setIGameNode( nodeToProcess );
    
    			if ( objectType == IGameObject::IGAME_BONE  ) {
    
    				exportNode->setExportNodeType( TYPE_EXPORT_BONE );
    				CBSkeletalBoneManager& boneManager = CBSkeletalBoneManager::getSharedCBSkeletalBoneManager();
    				boneManager.addCBExportNodeToBoneRegistry( nodeToProcess, exportNode );
    			}
    
    			nodeVector.push_back( exportNode );
    
    			++nodeIndex;
    
    			int childCount = nodeToProcess->GetChildCount();
    			for ( int i = 0; i < childCount; ++i ) {
    
    				IGameNode* childNode = nodeToProcess->GetNodeChild( i );
    				ProcessNode( maxScene, childNode, exportNode, nodeVector );
    			}
    		}
    
    		g_processedNodeSet.insert( nodeToProcess );
    	}
    
    
    	inline void ExtractNonSkinnedMesh( CBExportMesh*& exportMesh, const std::string& nodeName, IGameScene& maxScene, IGameMesh* gameMesh, IGameNode* nodeToProcess ) {
    
    		exportMesh = new CBExportMesh;
    		ExtractTransformationMatrices( maxScene, nodeToProcess, exportMesh );
    		ExtractAnimationTransformData( maxScene, nodeToProcess, exportMesh );
    		exportMesh->setNodeName( nodeName );
    		exportMesh->extractMeshVertexData( *(gameMesh) );
    
    	}
    
    
    	inline void ExtractSkinnedMesh( CBExportSkinnedMesh*& exportSkinnedMesh, const std::string& nodeName, IGameScene& maxScene, IGameMesh* gameMesh, IGameNode* nodeToProcess ) {
    
    		exportSkinnedMesh = new CBExportSkinnedMesh;
    		ExtractTransformationMatrices( maxScene, nodeToProcess, exportSkinnedMesh );
    		ExtractAnimationTransformData( maxScene, nodeToProcess, exportSkinnedMesh );
    		exportSkinnedMesh->setNodeName( nodeName );
    		exportSkinnedMesh->extractMeshVertexData( *(gameMesh) );
    
    	}
    
    
    	inline void ExtractTransformationMatrices( IGameScene& maxScene, IGameNode* nodeToExtract, CBExportNode* cbNodeToExtract ) {
    
    		if ( cbNodeToExtract  == nullptr || nodeToExtract == nullptr ) {
    			return;
    		}
    
    		GMatrix nodeWorldTM = nodeToExtract->GetWorldTM();
    		GMatrix nodeLocalTM = nodeWorldTM.Inverse();
    	
    		cbNodeToExtract ->setInitialLocalToWorldTransformationMatrix( nodeWorldTM );
    		cbNodeToExtract ->setInitialWorldToLocalTransformationMatrix( nodeLocalTM );
    
    	}
    
    
    	inline void ExtractAnimationTransformData( IGameScene& maxScene, IGameNode* nodeToExtract, CBExportNode* cbNodeToExtract ) {
    
    		const int framesPerSecond = 30;
    		const int maxSampleRate = 4800;
    		
    		TimeValue startSceneTime = maxScene.GetSceneStartTime();
    		TimeValue endSceneTime = maxScene.GetSceneEndTime();
    		TimeValue loopIncrementValue = maxSampleRate/framesPerSecond;
    	
    		for ( TimeValue i = startSceneTime; i < endSceneTime; i += loopIncrementValue ) {
    
    			GMatrix worldTransformMatrix = nodeToExtract->GetWorldTM( i );
    			cbNodeToExtract->addAnimationTransformation( worldTransformMatrix );
    		}
    
    	}
    
    	
    	inline void DetectIfNodesAreBoneNodesAndMarkThem( std::vector& nodeVector ) {
    
    		CBSkeletalBoneManager& skeletalBoneManager = CBSkeletalBoneManager::getSharedCBSkeletalBoneManager();
    
    		for ( size_t i = 0; i < nodeVector.size(); ++i ) {
    
    			CBExportNode* exportNode = nodeVector[i];
    			IGameNode* exportNodeIGameNode = exportNode->getIGameNode();
    			if ( exportNodeIGameNode == nullptr ) {
    				continue;
    			}
    
    			ExportNodeType nodeType = exportNode->getExportNodeType();
    			bool isABoneNode = skeletalBoneManager.isBoneNodeInSet( exportNodeIGameNode );
    
    			if ( isABoneNode && nodeType != TYPE_EXPORT_BONE ) {
    
    				exportNode->setExportNodeType( TYPE_EXPORT_BONE );
    				skeletalBoneManager.addCBExportNodeToBoneRegistry( exportNodeIGameNode, exportNode );
    			}
    		}
    	}
    
    
    	inline void ConnectVertexAndBoneData( std::vector& nodeVector ) {
    
    		CBSkeletalBoneManager& skeletalBoneManager = CBSkeletalBoneManager::getSharedCBSkeletalBoneManager();
    		skeletalBoneManager.formBoneIndexToExportNodeMap();
    
    		for ( size_t i = 0; i < nodeVector.size(); ++i ) {
    
    			CBExportNode* exportNode = nodeVector[i];
    
    			ExportNodeType nodeType = exportNode->getExportNodeType();
    
    			if ( nodeType == TYPE_EXPORT_SKINNED_MESH ) {
    				// Function to connect IGameNode* to bone index as part of export mesh
    				CBExportSkinnedMesh* exportSkinnedMesh = static_cast( exportNode );
    				exportSkinnedMesh->connectVertexBonesToBoneIndex();
    
    			}
    		}
    	}
    
    	inline bool IsMeshASkinnedMesh( IGameMesh* gameMesh ) {
    
    		bool isSkinnedMesh = false;
    		int numModifiers = gameMesh->GetNumModifiers();
    
    		for ( int i = 0; i < numModifiers; ++i ) {
    
    			IGameModifier* meshModifier =  gameMesh->GetIGameModifier( i );
    
    			if ( meshModifier == nullptr ) {
    				continue;
    			}
    
    			IGameModifier::ModType modType = meshModifier->GetModifierType();
    
    			if ( modType == IGameModifier::IGAME_SKINNING ) {
    
    				isSkinnedMesh = true;
    				IGameSkin* skin = static_cast( meshModifier );
    				break;
    			}
    		}
    
    		return isSkinnedMesh;
    	}
    
    
    	inline void ReleaseAndCleanUpIGameData( std::vector& nodeVector ) {
    
    		ReleaseAndCleanUpMaterialData();
    		ReleaseAndCleanUpBoneData();
    		ReleaseAndCleanUpExportNodeData( nodeVector );
    	}
    
    
    	inline void ReleaseAndCleanUpMaterialData() {
    
    		CBMaterialManager& materialManager = CBMaterialManager::getSharedMaterialManager();
    		materialManager.clearAndCleanUpCurrentMaterialRegistryAndMaterialMappings();
    	}
    
    
    	inline void ReleaseAndCleanUpBoneData() {
    
    		CBSkeletalBoneManager& boneManager = CBSkeletalBoneManager::getSharedCBSkeletalBoneManager();
    		boneManager.clearAndCleanUpNodeToBoneExportRegistry();
    	}
    
    
    	inline void ReleaseAndCleanUpExportNodeData( std::vector& nodeVector ) {
    
    		std::set::iterator itNode;
    		for ( itNode = g_processedNodeSet.begin(); itNode != g_processedNodeSet.end(); ++itNode ) {
    			
    			IGameNode* nodeToRelease = *(itNode);
    			if ( nodeToRelease != nullptr ) {
    
    				nodeToRelease->ReleaseIGameObject();
    			}
    
    		}
    
    		g_processedNodeSet.clear();
    
    		for ( size_t i = 0; i < nodeVector.size(); ++i ) {
    
    			CBExportNode * exportNode = nodeVector[i];
    			delete exportNode;
    		}
    	}
    
    } // end namespace
    
    
    #endif								
    							
  • CBMaxExporter.cpp

    
    //**************************************************************************/
    // DESCRIPTION: Appwizard generated plugin
    // AUTHOR: Paul Allen Renton
    //***************************************************************************/
    
    #include 
    #include 
    #include 
    #include 
    
    #include "CBMaxExporter.h"
    #include "IGame/IGame.h"
    #include "IGame/IGameObject.h"
    
    #include "CBExporter.hpp"
    #include "CBMeshFileExporter.hpp"
    #include "CBStringHelper.hpp"
    
    #define CBMaxExporter_CLASS_ID	Class_ID(0x85070332, 0xb5c34d48)
    
    class CBMaxExporter : public SceneExport {
    public:
    	//Constructor/Destructor
    	CBMaxExporter();
    	~CBMaxExporter();
    
    	int				ExtCount();					// Number of extensions supported
    	const TCHAR *	Ext(int n);					// Extension #n (i.e. "3DS")
    	const TCHAR *	LongDesc();					// Long ASCII description (i.e. "Autodesk 3D Studio File")
    	const TCHAR *	ShortDesc();				// Short ASCII description (i.e. "3D Studio")
    	const TCHAR *	AuthorName();				// ASCII Author name
    	const TCHAR *	CopyrightMessage();			// ASCII Copyright message
    	const TCHAR *	OtherMessage1();			// Other message #1
    	const TCHAR *	OtherMessage2();			// Other message #2
    	unsigned int	Version();					// Version number * 100 (i.e. v3.01 = 301)
    	void			ShowAbout(HWND hWnd);		// Show DLL's "About..." box
    
    	IGameScene *	m_IGameScene;
    	bool			m_exportSelected;
    
    	BOOL SupportsOptions(int ext, DWORD options);
    	int  DoExport(const TCHAR *name,ExpInterface *ei,Interface *i, BOOL suppressPrompts=FALSE, DWORD options=0);
    };
    
    
    
    class MaxSceneSaver : public ITreeEnumProc {
    public:
    	int callback(  INode * node  ); //that function is called for export
    	void processNode( INode * node ); //that function is called for process
    protected:
    
    private:
    
    };
    
    Interface *		g_interfaceFromDoExport = nullptr;
    
    /*
    PR: Attempts to convert a node to a triobject so we can access the mesh and other useful properties
    Returns nullptr if the conversion fails
    */
    TriObject * GetTriObjectFromNode( Interface * interf, INode *node, int &deleteIt)
    {
    	deleteIt = FALSE;
    	Object *obj = node->EvalWorldState(interf->GetTime()).obj;
    	if (obj->CanConvertToType(Class_ID(TRIOBJ_CLASS_ID,0)))
    	{
    		TriObject *tri = (TriObject *) obj->ConvertToType(interf->GetTime(), 
    			Class_ID(TRIOBJ_CLASS_ID, 0));
    		if (obj != tri) {
    			deleteIt = TRUE;
    		}
    		return tri;
    	} else {
    		return nullptr;
    	}
    }
    
    
    class CBMaxExporterClassDesc : public ClassDesc2 
    {
    public:
    	virtual int IsPublic() 							{ return TRUE; }
    	virtual void* Create(BOOL /*loading = FALSE*/) 		{ return new CBMaxExporter(); }
    	virtual const TCHAR *	ClassName() 			{ return GetString(IDS_CLASS_NAME); }
    	virtual SClass_ID SuperClassID() 				{ return SCENE_EXPORT_CLASS_ID; }
    	virtual Class_ID ClassID() 						{ return CBMaxExporter_CLASS_ID; }
    	virtual const TCHAR* Category() 				{ return GetString(IDS_CATEGORY); }
    
    	virtual const TCHAR* InternalName() 			{ return _T("CBMaxExporter"); }	// returns fixed parsable name (scripter-visible name)
    	virtual HINSTANCE HInstance() 					{ return hInstance; }					// returns owning module handle
    	
    
    };
    
    
    ClassDesc2* GetCBMaxExporterDesc() { 
    	static CBMaxExporterClassDesc CBMaxExporterDesc;
    	return &CBMaxExporterDesc; 
    }
    
    
    
    
    
    INT_PTR CALLBACK CBMaxExporterOptionsDlgProc(HWND hWnd,UINT message,WPARAM,LPARAM lParam) {
    	static CBMaxExporter* imp = nullptr;
    
    	switch(message) {
    		case WM_INITDIALOG:
    			imp = (CBMaxExporter *)lParam;
    			CenterWindow(hWnd,GetParent(hWnd));
    			return TRUE;
    
    		case WM_CLOSE:
    			EndDialog(hWnd, 0);
    			return 1;
    	}
    	return 0;
    }
    
    
    //--- CBMaxExporter -------------------------------------------------------
    CBMaxExporter::CBMaxExporter()
    {
    	
    }
    
    CBMaxExporter::~CBMaxExporter() 
    {
    
    }
    
    int CBMaxExporter::ExtCount()
    {
    	#pragma message(TODO("Returns the number of file name extensions supported by the plug-in."))
    	return 1;
    }
    
    const TCHAR *CBMaxExporter::Ext(int /*i*/)
    {		
    	#pragma message(TODO("Return the 'i-th' file name extension (i.e. \"3DS\")."))
    	return _T("CBE");
    }
    
    const TCHAR *CBMaxExporter::LongDesc()
    {
    	#pragma message(TODO("Return long ASCII description (i.e. \"Targa 2.0 Image File\")"))
    	return _T("");
    }
    	
    const TCHAR *CBMaxExporter::ShortDesc() 
    {			
    	#pragma message(TODO("Return short ASCII description (i.e. \"Targa\")"))
    	return _T("CBExporter");
    }
    
    const TCHAR *CBMaxExporter::AuthorName()
    {			
    	#pragma message(TODO("Return ASCII Author name"))
    	return _T("");
    }
    
    const TCHAR *CBMaxExporter::CopyrightMessage() 
    {	
    	#pragma message(TODO("Return ASCII Copyright message"))
    	return _T("");
    }
    
    const TCHAR *CBMaxExporter::OtherMessage1() 
    {		
    	//TODO: Return Other message #1 if any
    	return _T("");
    }
    
    const TCHAR *CBMaxExporter::OtherMessage2() 
    {		
    	//TODO: Return other message #2 in any
    	return _T("");
    }
    
    unsigned int CBMaxExporter::Version()
    {				
    	#pragma message(TODO("Return Version number * 100 (i.e. v3.01 = 301)"))
    	return 100;
    }
    
    void CBMaxExporter::ShowAbout(HWND /*hWnd*/)
    {			
    	// Optional
    }
    
    BOOL CBMaxExporter::SupportsOptions(int /*ext*/, DWORD /*options*/)
    {
    	#pragma message(TODO("Decide which options to support.  Simply return true for each option supported by each Extension the exporter supports."))
    	return TRUE;
    }
    
    
    int MaxSceneSaver::callback(  INode * node  ) {
    
    	processNode( node );
    	return TREE_CONTINUE;
    }
    
    
    void MaxSceneSaver::processNode( INode * node ) {
    
    	int deleteIt;
    	TriObject * triObject;
    	triObject = GetTriObjectFromNode( g_interfaceFromDoExport, node, deleteIt );
    	if ( triObject == nullptr ) {
    		// Object conversion failed during GetTriObjectFromNode
    		// Display Error Message
    		int errorNum = 3;
    
    	} else {
    		// Object was successfully converted to a TriObject 
    		Mesh & triObjectMesh = triObject->mesh;
    		Point3 vert;
    		for ( size_t i = 0; i < triObject->mesh.numFaces; ++i ) {
    			for ( size_t j = 0; j < cbengine::NUM_VERTS_IN_TRIANGLE; ++j ) {
    
    				Face triFace = triObjectMesh.faces[i];
    				TVFace triTVFace = triObjectMesh.tvFace[i];
    
    				vert = triObjectMesh.verts[ triObjectMesh.faces[i].v[j] ];
    
    			} // end inner for 
    		} // end outer for
    	}
    }
    
    int	CBMaxExporter::DoExport(const TCHAR* nameOfOutputFile, ExpInterface* expInterface, Interface* interf, BOOL suppressPrompts, DWORD options )
    {
    	#pragma message(TODO("Implement the actual file Export here and"))
    	
    	if(!suppressPrompts)
    		DialogBoxParam(hInstance, 
    				MAKEINTRESOURCE(IDD_PANEL), 
    				GetActiveWindow(), 
    				CBMaxExporterOptionsDlgProc, (LPARAM)this);
    
    	#pragma message(TODO("return TRUE If the file is exported properly"))
    
    	g_interfaceFromDoExport = interf;
    	m_exportSelected = (options & SCENE_EXPORT_SELECTED) ? true : false;
    
    	m_IGameScene = GetIGameInterface();
    	IGameConversionManager * conversionManager = GetConversionManager();
    	assert( m_IGameScene != nullptr );
    	m_IGameScene->InitialiseIGame( m_exportSelected );
    
    	std::string exportFileName;
    	cbengine::convertWideCharToString( nameOfOutputFile, exportFileName );
    
    	std::vector exportNodes;
    	cbengine::ExtractAllNodeMeshDataFromScene( *(m_IGameScene), exportNodes );
    
    	CBMeshFileExporter fileExporter( exportFileName, CBMeshFileExporter::TYPE_BINARY );
    	fileExporter.exportMaxNodeDataToFile( exportNodes );
    	
    	// Clean up
    	cbengine::ReleaseAndCleanUpIGameData( exportNodes );
    	m_IGameScene->ReleaseIGame();
    	m_IGameScene = nullptr;
    
    	return TRUE;
    }
    							
  • CBMeshFileExporter.hpp

    #ifndef included_CBMeshFileExporter
    #define included_CBMeshFileExporter
    #pragma once
    
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    #include 
    
    #include "CBExportSkinnedMesh.hpp"
    #include "CBExportMesh.hpp"
    #include "CBExportNode.hpp"
    #include "CBTriBatch.hpp"
    #include "CBMaterialManager.hpp"
    #include "CBStringHelper.hpp"
    #include "CBSkeletalBoneManager.hpp"
    #include "CBSkeletalBone.hpp"
    
    const std::string SKINNED_MESH_TYPE_STRING	= "SkinnedMesh";
    const std::string NODE_TYPE_STRING			= "Node";
    const std::string MESH_TYPE_STRING			= "Mesh";
    const std::string BONE_TYPE_STRING			= "Bone";
    const int		  NUM_BONES_TO_EXPORT		= 4;
    
    class CBMeshFileExporter {
    public:
    	typedef enum {
    		TYPE_TEXT,
    		TYPE_BINARY
    	} FileType;
    
    	~CBMeshFileExporter();
    	explicit CBMeshFileExporter( const std::string& exportFileName, FileType fileType );
    
    	bool exportMaxNodeDataToFile( const std::vector& exportNodes );
    	
    	// Convenience Functions
    	void getDiffuseTextureFilePath( IGameMaterial* material, std::string& diffuseTextureName );
    	void getSpecularColorTextureFilePath( IGameMaterial* material, std::string& specularColorTextureName );
    	void getSpecularLevelTextureFilePath( IGameMaterial* material, std::string& specularLevelTextureName );
    	void getNormalMapTextureFilePath( IGameMaterial* material, std::string& normalMapTextureName );
    	void getEmissiveTextureFilePath( IGameMaterial* material, std::string& emissiveTextureName );
    
    	// Inline Mutators
    	const FileType getFileType() const;
    protected:
    
    	bool exportMeshDataToFileAsText( const std::vector& exportMeshes );
    	bool exportMaxNodeDataToFileAsBinary( const std::vector& exportNodes );
    
    	//Binary
    	void writeMaterialsToBinaryFile( std::ofstream* binaryExportFile, int materialNumber, IGameMaterial* material );
    	void writeNodeDataVectorToBinaryFile( std::ofstream* binaryExportFile, const std::vector& exportNodes );
    	void writeNodeDataToBinaryFile( std::ofstream* binaryExportFile, CBExportNode* nodeToWrite );
    	void writeMeshDataToBinaryFile( std::ofstream* binaryExportFile, CBExportMesh* meshToWrite );
    	void writeSkinnedMeshDataToBinaryFile( std::ofstream* binaryExportFile, CBExportSkinnedMesh* meshToWrite );
    	void writeBoneNodeDataToBinaryFile( std::ofstream* binaryExportFile, CBExportNode* boneNodeToWrite );
    	void writeTriangleBatchDataToBinaryFile( std::ofstream* binaryExportFile, CBExportMesh* meshToWrite );
    	void writeSkinnedTriangleBatchDataToBinaryFile( std::ofstream* binaryExportFile, CBExportSkinnedMesh* meshToWrite );
    	
    	
    private:
    	FileType		m_fileType;
    	std::string		m_fileName;
    	mutable bool	m_exportedToFile;
    
    };
    
    
    inline const CBMeshFileExporter::FileType CBMeshFileExporter::getFileType() const {
    	return m_fileType;
    }
    
    #endif
    							
  • CBMeshFileExporter.cpp

    #include "CBMeshFileExporter.hpp"
    
    #include 
    
    #include "Vertex.hpp"
    #include "CBMeshVertex.hpp"
    
    CBMeshFileExporter::~CBMeshFileExporter() {
    
    }
    
    
    CBMeshFileExporter::CBMeshFileExporter( const std::string& exportFileName, FileType fileType ) {
    
    	m_fileName = exportFileName;
    	m_fileType = fileType;
    	m_exportedToFile = false;
    }
    
    
    bool CBMeshFileExporter::exportMaxNodeDataToFile( const std::vector& exportNodes ) {
    
    	bool didExport = false;
    
    	didExport = exportMaxNodeDataToFileAsBinary( exportNodes );
    	
    	return didExport;
    }
    
    
    bool CBMeshFileExporter::exportMaxNodeDataToFileAsBinary( const std::vector& exportNodes ) {
    
    	CBMaterialManager& materialManager = CBMaterialManager::getSharedMaterialManager();
    	materialManager.formMaterialToIDMappingsForExistingMaterials();
    
    	std::ofstream* binaryOutputFile = new std::ofstream( m_fileName.c_str(), std::ios::binary | std::ios::out ); 
    
    	// Export Materials First
    	std::map& materialIDMappings = materialManager.getMaterialIDMappings();
    	std::map::iterator itMaterial;
    
    	int numMaterials = static_cast( materialIDMappings.size() );
    
    	binaryOutputFile->write( (char*) &numMaterials, sizeof( numMaterials ) );
    
    	for ( itMaterial = materialIDMappings.begin(); itMaterial != materialIDMappings.end(); ++itMaterial ) {
    
    		IGameMaterial* material = itMaterial->first;
    		int materialID = itMaterial->second;
    		writeMaterialsToBinaryFile( binaryOutputFile, materialID, material );
    	}
    
    	writeNodeDataVectorToBinaryFile( binaryOutputFile, exportNodes );
    
    	binaryOutputFile->flush();
    	binaryOutputFile->close();
    
    	delete binaryOutputFile;
    
    	return true;
    }
    
    void CBMeshFileExporter::writeMaterialsToBinaryFile( std::ofstream* binaryExportFile, int materialNumber, IGameMaterial* material ) {
    
    	if ( material != nullptr ) {
    
    		binaryExportFile->write( (char*) &materialNumber, sizeof( materialNumber ) );
    
    		const TCHAR* materialNameAsWChar = material->GetMaterialName();
    		std::string materialNameAsString;
    		cbengine::convertWideCharToString( materialNameAsWChar, materialNameAsString );
    		int sizeOfMaterialNameString = static_cast( materialNameAsString.size() );
    
    		binaryExportFile->write( (char*) &sizeOfMaterialNameString, sizeof( sizeOfMaterialNameString ) );
    		binaryExportFile->write( &materialNameAsString[0], sizeOfMaterialNameString );
    		
    		std::string diffuseTextureName;
    		getDiffuseTextureFilePath( material, diffuseTextureName );
    		int sizeOfDiffuseTexture = static_cast( diffuseTextureName.size() );
    		binaryExportFile->write( (char*) &sizeOfDiffuseTexture, sizeof( sizeOfDiffuseTexture ) );
    		binaryExportFile->write( &diffuseTextureName[0],  sizeOfDiffuseTexture );
    		
    		std::string normalTextureName;
    		getNormalMapTextureFilePath( material, normalTextureName );
    		int sizeOfNormalTexture = static_cast( normalTextureName.size() );
    		binaryExportFile->write( (char*) &sizeOfNormalTexture, sizeof( sizeOfNormalTexture ) );
    		binaryExportFile->write( (char*) &normalTextureName[0], sizeOfNormalTexture );
    
    		std::string specularLevelTextureName;
    		getSpecularLevelTextureFilePath( material, specularLevelTextureName );
    		int sizeOfSpecularLevelTexture = static_cast( specularLevelTextureName.size() );
    		binaryExportFile->write( (char*) &sizeOfSpecularLevelTexture, sizeof( sizeOfSpecularLevelTexture ) );
    		binaryExportFile->write( (char*) &specularLevelTextureName[0], sizeOfSpecularLevelTexture );
    
    		std::string specularColorTextureName;
    		getSpecularColorTextureFilePath( material, specularColorTextureName );
    		int sizeOfSpecularColorTexture = static_cast( specularColorTextureName.size() );
    		binaryExportFile->write( (char*) &sizeOfSpecularColorTexture, sizeof( sizeOfSpecularColorTexture ) );
    		binaryExportFile->write( (char*) &specularColorTextureName[0], sizeOfSpecularColorTexture );
    
    		std::string emissiveTextureName;
    		getEmissiveTextureFilePath( material, emissiveTextureName );
    		int sizeOfEmissiveTexture = static_cast( emissiveTextureName.size() );
    		binaryExportFile->write( (char*) &sizeOfEmissiveTexture, sizeof( sizeOfEmissiveTexture ) );
    		binaryExportFile->write( (char*) &emissiveTextureName[0], sizeOfEmissiveTexture );
    
    	} 
    }
    
    
    void CBMeshFileExporter::writeNodeDataVectorToBinaryFile( std::ofstream* binaryExportFile, const std::vector& exportNodes ) {
    
    	int totalNumberOfNodes = static_cast( exportNodes.size() );
    	binaryExportFile->write( (char*) &totalNumberOfNodes, sizeof( totalNumberOfNodes ) );
    
    	for ( size_t i = 0; i < exportNodes.size(); ++i ) {
    
    		CBExportNode* exportNode = exportNodes[i];
    		const ExportNodeType& nodeType = exportNode->getExportNodeType();
    
    		if ( nodeType == TYPE_EXPORT_NODE) {
    
    			writeNodeDataToBinaryFile( binaryExportFile, exportNode );
    
    		} else if ( nodeType == TYPE_EXPORT_MESH ) {
    
    			CBExportMesh* exportMesh = static_cast( exportNode );
    			writeMeshDataToBinaryFile( binaryExportFile, exportMesh );
    
    		} else if ( nodeType == TYPE_EXPORT_BONE ) {
    
    			writeBoneNodeDataToBinaryFile( binaryExportFile, exportNode );
    
    		} else if ( nodeType == TYPE_EXPORT_SKINNED_MESH ) {
    
    			CBExportSkinnedMesh* exportSkinnedMesh = static_cast( exportNode );
    			writeSkinnedMeshDataToBinaryFile( binaryExportFile, exportSkinnedMesh );
    
    		}
    	}
    	
    }
    
    void CBMeshFileExporter::writeNodeDataToBinaryFile( std::ofstream* binaryExportFile, CBExportNode* nodeToWrite ) {
    
    	// Write the node type
    	int sizeOfNodeString = static_cast( NODE_TYPE_STRING.size() );
    	binaryExportFile->write( (char*) &sizeOfNodeString, sizeof( sizeOfNodeString ) );
    	binaryExportFile->write( &NODE_TYPE_STRING[0], sizeOfNodeString );
    
    	const std::string& nodeNameString = nodeToWrite->getNodeName();
    	int sizeOfNodeNameString = static_cast( nodeNameString.size() );
    	binaryExportFile->write( (char*) &sizeOfNodeNameString, sizeof( sizeOfNodeNameString ) );
    	binaryExportFile->write( (char*) &nodeNameString[0], sizeOfNodeNameString );
    
    	// Write the index of the node
    	int nodeIndex = nodeToWrite->getNodeIndex();
    	binaryExportFile->write( (char*) &nodeIndex, sizeof( nodeIndex ) );
    
    	// Write the parent index
    	int parentIndex = -1;
    	CBExportNode* exportNodeParent = nodeToWrite->getParentNode();
    	if ( exportNodeParent != nullptr ) {
    
    		parentIndex = exportNodeParent->getNodeIndex();
    	} 
    
    	binaryExportFile->write( (char*) &parentIndex, sizeof( parentIndex ) );
    	
    	// Local to World Transform
    	const GMatrix& localToWorldTransform = nodeToWrite->getInitialLocalToWorldTransformationMatrix();
    	binaryExportFile->write( (char*) &localToWorldTransform.GetAddr()[0], sizeof( GMatrix ) );
    
    	// World to Local Transform
    	const GMatrix& worldToLocalTransform = nodeToWrite->getInitialWorldToLocalTransformationMatrix();
    	binaryExportFile->write( (char*) &worldToLocalTransform.GetAddr()[0], sizeof( GMatrix ) );
    
    	const std::vector& animationVector = nodeToWrite->getAnimationTransformations();
    	int numberOfAnimTransformations = static_cast( animationVector.size() );
    
    	bool shouldExportAnimationList = false;
    	if ( numberOfAnimTransformations == 0 ) {
    
    		shouldExportAnimationList = false;
    	} else {
    		const GMatrix& firstMatrix = animationVector[0];
    		for ( int i = 1; i < numberOfAnimTransformations; ++i ) {
    
    			const GMatrix& matrixToCheck = animationVector[i];
    			if ( !firstMatrix.Equals( matrixToCheck ) ) {
    				shouldExportAnimationList = true;
    				break;
    			}
    		}
    	}
    
    	if ( shouldExportAnimationList ) {
    		binaryExportFile->write( (char*) &numberOfAnimTransformations, sizeof( numberOfAnimTransformations ) );
    		// Animations
    		for ( int i = 0; i < numberOfAnimTransformations; ++i ) {
    
    			const GMatrix& animTransform = animationVector[i];
    			binaryExportFile->write( (char*) &animTransform.GetAddr()[0], sizeof( GMatrix ) );
    		}
    
    	} else {
    
    		if ( numberOfAnimTransformations > 0 ) {
    
    			numberOfAnimTransformations = 1;
    			binaryExportFile->write( (char*) &numberOfAnimTransformations, sizeof( numberOfAnimTransformations ) );
    			const GMatrix& firstMatrix = animationVector[0];
    			binaryExportFile->write( (char*) &firstMatrix.GetAddr()[0], sizeof( GMatrix ) );
    		} else {
    
    			numberOfAnimTransformations = 0;
    			binaryExportFile->write( (char*) &numberOfAnimTransformations, sizeof( numberOfAnimTransformations ) );
    		}
    	}
    	
    }
    
    
    void CBMeshFileExporter::writeBoneNodeDataToBinaryFile( std::ofstream* binaryExportFile, CBExportNode* boneNodeToWrite ) {
    
    	// Write the node type
    	int sizeOfNodeString = static_cast( BONE_TYPE_STRING.size() );
    	binaryExportFile->write( (char*) &sizeOfNodeString, sizeof( sizeOfNodeString ) );
    	binaryExportFile->write( &BONE_TYPE_STRING[0], sizeOfNodeString );
    
    	const std::string& nodeNameString = boneNodeToWrite->getNodeName();
    	int sizeOfNodeNameString = static_cast( nodeNameString.size() );
    	binaryExportFile->write( (char*) &sizeOfNodeNameString, sizeof( sizeOfNodeNameString ) );
    	binaryExportFile->write( (char*) &nodeNameString[0], sizeOfNodeNameString );
    
    	// Write the index of the node
    	int nodeIndex = boneNodeToWrite->getNodeIndex();
    	binaryExportFile->write( (char*) &nodeIndex, sizeof( nodeIndex ) );
    
    	// Write out the bone index of the nodes
    	CBSkeletalBoneManager& skeletalBoneManager = CBSkeletalBoneManager::getSharedCBSkeletalBoneManager();
    	
    	int boneIndex = skeletalBoneManager.getBoneIndexForCBExportNode( boneNodeToWrite );
    	binaryExportFile->write( (char*) &boneIndex, sizeof( boneIndex ) );
    	assert( boneIndex != -1 );
    
    	// Write the parent index
    	int parentIndex = -1;
    	CBExportNode* exportNodeParent = boneNodeToWrite->getParentNode();
    	if ( exportNodeParent != nullptr ) {
    
    		parentIndex = exportNodeParent->getNodeIndex();
    	} 
    
    	binaryExportFile->write( (char*) &parentIndex, sizeof( parentIndex ) );
    
    	// Local to World Transform
    	const GMatrix& localToWorldTransform = boneNodeToWrite->getInitialLocalToWorldTransformationMatrix();
    	binaryExportFile->write( (char*) &localToWorldTransform.GetAddr()[0], sizeof( GMatrix ) );
    
    	// World to Local Transform
    	const GMatrix& worldToLocalTransform = boneNodeToWrite->getInitialWorldToLocalTransformationMatrix();
    	binaryExportFile->write( (char*) &worldToLocalTransform.GetAddr()[0], sizeof( GMatrix ) );
    
    	const std::vector& animationVector = boneNodeToWrite->getAnimationTransformations();
    	int numberOfAnimTransformations = static_cast( animationVector.size() );
    
    	bool shouldExportAnimationList = false;
    	if ( numberOfAnimTransformations == 0 ) {
    
    		shouldExportAnimationList = false;
    	} else {
    		const GMatrix& firstMatrix = animationVector[0];
    		for ( int i = 1; i < numberOfAnimTransformations; ++i ) {
    
    			const GMatrix& matrixToCheck = animationVector[i];
    			if ( !firstMatrix.Equals( matrixToCheck ) ) {
    				shouldExportAnimationList = true;
    				break;
    			}
    		}
    	}
    
    	if ( shouldExportAnimationList ) {
    		binaryExportFile->write( (char*) &numberOfAnimTransformations, sizeof( numberOfAnimTransformations ) );
    		// Animations
    		for ( int i = 0; i < numberOfAnimTransformations; ++i ) {
    
    			const GMatrix& animTransform = animationVector[i];
    			binaryExportFile->write( (char*) &animTransform.GetAddr()[0], sizeof( GMatrix ) );
    		}
    
    	} else {
    
    		if ( numberOfAnimTransformations > 0 ) {
    
    			numberOfAnimTransformations = 1;
    			binaryExportFile->write( (char*) &numberOfAnimTransformations, sizeof( numberOfAnimTransformations ) );
    			const GMatrix& firstMatrix = animationVector[0];
    			binaryExportFile->write( (char*) &firstMatrix.GetAddr()[0], sizeof( GMatrix ) );
    		} else {
    
    			numberOfAnimTransformations = 0;
    			binaryExportFile->write( (char*) &numberOfAnimTransformations, sizeof( numberOfAnimTransformations ) );
    		}
    	}
    
    }
    
    
    void CBMeshFileExporter::writeMeshDataToBinaryFile( std::ofstream* binaryExportFile, CBExportMesh* meshToWrite ) {
    
    	// Write the node type
    	int sizeOfMeshString = static_cast( MESH_TYPE_STRING.size() );
    	binaryExportFile->write( (char*) &sizeOfMeshString, sizeof( sizeOfMeshString ) );
    	binaryExportFile->write( &MESH_TYPE_STRING[0], sizeOfMeshString );
    
    	const std::string& nodeNameString = meshToWrite->getNodeName();
    	int sizeOfNodeNameString = static_cast( nodeNameString.size() );
    	binaryExportFile->write( (char*) &sizeOfNodeNameString, sizeof( sizeOfNodeNameString ) );
    	binaryExportFile->write( (char*) &nodeNameString[0], sizeOfNodeNameString );
    
    	// Write the index of the node
    	int nodeIndex = meshToWrite->getNodeIndex();
    	binaryExportFile->write( (char*) &nodeIndex, sizeof( nodeIndex ) );
    
    	// Write the parent index
    	int parentIndex = -1;
    	CBExportNode* exportNodeParent = meshToWrite->getParentNode();
    	if ( exportNodeParent != nullptr ) {
    
    		parentIndex = exportNodeParent->getNodeIndex();
    	} 
    
    	binaryExportFile->write( (char*) &parentIndex, sizeof( parentIndex ) );
    
    	// Local to World Transform
    	const GMatrix& localToWorldTransform = meshToWrite->getInitialLocalToWorldTransformationMatrix();
    	binaryExportFile->write( (char*) &localToWorldTransform.GetAddr()[0], sizeof( GMatrix ) );
    
    	// World to Local Transform
    	const GMatrix& worldToLocalTransform = meshToWrite->getInitialWorldToLocalTransformationMatrix();
    	binaryExportFile->write( (char*) &worldToLocalTransform.GetAddr()[0], sizeof( GMatrix ) );
    
    	const std::vector& animationVector = meshToWrite->getAnimationTransformations();
    	int numberOfAnimTransformations = static_cast( animationVector.size() );
    
    	// Animations
    	bool shouldExportAnimationList = false;
    	if ( numberOfAnimTransformations == 0 ) {
    
    		shouldExportAnimationList = false;
    	} else {
    		const GMatrix& firstMatrix = animationVector[0];
    		for ( int i = 1; i < numberOfAnimTransformations; ++i ) {
    
    			const GMatrix& matrixToCheck = animationVector[i];
    			if ( !firstMatrix.Equals( matrixToCheck ) ) {
    				shouldExportAnimationList = true;
    				break;
    			}
    		}
    	}
    
    	if ( shouldExportAnimationList ) {
    
    		binaryExportFile->write( (char*) &numberOfAnimTransformations, sizeof( numberOfAnimTransformations ) );
    
    		for ( int i = 0; i < numberOfAnimTransformations; ++i ) {
    
    			const GMatrix& animTransform = animationVector[i];
    			binaryExportFile->write( (char*) &animTransform.GetAddr()[0], sizeof( GMatrix ) );
    		}
    
    	} else {
    
    		if ( numberOfAnimTransformations > 0 ) {
    
    			numberOfAnimTransformations = 1;
    			binaryExportFile->write( (char*) &numberOfAnimTransformations, sizeof( numberOfAnimTransformations ) );
    			const GMatrix& firstMatrix = animationVector[0];
    			binaryExportFile->write( (char*) &firstMatrix.GetAddr()[0], sizeof( GMatrix ) );
    
    		} else {
    
    			numberOfAnimTransformations = 0;
    			binaryExportFile->write( (char*) &numberOfAnimTransformations, sizeof( numberOfAnimTransformations ) );
    		}
    	}
    
    	// Extract Mesh Tribatches
    	writeTriangleBatchDataToBinaryFile( binaryExportFile, meshToWrite );
    }
    
    
    void CBMeshFileExporter::writeSkinnedMeshDataToBinaryFile( std::ofstream* binaryExportFile, CBExportSkinnedMesh* meshToWrite ) {
    
    	// Write the node type
    	int sizeOfSkinnedMeshString = static_cast( SKINNED_MESH_TYPE_STRING.size() );
    	binaryExportFile->write( (char*) &sizeOfSkinnedMeshString, sizeof( sizeOfSkinnedMeshString ) );
    	binaryExportFile->write( &SKINNED_MESH_TYPE_STRING[0], sizeOfSkinnedMeshString );
    
    	const std::string& nodeNameString = meshToWrite->getNodeName();
    	int sizeOfNodeNameString = static_cast( nodeNameString.size() );
    	binaryExportFile->write( (char*) &sizeOfNodeNameString, sizeof( sizeOfNodeNameString ) );
    	binaryExportFile->write( (char*) &nodeNameString[0], sizeOfNodeNameString );
    
    	// Write the index of the node
    	int nodeIndex = meshToWrite->getNodeIndex();
    	binaryExportFile->write( (char*) &nodeIndex, sizeof( nodeIndex ) );
    
    	// Write the parent index
    	int parentIndex = -1;
    	CBExportNode* exportNodeParent = meshToWrite->getParentNode();
    	if ( exportNodeParent != nullptr ) {
    
    		parentIndex = exportNodeParent->getNodeIndex();
    	} 
    
    	binaryExportFile->write( (char*) &parentIndex, sizeof( parentIndex ) );
    
    	// Local to World Transform
    	const GMatrix& localToWorldTransform = meshToWrite->getInitialLocalToWorldTransformationMatrix();
    	binaryExportFile->write( (char*) &localToWorldTransform.GetAddr()[0], sizeof( GMatrix ) );
    
    	// World to Local Transform
    	const GMatrix& worldToLocalTransform = meshToWrite->getInitialWorldToLocalTransformationMatrix();
    	binaryExportFile->write( (char*) &worldToLocalTransform.GetAddr()[0], sizeof( GMatrix ) );
    
    	const std::vector& animationVector = meshToWrite->getAnimationTransformations();
    	int numberOfAnimTransformations = static_cast( animationVector.size() );
    
    	// Animations
    	bool shouldExportAnimationList = false;
    	if ( numberOfAnimTransformations == 0 ) {
    
    		shouldExportAnimationList = false;
    	} else {
    		const GMatrix& firstMatrix = animationVector[0];
    		for ( int i = 1; i < numberOfAnimTransformations; ++i ) {
    
    			const GMatrix& matrixToCheck = animationVector[i];
    			if ( !firstMatrix.Equals( matrixToCheck ) ) {
    				shouldExportAnimationList = true;
    				break;
    			}
    		}
    	}
    
    	if ( shouldExportAnimationList ) {
    
    		binaryExportFile->write( (char*) &numberOfAnimTransformations, sizeof( numberOfAnimTransformations ) );
    
    		for ( int i = 0; i < numberOfAnimTransformations; ++i ) {
    
    			const GMatrix& animTransform = animationVector[i];
    			binaryExportFile->write( (char*) &animTransform.GetAddr()[0], sizeof( GMatrix ) );
    		}
    
    	} else {
    
    		if ( numberOfAnimTransformations > 0 ) {
    
    			numberOfAnimTransformations = 1;
    			binaryExportFile->write( (char*) &numberOfAnimTransformations, sizeof( numberOfAnimTransformations ) );
    			const GMatrix& firstMatrix = animationVector[0];
    			binaryExportFile->write( (char*) &firstMatrix.GetAddr()[0], sizeof( GMatrix ) );
    
    		} else {
    
    			numberOfAnimTransformations = 0;
    			binaryExportFile->write( (char*) &numberOfAnimTransformations, sizeof( numberOfAnimTransformations ) );
    		}
    	}
    
    	// Extract Skinned Mesh Tribatches
    	writeSkinnedTriangleBatchDataToBinaryFile( binaryExportFile, meshToWrite );
    
    }
    
    
    void CBMeshFileExporter::writeTriangleBatchDataToBinaryFile( std::ofstream* binaryExportFile, CBExportMesh* meshToWrite ) {
    
    	CBMaterialManager& materialManager = CBMaterialManager::getSharedMaterialManager();
    
    	int totalNumTriBatches = 0;
    	const std::map& triBatchMap =  meshToWrite->getTriBatchMap();
    	totalNumTriBatches = static_cast( triBatchMap.size() );
    	binaryExportFile->write( (char*) &totalNumTriBatches, sizeof( totalNumTriBatches ) );
    
    	std::map::const_iterator itBatch;
    	for ( itBatch = triBatchMap.begin(); itBatch != triBatchMap.end(); ++itBatch ) {
    
    		IGameMaterial* batchMaterial = itBatch->first;
    		CBTriBatch* triBatch = itBatch->second;
    
    		int materialIndex = materialManager.getIndexOfIGameMaterial( batchMaterial );
    		if ( materialIndex != MATERIAL_NOT_FOUND ) {
    
    			binaryExportFile->write( (char*) &materialIndex, sizeof( materialIndex ) );
    
    			const std::vector& triBatchVerts = triBatch->getVerts();
    			int numVertsInBatch = static_cast( triBatchVerts.size() );
    
    			binaryExportFile->write( (char*) &numVertsInBatch, sizeof( numVertsInBatch ) );
    
    			for ( int i = 0; i < numVertsInBatch; ++i ) {
    
    				const CBMeshVertex& meshVert = triBatchVerts[i];
    				const cbengine::Vertex& vert = meshVert.getVertex();
    				binaryExportFile->write( (char*) &vert, sizeof( cbengine::Vertex ) );
    			}
    
    		} else {
    			// SHIT
    			assert( true == true );
    		}
    	}
    }
    
    
    void CBMeshFileExporter::writeSkinnedTriangleBatchDataToBinaryFile( std::ofstream* binaryExportFile, CBExportSkinnedMesh* meshToWrite ) {
    	
    	CBMaterialManager& materialManager = CBMaterialManager::getSharedMaterialManager();
    
    	int totalNumTriBatches = 0;
    	const std::map& triBatchMap =  meshToWrite->getTriBatchMap();
    	totalNumTriBatches = static_cast( triBatchMap.size() );
    	binaryExportFile->write( (char*) &totalNumTriBatches, sizeof( totalNumTriBatches ) );
    
    	std::map::const_iterator itBatch;
    	for ( itBatch = triBatchMap.begin(); itBatch != triBatchMap.end(); ++itBatch ) {
    
    		IGameMaterial* batchMaterial = itBatch->first;
    		CBTriBatch* triBatch = itBatch->second;
    
    		int materialIndex = materialManager.getIndexOfIGameMaterial( batchMaterial );
    		if ( materialIndex != MATERIAL_NOT_FOUND ) {
    
    			binaryExportFile->write( (char*) &materialIndex, sizeof( materialIndex ) );
    
    			const std::vector& triBatchVerts = triBatch->getVerts();
    			int numVertsInBatch = static_cast( triBatchVerts.size() );
    
    			binaryExportFile->write( (char*) &numVertsInBatch, sizeof( numVertsInBatch ) );
    
    			for ( int i = 0; i < numVertsInBatch; ++i ) {
    
    				// Extract Vert Data
    				const CBMeshVertex& meshVert = triBatchVerts[i];
    				const cbengine::Vertex& vert = meshVert.getVertex();
    				binaryExportFile->write( (char*) &vert, sizeof( cbengine::Vertex ) );
    
    				// Extract Bone Data
    				const std::multiset& vertBones = meshVert.getSkeletalBones();
    				std::multiset::const_iterator itBone;
    				int numBones = static_cast( vertBones.size() );
    				
    				binaryExportFile->write( (char*) &numBones, sizeof( numBones ) );
    
    				for ( itBone = vertBones.begin(); itBone != vertBones.end(); ++itBone ) {
    
    					const CBSkeletalBone& boneToExtract = *(itBone);
    					int boneIndex = boneToExtract.getBoneIndex();
    					float boneWeight = boneToExtract.getBoneWeight();
    
    					binaryExportFile->write( (char*) &boneIndex, sizeof( boneIndex ) );
    					binaryExportFile->write( (char*) &boneWeight, sizeof( boneWeight ) );
    				}
    			}
    
    		} else {
    			// SHIT
    			assert( true == true );
    		}
    	}
    
    }
    
    
    void CBMeshFileExporter::getDiffuseTextureFilePath( IGameMaterial* material, std::string& diffuseTextureName ) {
    
    	diffuseTextureName = "None";
    	if ( material == nullptr ) {
    		return;
    	}
    
    	int textureCount = material->GetNumberOfTextureMaps();
    	for ( int j = 0; j < textureCount; ++j ) {
    		IGameTextureMap* textureMap = material->GetIGameTextureMap(j);
    		if ( textureMap != nullptr ) {
    			if ( textureMap->IsEntitySupported() ) {
    				int textureType = textureMap->GetStdMapSlot();
    				if ( textureType == ID_DI ) {
    					const TCHAR* textureNameWideChar = textureMap->GetBitmapFileName();
    					cbengine::convertWideCharToString( textureNameWideChar, diffuseTextureName );
    				}
    				
    			}
    		}
    	}
    }
    
    
    void CBMeshFileExporter::getSpecularColorTextureFilePath( IGameMaterial* material, std::string& specularTextureName ) {
    
    	specularTextureName = "None";
    	if ( material == nullptr ) {
    		return;
    	}
    
    	int textureCount = material->GetNumberOfTextureMaps();
    	for ( int j = 0; j < textureCount; ++j ) {
    		IGameTextureMap* textureMap = material->GetIGameTextureMap(j);
    		if ( textureMap != nullptr ) {
    			if ( textureMap->IsEntitySupported() ) {
    				int textureType = textureMap->GetStdMapSlot();
    				if ( textureType == ID_SP ) { // SPEC COLOR
    					const TCHAR* textureNameWideChar = textureMap->GetBitmapFileName();
    					cbengine::convertWideCharToString( textureNameWideChar, specularTextureName );
    				}
    
    			}
    		}
    	}
    
    }
    
    
    void CBMeshFileExporter::getSpecularLevelTextureFilePath( IGameMaterial* material, std::string& specularLevelTextureName ) {
    
    	specularLevelTextureName = "None";
    	if ( material == nullptr ) {
    		return;
    	}
    
    	int textureCount = material->GetNumberOfTextureMaps();
    	for ( int j = 0; j < textureCount; ++j ) {
    		IGameTextureMap* textureMap = material->GetIGameTextureMap(j);
    		if ( textureMap != nullptr ) {
    			if ( textureMap->IsEntitySupported() ) {
    				int textureType = textureMap->GetStdMapSlot();
    				if ( textureType == ID_SS ) { // SPEC COLOR
    					const TCHAR* textureNameWideChar = textureMap->GetBitmapFileName();
    					cbengine::convertWideCharToString( textureNameWideChar, specularLevelTextureName );
    				}
    
    			}
    		}
    	}
    
    }
    
    
    void CBMeshFileExporter::getNormalMapTextureFilePath( IGameMaterial* material, std::string& normalMapTextureName ) {
    
    	normalMapTextureName = "None";
    	if ( material == nullptr ) {
    		return;
    	}
    
    	int textureCount = material->GetNumberOfTextureMaps();
    	for ( int j = 0; j < textureCount; ++j ) {
    		IGameTextureMap* textureMap = material->GetIGameTextureMap(j);
    		if ( textureMap != nullptr ) {
    			if ( textureMap->IsEntitySupported() ) {
    				int textureType = textureMap->GetStdMapSlot();
    				if ( textureType == ID_BU ) {
    					const TCHAR* textureNameWideChar = textureMap->GetBitmapFileName();
    					cbengine::convertWideCharToString( textureNameWideChar, normalMapTextureName );
    				} 
    			} else {
    				// no supported by IGameTextureMap, lets check if we can support it otherwise
    				Mtl* maxmtl = material->GetMaxMaterial();
    				StdMat* stdmtl = 0;
    				if ( maxmtl && maxmtl->ClassID() == Class_ID(DMTL_CLASS_ID,0) )
    					stdmtl = static_cast( maxmtl );
    				StdMat2* stdmtl2 = 0;
    				if ( stdmtl && stdmtl->SupportsShaders() )
    					stdmtl2 = static_cast( stdmtl );
    
    				if ( stdmtl )
    				{
    					const int mapslot = ID_BU;
    
    					const int chn = stdmtl2 ? stdmtl2->StdIDToChannel(mapslot) : mapslot;
    					Texmap*	texmap = stdmtl->GetSubTexmap( chn );
    					if ( texmap->NumSubTexmaps() > 0 )
    					{
    						Texmap* submap = texmap->GetSubTexmap( 0 );
    						if ( submap && submap->ClassID() == Class_ID(BMTEX_CLASS_ID,0) )
    						{
    							BitmapTex* bmptex = static_cast( submap );
    							if ( bmptex->GetMapName() )
    							{
    								const TCHAR* textureNameWideChar = bmptex->GetMapName();
    								cbengine::convertWideCharToString( textureNameWideChar, normalMapTextureName );
    								// NOTE: we dont support crop or uv offset/tiling but we just ignore those here
    							}
    						}
    					}
    				}
    			}
    		}
    	}
    }
    
    void CBMeshFileExporter::getEmissiveTextureFilePath( IGameMaterial* material, std::string& emissiveTextureName ) {
    
    	emissiveTextureName = "None";
    	if ( material == nullptr ) {
    		return;
    	}
    
    	int textureCount = material->GetNumberOfTextureMaps();
    	for ( int j = 0; j < textureCount; ++j ) {
    		IGameTextureMap* textureMap = material->GetIGameTextureMap(j);
    		if ( textureMap != nullptr ) {
    			if ( textureMap->IsEntitySupported() ) {
    				int textureType = textureMap->GetStdMapSlot();
    				if ( textureType == ID_SI ) {
    					const TCHAR* textureNameWideChar = textureMap->GetBitmapFileName();
    					cbengine::convertWideCharToString( textureNameWideChar, emissiveTextureName );
    				} 
    			}
    		}
    	}
    }
    							
  • CBExportNode.hpp

    #ifndef included_CBExportNode
    #define included_CBExportNode
    #pragma once
    
    // STD lib
    #include 
    #include 
    #include 
    
    // 3DS Max
    #include 
    
    // CBEngine
    #include "Vector2.hpp"
    #include "Vector3D.hpp"
    #include "Vector4.hpp"
    #include "Vertex.hpp"
    
    typedef enum {
    
    	TYPE_EXPORT_NODE,
    	TYPE_EXPORT_MESH,
    	TYPE_EXPORT_SKINNED_MESH,
    	TYPE_EXPORT_BONE,
    
    } ExportNodeType;
    
    class CBExportNode {
    public:
    	virtual ~CBExportNode();
    	explicit CBExportNode();
    
    	// Animations
    	virtual const std::vector& getAnimationTransformations() const;
    	virtual void addAnimationTransformation( const GMatrix& matrixToAdd );
    
    	// Inline Mutators
    
    	virtual void setExportNodeType( ExportNodeType nodeType );
    	virtual const ExportNodeType& getExportNodeType() const;
    
    	virtual void setParentNode( CBExportNode* parentNode );
    	virtual CBExportNode* CBExportNode::getParentNode() const;
    	virtual void setNodeName( const std::string& nodeName );
    	virtual const std::string& getNodeName() const;
    
    	virtual void setInitialWorldToLocalTransformationMatrix( const GMatrix& initialWorldToLocalTransform );
    	virtual const GMatrix& getInitialWorldToLocalTransformationMatrix() const;
    	virtual void setInitialLocalToWorldTransformationMatrix( const GMatrix& initialLocalToWorldTransform );
    	virtual const GMatrix& getInitialLocalToWorldTransformationMatrix() const;
    
    	void setNodeIndex( int nodeIndex );
    	int getNodeIndex() const;
    
    	void setIGameNode( IGameNode* nodeGeneratedFrom );
    	IGameNode* getIGameNode();
    protected:
    
    	void setExportNodeDefaults();
    
    	CBExportNode*								m_parentNode;
    	std::string									m_nodeName;
    	std::vector						m_animationTransformations;
    	GMatrix										m_initialWorldToLocalTransformationMatrix;
    	GMatrix										m_initialLocalToWorldTransformationMatrix;
    	
    	ExportNodeType								m_nodeType;
    
    	IGameNode*									m_IGameNode;
    private:
    	
    	int											m_nodeIndex;
    };
    
    
    // Inline Functions
    inline void CBExportNode::setExportNodeDefaults() {
    
    	m_nodeType = TYPE_EXPORT_NODE;
    	m_parentNode = nullptr;
    	m_nodeIndex = -1;
    }
    
    // Inline Mutators
    
    inline void CBExportNode::setExportNodeType( ExportNodeType nodeType ) {
    
    	m_nodeType = nodeType;
    }
    
    
    inline const ExportNodeType& CBExportNode::getExportNodeType() const {
    
    	return m_nodeType;
    }
    
    
    inline void CBExportNode::setParentNode( CBExportNode* parentNode ) {
    
    	m_parentNode = parentNode;
    }
    
    
    inline CBExportNode* CBExportNode::getParentNode() const {
    
    	return m_parentNode;
    }
    
    
    inline const std::vector& CBExportNode::getAnimationTransformations() const {
    
    	return m_animationTransformations;
    }
    
    
    inline void CBExportNode::setNodeName( const std::string& nodeName ) {
    	m_nodeName = nodeName;
    }
    
    
    inline const std::string& CBExportNode::getNodeName() const {
    	return m_nodeName;
    }
    
    inline void CBExportNode::addAnimationTransformation( const GMatrix& matrixToAdd ) {
    
    	m_animationTransformations.push_back( matrixToAdd );
    }
    
    
    inline void CBExportNode::setInitialWorldToLocalTransformationMatrix( const GMatrix& initialWorldToLocalTransform ) {
    
    	m_initialWorldToLocalTransformationMatrix = initialWorldToLocalTransform;
    }
    
    
    inline const GMatrix& CBExportNode::getInitialWorldToLocalTransformationMatrix() const {
    
    	return m_initialWorldToLocalTransformationMatrix;
    }
    
    
    inline void CBExportNode::setInitialLocalToWorldTransformationMatrix( const GMatrix& initialLocalToWorldTransform ) {
    
    	m_initialLocalToWorldTransformationMatrix = initialLocalToWorldTransform;
    }
    
    
    inline const GMatrix& CBExportNode::getInitialLocalToWorldTransformationMatrix() const {
    
    	return m_initialLocalToWorldTransformationMatrix;
    }
    
    
    inline void CBExportNode::setNodeIndex( int nodeIndex ) {
    
    	m_nodeIndex = nodeIndex;
    }
    
    
    inline int CBExportNode::getNodeIndex() const {
    	
    	return m_nodeIndex;
    }
    
    
    inline void CBExportNode::setIGameNode( IGameNode* nodeGeneratedFrom ) {
    
    	m_IGameNode = nodeGeneratedFrom;
    }
    
    
    inline IGameNode* CBExportNode::getIGameNode() {
    
    	return m_IGameNode;
    }
    
    #endif
    							
  • CBExportMesh.hpp

    #ifndef included_CBExportMesh
    #define included_CBExportMesh
    #pragma once
    
    #include "CBExportNode.hpp"
    
    #include "CBTriBatch.hpp"
    
    namespace cbengine {
    
    	const size_t NUM_VERTS_IN_TRIANGLE = 3;
    
    } // end namespace
    
    
    class CBExportMesh : public CBExportNode {
    public:
    	virtual ~CBExportMesh();
    	explicit CBExportMesh();
    
    	virtual void extractMeshVertexData( IGameMesh& maxMesh );
    
    	// Inline mutators
    	const std::map& getTriBatchMap() const;
    
    protected:
    	void setExportMeshDefaults();
    
    	// Inline Helper Functions
    	virtual void setPointToPositionInVertex( const Point3& positionPoint, cbengine::Vertex& vert  );
    	virtual void setPointToColorInVertex( const Point3& colorPoint, const float alphaValue, cbengine::Vertex& vert );
    	virtual void setPointToNormalInVertex( const Point3& normalPoint, cbengine::Vertex& vert );
    	virtual void setPointToTangentInVerteX( const Point3& tangentPoint, cbengine::Vertex& vert );
    	virtual void setPointToBitangentInVertex( const Point3& bitangentPoint, cbengine::Vertex& vert );
    	virtual void setPointToTextureCoordInVertex( const Point2& texCoordsPoint, cbengine::Vertex& vert );
    	
    	std::map		m_triBatches;
    	size_t										m_totalVerts;
    
    private:
    
    };
    
    // Inline Helper Functions
    inline void CBExportMesh::setPointToPositionInVertex( const Point3& positionPoint, cbengine::Vertex& vert ) {
    
    	vert.vertexPosition.x = positionPoint.x;
    	vert.vertexPosition.y = positionPoint.y;
    	vert.vertexPosition.z = positionPoint.z;
    }
    
    
    inline void CBExportMesh::setPointToColorInVertex( const Point3& colorPoint, const float alphaValue, cbengine::Vertex& vert ) {
    	/*
    	vert.vertexColor.x = colorPoint.x;
    	vert.vertexColor.y = colorPoint.y;
    	vert.vertexColor.z = colorPoint.z;
    	vert.vertexColor.w = alphaValue;
    	*/
    	vert.vertexColor.x = 1.0f;
    	vert.vertexColor.y = 1.0f;
    	vert.vertexColor.z = 1.0f;
    	vert.vertexColor.w = 1.0f;
    }
    
    
    inline void CBExportMesh::setPointToNormalInVertex( const Point3& normalPoint, cbengine::Vertex& vert ) {
    
    	vert.vertexNormal.x = normalPoint.x;
    	vert.vertexNormal.y = normalPoint.y;
    	vert.vertexNormal.z = normalPoint.z;
    }
    
    
    inline void CBExportMesh::setPointToTangentInVerteX( const Point3& tangentPoint, cbengine::Vertex& vert ) {
    
    	vert.vertexTangent.x = tangentPoint.x;
    	vert.vertexTangent.y = tangentPoint.y;
    	vert.vertexTangent.z = tangentPoint.z;
    }
    
    
    inline void CBExportMesh::setPointToBitangentInVertex( const Point3& bitangentPoint, cbengine::Vertex& vert ) {
    
    	vert.vertexBitangent.x = bitangentPoint.x;
    	vert.vertexBitangent.y = bitangentPoint.y;
    	vert.vertexBitangent.z = bitangentPoint.z;
    }
    
    
    inline void CBExportMesh::setPointToTextureCoordInVertex( const Point2& texCoordsPoint, cbengine::Vertex& vert ) {
    
    	vert.vertexTextureCoords.x = texCoordsPoint.x;
    	vert.vertexTextureCoords.y = texCoordsPoint.y;
    }
    
    // Inline Mutator Implementations
    inline const std::map& CBExportMesh::getTriBatchMap() const {
    	return m_triBatches;
    }
    
    
    #endif
    							
  • CBExportMesh.cpp

    #include "CBExportMesh.hpp"
    
    #include 
    
    #include 
    
    #include "CBStringHelper.hpp"
    #include "CBMaterialManager.hpp"
    
    #include "CBSkeletalBoneManager.hpp"
    
    CBExportMesh::~CBExportMesh() {
    	
    }
    
    
    CBExportMesh::CBExportMesh() {
    
    	setExportNodeDefaults();
    	setExportMeshDefaults();
    }
    
    
    void CBExportMesh::extractMeshVertexData( IGameMesh& maxMesh ) {
    
    	maxMesh.InitializeData();
    	size_t numFacesInMesh = maxMesh.GetNumberOfFaces();
    	m_totalVerts = ( numFacesInMesh * cbengine::NUM_VERTS_IN_TRIANGLE );
    	size_t numInvalidFaces = 0;
    	
    	for ( size_t i = 0; i < numFacesInMesh; ++i ) {
    
    		FaceEx * triFace = maxMesh.GetFace( static_cast(i ) );
    		if ( triFace == nullptr ) {
    			// TODO :: If this case occurs often, write code to handle this
    			++numInvalidFaces;
    			continue;
    		}
    		
    		CBMaterialManager& sharedMaterialManager = CBMaterialManager::getSharedMaterialManager();
    		CBTriBatch* currentTriBatch = nullptr;
    		IGameMaterial* triBatchMaterial = maxMesh.GetMaterialFromFace( triFace );
    		
    		sharedMaterialManager.addMaterialToRegistry( triBatchMaterial );
    		std::map::iterator it;
    		it = m_triBatches.find( triBatchMaterial );
    
    		if ( it != m_triBatches.end() ) {
    			currentTriBatch = it->second;
    		} else {
    			currentTriBatch = new CBTriBatch;
    			currentTriBatch->setTriBatchMaterial( triBatchMaterial );
    			m_triBatches.insert( std::pair( triBatchMaterial, currentTriBatch ) );
    		}
    		
    
    		// Extract Vertex Data
    		Point3 positionDataWorldSpace;
    		Point3 positionDataLocalSpace;
    		Point3 normalDataWorldSpace;
    		Point3 normalDataLocalSpace;
    		Point3 bitangentDataWorldSpace;
    		Point3 bitangentDataLocalspace;
    		Point3 tangentDataWorldSpace;
    		Point3 tangentDataLocalSpace;
    		Point3 colorData;
    		Point2 texCoords;
    		float  alphaValue;
    		cbengine::Vertex vert;
    		
    		for ( size_t faceVertIndex = 0; faceVertIndex < cbengine::NUM_VERTS_IN_TRIANGLE; ++faceVertIndex ) {
    			// Loop through each vertex in a face
    			
    			DWORD normalIndex = triFace->norm[faceVertIndex];
    			
    			maxMesh.GetVertex( triFace->vert[faceVertIndex], positionDataWorldSpace, false );
    			GMatrix worldToLocalTransformationMatrix = m_initialWorldToLocalTransformationMatrix;
    			positionDataLocalSpace =  positionDataWorldSpace * worldToLocalTransformationMatrix;
    			Point4 noTrans( 0.0f, 0.0f, 0.0f, 1.0f );
    			worldToLocalTransformationMatrix.SetRow( 3, noTrans );
    			maxMesh.GetNormal( normalIndex, normalDataWorldSpace, false );
    			normalDataLocalSpace = normalDataWorldSpace * worldToLocalTransformationMatrix;
    			maxMesh.GetTangent( normalIndex, tangentDataWorldSpace );
    			tangentDataLocalSpace = tangentDataWorldSpace * worldToLocalTransformationMatrix;
    			maxMesh.GetBinormal( normalIndex, bitangentDataWorldSpace );
    			bitangentDataLocalspace = bitangentDataWorldSpace * worldToLocalTransformationMatrix;
    			maxMesh.GetColorVertex( triFace->color[faceVertIndex], colorData );
    			maxMesh.GetTexVertex( triFace->texCoord[faceVertIndex], texCoords );
    			alphaValue = maxMesh.GetAlphaVertex( triFace->alpha[faceVertIndex] );
    
    			// Transfer point data to a single vertex object's data
    			setPointToPositionInVertex( positionDataLocalSpace, vert );
    			setPointToColorInVertex( colorData, alphaValue, vert );
    			setPointToNormalInVertex( normalDataLocalSpace, vert );
    			setPointToTangentInVerteX( tangentDataLocalSpace, vert );
    			setPointToBitangentInVertex( bitangentDataLocalspace, vert );
    			setPointToTextureCoordInVertex( texCoords, vert );
    			// Add vertex to the appropriate TriBatch
    			currentTriBatch->addVertex( vert );
    		} // end inner for
    	} // end for
    
    } // end extract function
    
    
    void CBExportMesh::setExportMeshDefaults() {
    
    	m_nodeType = TYPE_EXPORT_MESH;
    	m_totalVerts = 0;
    }
    							
  • CBTriBatch.hpp

    #ifndef included_CBTriBatch
    #define included_CBTriBatch
    #pragma once
    
    #include 
    #include 
    #include 
    
    #include 
    
    #include "Vertex.hpp"
    #include "CBMeshVertex.hpp"
    #include "CBSkeletalBone.hpp"
    
    class CBTriBatch {
    public:
    	explicit CBTriBatch();
    	~CBTriBatch();
    
    	void setTriBatchMaterial( IGameMaterial* batchMaterial );
    	void addVertex( const cbengine::Vertex& vertToAdd );
    	void addCBMeshVertex( const CBMeshVertex& meshVertexToAdd );
    	
    	std::vector& getVerts();
    protected:
    
    	void setTriBatchDefaults();
    
    	// Note: It is okay for material to be nullptr
    	IGameMaterial*							m_material;
    	std::vector				m_meshVerts;
    
    private:
    	
    
    };
    
    
    inline void CBTriBatch::addVertex( const cbengine::Vertex& vertToAdd ) {
    	
    	CBMeshVertex meshVertToAdd;
    	meshVertToAdd.setVertex( vertToAdd );
    	m_meshVerts.push_back( meshVertToAdd );
    }
    
    
    inline void CBTriBatch::addCBMeshVertex( const CBMeshVertex& meshVertexToAdd ) {
    
    	m_meshVerts.push_back( meshVertexToAdd );
    }
    
    // Note: It is okay for it to be nullptr
    inline void CBTriBatch::setTriBatchMaterial( IGameMaterial* batchMaterial ) {
    	m_material = batchMaterial;
    }
    
    
    inline std::vector& CBTriBatch::getVerts() {
    	return m_meshVerts;
    }
    
    #endif