Browse Source

FBX import mostly implemented - except VS2012 support...

Marko Pintera 13 years ago
parent
commit
7f69beadfe

+ 4 - 4
CamelotFBXImporter/CamelotFBXImporter.vcxproj

@@ -18,13 +18,13 @@
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
     <ConfigurationType>DynamicLibrary</ConfigurationType>
     <UseDebugLibraries>true</UseDebugLibraries>
-    <PlatformToolset>v110</PlatformToolset>
+    <PlatformToolset>v100</PlatformToolset>
     <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
     <ConfigurationType>DynamicLibrary</ConfigurationType>
     <UseDebugLibraries>false</UseDebugLibraries>
-    <PlatformToolset>v110</PlatformToolset>
+    <PlatformToolset>v100</PlatformToolset>
     <WholeProgramOptimization>true</WholeProgramOptimization>
     <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>
@@ -54,7 +54,7 @@
     <Link>
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <AdditionalLibraryDirectories>../lib/$(Configuration);../Dependencies/lib/Debug;./Dependencies/lib/Debug</AdditionalLibraryDirectories>
-      <AdditionalDependencies>CamelotRenderer.lib;CamelotUtility.lib;libboost_signals-vc110-mt-gd-1_49.lib;fbxsdk-2013.2-mdd.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalDependencies>CamelotRenderer.lib;CamelotUtility.lib;fbxsdk-2013.2-mdd.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <ImportLibrary>..\lib\$(Configuration)\$(TargetName).lib</ImportLibrary>
     </Link>
   </ItemDefinitionGroup>
@@ -72,7 +72,7 @@
       <EnableCOMDATFolding>true</EnableCOMDATFolding>
       <OptimizeReferences>true</OptimizeReferences>
       <AdditionalLibraryDirectories>../lib/$(Configuration);../Dependencies/lib/Release;./Dependencies/lib/Release</AdditionalLibraryDirectories>
-      <AdditionalDependencies>CamelotRenderer.lib;CamelotUtility.lib;libboost_signals-vc110-mt-1_49.lib;fbxsdk-2013.2-md.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalDependencies>CamelotRenderer.lib;CamelotUtility.lib;fbxsdk-2013.2-md.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <ImportLibrary>..\lib\$(Configuration)\$(TargetName).lib</ImportLibrary>
     </Link>
   </ItemDefinitionGroup>

+ 49 - 4
CamelotFBXImporter/Include/CmFBXImporter.h

@@ -4,10 +4,51 @@
 #include "CmSpecificImporter.h"
 #include "CmImporter.h"
 
+#define FBXSDK_NEW_API
+#include <fbxsdk.h>
+
 namespace CamelotEngine
 {
 	class CM_FBX_EXPORT FBXImporter : public SpecificImporter
 	{
+		struct FBXSubMeshData
+		{
+			FBXSubMeshData():
+				indexOffset(0), indexCount(0)
+			{ }
+
+			int indexOffset;
+			int indexCount;
+		};
+
+		struct FBXMeshData
+		{
+			FBXMeshData():
+				vertex(nullptr),
+				normal(nullptr),
+				tangent(nullptr),
+				bitangent(nullptr),
+				uv0(nullptr),
+				uv1(nullptr),
+				index(nullptr),
+				indexCount(0),
+				vertexCount(0)
+			{ }
+
+			Vector3* vertex;
+			Vector3* normal;
+			Vector3* tangent;
+			Vector3* bitangent;
+			Vector2* uv0;
+			Vector2* uv1;
+			int* index;
+
+			int indexCount;
+			int vertexCount;
+
+			vector<FBXSubMeshData>::type subMeshes;
+		};
+
 	public:
 		FBXImporter();
 		virtual ~FBXImporter();
@@ -32,12 +73,16 @@ namespace CamelotEngine
 		virtual bool isMagicNumberSupported(const UINT8* magicNumPtr, UINT32 numBytes) const; 
 
 		/** Inherited from SpecificImporter */
-		virtual ResourcePtr import(DataStreamPtr fileData);
+		virtual ResourcePtr import(const String& filePath);
 	private:
 		vector<String>::type mExtensions;
-		std::unordered_map<String, int> mExtensionToFID;
 
-		String magicNumToExtension(const UINT8* magic, UINT32 maxBytes) const;
-		TextureDataPtr importRawImage(DataStreamPtr fileData);
+		void startUpSdk(FbxManager*& manager, FbxScene*& scene);
+		void shutDownSdk(FbxManager* manager);
+
+		void loadScene(FbxManager* manager, FbxScene* scene, const String& filePath);
+		FBXMeshData* parseScene(FbxManager* manager, FbxScene* scene);
+
+		FBXMeshData* parseMesh(FbxMesh* mesh, bool createTangentsIfMissing = true);
 	};
 }

+ 479 - 6
CamelotFBXImporter/Source/CmFBXImporter.cpp

@@ -3,13 +3,16 @@
 #include "CmDebug.h"
 #include "CmDataStream.h"
 #include "CmPath.h"
+#include "CmVector2.h"
+#include "CmVector3.h"
+#include "CmVector4.h"
 
 namespace CamelotEngine
 {
 	FBXImporter::FBXImporter()
 		:SpecificImporter() 
 	{
-
+		mExtensions.push_back("fbx");
 	}
 
 	FBXImporter::~FBXImporter() 
@@ -27,19 +30,489 @@ namespace CamelotEngine
 
 	bool FBXImporter::isMagicNumberSupported(const UINT8* magicNumPtr, UINT32 numBytes) const
 	{
-		String ext = magicNumToExtension(magicNumPtr, numBytes);
+		return true; // FBX files can be plain-text so I don't even check for magic number
+	}
+
+	ResourcePtr FBXImporter::import(const String& filePath)
+	{
+		FbxManager* fbxManager = nullptr;
+		FbxScene* fbxScene = nullptr;
+
+		// TODO - Set up FBX allocators
+
+		startUpSdk(fbxManager, fbxScene);
+		loadScene(fbxManager, fbxScene, filePath);
 
-		return isExtensionSupported(ext);
+		FBXMeshData* mesh = parseScene(fbxManager, fbxScene);	
+
+		shutDownSdk(fbxManager);
+
+		// TODO - Free FBXMeshData
+
+		return nullptr;
 	}
 
-	String FBXImporter::magicNumToExtension(const UINT8* magic, UINT32 maxBytes) const
+	void FBXImporter::startUpSdk(FbxManager*& manager, FbxScene*& scene)
 	{
+		manager = FbxManager::Create();
+		if(manager == nullptr)
+			CM_EXCEPT(InternalErrorException, "FBX SDK failed to initialize. FbxManager::Create() failed.");
+
+		FbxIOSettings* ios = FbxIOSettings::Create(manager, IOSROOT);
+		manager->SetIOSettings(ios);
+
+		scene = FbxScene::Create(manager, "Import Scene");
+		if(scene == nullptr)
+			CM_EXCEPT(InternalErrorException, "Failed to create FBX scene.");
+	}
+
+	void FBXImporter::shutDownSdk(FbxManager* manager)
+	{
+		manager->Destroy();
+	}
+
+	void FBXImporter::loadScene(FbxManager* manager, FbxScene* scene, const String& filePath)
+	{
+		int lFileMajor, lFileMinor, lFileRevision;
+		int lSDKMajor,  lSDKMinor,  lSDKRevision;
+		FbxManager::GetFileFormatVersion(lSDKMajor, lSDKMinor, lSDKRevision);
+
+		FbxImporter* importer = FbxImporter::Create(manager, "");
+		bool importStatus = importer->Initialize(filePath.c_str(), -1, manager->GetIOSettings());
+		
+		importer->GetFileVersion(lFileMajor, lFileMinor, lFileRevision);
+
+		if(!importStatus)
+		{
+			CM_EXCEPT(InternalErrorException, "Call to FbxImporter::Initialize() failed.\n" +
+				String("Error returned: %s\n\n") + String(importer->GetLastErrorString()));
+		}
+
+		manager->GetIOSettings()->SetBoolProp(IMP_FBX_ANIMATION, false);
+		manager->GetIOSettings()->SetBoolProp(IMP_FBX_TEXTURE, false);
+		manager->GetIOSettings()->SetBoolProp(IMP_FBX_LINK, false);
+		manager->GetIOSettings()->SetBoolProp(IMP_FBX_GOBO, false);
+		manager->GetIOSettings()->SetBoolProp(IMP_FBX_SHAPE, false);
+
+		// TODO - Parse animations
+		// TODO - Parse blend shapes
+
+		importStatus = importer->Import(scene);
 
-		return StringUtil::BLANK;
+		if(!importStatus)
+		{
+			importer->Destroy();
+
+			CM_EXCEPT(InternalErrorException, "Call to FbxImporter::Initialize() failed.\n" +
+				String("Error returned: %s\n\n") + String(importer->GetLastErrorString()));
+		}
+
+		importer->Destroy();
 	}
 
-	ResourcePtr FBXImporter::import(DataStreamPtr fileData)
+	FBXImporter::FBXMeshData* FBXImporter::parseScene(FbxManager* manager, FbxScene* scene)
 	{
+		stack<FbxNode*>::type todo;
+		todo.push(scene->GetRootNode());
+
+		while(!todo.empty())
+		{
+			FbxNode* curNode = todo.top();
+			todo.pop();
+
+			const char* name = curNode->GetName();
+
+			FbxNodeAttribute* attrib = curNode->GetNodeAttribute();
+			if(attrib != nullptr)
+			{
+				FbxNodeAttribute::EType attribType = attrib->GetAttributeType();
+
+				switch(attribType)
+				{
+				case FbxNodeAttribute::eMesh:
+					{
+						FbxMesh* mesh = static_cast<FbxMesh*>(attrib);
+						if(!mesh->IsTriangleMesh())
+						{
+							FbxGeometryConverter geomConverter(manager);
+							geomConverter.TriangulateInPlace(curNode);
+							attrib = curNode->GetNodeAttribute();
+							mesh = static_cast<FbxMesh*>(attrib);
+						}
+
+						// TODO - We only parse the first mesh in the file. Later when I have prefabs or something similar
+						// we can parse an entire hierarchy
+						return parseMesh(mesh); 
+					}
+					break;
+				case FbxNodeAttribute::eSkeleton:
+					break; // TODO - I should probably implement skeleton parsing
+
+				}
+			}
+
+			for(int i = 0; i < curNode->GetChildCount(); i++)
+				todo.push(curNode->GetChild(i));
+		}
+
 		return nullptr;
 	}
+
+	FBXImporter::FBXMeshData* FBXImporter::parseMesh(FbxMesh* mesh, bool createTangentsIfMissing)
+	{
+		FBXMeshData* meshData = new FBXMeshData();
+
+		if (!mesh->GetNode())
+			return meshData;
+
+		if(createTangentsIfMissing && mesh->GetElementUVCount() > 0)
+			mesh->GenerateTangentsData(0, false);
+
+		const int lPolygonCount = mesh->GetPolygonCount();
+
+		// Count the polygon count of each material
+		FbxLayerElementArrayTemplate<int>* lMaterialIndice = NULL;
+		FbxGeometryElement::EMappingMode lMaterialMappingMode = FbxGeometryElement::eNone;
+		if (mesh->GetElementMaterial())
+		{
+			lMaterialIndice = &mesh->GetElementMaterial()->GetIndexArray();
+			lMaterialMappingMode = mesh->GetElementMaterial()->GetMappingMode();
+			if (lMaterialIndice && lMaterialMappingMode == FbxGeometryElement::eByPolygon)
+			{
+				FBX_ASSERT(lMaterialIndice->GetCount() == lPolygonCount);
+				if (lMaterialIndice->GetCount() == lPolygonCount)
+				{
+					// Count the faces of each material
+					for (int lPolygonIndex = 0; lPolygonIndex < lPolygonCount; ++lPolygonIndex)
+					{
+						const int lMaterialIndex = lMaterialIndice->GetAt(lPolygonIndex);
+						if (meshData->subMeshes.size() < lMaterialIndex + 1)
+						{
+							meshData->subMeshes.resize(lMaterialIndex + 1);
+						}
+
+						meshData->subMeshes[lMaterialIndex].indexCount += 3;
+					}
+
+					// Record the offset (how many vertex)
+					const int lMaterialCount = meshData->subMeshes.size();
+					int lOffset = 0;
+					for (int lIndex = 0; lIndex < lMaterialCount; ++lIndex)
+					{
+						meshData->subMeshes[lIndex].indexOffset = lOffset;
+						lOffset += meshData->subMeshes[lIndex].indexCount;
+						// This will be used as counter in the following procedures, reset to zero
+						meshData->subMeshes[lIndex].indexCount = 0;
+					}
+					FBX_ASSERT(lOffset == lPolygonCount * 3);
+				}
+			}
+		}
+
+		// All faces will use the same material.
+		if (meshData->subMeshes.size() == 0)
+			meshData->subMeshes.resize(1);
+
+		// Find out which vertex attributes exist
+		bool allByControlPoint = true;
+
+		bool hasNormal = mesh->GetElementNormalCount() > 0;
+		FbxGeometryElement::EMappingMode lNormalMappingMode = FbxGeometryElement::eNone;
+		
+		if (hasNormal)
+		{
+			lNormalMappingMode = mesh->GetElementNormal(0)->GetMappingMode();
+			if (lNormalMappingMode == FbxGeometryElement::eNone)
+			{
+				hasNormal = false;
+			}
+			if (hasNormal && lNormalMappingMode != FbxGeometryElement::eByControlPoint)
+			{
+				allByControlPoint = false;
+			}
+		}
+
+		bool hasTangent = mesh->GetElementTangentCount() > 0;
+		FbxGeometryElement::EMappingMode lTangentMappingMode = FbxGeometryElement::eNone;
+
+		if (hasTangent)
+		{
+			lTangentMappingMode = mesh->GetElementTangent(0)->GetMappingMode();
+			if (lTangentMappingMode == FbxGeometryElement::eNone)
+			{
+				hasTangent = false;
+			}
+			if (hasTangent && lTangentMappingMode != FbxGeometryElement::eByControlPoint)
+			{
+				allByControlPoint = false;
+			}
+		}
+
+		bool hasBitangent = mesh->GetElementBinormalCount() > 0;
+		FbxGeometryElement::EMappingMode lBitangentMappingMode = FbxGeometryElement::eNone;
+
+		if (hasBitangent)
+		{
+			lBitangentMappingMode = mesh->GetElementBinormal(0)->GetMappingMode();
+			if (lBitangentMappingMode == FbxGeometryElement::eNone)
+			{
+				hasBitangent = false;
+			}
+			if (hasBitangent && lBitangentMappingMode != FbxGeometryElement::eByControlPoint)
+			{
+				allByControlPoint = false;
+			}
+		}
+
+		bool hasUV0 = mesh->GetElementUVCount() > 0;
+		FbxGeometryElement::EMappingMode lUVMappingMode0 = FbxGeometryElement::eNone;
+		if (hasUV0)
+		{
+			lUVMappingMode0 = mesh->GetElementUV(0)->GetMappingMode();
+			if (lUVMappingMode0 == FbxGeometryElement::eNone)
+				hasUV0 = false;
+
+			if (hasUV0 && lUVMappingMode0 != FbxGeometryElement::eByControlPoint)
+				allByControlPoint = false;
+		}
+
+		bool hasUV1 = mesh->GetElementUVCount() > 1;
+		FbxGeometryElement::EMappingMode lUVMappingMode1 = FbxGeometryElement::eNone;
+		if (hasUV1)
+		{
+			lUVMappingMode1 = mesh->GetElementUV(1)->GetMappingMode();
+			if (lUVMappingMode1 == FbxGeometryElement::eNone)
+				hasUV1 = false;
+
+			if (hasUV1 && lUVMappingMode1 != FbxGeometryElement::eByControlPoint)
+				allByControlPoint = false;
+		}
+
+		// Allocate the array memory, by control point or by polygon vertex.
+		int lPolygonVertexCount = mesh->GetControlPointsCount();
+		if (!allByControlPoint)
+			lPolygonVertexCount = lPolygonCount * 3;
+
+		meshData->indexCount = lPolygonCount * 3;
+		meshData->vertexCount = lPolygonVertexCount;
+		
+		meshData->index = new int[lPolygonCount * 3];
+		meshData->vertex = new Vector3[lPolygonVertexCount];
+
+		if (hasNormal)
+			meshData->normal = new Vector3[lPolygonVertexCount];
+
+		if (hasTangent)
+			meshData->tangent = new Vector3[lPolygonVertexCount];
+
+		if (hasBitangent)
+			meshData->bitangent = new Vector3[lPolygonVertexCount];
+
+		FbxStringList lUVNames;
+		mesh->GetUVSetNames(lUVNames);
+		const char * lUVName0 = NULL;
+		if (hasUV0 && lUVNames.GetCount() > 0)
+		{
+			meshData->uv0 = new Vector2[lPolygonVertexCount];
+			lUVName0 = lUVNames[0];
+		}
+
+		const char * lUVName1 = NULL;
+		if (hasUV1 && lUVNames.GetCount() > 1)
+		{
+			meshData->uv1 = new Vector2[lPolygonVertexCount];
+			lUVName1 = lUVNames[1];
+		}
+
+		// Populate the array with vertex attribute, if by control point.
+		const FbxVector4 * lControlPoints = mesh->GetControlPoints();
+		FbxVector4 lCurrentVertex;
+		FbxVector4 lCurrentNormal;
+		FbxVector2 lCurrentUV;
+
+		const FbxGeometryElementTangent * lTangentElement = NULL;
+		if (hasTangent)
+			lTangentElement = mesh->GetElementTangent(0);
+
+		const FbxGeometryElementBinormal * lBitangentElement = NULL;
+		if (hasBitangent)
+			lBitangentElement = mesh->GetElementBinormal(0);
+
+		if (allByControlPoint)
+		{
+			const FbxGeometryElementNormal * lNormalElement = NULL;
+			if (hasNormal)
+				lNormalElement = mesh->GetElementNormal(0);
+
+			const FbxGeometryElementUV * lUVElement0 = NULL;
+			if (hasUV0)
+				lUVElement0 = mesh->GetElementUV(0);
+
+			const FbxGeometryElementUV * lUVElement1 = NULL;
+			if (hasUV1)
+				lUVElement1 = mesh->GetElementUV(1);
+
+			for (int lIndex = 0; lIndex < lPolygonVertexCount; ++lIndex)
+			{
+				// Save the vertex position.
+				lCurrentVertex = lControlPoints[lIndex];
+				meshData->vertex[lIndex][0] = static_cast<float>(lCurrentVertex[0]);
+				meshData->vertex[lIndex][1] = static_cast<float>(lCurrentVertex[1]);
+				meshData->vertex[lIndex][2] = static_cast<float>(lCurrentVertex[2]);
+
+				// Save the normal.
+				if (hasNormal)
+				{
+					int lNormalIndex = lIndex;
+					if (lNormalElement->GetReferenceMode() == FbxLayerElement::eIndexToDirect)
+						lNormalIndex = lNormalElement->GetIndexArray().GetAt(lIndex);
+
+					lCurrentNormal = lNormalElement->GetDirectArray().GetAt(lNormalIndex);
+					meshData->normal[lIndex][0] = static_cast<float>(lCurrentNormal[0]);
+					meshData->normal[lIndex][1] = static_cast<float>(lCurrentNormal[1]);
+					meshData->normal[lIndex][2] = static_cast<float>(lCurrentNormal[2]);
+				}
+
+				// Save the tangent.
+				if (hasTangent)
+				{
+					int lTangentIndex = lIndex;
+					if (lTangentElement->GetReferenceMode() == FbxLayerElement::eIndexToDirect)
+						lTangentIndex = lTangentElement->GetIndexArray().GetAt(lIndex);
+
+					FbxVector4 lCurrentTangent = lTangentElement->GetDirectArray().GetAt(lTangentIndex);
+					meshData->tangent[lIndex][0] = static_cast<float>(lCurrentTangent[0]);
+					meshData->tangent[lIndex][1] = static_cast<float>(lCurrentTangent[1]);
+					meshData->tangent[lIndex][2] = static_cast<float>(lCurrentTangent[2]);
+				}
+
+				// Save the tangent.
+				if (hasBitangent)
+				{
+					int lBitangentIndex = lIndex;
+					if (lBitangentElement->GetReferenceMode() == FbxLayerElement::eIndexToDirect)
+						lBitangentIndex = lBitangentElement->GetIndexArray().GetAt(lIndex);
+
+					FbxVector4 lCurrentBitangent = lBitangentElement->GetDirectArray().GetAt(lBitangentIndex);
+					meshData->bitangent[lIndex][0] = static_cast<float>(lCurrentBitangent[0]);
+					meshData->bitangent[lIndex][1] = static_cast<float>(lCurrentBitangent[1]);
+					meshData->bitangent[lIndex][2] = static_cast<float>(lCurrentBitangent[2]);
+				}
+
+				// Save the UV.
+				if (hasUV0)
+				{
+					int lUVIndex = lIndex;
+					if (lUVElement0->GetReferenceMode() == FbxLayerElement::eIndexToDirect)
+						lUVIndex = lUVElement0->GetIndexArray().GetAt(lIndex);
+
+					lCurrentUV = lUVElement0->GetDirectArray().GetAt(lUVIndex);
+					meshData->uv0[lIndex][0] = static_cast<float>(lCurrentUV[0]);
+					meshData->uv0[lIndex][1] = static_cast<float>(lCurrentUV[1]);
+				}
+
+				if (hasUV1)
+				{
+					int lUVIndex = lIndex;
+					if (lUVElement1->GetReferenceMode() == FbxLayerElement::eIndexToDirect)
+						lUVIndex = lUVElement1->GetIndexArray().GetAt(lIndex);
+
+					lCurrentUV = lUVElement1->GetDirectArray().GetAt(lUVIndex);
+					meshData->uv1[lIndex][0] = static_cast<float>(lCurrentUV[0]);
+					meshData->uv1[lIndex][1] = static_cast<float>(lCurrentUV[1]);
+				}
+			}
+		}
+
+		int lVertexCount = 0;
+		for (int lPolygonIndex = 0; lPolygonIndex < lPolygonCount; ++lPolygonIndex)
+		{
+			// The material for current face.
+			int lMaterialIndex = 0;
+			if (lMaterialIndice && lMaterialMappingMode == FbxGeometryElement::eByPolygon)
+			{
+				lMaterialIndex = lMaterialIndice->GetAt(lPolygonIndex);
+			}
+
+			// Where should I save the vertex attribute index, according to the material
+			const int lIndexOffset = meshData->subMeshes[lMaterialIndex].indexOffset + meshData->subMeshes[lMaterialIndex].indexCount;
+			for (int lVerticeIndex = 0; lVerticeIndex < 3; ++lVerticeIndex)
+			{
+				const int lControlPointIndex = mesh->GetPolygonVertex(lPolygonIndex, lVerticeIndex);
+
+				if (allByControlPoint)
+				{
+					meshData->index[lIndexOffset + lVerticeIndex] = static_cast<unsigned int>(lControlPointIndex);
+				}
+				// Populate the array with vertex attribute, if by polygon vertex.
+				else
+				{
+					meshData->index[lIndexOffset + lVerticeIndex] = static_cast<unsigned int>(lVertexCount);
+
+					lCurrentVertex = lControlPoints[lControlPointIndex];
+					meshData->vertex[lVertexCount][0] = static_cast<float>(lCurrentVertex[0]);
+					meshData->vertex[lVertexCount][1] = static_cast<float>(lCurrentVertex[1]);
+					meshData->vertex[lVertexCount][2] = static_cast<float>(lCurrentVertex[2]);
+
+					if (hasNormal)
+					{
+						mesh->GetPolygonVertexNormal(lPolygonIndex, lVerticeIndex, lCurrentNormal);
+						meshData->normal[lVertexCount][0] = static_cast<float>(lCurrentNormal[0]);
+						meshData->normal[lVertexCount][1] = static_cast<float>(lCurrentNormal[1]);
+						meshData->normal[lVertexCount][2] = static_cast<float>(lCurrentNormal[2]);
+					}
+
+					if (hasTangent)
+					{
+						int lTangentIndex = lIndexOffset + lVerticeIndex; // TODO - Is this right?
+						if (lTangentElement->GetReferenceMode() == FbxLayerElement::eIndexToDirect)
+							lTangentIndex = lTangentElement->GetIndexArray().GetAt(lTangentIndex);
+
+						FbxVector4 lCurrentTangent = lTangentElement->GetDirectArray().GetAt(lTangentIndex);
+						meshData->tangent[lVertexCount][0] = static_cast<float>(lCurrentTangent[0]);
+						meshData->tangent[lVertexCount][1] = static_cast<float>(lCurrentTangent[1]);
+						meshData->tangent[lVertexCount][2] = static_cast<float>(lCurrentTangent[2]);
+					}
+
+					if (hasBitangent)
+					{
+						int lBitangentIndex = lIndexOffset + lVerticeIndex; // TODO - Is this right?
+						if (lBitangentElement->GetReferenceMode() == FbxLayerElement::eIndexToDirect)
+							lBitangentIndex = lBitangentElement->GetIndexArray().GetAt(lBitangentIndex);
+
+						FbxVector4 lCurrentBitangent = lBitangentElement->GetDirectArray().GetAt(lBitangentIndex);
+						meshData->bitangent[lVertexCount][0] = static_cast<float>(lCurrentBitangent[0]);
+						meshData->bitangent[lVertexCount][1] = static_cast<float>(lCurrentBitangent[1]);
+						meshData->bitangent[lVertexCount][2] = static_cast<float>(lCurrentBitangent[2]);
+					}
+
+					if (hasNormal)
+					{
+						mesh->GetPolygonVertexNormal(lPolygonIndex, lVerticeIndex, lCurrentNormal);
+						meshData->normal[lVertexCount][0] = static_cast<float>(lCurrentNormal[0]);
+						meshData->normal[lVertexCount][1] = static_cast<float>(lCurrentNormal[1]);
+						meshData->normal[lVertexCount][2] = static_cast<float>(lCurrentNormal[2]);
+					}
+
+					if (hasUV0)
+					{
+						mesh->GetPolygonVertexUV(lPolygonIndex, lVerticeIndex, lUVName0, lCurrentUV);
+						meshData->uv0[lVertexCount][0] = static_cast<float>(lCurrentUV[0]);
+						meshData->uv0[lVertexCount][1] = static_cast<float>(lCurrentUV[1]);
+					}
+
+					if (hasUV1)
+					{
+						mesh->GetPolygonVertexUV(lPolygonIndex, lVerticeIndex, lUVName1, lCurrentUV);
+						meshData->uv1[lVertexCount][0] = static_cast<float>(lCurrentUV[0]);
+						meshData->uv1[lVertexCount][1] = static_cast<float>(lCurrentUV[1]);
+					}
+				}
+				++lVertexCount;
+			}
+
+			meshData->subMeshes[lMaterialIndex].indexCount += 3;
+		}
+
+	}
 }

+ 1 - 1
CamelotFreeImgImporter/Include/CmFreeImgImporter.h

@@ -32,7 +32,7 @@ namespace CamelotEngine
 		virtual bool isMagicNumberSupported(const UINT8* magicNumPtr, UINT32 numBytes) const; 
 
 		/** Inherited from SpecificImporter */
-		virtual ResourcePtr import(DataStreamPtr fileData);
+		virtual ResourcePtr import(const String& filePath);
 	private:
 		vector<String>::type mExtensions;
 		std::unordered_map<String, int> mExtensionToFID;

+ 6 - 1
CamelotFreeImgImporter/Source/CmFreeImgImporter.cpp

@@ -6,6 +6,7 @@
 #include "CmTextureData.h"
 #include "CmTextureManager.h"
 #include "CmTexture.h"
+#include "CmFileSystem.h"
 
 #include "FreeImage.h"
 
@@ -126,8 +127,10 @@ namespace CamelotEngine
 		}
 	}
 
-	ResourcePtr FreeImgImporter::import(DataStreamPtr fileData)
+	ResourcePtr FreeImgImporter::import(const String& filePath)
 	{
+		DataStreamPtr fileData = FileSystem::open(filePath, true);
+
 		TextureDataPtr imgData = importRawImage(fileData);
 		if(imgData == nullptr || imgData->getData() == nullptr)
 			return nullptr;
@@ -137,6 +140,8 @@ namespace CamelotEngine
 
 		newTexture->setTextureData(0, imgData);
 
+		fileData->close();
+
 		return newTexture;
 	}
 

+ 1 - 1
CamelotRenderer/Include/CmSpecificImporter.h

@@ -28,6 +28,6 @@ namespace CamelotEngine
 		 *
 		 * @return	null if it fails, otherwise the loaded object.
 		 */
-		virtual ResourcePtr import(DataStreamPtr fileData) = 0;
+		virtual ResourcePtr import(const String& filePath) = 0;
 	};
 }

+ 1 - 2
CamelotRenderer/Source/CmImporter.cpp

@@ -70,8 +70,7 @@ namespace CamelotEngine
 			}
 		}
 
-		DataStreamPtr fileSteam = FileSystem::open(inputFilePath, true);
-		ResourcePtr importedResource = importer->import(fileSteam);
+		ResourcePtr importedResource = importer->import(inputFilePath);
 		importedResource->load();
 
 		return importedResource;