Browse Source

More AssetImporter functionality.
Moved getD3DColor() as an inline function outside Renderer.
Fixed terminology in shaders: bitangent instead of binormal.

Lasse Öörni 15 years ago
parent
commit
e14db52ca0

+ 11 - 0
Engine/Common/Color.h

@@ -164,4 +164,15 @@ public:
     float mTime;
 };
 
+//! Return color packed to a 32-bit integer
+inline unsigned getD3DColor(const Color& color)
+{
+    unsigned r = (unsigned)(color.mR * 255.0f);
+    unsigned g = (unsigned)(color.mG * 255.0f);
+    unsigned b = (unsigned)(color.mB * 255.0f);
+    unsigned a = (unsigned)(color.mA * 255.0f);
+    
+    return (((a) & 0xff) << 24) | (((r) & 0xff) << 16) | (((g) & 0xff) << 8) | ((b) & 0xff);
+}
+
 #endif // COMMON_COLOR_H

+ 1 - 1
Engine/Renderer/BillboardSet.cpp

@@ -532,7 +532,7 @@ void BillboardSet::updateVertexBuffer(const FrameInfo& frame)
         else
             size = Vector2(mBillboards[index].mSize.mX * worldScale.mX, mBillboards[index].mSize.mY * worldScale.mY);
         
-        unsigned color = Renderer::getD3DColor(mBillboards[index].mColor);
+        unsigned color = getD3DColor(mBillboards[index].mColor);
         
         static float rotationMatrix[2][2];
         float angleRad = mBillboards[index].mRotation * M_DEGTORAD;

+ 6 - 6
Engine/Renderer/DebugRenderer.cpp

@@ -133,9 +133,9 @@ void DebugRenderer::render()
 void DebugRenderer::addLine(const Vector3& start, const Vector3& end, const Color& color, bool depthTest)
 {
     if (depthTest)
-        mLines.push_back(DebugLine(start, end, Renderer::getD3DColor(color)));
+        mLines.push_back(DebugLine(start, end, getD3DColor(color)));
     else
-        mNoDepthLines.push_back(DebugLine(start, end, Renderer::getD3DColor(color)));
+        mNoDepthLines.push_back(DebugLine(start, end, getD3DColor(color)));
 }
 
 void DebugRenderer::addBoundingBox(const BoundingBox& box, const Color& color, bool depthTest)
@@ -150,7 +150,7 @@ void DebugRenderer::addBoundingBox(const BoundingBox& box, const Color& color, b
     Vector3 v4(max.mX, min.mY, max.mZ);
     Vector3 v5(min.mX, max.mY, max.mZ);
     
-    unsigned d3dColor = Renderer::getD3DColor(color);
+    unsigned d3dColor = getD3DColor(color);
     
     std::vector<DebugLine>* dest = &mLines;
     if (!depthTest)
@@ -184,7 +184,7 @@ void DebugRenderer::addBoundingBox(const BoundingBox& box, const Matrix4x3& tran
     Vector3 v6(transform * Vector3(max.mX, max.mY, max.mZ));
     Vector3 v7(transform * Vector3(min.mX, max.mY, max.mZ));
     
-    unsigned d3dColor = Renderer::getD3DColor(color);
+    unsigned d3dColor = getD3DColor(color);
     
     std::vector<DebugLine>* dest = &mLines;
     if (!depthTest)
@@ -207,7 +207,7 @@ void DebugRenderer::addBoundingBox(const BoundingBox& box, const Matrix4x3& tran
 void DebugRenderer::addFrustum(const Frustum& frustum, const Color& color, bool depthTest)
 {
     const Vector3* vertices = frustum.getVertices();
-    unsigned d3dColor = Renderer::getD3DColor(color);
+    unsigned d3dColor = getD3DColor(color);
     
     std::vector<DebugLine>* dest = &mLines;
     if (!depthTest)
@@ -234,7 +234,7 @@ void DebugRenderer::addSkeleton(const Skeleton& skeleton, const Color& color, bo
         return;
     
     DebugLine newLine;
-    newLine.mColor = Renderer::getD3DColor(color);
+    newLine.mColor = getD3DColor(color);
     
     std::vector<DebugLine>* dest = &mLines;
     if (!depthTest)

+ 0 - 11
Engine/Renderer/Renderer.h

@@ -328,17 +328,6 @@ public:
     //! Return screen buffer for post-processing
     Texture2D* getScreenBuffer() const { return mScreenBuffer; }
     
-    //! Return color packed to a 32-bit integer
-    static unsigned getD3DColor(const Color& color)
-    {
-        unsigned r = (unsigned)(color.mR * 255.0f);
-        unsigned g = (unsigned)(color.mG * 255.0f);
-        unsigned b = (unsigned)(color.mB * 255.0f);
-        unsigned a = (unsigned)(color.mA * 255.0f);
-        
-        return (((a) & 0xff) << 24) | (((r) & 0xff) << 16) | (((g) & 0xff) << 8) | ((b) & 0xff);
-    }
-    
     //! Add a GPU object to keep track of. Called by GPUObject.
     void addGPUObject(GPUObject* object);
     //! Remove a GPU object. Called by GPUObject

+ 4 - 4
Engine/UI/UIBatch.cpp

@@ -67,7 +67,7 @@ void UIBatch::addQuad(UIElement& element, int x, int y, int width, int height, i
     else
     {
         const Color& color = element.getColor(C_TOPLEFT);
-        unsigned finalColor = Renderer::getD3DColor(Color(color.mR, color.mG, color.mB, element.getDerivedOpacity()));
+        unsigned finalColor = getD3DColor(Color(color.mR, color.mG, color.mB, element.getDerivedOpacity()));
         quad.mTopLeftColor = finalColor;
         quad.mTopRightColor = finalColor;
         quad.mBottomLeftColor = finalColor;
@@ -105,7 +105,7 @@ void UIBatch::addQuad(UIElement& element, int x, int y, int width, int height, i
     else
     {
         const Color& color = element.getColor(C_TOPLEFT);
-        unsigned finalColor = Renderer::getD3DColor(Color(color.mR, color.mG, color.mB, element.getDerivedOpacity()));
+        unsigned finalColor = getD3DColor(Color(color.mR, color.mG, color.mB, element.getDerivedOpacity()));
         quad.mTopLeftColor = finalColor;
         quad.mTopRightColor = finalColor;
         quad.mBottomLeftColor = finalColor;
@@ -256,11 +256,11 @@ unsigned UIBatch::getInterpolatedColor(UIElement& element, int x, int y)
         Color topColor = element.getColor(C_TOPLEFT).lerp(element.getColor(C_TOPRIGHT), cLerpX);
         Color bottomColor = element.getColor(C_BOTTOMLEFT).lerp(element.getColor(C_BOTTOMRIGHT), cLerpX);
         Color color = topColor.lerp(bottomColor, cLerpY);
-        return Renderer::getD3DColor(Color(color.mR, color.mG, color.mB, element.getDerivedOpacity()));
+        return getD3DColor(Color(color.mR, color.mG, color.mB, element.getDerivedOpacity()));
     }
     else
     {
         const Color& color = element.getColor(C_TOPLEFT);
-        return Renderer::getD3DColor(Color(color.mR, color.mG, color.mB, element.getDerivedOpacity()));
+        return getD3DColor(Color(color.mR, color.mG, color.mB, element.getDerivedOpacity()));
     }
 }

+ 4 - 4
SourceAssets/Shaders/Deferred/GBuffer.hlsl

@@ -22,7 +22,7 @@ void vs(float4 iPos : POSITION,
     #ifdef NORMALMAP
         out float3 oNormal : TEXCOORD2,
         out float3 oTangent : TEXCOORD3,
-        out float3 oBinormal : TEXCOORD4,
+        out float3 oBitangent : TEXCOORD4,
     #else
         out float3 oNormal : TEXCOORD2,
     #endif
@@ -62,7 +62,7 @@ void vs(float4 iPos : POSITION,
     oDepth = calculateDepth(oPos);
     
     #ifdef NORMALMAP
-        oBinormal = cross(oTangent, oNormal) * iTangent.w;
+        oBitangent = cross(oTangent, oNormal) * iTangent.w;
     #endif
 }
 
@@ -72,7 +72,7 @@ void ps(
     #ifdef NORMALMAP
         float3 iNormal : TEXCOORD2,
         float3 iTangent : TEXCOORD3,
-        float3 iBinormal : TEXCOORD4,
+        float3 iBitangent : TEXCOORD4,
     #else
         float3 iNormal : TEXCOORD2,
     #endif
@@ -94,7 +94,7 @@ void ps(
     #endif
 
     #ifdef NORMALMAP
-        float3x3 tbn = float3x3(iTangent, iBinormal, iNormal);
+        float3x3 tbn = float3x3(iTangent, iBitangent, iNormal);
         float3 normal = normalize(mul(unpackNormal(tex2D(sNormalMap, iTexCoord)), tbn));
     #else
         float3 normal = normalize(iNormal);

+ 4 - 4
SourceAssets/Shaders/Forward.hlsl

@@ -23,7 +23,7 @@ void vs(float4 iPos : POSITION,
     out float3 oNormal : TEXCOORD2,
     #ifdef NORMALMAP
         out float3 oTangent : TEXCOORD3,
-        out float3 oBinormal : TEXCOORD4,
+        out float3 oBitangent : TEXCOORD4,
     #endif
     #ifdef SHADOW
         out float4 oShadowPos : TEXCOORD5,
@@ -83,7 +83,7 @@ void vs(float4 iPos : POSITION,
     #endif
     
     #ifdef NORMALMAP
-        oBinormal = cross(oTangent, oNormal) * iTangent.w;
+        oBitangent = cross(oTangent, oNormal) * iTangent.w;
     #endif
     
     oTexCoord = evaluateTexCoord(iTexCoord);
@@ -94,7 +94,7 @@ void ps(float2 iTexCoord : TEXCOORD0,
     #ifdef NORMALMAP
         float3 iNormal : TEXCOORD2,
         float3 iTangent : TEXCOORD3,
-        float3 iBinormal : TEXCOORD4,
+        float3 iBitangent : TEXCOORD4,
     #else
         float3 iNormal : TEXCOORD2,
     #endif
@@ -129,7 +129,7 @@ void ps(float2 iTexCoord : TEXCOORD0,
         #ifndef NEGATIVE
             // Normal (positive) lighting
             #ifdef NORMALMAP
-                float3x3 tbn = float3x3(iTangent, iBinormal, iNormal);
+                float3x3 tbn = float3x3(iTangent, iBitangent, iNormal);
                 float3 normal = normalize(mul(unpackNormal(tex2D(sNormalMap, iTexCoord)), tbn));
             #else
                 float3 normal = normalize(iNormal);

+ 4 - 4
SourceAssets/Shaders/Prepass/GBuffer.hlsl

@@ -22,7 +22,7 @@ void vs(float4 iPos : POSITION,
     #ifdef NORMALMAP
         out float3 oNormal : TEXCOORD2,
         out float3 oTangent : TEXCOORD3,
-        out float3 oBinormal : TEXCOORD4,
+        out float3 oBitangent : TEXCOORD4,
     #else
         out float3 oNormal : TEXCOORD2,
     #endif
@@ -62,7 +62,7 @@ void vs(float4 iPos : POSITION,
     oDepth = calculateDepth(oPos);
     
     #ifdef NORMALMAP
-        oBinormal = cross(oTangent, oNormal) * iTangent.w;
+        oBitangent = cross(oTangent, oNormal) * iTangent.w;
     #endif
 }
 
@@ -72,7 +72,7 @@ void ps(
     #ifdef NORMALMAP
         float3 iNormal : TEXCOORD2,
         float3 iTangent : TEXCOORD3,
-        float3 iBinormal : TEXCOORD4,
+        float3 iBitangent : TEXCOORD4,
     #else
         float3 iNormal : TEXCOORD2,
     #endif
@@ -88,7 +88,7 @@ void ps(
     #endif
 
     #ifdef NORMALMAP
-        float3x3 tbn = float3x3(iTangent, iBinormal, iNormal);
+        float3x3 tbn = float3x3(iTangent, iBitangent, iNormal);
         float3 normal = normalize(mul(unpackNormal(tex2D(sNormalMap, iTexCoord)), tbn));
     #else
         float3 normal = normalize(iNormal);

+ 292 - 84
Tools/AssetImporter/AssetImporter.cpp

@@ -63,16 +63,23 @@ struct ExportModel
 
 int main(int argc, char** argv);
 void run(const std::vector<std::string>& arguments);
-void errorExit(const std::string& error);
+void dumpNodes(aiNode* rootNode, unsigned level);
 void exportModel(ExportModel& model);
 void collectMeshes(ExportModel& model, aiNode* node);
 void buildModel(ExportModel& model);
+void writeShortIndices(unsigned short*& dest, aiMesh* mesh, unsigned index, unsigned offset);
+void writeLargeIndices(unsigned*& dest, aiMesh* mesh, unsigned index, unsigned offset);
+void writeVertex(float*& dest, aiMesh* mesh, unsigned index, unsigned elementMask, BoundingBox& box,
+    const Matrix4x3& vertexTransform, const Matrix3& normalTransform);
+unsigned getElementMask(aiMesh* mesh);
+aiNode* findNode(const std::string& name, aiNode* rootNode);
 std::string toStdString(const aiString& str);
 Vector3 toVector3(const aiVector3D& vec);
 Vector2 toVector2(const aiVector2D& vec);
 Quaternion toQuaternion(const aiQuaternion& quat);
-aiMatrix4x4 getWorldTransform(aiNode* node, aiNode* baseNode);
+aiMatrix4x4 getWorldTransform(aiNode* node, aiNode* rootNode);
 void getPosRotScale(const aiMatrix4x4& transform, Vector3& pos, Quaternion& rot, Vector3& scale);
+void errorExit(const std::string& error);
 
 int main(int argc, char** argv)
 {
@@ -97,7 +104,7 @@ int main(int argc, char** argv)
 void run(const std::vector<std::string>& arguments)
 {
     if (arguments.size() < 2)
-        errorExit("Usage: AssetImporter <inputfile> <outputfile>\n");
+        errorExit("Usage: AssetImporter <inputfile> <outputfile> [rootnode]\n");
     
     Assimp::Importer importer;
     const aiScene* scene = importer.ReadFile(arguments[0].c_str(),
@@ -115,13 +122,46 @@ void run(const std::vector<std::string>& arguments)
     if (!scene)
         errorExit("Could not open input file " + arguments[0]);
     
+    dumpNodes(scene->mRootNode, 0);
+    
     ExportModel model;
     model.mOutName = arguments[1];
     model.mScene = scene;
-    model.mRootNode = scene->mRootNode;
+    
+    if (arguments.size() < 3)
+        model.mRootNode = scene->mRootNode;
+    else
+    {
+        model.mRootNode = findNode(arguments[2], scene->mRootNode);
+        if (!model.mRootNode)
+            errorExit("Could not find scene node " + arguments[2]);
+    }
+    
     exportModel(model);
 }
 
+void dumpNodes(aiNode* rootNode, unsigned level)
+{
+    if (!rootNode)
+        return;
+    
+    std::string indent;
+    indent.resize(level * 2);
+    for (unsigned i = 0; i < level * 2; ++i)
+        indent[i] = ' ';
+    
+    if (!rootNode->mNumMeshes)
+        std::cout << indent << "Node " << toStdString(rootNode->mName) << std::endl;
+    else
+    {
+        std::cout << indent << "Node " << toStdString(rootNode->mName) << " - " << rootNode->mNumMeshes << " geometries"
+            << std::endl;
+    }
+    
+    for (unsigned i = 0; i < rootNode->mNumChildren; ++i)
+        dumpNodes(rootNode->mChildren[i], level + 1);
+}
+
 void exportModel(ExportModel& model)
 {
     collectMeshes(model, model.mRootNode);
@@ -133,9 +173,17 @@ void collectMeshes(ExportModel& model, aiNode* node)
     for (unsigned i = 0; i < node->mNumMeshes; ++i)
     {
         aiMesh* mesh = model.mScene->mMeshes[node->mMeshes[i]];
+        for (unsigned j = 0; j < model.mMeshes.size(); ++j)
+        {
+            if (mesh == model.mMeshes[j])
+            {
+                std::cout << "Warning: same mesh found multiple times" << std::endl;
+                break;
+            }
+        }
+        
         model.mMeshes.push_back(mesh);
         model.mMeshNodes.push_back(node);
-        
         model.mTotalVertices += mesh->mNumVertices;
         model.mTotalIndices += mesh->mNumFaces * 3;
     }
@@ -146,109 +194,263 @@ void collectMeshes(ExportModel& model, aiNode* node)
 
 void buildModel(ExportModel& model)
 {
+    if (!model.mRootNode)
+        errorExit("Null root node for model");
+    if (!model.mMeshes.size())
+        errorExit("No meshes");
+    
+    std::cout << "Writing model from node " << toStdString(model.mRootNode->mName) << std::endl;
+    
     SharedPtr<Model> outModel(new Model(0));
     outModel->setNumGeometries(model.mMeshes.size());
     BoundingBox box;
     
-    for (unsigned i = 0; i < model.mMeshes.size(); ++i)
+    bool combineBuffers = true;
+    // Check if buffers can be combined (same vertex element mask, under 65535 vertices)
+    unsigned elementMask = getElementMask(model.mMeshes[0]);
+    for (unsigned i = 1; i < model.mMeshes.size(); ++i)
     {
-        SharedPtr<IndexBuffer> ib(new IndexBuffer(0));
-        SharedPtr<VertexBuffer> vb(new VertexBuffer(0));
-        SharedPtr<Geometry> geom(new Geometry());
-        
-        // Get the world transform of the mesh for baking into the vertices
-        Vector3 pos;
-        Quaternion rot;
-        Vector3 scale;
-        getPosRotScale(getWorldTransform(model.mMeshNodes[i], model.mRootNode), pos, rot, scale);
-        Matrix4x3 vertexTransform;
-        vertexTransform.define(pos, rot, scale);
-        Matrix3 normalTransform = rot.getRotationMatrix();
-        
-        aiMesh* mesh = model.mMeshes[i];
-        bool largeIndices = mesh->mNumVertices > 65535;
-        unsigned elementMask = MASK_POSITION;
-        if (mesh->HasNormals())
-            elementMask |= MASK_NORMAL;
-        //if (mesh->HasTangentsAndBitangents())
-        //    elementMask |= MASK_TANGENT;
-        //if (mesh->GetNumColorChannels() > 0)
-        //    elementMask |= MASK_COLOR;
-        if (mesh->GetNumUVChannels() > 0)
-            elementMask |= MASK_TEXCOORD1;
-        //if (mesh->GetNumUVChannels() > 1)
-        //    elementMask |= MASK_TEXCOORD2;
-        
-        ib->setSize(mesh->mNumFaces * 3, largeIndices);
-        vb->setSize(mesh->mNumVertices, elementMask);
-        
-        // Build the index data
-        void* indexData = ib->lock(0, ib->getIndexCount(), LOCK_NORMAL);
-        if (!largeIndices)
+        if (getElementMask(model.mMeshes[i]) != elementMask)
         {
-            unsigned short* dest = (unsigned short*)indexData;
-            for (unsigned j = 0; j < mesh->mNumFaces; ++j)
-            {
-                *dest++ = mesh->mFaces[j].mIndices[0];
-                *dest++ = mesh->mFaces[j].mIndices[1];
-                *dest++ = mesh->mFaces[j].mIndices[2];
-            }
+            combineBuffers = false;
+            break;
         }
-        else
+    }
+    // Check if keeping separate buffers allows to avoid 32-bit indices
+    if ((combineBuffers) && (model.mTotalVertices > 65535))
+    {
+        bool allUnder65k = true;
+        for (unsigned i = 0; i < model.mMeshes.size(); ++i)
         {
-            unsigned* dest = (unsigned*)indexData;
-            for (unsigned j = 0; j < mesh->mNumFaces; ++j)
-            {
-                *dest++ = mesh->mFaces[j].mIndices[0];
-                *dest++ = mesh->mFaces[j].mIndices[1];
-                *dest++ = mesh->mFaces[j].mIndices[2];
-            }
+            if (model.mMeshes[i]->mNumVertices > 65535)
+                allUnder65k = false;
         }
-        
-        // Build the vertex data
-        void* vertexData = vb->lock(0, vb->getVertexCount(), LOCK_NORMAL);
-        float* dest = (float*)vertexData;
-        for (unsigned j = 0; j < mesh->mNumVertices; ++j)
+        if (allUnder65k == true)
+            combineBuffers = false;
+    }
+    
+    if (!combineBuffers)
+    {
+        std::cout << "Using separate buffers" << std::endl;
+        for (unsigned i = 0; i < model.mMeshes.size(); ++i)
         {
-            Vector3 vertex = vertexTransform * toVector3(mesh->mVertices[j]);
-            box.merge(vertex);
-            *dest++ = vertex.mX;
-            *dest++ = vertex.mY;
-            *dest++ = vertex.mZ;
-            if (elementMask & MASK_NORMAL)
+            SharedPtr<IndexBuffer> ib(new IndexBuffer(0));
+            SharedPtr<VertexBuffer> vb(new VertexBuffer(0));
+            SharedPtr<Geometry> geom(new Geometry());
+            // Get the world transform of the mesh for baking into the vertices
+            Vector3 pos, scale;
+            Quaternion rot;
+            getPosRotScale(getWorldTransform(model.mMeshNodes[i], model.mRootNode), pos, rot, scale);
+            Matrix4x3 vertexTransform;
+            vertexTransform.define(pos, rot, scale);
+            Matrix3 normalTransform = rot.getRotationMatrix();
+            
+            aiMesh* mesh = model.mMeshes[i];
+            std::cout << "Geometry " << i << ": " << mesh->mNumVertices << " vertices " << mesh->mNumFaces * 3 << " indices"
+                << std::endl;
+            
+            bool largeIndices = mesh->mNumVertices > 65535;
+            unsigned elementMask = getElementMask(mesh);
+            
+            ib->setSize(mesh->mNumFaces * 3, largeIndices);
+            vb->setSize(mesh->mNumVertices, elementMask);
+            
+            // Build the index data
+            void* indexData = ib->lock(0, ib->getIndexCount(), LOCK_NORMAL);
+            if (!largeIndices)
             {
-                Vector3 normal = normalTransform * toVector3(mesh->mNormals[j]);
-                *dest++ = normal.mX;
-                *dest++ = normal.mY;
-                *dest++ = normal.mZ;
+                unsigned short* dest = (unsigned short*)indexData;
+                for (unsigned j = 0; j < mesh->mNumFaces; ++j)
+                    writeShortIndices(dest, mesh, j, 0);
             }
-            if (elementMask & MASK_TEXCOORD1)
+            else
             {
-                Vector3 texCoord = toVector3(mesh->mTextureCoords[0][j]);
-                *dest++ = texCoord.mX;
-                *dest++ = texCoord.mY;
+                unsigned* dest = (unsigned*)indexData;
+                for (unsigned j = 0; j < mesh->mNumFaces; ++j)
+                    writeLargeIndices(dest, mesh, j, 0);
             }
+            
+            // Build the vertex data
+            void* vertexData = vb->lock(0, vb->getVertexCount(), LOCK_NORMAL);
+            float* dest = (float*)vertexData;
+            for (unsigned j = 0; j < mesh->mNumVertices; ++j)
+                writeVertex(dest, mesh, j, elementMask, box, vertexTransform, normalTransform);
+            
+            ib->unlock();
+            vb->unlock();
+            
+            // Define the geometry
+            geom->setIndexBuffer(ib);
+            geom->setVertexBuffer(0, vb);
+            geom->setDrawRange(TRIANGLE_LIST, 0, mesh->mNumFaces * 3, true);
+            outModel->setNumGeometryLodLevels(i, 1);
+            outModel->setGeometry(i, 0, geom);
         }
+    }
+    else
+    {
+        std::cout << "Using combined buffers" << std::endl;
+        SharedPtr<IndexBuffer> ib(new IndexBuffer(0));
+        SharedPtr<VertexBuffer> vb(new VertexBuffer(0));
         
+        bool largeIndices = model.mTotalIndices > 65535;
+        ib->setSize(model.mTotalIndices, largeIndices);
+        vb->setSize(model.mTotalVertices, elementMask);
+        
+        unsigned startVertexOffset = 0;
+        unsigned startIndexOffset = 0;
+        void* indexData = ib->lock(0, ib->getIndexCount(), LOCK_NORMAL);
+        void* vertexData = vb->lock(0, vb->getVertexCount(), LOCK_NORMAL);
+        // The buffer is in CPU memory, and therefore locking is irrelevant. Unlock so that draw range checking can lock again
         ib->unlock();
         vb->unlock();
         
-        // Define the geometry
-        geom->setIndexBuffer(ib);
-        geom->setVertexBuffer(0, vb);
-        geom->setDrawRange(TRIANGLE_LIST, 0, mesh->mNumFaces * 3, true);
-        outModel->setNumGeometryLodLevels(i, 1);
-        outModel->setGeometry(i, 0, geom);
-        outModel->setBoundingBox(box);
+        for (unsigned i = 0; i < model.mMeshes.size(); ++i)
+        {
+            SharedPtr<Geometry> geom(new Geometry());
+            
+            // Get the world transform of the mesh for baking into the vertices
+            Vector3 pos, scale;
+            Quaternion rot;
+            getPosRotScale(getWorldTransform(model.mMeshNodes[i], model.mRootNode), pos, rot, scale);
+            Matrix4x3 vertexTransform;
+            vertexTransform.define(pos, rot, scale);
+            Matrix3 normalTransform = rot.getRotationMatrix();
+            
+            aiMesh* mesh = model.mMeshes[i];
+            std::cout << "Geometry " << i << ": " << mesh->mNumVertices << " vertices " << mesh->mNumFaces * 3 << " indices"
+                << std::endl;
+            
+            // Build the index data
+            if (!largeIndices)
+            {
+                unsigned short* dest = (unsigned short*)indexData + startIndexOffset;
+                for (unsigned j = 0; j < mesh->mNumFaces; ++j)
+                    writeShortIndices(dest, mesh, j, startVertexOffset);
+            }
+            else
+            {
+                unsigned* dest = (unsigned*)indexData + startIndexOffset;
+                for (unsigned j = 0; j < mesh->mNumFaces; ++j)
+                    writeLargeIndices(dest, mesh, j, startVertexOffset);
+            }
+            
+            // Build the vertex data
+            float* dest = (float*)((unsigned char*)vertexData + startVertexOffset * vb->getVertexSize());
+            for (unsigned j = 0; j < mesh->mNumVertices; ++j)
+                writeVertex(dest, mesh, j, elementMask, box, vertexTransform, normalTransform);
+            
+            // Define the geometry
+            geom->setIndexBuffer(ib);
+            geom->setVertexBuffer(0, vb);
+            geom->setDrawRange(TRIANGLE_LIST, startIndexOffset, mesh->mNumFaces * 3, true);
+            outModel->setNumGeometryLodLevels(i, 1);
+            outModel->setGeometry(i, 0, geom);
+            
+            startVertexOffset += mesh->mNumVertices;
+            startIndexOffset += mesh->mNumFaces * 3;
+        }
     }
     
+    outModel->setBoundingBox(box);
+    
     File outFile(model.mOutName, FILE_WRITE);
     outModel->save(outFile);
 }
 
-void errorExit(const std::string& error)
+void writeShortIndices(unsigned short*& dest, aiMesh* mesh, unsigned index, unsigned offset)
 {
-    throw Exception(error);
+    *dest++ = mesh->mFaces[index].mIndices[0] + offset;
+    *dest++ = mesh->mFaces[index].mIndices[1] + offset;
+    *dest++ = mesh->mFaces[index].mIndices[2] + offset;
+}
+
+void writeLargeIndices(unsigned*& dest, aiMesh* mesh, unsigned index, unsigned offset)
+{
+    *dest++ = mesh->mFaces[index].mIndices[0] + offset;
+    *dest++ = mesh->mFaces[index].mIndices[1] + offset;
+    *dest++ = mesh->mFaces[index].mIndices[2] + offset;
+}
+
+void writeVertex(float*& dest, aiMesh* mesh, unsigned index, unsigned elementMask, BoundingBox& box,
+    const Matrix4x3& vertexTransform, const Matrix3& normalTransform)
+{
+    Vector3 vertex = vertexTransform * toVector3(mesh->mVertices[index]);
+    box.merge(vertex);
+    *dest++ = vertex.mX;
+    *dest++ = vertex.mY;
+    *dest++ = vertex.mZ;
+    if (elementMask & MASK_NORMAL)
+    {
+        Vector3 normal = normalTransform * toVector3(mesh->mNormals[index]);
+        *dest++ = normal.mX;
+        *dest++ = normal.mY;
+        *dest++ = normal.mZ;
+    }
+    if (elementMask & MASK_COLOR)
+    {
+        *((unsigned*)dest) = getD3DColor(Color(mesh->mColors[0][index].r, mesh->mColors[0][index].g, mesh->mColors[0][index].b,
+            mesh->mColors[0][index].a));
+        ++dest;
+    }
+    if (elementMask & MASK_TEXCOORD1)
+    {
+        Vector3 texCoord = toVector3(mesh->mTextureCoords[0][index]);
+        *dest++ = texCoord.mX;
+        *dest++ = texCoord.mY;
+    }
+    if (elementMask & MASK_TEXCOORD2)
+    {
+        Vector3 texCoord = toVector3(mesh->mTextureCoords[1][index]);
+        *dest++ = texCoord.mX;
+        *dest++ = texCoord.mY;
+    }
+    if (elementMask & MASK_TANGENT)
+    {
+        Vector3 tangent = normalTransform * toVector3(mesh->mTangents[index]);
+        Vector3 normal = normalTransform * toVector3(mesh->mNormals[index]);
+        Vector3 bitangent = normalTransform * toVector3(mesh->mBitangents[index]);
+        // Check handedness
+        float w = 1.0f;
+        if ((tangent.crossProduct(normal)).dotProduct(bitangent) < 0.5f)
+            w = -1.0f;
+        
+        *dest++ = tangent.mX;
+        *dest++ = tangent.mY;
+        *dest++ = tangent.mZ;
+        *dest++ = w;
+    }
+}
+
+unsigned getElementMask(aiMesh* mesh)
+{
+    unsigned elementMask = MASK_POSITION;
+    if (mesh->HasNormals())
+        elementMask |= MASK_NORMAL;
+    if (mesh->HasTangentsAndBitangents())
+        elementMask |= MASK_TANGENT;
+    if (mesh->GetNumColorChannels() > 0)
+        elementMask |= MASK_COLOR;
+    if (mesh->GetNumUVChannels() > 0)
+        elementMask |= MASK_TEXCOORD1;
+    if (mesh->GetNumUVChannels() > 1)
+        elementMask |= MASK_TEXCOORD2;
+    return elementMask;
+}
+
+aiNode* findNode(const std::string& name, aiNode* rootNode)
+{
+    if (!rootNode)
+        return 0;
+    if (toLower(toStdString(rootNode->mName)) == toLower(name))
+        return rootNode;
+    for (unsigned i = 0; i < rootNode->mNumChildren; ++i)
+    {
+        aiNode* found = findNode(name, rootNode->mChildren[i]);
+        if (found)
+            return found;
+    }
+    return 0;
 }
 
 std::string toStdString(const aiString& str)
@@ -271,11 +473,11 @@ Quaternion toQuaternion(const aiQuaternion& quat)
     return Quaternion(quat.w, quat.x, quat.y, quat.z);
 }
 
-aiMatrix4x4 getWorldTransform(aiNode* node, aiNode* baseNode)
+aiMatrix4x4 getWorldTransform(aiNode* node, aiNode* rootNode)
 {
     aiMatrix4x4 current = node->mTransformation;
     // If basenode is defined, go only up to it in the parent chain
-    while ((node->mParent) && (node != baseNode))
+    while ((node->mParent) && (node != rootNode))
     {
         node = node->mParent;
         current = node->mTransformation * current;
@@ -293,3 +495,9 @@ void getPosRotScale(const aiMatrix4x4& transform, Vector3& pos, Quaternion& rot,
     rot = toQuaternion(aiRot);
     scale = toVector3(aiScale);
 }
+
+void errorExit(const std::string& error)
+{
+    throw Exception(error);
+}
+

+ 1 - 1
Tools/ModelConverter/ModelConverterUtils.h

@@ -129,7 +129,7 @@ struct ModelVertexBuffer
             if (mElementMask & MASK_NORMAL)
                 dest.writeVector3(mVertices[i].mNormal);
             if (mElementMask & MASK_COLOR)
-                dest.writeUInt(Renderer::getD3DColor(mVertices[i].mColor));
+                dest.writeUInt(getD3DColor(mVertices[i].mColor));
             if (mElementMask & MASK_TEXCOORD1)
                 dest.writeVector2(mVertices[i].mTexCoord1);
             if (mElementMask & MASK_TEXCOORD2)