Просмотр исходного кода

Added indexed mesh support to Polycode, added indexed mesh support to .mesh format, polyimport will now always generate an indexed mesh file, rewrote .mesh format to support flags for different vertex attributes, updated polyimport with options to only include chosen vertex attributes, changed 3d asset import UI to reflect new polyimport changes, added support for secondary UV coordinates

Ivan Safrin 12 лет назад
Родитель
Сommit
56d250823c

+ 20 - 6
Core/Contents/Include/PolyMesh.h

@@ -152,10 +152,10 @@ namespace Polycode {
 			* Saves mesh to a file.
 			* @param fileName Path to file to save to.
 			*/			
-			void saveToFile(const String& fileName);
+			void saveToFile(const String& fileName, bool writeNormals = true, bool writeTangents = true, bool writeColors = true, bool writeBoneWeights = true, bool writeUVs = true, bool writeSecondaryUVs = false);
 
 			void loadFromFile(OSFILE *inFile);
-			void saveToFile(OSFILE *outFile);
+			void saveToFile(OSFILE *outFile, bool writeNormals = true, bool writeTangents = true, bool writeColors = true, bool writeBoneWeights = true, bool writeUVs = true, bool writeSecondaryUVs = false);
 			
 			
 			/**
@@ -274,7 +274,7 @@ namespace Polycode {
 			* @param smooth If true, will use smooth normals.
 			* @param smoothAngle If smooth, this parameter sets the angle tolerance for the approximation function.
 			*/
-			void calculateNormals(bool smooth=true, Number smoothAngle=90.0);	
+			void calculateNormals(bool generateFaceNormals = false);
 
 			/**
 			* Recalculates the tangent space vector for all vertices.
@@ -295,6 +295,9 @@ namespace Polycode {
 			void dirtyArray(unsigned int arrayIndex);
 			void dirtyArrays();
 
+            void setUseFaceNormals(bool val);
+            bool getUseFaceNormals();
+        
 			/**
 			* Calculates the mesh bounding box.
 			*/
@@ -358,13 +361,24 @@ namespace Polycode {
 			* If set to true, the renderer will use the vertex colors instead of entity color transform to render this mesh.
 			*/
 			bool useVertexColors;
-			
-		
+            bool indexedMesh;
+        
+            void addIndexedFace(unsigned int i1, unsigned int i2, unsigned int i3);
+            void addIndexedFace(unsigned int i1, unsigned int i2, unsigned int i3, unsigned int i4);
+            void addIndex(unsigned int index);
+        
+            Vector3 getFaceNormalForVertex(unsigned int index);
+        
 		protected:
-					
+        
+            bool useFaceNormals;
+        
             VertexBuffer *vertexBuffer;
             bool meshHasVertexBuffer;
             int meshType;
+        
+            std::vector<Vector3> faceNormals;
+            std::vector<unsigned int> indices;
             std::vector <Vertex*> vertices;
 	};
 }

+ 6 - 2
Core/Contents/Include/PolyVertex.h

@@ -147,7 +147,10 @@ namespace Polycode {
 			* @param v New vertical texture coordinate.			
 			*/
 			void setTexCoord(Number u, Number v);
-			
+
+			Vector2 getSecondaryTexCoord();
+            void setSecondaryTexCoord(Number u, Number v);
+        
 			/**
 			* Sets the normal
 			* @param x Normal x.
@@ -185,7 +188,8 @@ namespace Polycode {
 			* Texture coordinates
 			*/
 			Vector2 texCoord;
-			
+			Vector2 secondaryTexCoord;
+        
 			bool useVertexColor;
 				
 		protected:

+ 10 - 3
Core/Contents/Source/PolyGLRenderer.cpp

@@ -909,9 +909,16 @@ RenderDataArray *OpenGLRenderer::createRenderDataArrayForMesh(Mesh *mesh, int ar
 			for(int i=0; i < mesh->getVertexCount(); i++) {
                 newBufferSize = bufferSize + 3;
                 buffer = (GLfloat*)realloc(buffer, newBufferSize * sizeof(GLfloat));
-                buffer[bufferSize+0] = mesh->getVertex(i)->normal.x;
-                buffer[bufferSize+1] = mesh->getVertex(i)->normal.y;
-                buffer[bufferSize+2] = mesh->getVertex(i)->normal.z;
+                if(mesh->getUseFaceNormals()) {
+                    Vector3 n = mesh->getFaceNormalForVertex(i);
+                    buffer[bufferSize+0] = n.x;
+                    buffer[bufferSize+1] = n.y;
+                    buffer[bufferSize+2] = n.z;
+                } else {
+                    buffer[bufferSize+0] = mesh->getVertex(i)->normal.x;
+                    buffer[bufferSize+1] = mesh->getVertex(i)->normal.y;
+                    buffer[bufferSize+2] = mesh->getVertex(i)->normal.z;
+                }
                 bufferSize = newBufferSize;
 			}			
 		}

+ 10 - 3
Core/Contents/Source/PolyGLVertexBuffer.cpp

@@ -97,9 +97,16 @@ OpenGLVertexBuffer::OpenGLVertexBuffer(Mesh *mesh) : VertexBuffer() {
 	for(int i=0; i < mesh->getVertexCount(); i++) {
         newBufferSize = bufferSize + 3;
         buffer = (GLfloat*)realloc(buffer, newBufferSize * sizeof(GLfloat));
-        buffer[bufferSize+0] = mesh->getVertex(i)->normal.x;
-        buffer[bufferSize+1] = mesh->getVertex(i)->normal.y;
-        buffer[bufferSize+2] = mesh->getVertex(i)->normal.z;
+        if(mesh->getUseFaceNormals()) {
+            Vector3 n = mesh->getFaceNormalForVertex(i);
+            buffer[bufferSize+0] = n.x;
+            buffer[bufferSize+1] = n.y;
+            buffer[bufferSize+2] = n.z;
+        } else {
+            buffer[bufferSize+0] = mesh->getVertex(i)->normal.x;
+            buffer[bufferSize+1] = mesh->getVertex(i)->normal.y;
+            buffer[bufferSize+2] = mesh->getVertex(i)->normal.z;
+        }
         bufferSize = newBufferSize;
 	}
 	

+ 235 - 111
Core/Contents/Source/PolyMesh.cpp

@@ -37,12 +37,13 @@ Mesh::Mesh(const String& fileName) {
         renderDataArrays[i] = NULL;
     }
 
-    
+    indexedMesh = false;
     meshType = TRI_MESH;
     meshHasVertexBuffer = false;
     loadMesh(fileName);
     vertexBuffer = NULL;			
     useVertexColors = false;
+    useFaceNormals = false;
 }
 
 Mesh::Mesh(int meshType) {
@@ -53,7 +54,9 @@ Mesh::Mesh(int meshType) {
     this->meshType = meshType;
     meshHasVertexBuffer = false;		
     vertexBuffer = NULL;
-    useVertexColors = false;				
+    useVertexColors = false;
+    indexedMesh = false;
+    useFaceNormals = false;
 }
 
 Mesh *Mesh::MeshFromFileName(String& fileName) {
@@ -80,6 +83,8 @@ void Mesh::clearMesh() {
             renderDataArrays[i] = NULL;
         }
     }
+    indexedMesh = false;
+    useFaceNormals = false;
     meshHasVertexBuffer = false;
 }
 
@@ -87,6 +92,16 @@ VertexBuffer *Mesh::getVertexBuffer() {
     return vertexBuffer;
 }
 
+void Mesh::setUseFaceNormals(bool val) {
+    useFaceNormals = val;
+    arrayDirtyMap[RenderDataArray::NORMAL_DATA_ARRAY] = true;
+}
+
+bool Mesh::getUseFaceNormals() {
+    return useFaceNormals;
+}
+
+
 void Mesh::setVertexBuffer(VertexBuffer *buffer) {
     vertexBuffer = buffer;
     meshHasVertexBuffer = true;
@@ -104,10 +119,36 @@ Number Mesh::getRadius() {
     return hRad;
 }
 
-void Mesh::saveToFile(OSFILE *outFile) {				
+void Mesh::saveToFile(OSFILE *outFile, bool writeNormals, bool writeTangents, bool writeColors, bool writeBoneWeights, bool writeUVs, bool writeSecondaryUVs) {
+    
+    unsigned char meshFlags = 0;
+    
+    if(indexedMesh) {
+        meshFlags |= 1 << 0;
+    }
+    if(writeNormals) {
+        meshFlags |= 1 << 1;
+    }
+    if(writeTangents) {
+        meshFlags |= 1 << 2;
+    }
+    if(writeColors) {
+        meshFlags |= 1 << 3;
+    }
+    if(writeUVs) {
+        meshFlags |= 1 << 4;
+    }
+    if(writeSecondaryUVs) {
+        meshFlags |= 1 << 5;
+    }
+    if(writeBoneWeights) {
+        meshFlags |= 1 << 6;
+    }
+    
+    OSBasics::write(&meshFlags, sizeof(unsigned char), 1, outFile);
+    
     unsigned int numVertices = vertices.size();
-
-    OSBasics::write(&meshType, sizeof(unsigned int), 1, outFile);		
+    OSBasics::write(&meshType, sizeof(unsigned int), 1, outFile);
     OSBasics::write(&numVertices, sizeof(unsigned int), 1, outFile);
 
     Vector3_struct pos;
@@ -115,7 +156,8 @@ void Mesh::saveToFile(OSFILE *outFile) {
     Vector3_struct tan;
     Vector4_struct col;
     Vector2_struct tex;
-
+    Vector2_struct tex2;
+    
     for(int i=0; i < vertices.size(); i++) {
         pos.x =  vertices[i]->x;
         pos.y =  vertices[i]->y;
@@ -136,30 +178,66 @@ void Mesh::saveToFile(OSFILE *outFile) {
         
         tex.x = vertices[i]->getTexCoord().x;
         tex.y = vertices[i]->getTexCoord().y;
-        
+
+        tex2.x = vertices[i]->getSecondaryTexCoord().x;
+        tex2.y = vertices[i]->getSecondaryTexCoord().y;
+
         OSBasics::write(&pos, sizeof(Vector3_struct), 1, outFile);
-        OSBasics::write(&nor, sizeof(Vector3_struct), 1, outFile);
-        OSBasics::write(&tan, sizeof(Vector3_struct), 1, outFile);				
-        OSBasics::write(&col, sizeof(Vector4_struct), 1, outFile);				
-        OSBasics::write(&tex, sizeof(Vector2_struct), 1, outFile);
-
-        unsigned int numBoneWeights = vertices[i]->getNumBoneAssignments();
-        OSBasics::write(&numBoneWeights, sizeof(unsigned int), 1, outFile);					
-        for(int b=0; b < numBoneWeights; b++) {
-            BoneAssignment *a = vertices[i]->getBoneAssignment(b);
-            unsigned int boneID = a->boneID;
-            float weight = a->weight;
-            OSBasics::write(&boneID, sizeof(unsigned int), 1, outFile);
-            OSBasics::write(&weight, sizeof(float), 1, outFile);												
+        
+        if(writeNormals) {
+            OSBasics::write(&nor, sizeof(Vector3_struct), 1, outFile);
+        }
+        if(writeTangents) {
+            OSBasics::write(&tan, sizeof(Vector3_struct), 1, outFile);
+        }
+        if(writeColors) {
+            OSBasics::write(&col, sizeof(Vector4_struct), 1, outFile);
+        }
+        if(writeUVs) {
+            OSBasics::write(&tex, sizeof(Vector2_struct), 1, outFile);
+        }
+        if(writeSecondaryUVs) {
+            OSBasics::write(&tex2, sizeof(Vector2_struct), 1, outFile);
+        }
+        
+        if(writeBoneWeights) {
+            unsigned int numBoneWeights = vertices[i]->getNumBoneAssignments();
+            OSBasics::write(&numBoneWeights, sizeof(unsigned int), 1, outFile);					
+            for(int b=0; b < numBoneWeights; b++) {
+                BoneAssignment *a = vertices[i]->getBoneAssignment(b);
+                unsigned int boneID = a->boneID;
+                float weight = a->weight;
+                OSBasics::write(&boneID, sizeof(unsigned int), 1, outFile);
+                OSBasics::write(&weight, sizeof(float), 1, outFile);												
+            }
+        }
+    }
+    
+    if(indexedMesh) {
+        unsigned int numIndices = indices.size();
+        OSBasics::write(&numIndices, sizeof(unsigned int), 1, outFile);
+        for(int i=0; i < numIndices; i++) {
+            OSBasics::write(&indices[i], sizeof(unsigned int), 1, outFile);
         }
     }
 }
 
 
 void Mesh::loadFromFile(OSFILE *inFile) {
-
+    
+    unsigned char meshFlags;
+    OSBasics::read(&meshFlags, sizeof(unsigned char), 1, inFile);
+    
+    indexedMesh = meshFlags & (1 << 0);
+    bool hasNormals = meshFlags & (1 << 1);
+    bool hasTangents = meshFlags & (1 << 2);
+    bool hasColors = meshFlags & (1 << 3);
+    bool hasUV = meshFlags & (1 << 4);
+    bool hasSecondaryUVs = meshFlags & (1 << 5);
+    bool hasBoneWeights = meshFlags & (1 << 6);
+    
     unsigned int meshType;		
-    OSBasics::read(&meshType, sizeof(unsigned int), 1, inFile);				
+    OSBasics::read(&meshType, sizeof(unsigned int), 1, inFile);
     setMeshType(meshType);
     
     unsigned int numVertices;
@@ -173,47 +251,70 @@ void Mesh::loadFromFile(OSFILE *inFile) {
     
     for(int i=0; i < numVertices; i++) {
         OSBasics::read(&pos, sizeof(Vector3_struct), 1, inFile);
-        OSBasics::read(&nor, sizeof(Vector3_struct), 1, inFile);
-        OSBasics::read(&tan, sizeof(Vector3_struct), 1, inFile);				
-        OSBasics::read(&col, sizeof(Vector4_struct), 1, inFile);						
-        OSBasics::read(&tex, sizeof(Vector2_struct), 1, inFile);						
-        
         Vertex *vertex = new Vertex(pos.x, pos.y, pos.z);
-        vertex->setNormal(nor.x,nor.y, nor.z);
-        vertex->tangent = Vector3(tan.x, tan.y, tan.z);
-        vertex->restNormal.set(nor.x,nor.y, nor.z);
-        vertex->vertexColor.setColor(col.x,col.y, col.z, col.w);
-        vertex->setTexCoord(tex.x, tex.y);
         
-        unsigned int numBoneWeights;
-        OSBasics::read(&numBoneWeights, sizeof(unsigned int), 1, inFile);								
-        for(int b=0; b < numBoneWeights; b++) {
-            float weight;
-            unsigned int boneID;
-            OSBasics::read(&boneID, sizeof(unsigned int), 1, inFile);													
-            OSBasics::read(&weight, sizeof(float), 1, inFile);																		
-            vertex->addBoneAssignment(boneID, weight);
+        if(hasNormals) {
+            OSBasics::read(&nor, sizeof(Vector3_struct), 1, inFile);
+            vertex->setNormal(nor.x,nor.y, nor.z);
+            vertex->restNormal.set(nor.x,nor.y, nor.z);
+        }
+        if(hasTangents) {
+            OSBasics::read(&tan, sizeof(Vector3_struct), 1, inFile);
+            vertex->tangent = Vector3(tan.x, tan.y, tan.z);
         }
         
-        Number totalWeight = 0;				
-        for(int m=0; m < vertex->getNumBoneAssignments(); m++) {
-            BoneAssignment *ba = vertex->getBoneAssignment(m);					
-            totalWeight += ba->weight;
-        }				
-
-        for(int m=0; m < vertex->getNumBoneAssignments(); m++) {
-            BoneAssignment *ba = vertex->getBoneAssignment(m);					
-            ba->weight = ba->weight/totalWeight;
-        }				
+        if(hasColors) {
+            OSBasics::read(&col, sizeof(Vector4_struct), 1, inFile);
+            vertex->vertexColor.setColor(col.x,col.y, col.z, col.w);
+        }
         
+        if(hasUV) {
+            OSBasics::read(&tex, sizeof(Vector2_struct), 1, inFile);
+            vertex->setTexCoord(tex.x, tex.y);
+        }
+        
+        if(hasSecondaryUVs) {
+            OSBasics::read(&tex, sizeof(Vector2_struct), 1, inFile);
+            vertex->setSecondaryTexCoord(tex.x, tex.y);
+        }
+        
+        if(hasBoneWeights) {
+            unsigned int numBoneWeights;
+            OSBasics::read(&numBoneWeights, sizeof(unsigned int), 1, inFile);								
+            for(int b=0; b < numBoneWeights; b++) {
+                float weight;
+                unsigned int boneID;
+                OSBasics::read(&boneID, sizeof(unsigned int), 1, inFile);													
+                OSBasics::read(&weight, sizeof(float), 1, inFile);																		
+                vertex->addBoneAssignment(boneID, weight);
+            }
+            
+            Number totalWeight = 0;				
+            for(int m=0; m < vertex->getNumBoneAssignments(); m++) {
+                BoneAssignment *ba = vertex->getBoneAssignment(m);					
+                totalWeight += ba->weight;
+            }				
+
+            for(int m=0; m < vertex->getNumBoneAssignments(); m++) {
+                BoneAssignment *ba = vertex->getBoneAssignment(m);					
+                ba->weight = ba->weight/totalWeight;
+            }				
+        }
         addVertex(vertex);
     }
+    
+    if(indexedMesh) {
+        unsigned int numIndices;
+        OSBasics::read(&numIndices, sizeof(unsigned int), 1, inFile);
+        indices.clear();
+        unsigned int val;
+        for(int i=0; i < numIndices; i++) {
+            OSBasics::read(&val, sizeof(unsigned int), 1, inFile);
+            indices.push_back(val);
+        }
+    }
 
-    arrayDirtyMap[RenderDataArray::VERTEX_DATA_ARRAY] = true;		
-    arrayDirtyMap[RenderDataArray::COLOR_DATA_ARRAY] = true;				
-    arrayDirtyMap[RenderDataArray::TEXCOORD_DATA_ARRAY] = true;
-    arrayDirtyMap[RenderDataArray::NORMAL_DATA_ARRAY] = true;	
-    arrayDirtyMap[RenderDataArray::TANGENT_DATA_ARRAY] = true;								
+    dirtyArrays();
 }
 
 Vertex *Mesh::addVertex(Number x, Number y, Number z) {
@@ -232,12 +333,12 @@ Vertex *Mesh::addVertex(Number x, Number y, Number z, Number u, Number v) {
     return vertex;
 }
 
-void Mesh::saveToFile(const String& fileName) {
+void Mesh::saveToFile(const String& fileName, bool writeNormals, bool writeTangents, bool writeColors, bool writeBoneWeights, bool writeUVs, bool writeSecondaryUVs) {
     OSFILE *outFile = OSBasics::open(fileName, "wb");
     if(!outFile) {
         Logger::log("Error opening mesh file for saving: %s", fileName.c_str());
     }
-    saveToFile(outFile);
+    saveToFile(outFile, writeNormals, writeTangents, writeColors, writeBoneWeights, writeUVs, writeSecondaryUVs);
     OSBasics::close(outFile);	
 
 }
@@ -423,7 +524,6 @@ void Mesh::createSphere(Number _radius, int _segmentsH, int _segmentsW) {
         Number horangle = ((float)j) / ((float)_segmentsH) * PI;
         Number z = -_radius * cos(horangle);
         Number ringradius = _radius * sin(horangle);
-
         for (int i = 0; i < _segmentsW; i++) {
             Number verangle = 2.0 * ((float)i) / ((float)_segmentsW) * PI;
             Number x = ringradius * sin(verangle);
@@ -483,7 +583,11 @@ void Mesh::createSphere(Number _radius, int _segmentsH, int _segmentsW) {
 }
 
 unsigned int Mesh::getVertexCount() {
-    return vertices.size();
+    if(indexedMesh) {
+        return indices.size();
+    } else {
+        return vertices.size();
+    }
 }
 
 void Mesh::createTorus(Number radius, Number tubeRadius, int rSegments, int tSegments) {
@@ -641,64 +745,58 @@ void Mesh::createCone(Number height, Number radius, int numSegments) {
 
 }
 
+void Mesh::addIndex(unsigned int index) {
+    indices.push_back(index);
+}
+
+void Mesh::addIndexedFace(unsigned int i1, unsigned int i2, unsigned int i3) {
+    indices.push_back(i1);
+    indices.push_back(i2);
+    indices.push_back(i3);
+}
+
+void Mesh::addIndexedFace(unsigned int i1, unsigned int i2, unsigned int i3, unsigned int i4) {
+    indices.push_back(i1);
+    indices.push_back(i2);
+    indices.push_back(i3);
+    indices.push_back(i4);
+}
+
 void Mesh::createBox(Number w, Number d, Number h) {
     setMeshType(Mesh::TRI_MESH);
+    indexedMesh = true;
     
     addVertex(w,0,h, 1, 1);
     addVertex(0,0,h, 1, 0);
     addVertex(0,0,0,0,0);
-    
-    addVertex(w,0,h, 1, 1);
-    addVertex(0,0,0,0,0);
     addVertex(w,0,0,0,1);
-
-    addVertex(w,d,h, 1, 1);
-    addVertex(w,d,0, 1, 0);
-    addVertex(0,d,0,0,0);
-
     addVertex(w,d,h, 1, 1);
+    addVertex(0,d,h, 1, 0);
     addVertex(0,d,0,0,0);
-    addVertex(0,d,h,0,1);
-
-    addVertex(0,d,0,0,1);
-    addVertex(w,d,0, 1, 1);
-    addVertex(w,0,0, 1, 0);
-
-    addVertex(0,d,0,0,1);
-    addVertex(w,0,0, 1, 0);
-    addVertex(0,0,0,0,0);
-
-    addVertex(0,0,h,0,0);
-    addVertex(w,0,h, 1, 0);
-    addVertex(w,d,h, 1, 1);
-
-    addVertex(0,0,h,0,0);
-    addVertex(w,d,h, 1, 1);
-    addVertex(0,d,h,0,1);
-
-    addVertex(0,0,h,0,1);
-    addVertex(0,d,h, 1, 1);
-    addVertex(0,d,0, 1, 0);
-
-    addVertex(0,0,h,0,1);
-    addVertex(0,d,0, 1, 0);
-    addVertex(0,0,0,0,0);
-
-    addVertex(w,0,h,0,1);
-    addVertex(w,0,0, 1, 1);
-    addVertex(w,d,0, 1, 0);
-
-    addVertex(w,0,h,0,1);
-    addVertex(w,d,0, 1, 0);
-    addVertex(w,d,h,0,0);
+    addVertex(w,d,0,0,1);
 
     for(int i=0; i < vertices.size(); i++) {
         vertices[i]->x = vertices[i]->x - (w/2.0f);
         vertices[i]->y = vertices[i]->y - (d/2.0f);
         vertices[i]->z = vertices[i]->z - (h/2.0f);
     }
-
-    calculateNormals(false);
+    
+    addIndexedFace(0, 1, 2);
+    addIndexedFace(0, 2, 3);
+    addIndexedFace(4, 7, 6);
+    addIndexedFace(4, 6, 5);
+    addIndexedFace(6, 7, 3);
+    addIndexedFace(6, 3, 2);
+    addIndexedFace(1, 0, 4);
+    addIndexedFace(1, 4, 5);
+    addIndexedFace(1, 5, 6);
+    addIndexedFace(1, 6, 2);
+    addIndexedFace(0, 3, 7);
+    addIndexedFace(0, 7, 4);
+
+    calculateNormals(true);
+    setUseFaceNormals(true);
+    
     calculateTangents();
     arrayDirtyMap[RenderDataArray::VERTEX_DATA_ARRAY] = true;		
     arrayDirtyMap[RenderDataArray::COLOR_DATA_ARRAY] = true;				
@@ -719,7 +817,11 @@ void Mesh::dirtyArrays() {
 }
 
 Vertex *Mesh::getVertex(unsigned int index) const {
-    return vertices[index];
+    if(indexedMesh) {
+        return vertices[indices[index]];
+    } else {
+        return vertices[index];
+    }
 }
 
 void Mesh::calculateTangents() {
@@ -727,25 +829,47 @@ void Mesh::calculateTangents() {
     arrayDirtyMap[RenderDataArray::TANGENT_DATA_ARRAY] = true;		
 }
 
-void Mesh::calculateNormals(bool smooth, Number smoothAngle) {
+Vector3 Mesh::getFaceNormalForVertex(unsigned int index) {
+    unsigned int faceNormalIndex;
+    if(meshType == Mesh::QUAD_MESH) {
+        faceNormalIndex = floor(index/4);
+    } else {
+        faceNormalIndex = floor(index/3);
+    }
+    
+    if(faceNormalIndex < faceNormals.size()) {
+        return faceNormals[faceNormalIndex];
+    } else {
+        return Vector3();
+    }
+}
+
+void Mesh::calculateNormals(bool generateFaceNormals) {
     
     int polySize = 3;
     if(meshType == Mesh::QUAD_MESH) {
         polySize = 4;
     }
     
+    faceNormals.clear();
     for(int i=0; i < vertices.size(); i++) {
         vertices[i]->normal = Vector3();
     }
 
-    for(int i=0; i+2 < vertices.size(); i += polySize) {
-        const Vector3 e1 = *(vertices[i]) - *(vertices[i+1]);
-        const Vector3 e2 = *(vertices[i+2]) - *(vertices[i+1]);
-        const Vector3 no = e1.crossProduct(e2);
+    if(indexedMesh) {
+        for(int i=0; i+polySize-1 < indices.size(); i += polySize) {
+            const Vector3 e1 = *(vertices[indices[i]]) - *(vertices[indices[i+1]]);
+            const Vector3 e2 = *(vertices[indices[i+2]]) - *(vertices[indices[i+1]]);
+            const Vector3 no = e1.crossProduct(e2);
+                
+            vertices[indices[i]]->normal -= no;
+            vertices[indices[i+1]]->normal -= no;
+            vertices[indices[i+2]]->normal -= no;
             
-        vertices[i]->normal -= no;
-        vertices[i+1]->normal -= no;
-        vertices[i+2]->normal -= no;
+            if(generateFaceNormals) {
+                faceNormals.push_back(no * -1.0);
+            }
+        }
     }
     
     arrayDirtyMap[RenderDataArray::NORMAL_DATA_ARRAY] = true;		

+ 9 - 0
Core/Contents/Source/PolyVertex.cpp

@@ -108,4 +108,13 @@ Vector2 Vertex::getTexCoord() {
 void Vertex::setTexCoord(Number u, Number v) {
 	texCoord.x = u;
 	texCoord.y = v;
+}
+
+Vector2 Vertex::getSecondaryTexCoord() {
+	return secondaryTexCoord;
+}
+
+void Vertex::setSecondaryTexCoord(Number u, Number v) {
+	secondaryTexCoord.x = u;
+	secondaryTexCoord.y = v;
 }

+ 1 - 1
IDE/Contents/Include/PolycodeToolLauncher.h

@@ -53,7 +53,7 @@ class PolycodeToolLauncher {
 		static void openExternalEditor(String app, String file, String inFolder);
 		static String generateTempPath(PolycodeProject *project);
 		static void buildProject(PolycodeProject *project, String destinationPath, bool compileScripts);
-		static String importAssets(String sourceFile, String inFolder, bool addMeshes, String prefix, bool swapZY, bool generateTangents, bool listOnly);
+		static String importAssets(String sourceFile, String inFolder, bool addMeshes, String prefix, bool swapZY, bool generateTangents, bool listOnly,bool writeNormals, bool writeTangents, bool writeColors, bool writeBoneWeights, bool writeUVs, bool writeSecondaryUVs);
 
 		static void runPolyapp(String polyappPath);
 };

+ 8 - 1
IDE/Contents/Include/ToolWindows.h

@@ -112,7 +112,14 @@ class AssetImporterWindow : public UIWindow {
 		UICheckBox *addMeshesCheckbox;
 		UICheckBox *generateTangensCheckbox;
 		UICheckBox *swapZYAxisCheckbox;
-				
+
+        UICheckBox *exportNormals;
+        UICheckBox *exportTangents;
+        UICheckBox *exportColors;
+        UICheckBox *exportBoneWeights;
+        UICheckBox *exportUVs;
+        UICheckBox *exportSecondaryUVs;
+    
 		Entity *filesAnchor;
 		UIScrollContainer *filesScroller;
 

+ 1 - 1
IDE/Contents/Source/PolycodeMeshEditor.cpp

@@ -131,7 +131,7 @@ bool PolycodeMeshEditor::openFile(OSFileEntry filePath) {
 	previewBase->addChild(previewMesh);
 	previewMesh->setMaterialByName("Default");
 	PolycodeEditor::openFile(filePath);
-	
+
 	previewMesh->alphaTest = true;
 	CoreServices::getInstance()->getRenderer()->alphaTestValue = 0.9;
 	

+ 21 - 1
IDE/Contents/Source/PolycodeToolLauncher.cpp

@@ -113,7 +113,7 @@ void PolycodeToolLauncher::buildProject(PolycodeProject *project, String destina
 
 }
 
-String PolycodeToolLauncher::importAssets(String sourceFile, String inFolder, bool addMeshes, String prefix, bool swapZY, bool generateTangents, bool listOnly) {
+String PolycodeToolLauncher::importAssets(String sourceFile, String inFolder, bool addMeshes, String prefix, bool swapZY, bool generateTangents, bool listOnly, bool writeNormals, bool writeTangents, bool writeColors, bool writeBoneWeights, bool writeUVs, bool writeSecondaryUVs) {
 
 	String ret;
 	String polycodeBasePath = CoreServices::getInstance()->getCore()->getDefaultWorkingDirectory();
@@ -131,9 +131,29 @@ String PolycodeToolLauncher::importAssets(String sourceFile, String inFolder, bo
 	if(generateTangents) {
 		args = "-t "+args;
 	}
+    if(writeNormals) {
+		args = "-n "+args;
+    }
+    if(writeTangents) {
+		args = "-g "+args;
+    }
+    if(writeColors) {
+		args = "-c "+args;
+    }
+    if(writeBoneWeights) {
+		args = "-w "+args;
+    }
+    if(writeUVs) {
+		args = "-u "+args;
+    }
+    if(writeSecondaryUVs) {
+		args = "-v "+args;
+    }
+    
 	if(prefix != "") {
 		args = "-p "+prefix+" "+args;
 	}
+    
 
 	
 #ifdef _WINDOWS

+ 36 - 11
IDE/Contents/Source/ToolWindows.cpp

@@ -197,7 +197,7 @@ YesNoCancelPopup::~YesNoCancelPopup() {
 	
 }
 
-AssetImporterWindow::AssetImporterWindow() : UIWindow("3D Asset Importer", 500, 300) {
+AssetImporterWindow::AssetImporterWindow() : UIWindow("3D Asset Importer", 650, 250) {
 	filesToImportLabel = new UILabel("Files that will be imported:", 12);
 	addChild(filesToImportLabel);
 	filesToImportLabel->setPosition(padding, 35);
@@ -211,37 +211,62 @@ AssetImporterWindow::AssetImporterWindow() : UIWindow("3D Asset Importer", 500,
 	cancelButton = new UIButton(L"Cancel", 100);
 	cancelButton->addEventListener(this, UIEvent::CLICK_EVENT);
 	addChild(cancelButton);
-	cancelButton->setPosition(padding+500-100-100-10-10, 285);		
+	cancelButton->setPosition(padding+650-100-100-10-10, 235);
 	
 	okButton = new UIButton(L"OK", 100);
 	okButton->addEventListener(this, UIEvent::CLICK_EVENT);
 	addChild(okButton);
-	okButton->setPosition(padding+500-100-10, 285);
+	okButton->setPosition(padding+650-100-10, 235);
 	
 	closeOnEscape = true;
 
 	prefixInput = new UITextInput(false, 200, 16);
-	prefixInput->setPosition(290, 60);
+	prefixInput->setPosition(290, 30);
 	addChild(prefixInput); 
 	prefixInput->addEventListener(this, UIEvent::CHANGE_EVENT);
 		
 	usePrefixCheckbox = new UICheckBox("Custom filename prefix", false);
-	usePrefixCheckbox->setPosition(290, 90);
+	usePrefixCheckbox->setPosition(290, 60);
 	addChild(usePrefixCheckbox);
 	usePrefixCheckbox->addEventListener(this, UIEvent::CHANGE_EVENT);
 	
 	addMeshesCheckbox = new UICheckBox("Add all meshes to a single mesh", false);
-	addMeshesCheckbox->setPosition(290, 120);
+	addMeshesCheckbox->setPosition(290, 90);
 	addChild(addMeshesCheckbox); 
 	addMeshesCheckbox->addEventListener(this, UIEvent::CHANGE_EVENT);
 	
 	generateTangensCheckbox = new UICheckBox("Generate tangents", true);
-	generateTangensCheckbox->setPosition(290, 150);
+	generateTangensCheckbox->setPosition(290, 120);
 	addChild(generateTangensCheckbox); 
 	
 	swapZYAxisCheckbox = new UICheckBox("Swap Z/Y axis (e.g. for Blender)", false);
-	swapZYAxisCheckbox->setPosition(290, 180);
-	addChild(swapZYAxisCheckbox); 
+	swapZYAxisCheckbox->setPosition(290, 150);
+	addChild(swapZYAxisCheckbox);
+    
+    exportNormals = new UICheckBox("Vertex normals", true);
+	exportNormals->setPosition(520, 30);
+	addChild(exportNormals);
+    
+    exportTangents = new UICheckBox("Vertex tangents", true);
+	exportTangents->setPosition(520, 60);
+	addChild(exportTangents);
+    
+    exportColors = new UICheckBox("Vertex colors", false);
+	exportColors->setPosition(520, 90);
+	addChild(exportColors);
+    
+    exportBoneWeights = new UICheckBox("Bone weights", false);
+	exportBoneWeights->setPosition(520, 120);
+	addChild(exportBoneWeights);
+    
+    exportUVs = new UICheckBox("UV coordinates", true);
+	exportUVs->setPosition(520, 150);
+	addChild(exportUVs);
+    
+    exportSecondaryUVs = new UICheckBox("Secondary UVs", true);
+	exportSecondaryUVs->setPosition(520, 180);
+	addChild(exportSecondaryUVs);
+    
 }
 
 void AssetImporterWindow::handleEvent(Event *event) {
@@ -254,7 +279,7 @@ void AssetImporterWindow::handleEvent(Event *event) {
 		if(usePrefixCheckbox->isChecked() && prefixInput->getText() != "") {
 			prefixString = prefixInput->getText().replace(" ", "_");
 		}
-		PolycodeToolLauncher::importAssets(file, folder, addMeshesCheckbox->isChecked(), prefixString, swapZYAxisCheckbox->isChecked(), generateTangensCheckbox->isChecked(), false);	
+		PolycodeToolLauncher::importAssets(file, folder, addMeshesCheckbox->isChecked(), prefixString, swapZYAxisCheckbox->isChecked(), generateTangensCheckbox->isChecked(), false, exportNormals->isChecked(), exportTangents->isChecked(), exportColors->isChecked(), exportBoneWeights->isChecked(), exportUVs->isChecked(), exportSecondaryUVs->isChecked());
 	
 		dispatchEvent(new UIEvent(), UIEvent::OK_EVENT);
 		dispatchEvent(new UIEvent(), UIEvent::CLOSE_EVENT);	
@@ -301,7 +326,7 @@ void AssetImporterWindow::refreshPreview() {
 	if(usePrefixCheckbox->isChecked() && prefixInput->getText() != "") {
 		prefixString = prefixInput->getText().replace(" ", "_");
 	}
-	String fileList = PolycodeToolLauncher::importAssets(file, folder, addMeshesCheckbox->isChecked(), prefixString, swapZYAxisCheckbox->isChecked(), generateTangensCheckbox->isChecked(), true);
+	String fileList = PolycodeToolLauncher::importAssets(file, folder, addMeshesCheckbox->isChecked(), prefixString, swapZYAxisCheckbox->isChecked(), generateTangensCheckbox->isChecked(), true, false, false, false, false, false, false);
 	setFilesToImport(fileList);		
 }
 

+ 117 - 72
Tools/Contents/polyimport/Source/polyimport.cpp

@@ -12,6 +12,13 @@ bool hasWeights = false;
 vector<aiBone*> bones;
 unsigned int numBones = 0;
 
+bool writeNormals = false;
+bool writeTangents = false;
+bool writeColors = false;
+bool writeBoneWeights = false;
+bool writeUVs = false;
+bool writeSecondaryUVs = false;
+
 unsigned int addBone(aiBone *bone) {
 	for(int i=0; i < bones.size(); i++) {
 		if(bones[i]->mName == bone->mName)
@@ -30,6 +37,7 @@ void addToMesh(String prefix, Polycode::Mesh *tmesh, const struct aiScene *sc, c
 	
 		if(!addSubmeshes) {
 			tmesh = new Polycode::Mesh(Mesh::TRI_MESH);
+            tmesh->indexedMesh = true;
 		}
 	
 		const struct aiMesh* mesh = scene->mMeshes[nd->mMeshes[n]];
@@ -41,61 +49,73 @@ void addToMesh(String prefix, Polycode::Mesh *tmesh, const struct aiScene *sc, c
 			printf("Importing mesh:%s (%d vertices) (%d faces) \n", mesh->mName.data, mesh->mNumVertices, mesh->mNumFaces);
 		}
 		//apply_material(sc->mMaterials[mesh->mMaterialIndex]);
-
-		for (t = 0; t < mesh->mNumFaces; ++t) {
-			const struct aiFace* face = &mesh->mFaces[t];
-	
-			for(i = 0; i < face->mNumIndices; i++) {
-				Vertex *vertex = new Vertex();
-
-				int index = face->mIndices[i];
-				if(mesh->mColors[0] != NULL) {
-					vertex->vertexColor.setColorRGBA(mesh->mColors[0][index].r, mesh->mColors[0][index].g, mesh->mColors[0][index].b, mesh->mColors[0][index].a);
-				}
-
-				if(mesh->mTangents != NULL)  {
-					if(swapZY)
-						vertex->tangent = Vector3(mesh->mTangents[index].x, mesh->mTangents[index].z, -mesh->mTangents[index].y);
-					else
-						vertex->tangent = Vector3(mesh->mTangents[index].x, mesh->mTangents[index].y, mesh->mTangents[index].z);
-				}
-
-				if(mesh->mNormals != NULL)  {
-					if(swapZY)
-						vertex->setNormal(mesh->mNormals[index].x, mesh->mNormals[index].z, -mesh->mNormals[index].y);
-					else
-						vertex->setNormal(mesh->mNormals[index].x, mesh->mNormals[index].y, mesh->mNormals[index].z);
-				}
-
-				if(mesh->HasTextureCoords(0))
-				{
-					vertex->setTexCoord(mesh->mTextureCoords[0][index].x, mesh->mTextureCoords[0][index].y);
-				}
-
-				for( unsigned int a = 0; a < mesh->mNumBones; a++) {
-					aiBone* bone = mesh->mBones[a];
-					unsigned int boneIndex = addBone(bone);
-
-					for( unsigned int b = 0; b < bone->mNumWeights; b++) {
-						if(bone->mWeights[b].mVertexId == index) {
-							vertex->addBoneAssignment(boneIndex, bone->mWeights[b].mWeight);
-							hasWeights = true;
-						}
-					}
-				}
-	
-				if(swapZY)
+        
+		for (t = 0; t < mesh->mNumVertices; ++t) {
+            Vertex *vertex = new Vertex();
+            int index = t;
+            if(mesh->mColors[0] != NULL) {
+                vertex->vertexColor.setColorRGBA(mesh->mColors[0][index].r, mesh->mColors[0][index].g, mesh->mColors[0][index].b, mesh->mColors[0][index].a);
+            }
+
+            if(mesh->mTangents != NULL)  {
+                if(swapZY)
+                    vertex->tangent = Vector3(mesh->mTangents[index].x, mesh->mTangents[index].z, -mesh->mTangents[index].y);
+                else
+                    vertex->tangent = Vector3(mesh->mTangents[index].x, mesh->mTangents[index].y, mesh->mTangents[index].z);
+            }
+
+            if(mesh->mNormals != NULL)  {
+                if(swapZY)
+                    vertex->setNormal(mesh->mNormals[index].x, mesh->mNormals[index].z, -mesh->mNormals[index].y);
+                else
+                    vertex->setNormal(mesh->mNormals[index].x, mesh->mNormals[index].y, mesh->mNormals[index].z);
+            }
+
+            if(mesh->HasTextureCoords(0))
+            {
+                vertex->setTexCoord(mesh->mTextureCoords[0][index].x, mesh->mTextureCoords[0][index].y);
+            }
+
+            if(mesh->HasTextureCoords(1))
+            {
+                vertex->setSecondaryTexCoord(mesh->mTextureCoords[1][index].x, mesh->mTextureCoords[1][index].y);
+            }
+
+            
+            for( unsigned int a = 0; a < mesh->mNumBones; a++) {
+                aiBone* bone = mesh->mBones[a];
+                unsigned int boneIndex = addBone(bone);
+
+                for( unsigned int b = 0; b < bone->mNumWeights; b++) {
+                    if(bone->mWeights[b].mVertexId == index) {
+                        vertex->addBoneAssignment(boneIndex, bone->mWeights[b].mWeight);
+                        hasWeights = true;
+                    }
+                }
+            }
+
+            if(swapZY) {
 					vertex->set(mesh->mVertices[index].x, mesh->mVertices[index].z, -mesh->mVertices[index].y);
-				else
-					vertex->set(mesh->mVertices[index].x, mesh->mVertices[index].y, mesh->mVertices[index].z);
-				tmesh->addVertex(vertex);
-			}
+            } else {
+                vertex->set(mesh->mVertices[index].x, mesh->mVertices[index].y, mesh->mVertices[index].z);
+            }
+            tmesh->addVertex(vertex);
 		}
+        
+
+         for (t = 0; t < mesh->mNumFaces; ++t) {
+             const struct aiFace* face = &mesh->mFaces[t];
+
+             for(i = 0; i < face->mNumIndices; i++) {
+                 int index = face->mIndices[i];
+                 tmesh->addIndex(index);
+             }
+         }
 		
 		if(!addSubmeshes && !listOnly) {
 			String fileNameMesh = prefix+String(nd->mName.data)+".mesh";			
 			OSFILE *outFile = OSBasics::open(fileNameMesh.c_str(), "wb");	
-			tmesh->saveToFile(outFile);
+			tmesh->saveToFile(outFile, writeNormals, writeTangents, writeColors, writeBoneWeights, writeUVs, writeSecondaryUVs);
 			OSBasics::close(outFile);
 			delete tmesh;
 		}
@@ -139,6 +159,7 @@ void addToISkeleton(ISkeleton *skel, IBone *parent, const struct aiScene *sc, co
 int exportToFile(String prefix, bool swapZY, bool addSubmeshes, bool listOnly) {
 		
 	Polycode::Mesh *mesh = new Polycode::Mesh(Mesh::TRI_MESH);
+    mesh->indexedMesh = true;
 	addToMesh(prefix, mesh, scene, scene->mRootNode, swapZY, addSubmeshes, listOnly);
 	
 	if(addSubmeshes) {		
@@ -153,7 +174,7 @@ int exportToFile(String prefix, bool swapZY, bool addSubmeshes, bool listOnly) {
 			printf("%s\n", fileNameMesh.c_str());
 		} else {
 			OSFILE *outFile = OSBasics::open(fileNameMesh.c_str(), "wb");	
-			mesh->saveToFile(outFile);
+			mesh->saveToFile(outFile, writeNormals, writeTangents, writeColors, writeBoneWeights, writeUVs, writeSecondaryUVs);
 			OSBasics::close(outFile);
 		}
 	}
@@ -234,12 +255,30 @@ int main(int argc, char **argv) {
 	bool addSubmeshes = false;
 	bool listOnly = false;
 	bool showAssimpDebug = false;
-	
+	   
 	String prefix;
 	
 	int opt;
-	while ((opt = getopt(argc, argv, "adlhp:st")) != -1) {
+	while ((opt = getopt(argc, argv, "ngcwuvadlhp:st")) != -1) {
 		switch ((char)opt) {
+            case 'n':
+                writeNormals = true;
+            break;
+            case 'g':
+                writeTangents = true;
+            break;
+            case 'c':
+                writeColors = true;
+            break;
+            case 'w':
+                writeBoneWeights = true;
+            break;
+            case 'u':
+                writeUVs = true;
+            break;
+            case 'v':
+                writeSecondaryUVs = true;
+            break;
 			case 's':
 				swapZYAxis = true;
 			break;
@@ -280,15 +319,24 @@ int main(int argc, char **argv) {
 		return 0;		
 	}
 	
-	if(showHelp) {
-		printf("usage: polyimport [-adhlst] [-p output_prefix] source_file\n\n");
-		printf("a: Add all meshes to a single mesh.\n");
+	if(showHelp || argc < 2) {
+		printf("usage: polyimport [-adhlstngcwuv] [-p output_prefix] source_file\n\n");
+		printf("Misc options:\n");
 		printf("d: Show Assimp debug info.\n");
-		printf("h: Show this help.\n");		
-		printf("l: List output files, but do not convert.\n");				
-		printf("p: Specify a file prefix for exported files.\n");			
+		printf("h: Show this help.\n");
+		printf("l: List output files, but do not convert.\n");
+		printf("p: Specify a file prefix for exported files.\n\n");
+		printf("Mesh import options:\n");
+		printf("a: Add all meshes to a single mesh.\n");
 		printf("s: Swap Z/Y axis (e.g. import from Blender)\n");
-		printf("t: Generate tangents.\n");
+		printf("t: Generate tangents.\n\n");
+		printf("Mesh export options:\n");
+		printf("n: Export normals\n");
+		printf("g: Export tangents\n");
+		printf("c: Export colors\n");
+		printf("w: Export bone weights\n");
+		printf("u: Export UV coordinates\n");
+		printf("v: Export secondary UV coordinates\n");
 		printf("\n");
 		return 0;
 	}
@@ -300,25 +348,22 @@ int main(int argc, char **argv) {
 		stream = aiGetPredefinedLogStream(aiDefaultLogStream_STDOUT,NULL);
 		aiAttachLogStream(&stream);
 	}
-	
-	if(argc < 2) {
-		printf("Please specify input filename\n");
-		return 0;
-	}	
-	
+		
 	int inputArg = argc-1;
 
 	if(!listOnly) {
 		printf("Loading %s...\n", argv[inputArg]);
 	}
 	
-	scene = aiImportFile(argv[inputArg],aiProcessPreset_TargetRealtime_Quality);
-	
-	if(generateTangents && !listOnly) {
-		aiApplyPostProcessing(scene, aiProcess_CalcTangentSpace);
-	}
-	
-	if(scene) {
+	scene = aiImportFile(argv[inputArg], aiProcess_JoinIdenticalVertices|
+                         aiProcess_Triangulate);
+    
+    if(scene) {
+        
+        if(generateTangents && !listOnly) {
+            aiApplyPostProcessing(scene, aiProcess_CalcTangentSpace);
+        }
+        
 		exportToFile(prefix, swapZYAxis, addSubmeshes, listOnly);
 	} else {
 		printf("Error opening scene...\n");