/*======================================================================== * (C) 2005 Universitat Jaume I *======================================================================== * PROYECT: GAME TOOLS *========================================================================*/ /* CONTENT: * * * @file GeoMeshLoader.cpp *========================================================================*/ #include "GeoMeshLoader.h" #include #include #include using namespace Geometry; using namespace std; //------------------------------------------------------------------------- // Jump a chunk. //------------------------------------------------------------------------- void GeoMeshLoader::jumpChunk(FILE *f) { fseek(f,-(long)CHUNK_OVERHEAD_SIZE,1); // Return to the begin of the chunk. fseek(f,long_actual,SEEK_CUR); } //------------------------------------------------------------------------- // Read a chunk. //------------------------------------------------------------------------- unsigned short GeoMeshLoader::readChunk(FILE *f) { unsigned short id; fread(&id,sizeof(unsigned short),1,f); fread(&long_actual,sizeof(unsigned long),1,f); return id; } //------------------------------------------------------------------------- // Read geometry vertex element. //------------------------------------------------------------------------- void GeoMeshLoader::readGeometryVertexElement(FILE *f, Mesh *geoMesh) { unsigned short source; GeometryElement aux; size_t i; bool found; VertexElementType vType; i = 0; found = false; // VertexElementSemantic vSemantic; // unsigned short source; // buffer bind source fread(&source,sizeof(unsigned short),1,f); // unsigned short type; // VertexElementType fread(&aux.type,sizeof(unsigned short),1,f); vType = static_cast(aux.type); // unsigned short semantic; // VertexElementSemantic fread(&aux.semantic,sizeof(unsigned short),1,f); // vSemantic = static_cast(tmp); // unsigned short offset; // start offset in buffer in bytes fread(&aux.offset,sizeof(unsigned short),1,f); // unsigned short index; // index of the semantic /* VES_POSITION Position, 3 reals per vertex. VES_BLEND_WEIGHTS Blending weights. VES_BLEND_INDICES Blending indices. VES_NORMAL Normal, 3 reals per vertex. VES_DIFFUSE Diffuse colours. VES_SPECULAR Specular colours. VES_TEXTURE_COORDINATES Texture coordinates. VES_BINORMAL Binormal (Y axis if normal is Z). VES_TANGENT Tangent (X axis if normal is Z). */ fread(&aux.index,sizeof(unsigned short),1,f); while ((i < list.size()) && (!found)) { if (list[i].source==source) { found = true; } else { i++; } } if (found) { list[i].list.push_back(aux); } else { GT aux2; aux2.source = source; aux2.list.push_back(aux); list.push_back(aux2); } } //------------------------------------------------------------------------- // Read geometry vertex declaration. //------------------------------------------------------------------------- void GeoMeshLoader::readGeometryVertexDeclaration(FILE *f, Mesh *geoMesh) { unsigned short chunkID; // Find optional geometry chunks if (!feof(f)) { chunkID = readChunk(f); while(!feof(f) && (chunkID == M_GEOMETRY_VERTEX_ELEMENT )) { switch (chunkID) { case M_GEOMETRY_VERTEX_ELEMENT: // Debug. cout << " M_GEOMETRY_VERTEX_ELEMENT" << endl; readGeometryVertexElement(f, geoMesh); break; } // Get next chunk if (!feof(f)) { chunkID = readChunk(f); } }// End while. if (!feof(f)) { // Backpedal back to start of non-submesh chunk fseek(f,-(long)CHUNK_OVERHEAD_SIZE,1); } }// End if (!feof(f)) }// End readGeometryVertexDeclaration. //------------------------------------------------------------------------- // Read geometry vertex buffer. //------------------------------------------------------------------------- void GeoMeshLoader::readGeometryVertexBuffer( FILE *f, Mesh *geoMesh, int option) { unsigned short bindIndex; unsigned short vertexSize; unsigned short headerID; size_t i; //float aux; size_t k; bool found; float x,y,z; SubMesh *geoSubMesh; VertexBuffer *vertex_buffer; i = 0; k = 0; found = false; if (option == GEOMESH_BUILD) { // If is the main mesh. if (currentSubMesh == -1) { vertex_buffer = geoMesh->mVertexBuffer; } // If is a submesh. else { // Gets the current submesh geoSubMesh = &geoMesh->mSubMesh[currentSubMesh]; vertex_buffer = geoSubMesh->mVertexBuffer; } } // Index to bind this buffer to fread(&bindIndex,sizeof(unsigned short),1,f); // Per-vertex size, must agree with declaration at this index fread(&vertexSize,sizeof(unsigned short),1,f); // Check for vertex data header headerID = readChunk(f); if (headerID != M_GEOMETRY_VERTEX_BUFFER_DATA) { cout << "Can't find vertex buffer data area" << endl; } else { // Debug. cout << " M_GEOMETRY_VERTEX_BUFFER_DATA" << endl; } while ((imVertexInfo |= VERTEX_POSITION; vertex_buffer->mPosition[k].x = x; vertex_buffer->mPosition[k].y = y; vertex_buffer->mPosition[k].z = z; } } // If are not vertices. else { if (list[i].list[j].type == 2) { fread(&x,sizeof(float),1,f); fread(&y,sizeof(float),1,f); fread(&z,sizeof(float),1,f); if (option == GEOMESH_BUILD) { vertex_buffer->mVertexInfo |= VERTEX_NORMAL; vertex_buffer->mNormal[k].x = x; vertex_buffer->mNormal[k].y = y; vertex_buffer->mNormal[k].z = z; } } if (list[i].list[j].type == 1) { fread(&x,sizeof(float),1,f); fread(&y,sizeof(float),1,f); if (option == GEOMESH_BUILD) { vertex_buffer->mVertexInfo |= VERTEX_TEXCOORDS; vertex_buffer->mTexCoords[k].x = x; vertex_buffer->mTexCoords[k].y = y; } } } } } } else { // Debug. cout << "Error: Source not found." << endl; // Error. mError = true; } } //------------------------------------------------------------------------- // Read Geometry. //------------------------------------------------------------------------- void GeoMeshLoader::readGeometry(FILE *f, Mesh *geoMesh, int option) { SubMesh *geoSubMesh; VertexBuffer *vertex_buffer; fread(&numVertices,sizeof(unsigned int),1,f); if (option == GEOMESH_BUILD) { if (currentSubMesh == -1) { // Get the current vertex buffer. vertex_buffer = geoMesh->mVertexBuffer; } else { // Get the current submesh. geoSubMesh = &geoMesh->mSubMesh[currentSubMesh]; // Create the VertexBuffer of the submesh. geoSubMesh->mVertexBuffer = new VertexBuffer(); // Get the current vertex buffer. vertex_buffer = geoSubMesh->mVertexBuffer; } // Initialize the VertexBuffer of the current submesh. vertex_buffer->mVertexCount = numVertices; // Initialize the position array. vertex_buffer->mPosition = new Vector3[numVertices]; // Initialize the normal array. vertex_buffer->mNormal = new Vector3[numVertices]; // Initialize the texture coords array. vertex_buffer->mTexCoords = new Vector2[numVertices]; } // Find optional geometry chunks if (!feof(f)) { unsigned short chunkID = readChunk(f); while(!feof(f) && (chunkID == M_GEOMETRY_VERTEX_DECLARATION || chunkID == M_GEOMETRY_VERTEX_BUFFER )) { switch (chunkID) { case M_GEOMETRY_VERTEX_DECLARATION: // Debug. cout << " M_GEOMETRY_VERTEX_DECLARATION" << endl; readGeometryVertexDeclaration(f, geoMesh); break; case M_GEOMETRY_VERTEX_BUFFER: // Debug. cout << " M_GEOMETRY_VERTEX_BUFFER" << endl; readGeometryVertexBuffer(f, geoMesh,option); break; } // Get next chunk. if (!feof(f)) { chunkID = readChunk(f); } } if (!feof(f)) { // Backpedal back to start of non-submesh chunk. fseek(f,-(long)CHUNK_OVERHEAD_SIZE,1); } } } //------------------------------------------------------------------------- // Read a submesh operation. //------------------------------------------------------------------------- void GeoMeshLoader::readSubMeshOperation( FILE *f, Mesh *geoMesh, int option) { unsigned short opType; fread(&opType,sizeof(unsigned short),1,f); if (option == GEOMESH_BUILD) { if (opType == 5) { geoMesh->mSubMesh[currentSubMesh].mType = GEO_TRIANGLE_STRIPS; } else { geoMesh->mSubMesh[currentSubMesh].mType = GEO_TRIANGLE_LIST; } } } //------------------------------------------------------------------------- // Read a submesh. //------------------------------------------------------------------------- void GeoMeshLoader::readSubMesh(FILE *f, Mesh *geoMesh, int option) { SubMesh *geoSubMesh; unsigned short chunkID; char materialName[255]; bool useSharedVertices; unsigned int numIndices; bool idx32bit; switch (option) { case SUBMESH_COUNT: geoMesh->mSubMeshCount++; break; case GEOMESH_BUILD: // Initialize the new subMesh. geoSubMesh = &geoMesh->mSubMesh[currentSubMesh]; } list.clear(); // Gets material name. fgets(materialName,255,f); materialName[strlen(materialName) - 1] = '\0'; fread(&useSharedVertices,sizeof(bool),1,f); if (option == GEOMESH_BUILD) { // Obtain the material name. strcpy(geoSubMesh->mMaterialName,materialName); // Obtain the flag of vertex shared. geoSubMesh->mSharedVertexBuffer = useSharedVertices; if (useSharedVertices) { // The VB of the submesh points to the VB of the mesh. geoSubMesh->mVertexBuffer = geoMesh->mVertexBuffer; } } fread(&numIndices,sizeof(unsigned int),1,f); fread(&idx32bit,sizeof(bool),1,f); if (option == GEOMESH_BUILD) { // Sets the index count of the submesh. geoSubMesh->mIndexCount = numIndices; // Create the index arrar for this submesh. geoSubMesh->mIndex = new Index[numIndices]; } if (idx32bit) { unsigned int aux; for (size_t i = 0; i < numIndices; i++) { fread(&aux,sizeof(unsigned int),1,f); if (option == GEOMESH_BUILD) { geoSubMesh->mIndex[i] = aux; } } } else { unsigned short aux; for (size_t i = 0; i < numIndices; i++) { fread(&aux,sizeof(unsigned short),1,f); if (option == GEOMESH_BUILD) { geoSubMesh->mIndex[i] = aux; } } } // M_GEOMETRY chunk // (Optional: present only if useSharedVertices = false) if (!useSharedVertices) { chunkID = readChunk(f); if (chunkID != M_GEOMETRY) { // Debug. cout << "Error: Missing mesh geometry." << endl; // Error. mError = true; } readGeometry(f, geoMesh, option); } // Find all bone assignments (if present) if (!feof(f)) { chunkID = readChunk(f); while(!feof(f) && (chunkID == M_SUBMESH_BONE_ASSIGNMENT || chunkID == M_SUBMESH_OPERATION)) { switch(chunkID) { case M_SUBMESH_OPERATION: // Debug. cout << " M_SUBMESH_OPERATION" << endl; readSubMeshOperation(f, geoMesh, option); break; case M_SUBMESH_BONE_ASSIGNMENT: // Debug. //cout << " M_SUBMESH_BONE_ASSIGNMENT" // << endl; if (option == GEOMESH_BUILD) { readSubMeshBoneAssignment(f, geoSubMesh, option); } else { jumpChunk(f); } break; } if (!feof(f)) { chunkID = readChunk(f); } } if (!feof(f)) { // Backpedal back to start of chunk. fseek(f,-(long)CHUNK_OVERHEAD_SIZE,1); } } } //------------------------------------------------------------------------- // Read a mesh lod information. //------------------------------------------------------------------------- void GeoMeshLoader::readMeshLodInfo(FILE *f, Mesh *geoMesh) { unsigned short chunkID; unsigned short i; unsigned short aux; bool aux2; // unsigned short numLevels; fread(&aux,sizeof(unsigned short),1,f); // bool manual; // (true for manual alternate meshes, false for generated) fread(&aux2,sizeof(bool),1,f); // Loop from 1 rather than 0 (full detail index is not in file) for (i = 1; i < aux; ++i) { chunkID = readChunk(f); if (chunkID != M_MESH_LOD_USAGE) { // Debug. cout << "Error: Missing M_MESH_LOD_USAGE chunk" << endl; } else { cout << " M_MESH_LOD_USAGE" << endl; } jumpChunk(f); } } //------------------------------------------------------------------------- // Read a submesh name table. //------------------------------------------------------------------------- void GeoMeshLoader::readSubMeshNameTable(FILE *f, Mesh *geoMesh) { unsigned short chunkID; unsigned short subMeshIndex; char string[255]; if (!feof(f)) { chunkID = readChunk(f); while (!feof(f) && (chunkID == M_SUBMESH_NAME_TABLE_ELEMENT )) { // Debug. cout << " M_SUBMESH_NAME_TABLE_ELEMENT" << endl; // Read in the index of the submesh. fread(&subMeshIndex,sizeof(unsigned short),1,f); // Read in the String and map it to its index. fgets(string,255,f); // If we're not end of file get the next chunk ID. if (!feof(f)) { chunkID = readChunk(f); } } if (!feof(f)) { // Backpedal back to start of chunk. fseek(f,-(long)CHUNK_OVERHEAD_SIZE,1); } } } //------------------------------------------------------------------------- // Read a mesh file. //------------------------------------------------------------------------- #include "GeoLodStripsLibrary.h" #include "GeoLodStripsConstructor.h" void GeoMeshLoader::readMesh(FILE *f, Mesh *geoMesh, int option) { unsigned short chunkID; bool nada; // Create the VertexBuffer of the mesh. geoMesh->mVertexBuffer = new VertexBuffer(); geoMesh->mVertexBuffer->mVertexCount = 0; //La vacio antes de leer el mesh list.clear(); // bool skeletallyAnimated fread(&nada,sizeof(bool),1,f); // Find all subchunks if (!feof(f)) { chunkID = readChunk(f); while(!feof(f) && (chunkID == M_GEOMETRY || chunkID == M_SUBMESH || chunkID == M_MESH_SKELETON_LINK || chunkID == M_MESH_BONE_ASSIGNMENT || chunkID == M_MESH_LOD || chunkID == M_MESH_BOUNDS || chunkID == M_SUBMESH_NAME_TABLE || chunkID == M_EDGE_LISTS || chunkID == 0xabcd || chunkID == 0xdcba)) { switch(chunkID) { case 0xabcd: // Debug. cout << "LODSTRIPS_Chunk" << endl; lodstripsdata = new Geometry::LodStripsLibraryData; int aux,v,c; LODRegisterType lod_register; LODData dataaux; int tam; fread(&tam, sizeof(int), 1, f); lodstripsdata->mFileVertices.clear(); for (v = 0; v < tam; v++) { fread(&aux, sizeof(int), 1, f); lodstripsdata->mFileVertices.push_back(aux); } lodstripsdata->mFileChangesLOD.clear(); fread(&tam, sizeof(int), 1, f); for (c = 0; c < tam; c++) { fread(&dataaux, sizeof(LODData), 1, f); lod_register.strip= dataaux.strip; lod_register.position= dataaux.nP; lod_register.vertexRepetition= dataaux.nL1; lod_register.edgeRepetition= dataaux.nL2; lod_register.obligatory=dataaux.obligatory; lodstripsdata->mFileChangesLOD.push_back(lod_register); } lodstripsdata->mData.clear(); fread(&tam, sizeof(int), 1, f); for (int b = 0; b < tam; b++) { fread(&aux, sizeof(int), 1, f); lodstripsdata->mData.push_back(aux); } lodstripsdata->p_changes.clear(); fread(&tam, sizeof(int), 1, f); for (int p = 0; p < tam; p++) { fread(&aux, sizeof(int), 1, f); lodstripsdata->p_changes.push_back(aux); } break; case 0xdcba: cout << "LODTREES_Chunk" << endl; treesimpseq = new Geometry::TreeSimplificationSequence; int size; fread(&size, sizeof(int), 1, f); treesimpseq->mSteps.clear(); for (int i=0; imSteps.push_back(auxstep); } break; case M_GEOMETRY: // Debug. cout << " M_GEOMETRY" << endl; readGeometry(f, geoMesh, option); break; case M_SUBMESH: // Debug. cout << " M_SUBMESH" << endl; if (option == GEOMESH_BUILD) { // Increments the current submesh. currentSubMesh++; } readSubMesh(f, geoMesh, option); break; case M_MESH_SKELETON_LINK: // Debug. cout << " M_MESH_SKELETON_LINK " << endl; readSkeletonLink(f, geoMesh, option); break; case M_MESH_BONE_ASSIGNMENT: // Debug. //cout << " M_MESH_BONE_ASSIGNMENT " // << endl; readMeshBoneAssignment(f, geoMesh, option); break; case M_MESH_LOD: // Debug. cout << " M_MESH_LOD" << endl; readMeshLodInfo(f, geoMesh); break; case M_MESH_BOUNDS: // Debug. cout << " M_MESH_BOUNDS " << endl; //jumpChunk(f); readMeshBounds(f, geoMesh, option); break; case M_SUBMESH_NAME_TABLE: // Debug. cout << " M_SUBMESH_NAME_TABLE " << endl; readSubMeshNameTable(f, geoMesh); break; case M_EDGE_LISTS: // Debug. cout << " M_EDGE_LISTS " << endl; jumpChunk(f); break; } if (!feof(f)) { chunkID = readChunk(f); } } if (!feof(f)) { // Backpedal back to start of chunk fseek(f,-(long)CHUNK_OVERHEAD_SIZE,1); // Debug. cout << "Error: Reading failure." << endl; // Error. mError = true; } } } //------------------------------------------------------------------------- // Allocate memory to the array of strips //------------------------------------------------------------------------- SubMesh* GeoMeshLoader::BuildStripsGeoSubMesh(SubMesh* geoSubMesh) { bool head_found; bool tail_found; size_t strip_count; size_t tailIndex; //size_t tail; head_found = false; tail_found = false; geoSubMesh->mStripCount = 1; // Foreachone of the indices. // Obtains the number of triangle strips. for (size_t i = 0; i < (geoSubMesh->mIndexCount - 1); i++) { if (geoSubMesh->mIndex[i] == geoSubMesh->mIndex[i+1]) { if (head_found) { tail_found = true; } else { head_found = true; } // Jump one index. i++; } else { // Increments the number of triangle strips. if (tail_found) { geoSubMesh->mStripCount++; } head_found = false; tail_found = false; } } geoSubMesh->mStrip = (Index**) malloc( sizeof(Index*) * geoSubMesh->mStripCount); // Number of strips. Initially there is one triangle strip. strip_count = 1; head_found = false; tail_found = false; // Initialize the fist triangle strip. geoSubMesh->mStrip[0] = &geoSubMesh->mIndex[0]; // Foreachone of the indices. // Assigns the beginning of the triangle strips. for(size_t i = 0;i < (geoSubMesh->mIndexCount - 1); i++) { if(geoSubMesh->mIndex[i] == geoSubMesh->mIndex[i+1]) { if(head_found) { if (!tail_found) { tailIndex = i; } tail_found = true; } else { head_found = true; } // Jump one index. i++; } else { // Increments the number of triangle strips. if(tail_found) { geoSubMesh->mStrip[strip_count++] = &geoSubMesh->mIndex[tailIndex]; } head_found = false; tail_found = false; } } // Remove degenerate triangles of a submesh given. //geoSubMesh = removeDegenerateTriangles(geoSubMesh); return geoSubMesh; } //------------------------------------------------------------------------- // Remove degenerate triangles of a submesh given. //------------------------------------------------------------------------- SubMesh * GeoMeshLoader::removeDegenerateTriangles(SubMesh *geoSubMesh) { Index *indices; Index *index; Index *indexBegin; Index *indexEnd; Index *new_strip_starts; size_t new_index_count; size_t current_index; // Stores the new starts of strips. new_strip_starts = new Index[geoSubMesh->mStripCount]; // Calculate the new index count. new_index_count = geoSubMesh->mIndexCount - (2 * geoSubMesh->mStripCount) + 2; // Auxiliar index array. indices = new Index[new_index_count]; // Initialize the current index. current_index = 0; // For each one of the strips. for (size_t strip = 0; strip < geoSubMesh->mStripCount; strip++) { // Stars of strip without degenerate triangles. new_strip_starts[strip] = (Index)current_index; // First index of the strip. indexBegin = geoSubMesh->mStrip[strip]; // If is the final strip if (strip == (geoSubMesh->mStripCount - 1)) { // The end of the index array. indexEnd = &geoSubMesh->mIndex[geoSubMesh->mIndexCount]; } else { // The beginning of the next strip. indexEnd = geoSubMesh->mStrip[strip + 1]; } int i; i = 0; // If is not the first strip. if (strip != 0) { indexBegin++; } // If is not the last strip. if (strip != (geoSubMesh->mStripCount - 1)) { indexEnd--; } // For each index of the strip. for (index = indexBegin; index < indexEnd; index++) { indices[current_index++] = indexBegin[i]; // Increments i. i++; } } // Free Index memory. delete []geoSubMesh->mIndex; // Update index count. geoSubMesh->mIndexCount = new_index_count; geoSubMesh->mIndex = new Index[new_index_count]; // Store new index array without degenerate triangles. for (size_t i = 0; i < geoSubMesh->mIndexCount; i++) { geoSubMesh->mIndex[i] = indices[i]; } // Free auxiliar index array; delete []indices; // Update start of the strip. for (size_t strip = 0; strip < geoSubMesh->mStripCount; strip++) { geoSubMesh->mStrip[strip] = &geoSubMesh->mIndex[new_strip_starts[strip]]; } // Free auxiliar strip starts. delete []new_strip_starts; return geoSubMesh; } //------------------------------------------------------------------------- // Loads a mesh. //------------------------------------------------------------------------- Mesh* GeoMeshLoader::load(char *nameFileMesh) { unsigned short uno; unsigned short chunkID; char version[255]; FILE *pFile; SubMesh *geosubmesh; // Debug. cout << "---------------------------------" << endl << "\t LOAD MESH" << endl << "---------------------------------" << endl; // retrieve the extension of the file std::string fileExt; std::string completeFileName(nameFileMesh); for (std::string::reverse_iterator it = completeFileName.rbegin(); it!=completeFileName.rend(); it++) if (*it=='.') break; else fileExt += *it; std::transform(fileExt.begin(), fileExt.end(), fileExt.begin(), std::toupper); reverse(fileExt.begin(),fileExt.end()); geoMesh = NULL; if (lodstripsdata) { delete lodstripsdata; } lodstripsdata = NULL; if (treesimpseq) { delete treesimpseq; } treesimpseq = NULL; // Open the mesh file. pFile = fopen(nameFileMesh, "rb"); if (pFile) { // Initialize the current submesh; currentSubMesh = -1; // Initialize the return value. geoMesh = new Mesh(); if (fileExt == std::string("OBJ")) { mError = false; importOBJ(pFile,geoMesh); } else { // Count the submeshes // and next build the geomesh. for (int option = 0; option < 2;option++) { // Initialize Error. mError = false; fread(&uno,sizeof(unsigned short),1,pFile); if (uno != M_HEADER) { // Debug. cout << "Error: Header not found." << endl; // Error. mError = true; } // Read version. fgets(version,255,pFile); cout << version << endl; while(!feof(pFile)) { chunkID = readChunk(pFile); switch (chunkID) { case M_MESH: readMesh(pFile, geoMesh, option); break; } } // Create the submesh array. if (option == SUBMESH_COUNT) { geoMesh->mSubMesh = new SubMesh[geoMesh->mSubMeshCount]; } // Move the curso to the begining of the file. fseek(pFile,0,SEEK_SET); } // Goes to the end of the file. fseek(pFile,0,SEEK_END); // Gets the size of the file. mFileSize = ftell(pFile); } // Close the mesh file. fclose(pFile); // If no error. if (!mError) { for (size_t submesh = 0; submesh < geoMesh->mSubMeshCount; submesh++) { // Gets the actual submesh. geosubmesh = &geoMesh->mSubMesh[submesh]; if (geosubmesh->mType == Geometry::GEO_TRIANGLE_STRIPS) { // Fill the strips list. geosubmesh = BuildStripsGeoSubMesh(geosubmesh); } } // Sets coods between -1 and 1. normalizeModel(geoMesh); } } else { // Debug. cout << "Error: File not found." << endl; // File not found. mError = true; } // If an error happens. if (mError) { delete geoMesh; geoMesh = NULL; } return geoMesh; } //------------------------------------------------------------------------- // Sets coords between -1 and 1. //------------------------------------------------------------------------- void GeoMeshLoader::normalizeModel(Mesh *geoMesh) { float maxx, minx, maxy, miny, maxz, minz; float cx, cy, cz, w, h, d, max; float scale; VertexBuffer *vertex_buffer; // Gets vertex buffer. vertex_buffer = geoMesh->mSubMesh[0].mVertexBuffer; // Get the max/mins. maxx = minx = vertex_buffer->mPosition[0].x; maxy = miny = vertex_buffer->mPosition[0].y; maxz = minz = vertex_buffer->mPosition[0].z; // For each submesh. for (size_t submesh = 0; submesh < geoMesh->mSubMeshCount; submesh++) { // Gets the actual submesh. vertex_buffer = geoMesh->mSubMesh[submesh].mVertexBuffer; // For each index of the strip. for (size_t i = 0; i < vertex_buffer->mVertexCount; i++) { if (maxx < vertex_buffer->mPosition[i].x) { maxx = vertex_buffer->mPosition[i].x; } if (minx > vertex_buffer->mPosition[i].x) { minx = vertex_buffer->mPosition[i].x; } if (maxy < vertex_buffer->mPosition[i].y) { maxy = vertex_buffer->mPosition[i].y; } if (miny > vertex_buffer->mPosition[i].y) { miny = vertex_buffer->mPosition[i].y; } if (maxz < vertex_buffer->mPosition[i].z) { maxz = vertex_buffer->mPosition[i].z; } if (minz > vertex_buffer->mPosition[i].z) { minz = vertex_buffer->mPosition[i].z; } } // If is a shared vertex Buffer. if (geoMesh->mSubMesh[submesh].mSharedVertexBuffer) { break; } } // Calculate model width, height, and depth. w = fabs(maxx) + fabs(minx); h = fabs(maxy) + fabs(miny); d = fabs(maxz) + fabs(minz); // Calculate center of the model. cx = (maxx + minx) / 2.0f; cy = (maxy + miny) / 2.0f; cz = (maxz + minz) / 2.0f; // Calculate max dimension. if (w > h) { max = w; } else { max = h; } if (d > max) { max = d; } // Calculate unitizing scale factor. scale = 1.0f / max; geoMesh->mMeshBounds.scaleFactor = scale; bool *sharedmesh; sharedmesh = new bool[geoMesh->mSubMeshCount]; bool firstsharedmesh = true; for (size_t submesh = 0; submesh < geoMesh->mSubMeshCount; submesh++) { if (geoMesh->mSubMesh[submesh].mSharedVertexBuffer) { sharedmesh[submesh] = true; } else { sharedmesh[submesh] = false; } } // Translate around center then scale. // For each submesh. for (size_t submesh = 0; submesh < geoMesh->mSubMeshCount; submesh++) { // If is a shared vertex Buffer. if (geoMesh->mSubMesh[submesh].mSharedVertexBuffer) { if (!firstsharedmesh) { continue; } else { firstsharedmesh = false; } } // Gets the actual submesh. vertex_buffer = geoMesh->mSubMesh[submesh].mVertexBuffer; // For each index of the strip. for (size_t i = 0; i < vertex_buffer->mVertexCount; i++) { vertex_buffer->mPosition[i].x -= cx; vertex_buffer->mPosition[i].y -= cy; vertex_buffer->mPosition[i].z -= cz; vertex_buffer->mPosition[i].x *= scale; vertex_buffer->mPosition[i].y *= scale; vertex_buffer->mPosition[i].z *= scale; } } delete[] sharedmesh; } //------------------------------------------------------------------------- // Get the size in bytes of the file. //------------------------------------------------------------------------- size_t GeoMeshLoader::getFileSize() { return mFileSize; } //------------------------------------------------------------------------- // Constructor //------------------------------------------------------------------------- GeoMeshLoader::GeoMeshLoader() { geoMesh = NULL; mFileSize = 0; lodstripsdata = NULL; treesimpseq = NULL; } //------------------------------------------------------------------------- // Destroyer. //------------------------------------------------------------------------- GeoMeshLoader::~GeoMeshLoader() { if (geoMesh) { delete geoMesh; } if (lodstripsdata) { delete lodstripsdata; } if (treesimpseq) { delete treesimpseq; } } //------------------------------------------------------------------------- // Read bones of the submesh. //------------------------------------------------------------------------- void GeoMeshLoader::readSubMeshBoneAssignment(FILE *f, SubMesh *geoSubMesh, int option) { if (option == GEOMESH_BUILD) { VertexBoneAssignment assign; // unsigned int vertexIndex; fread(&(assign.vertexIndex),sizeof(unsigned int),1,f); // unsigned short boneIndex; fread(&(assign.boneIndex),sizeof(unsigned short),1,f); // float weight fread(&(assign.weight),sizeof(float),1,f); geoSubMesh->mBones.push_back(assign); } } //------------------------------------------------------------------------- // Read bones of the main mesh. //------------------------------------------------------------------------- void GeoMeshLoader::readMeshBoneAssignment(FILE *f, Mesh *geoMesh, int option) { if (option == GEOMESH_BUILD) { VertexBoneAssignment assign; // unsigned int vertexIndex; fread(&(assign.vertexIndex),sizeof(unsigned int),1,f); // unsigned short boneIndex; fread(&(assign.boneIndex),sizeof(unsigned short),1,f); // float weight fread(&(assign.weight),sizeof(float),1,f); geoMesh->mBones.push_back(assign); } } //------------------------------------------------------------------------- // Read skeleton link. //------------------------------------------------------------------------- void GeoMeshLoader::readSkeletonLink(FILE *f, Mesh *geoMesh, int option) { if (option == GEOMESH_BUILD) { fgets(geoMesh->mSkeletonName,255,f); geoMesh->hasSkeleton = true; // Debug. cout << "Skeleton Name: " << geoMesh->mSkeletonName << endl; } } //------------------------------------------------------------------------- // Read bounding box settings. //------------------------------------------------------------------------- void GeoMeshLoader::readMeshBounds(FILE *f, Mesh *geoMesh, int option) { if (option == GEOMESH_BUILD) { fread(&(geoMesh->mMeshBounds.minX),sizeof(float),1,f); fread(&(geoMesh->mMeshBounds.minY),sizeof(float),1,f); fread(&(geoMesh->mMeshBounds.minZ),sizeof(float),1,f); fread(&(geoMesh->mMeshBounds.maxX),sizeof(float),1,f); fread(&(geoMesh->mMeshBounds.maxY),sizeof(float),1,f); fread(&(geoMesh->mMeshBounds.maxZ),sizeof(float),1,f); fread(&(geoMesh->mMeshBounds.radius),sizeof(float),1,f); } } struct face_t { int v1,v2,v3; int t1,t2,t3; int n1,n2,n3; }; class VertexArranger { public: VertexArranger(Geometry::Mesh *m) { mesh = m; current_submesh = 0; current_tris = new int[m->mSubMeshCount]; for (size_t i = 0; i < m->mSubMeshCount; i++) { current_tris[i] = 0; } } ~VertexArranger(void) { delete[] current_tris; } void AddFace(int v1, int v2, int v3, int t1, int t2, int t3, int n1, int n2, int n3){ Geometry::SubMesh *submesh = mesh->mSubMesh + current_submesh; vertex_arranger_node vertex1(v1,n1,t1); vertex_arranger_node vertex2(v2,n2,t2); vertex_arranger_node vertex3(v3,n3,t3); int j = current_tris[current_submesh]; std::map::iterator res; res=vertex_map.find(vertex1); if (res==vertex_map.end()) { int val = (int)vertex_map.size(); vertex_map[vertex1] = val; submesh->mIndex[j*3+0] = val; } else submesh->mIndex[j*3+0] = res->second; res=vertex_map.find(vertex2); if (res==vertex_map.end()) { int val = (int)vertex_map.size(); vertex_map[vertex2] = val; submesh->mIndex[j*3+1] = val; } else submesh->mIndex[j*3+1] = res->second; res=vertex_map.find(vertex3); if (res==vertex_map.end()) { int val = (int)vertex_map.size(); vertex_map[vertex3] = val; submesh->mIndex[j*3+2] = val; } else { submesh->mIndex[j*3+2] = res->second; } current_tris[current_submesh] ++; } int GetVertexCount(void) const { return (int)vertex_map.size(); } void SetCurrentSubMesh(int i) { current_submesh = i; } class vertex_arranger_node { public: int v, n, t; vertex_arranger_node(void){ v=n=t=-1; } vertex_arranger_node(int iv, int in=-1, int it=-1){ v=iv; n=in; t=it; } bool operator<(const vertex_arranger_node &vu) const { if (vvu.v) return false; if (nvu.n) return false; if (tvu.t) return false; return false; } bool operator==(const vertex_arranger_node &vu) const { return (v==vu.v && v==vu.v && n==vu.n && n==vu.n && t==vu.t && t==vu.t); } }; /* VertexArranger::vertex_arranger_node *GetVertexInfo(void) const { vertex_arranger_node * vertex_list = new vertex_arranger_node[GetVertexCount()]; for (std::map::const_iterator it=vertex_map.begin(); it!=vertex_map.end(); it++) vertex_list[it->second] = it->first; return vertex_list; } const std::vector GetIndexInfo(void) const { return indices; }*/ void Arrange( const std::vector & vertices, const std::vector & normals, const std::vector & texcoords){ mesh->mVertexBuffer=new Geometry::VertexBuffer; mesh->mVertexBuffer->mVertexCount = GetVertexCount(); mesh->mVertexBuffer->mPosition = new Geometry::Vector3[mesh->mVertexBuffer->mVertexCount]; mesh->mVertexBuffer->mTexCoords = texcoords.empty()?NULL:new Geometry::Vector2[mesh->mVertexBuffer->mVertexCount]; mesh->mVertexBuffer->mNormal = normals.empty()?NULL:new Geometry::Vector3[mesh->mVertexBuffer->mVertexCount]; mesh->mVertexBuffer->mVertexInfo = Geometry::VERTEX_POSITION | (texcoords.empty()?0:Geometry::VERTEX_TEXCOORDS) | (normals.empty()?0:Geometry::VERTEX_NORMAL); // sort the calculated vertices vertex_arranger_node * vertex_list = new vertex_arranger_node[mesh->mVertexBuffer->mVertexCount]; for (std::map::iterator it=vertex_map.begin(); it!=vertex_map.end(); it++) vertex_list[it->second] = it->first; for ( size_t i = 0; i < mesh->mSubMeshCount; i++) { mesh->mSubMesh[i].mVertexBuffer = mesh->mVertexBuffer; } for (size_t j = 0; j < mesh->mVertexBuffer->mVertexCount; j++) { int vi = vertex_list[j].v; int ti = vertex_list[j].t; int ni = vertex_list[j].n; Geometry::Vector3 auxpos(vertices[vi]); if (auxpos.x < mesh->mMeshBounds.minX) { mesh->mMeshBounds.minX = auxpos.x; } if (auxpos.y < mesh->mMeshBounds.minY) { mesh->mMeshBounds.minY = auxpos.y; } if (auxpos.z < mesh->mMeshBounds.minZ) { mesh->mMeshBounds.minZ = auxpos.z; } if (auxpos.x > mesh->mMeshBounds.maxX) { mesh->mMeshBounds.maxX = auxpos.x; } if (auxpos.y > mesh->mMeshBounds.maxY) { mesh->mMeshBounds.maxY = auxpos.y; } if (auxpos.z > mesh->mMeshBounds.maxZ) { mesh->mMeshBounds.maxZ = auxpos.z; } mesh->mVertexBuffer->mPosition[j] = auxpos; mesh->mVertexBuffer->mNormal[j] = normals[ni]; if (texcoords.empty() == false) { mesh->mVertexBuffer->mTexCoords[j] = texcoords[ti]; } } delete[] vertex_list; } //private: std::map vertex_map; Geometry::Mesh *mesh; int current_submesh; int *current_tris; }; void GeoMeshLoader::importOBJ(FILE *f, Mesh *mesh) { mesh->hasSkeleton=false; mesh->mSubMeshCount=0; std::vector vertices; std::vector normals; std::vector texcoords; std::vector > faces; std::vector current_faces; mesh->mMeshBounds.maxX = -99999999.9f; mesh->mMeshBounds.maxY = -99999999.9f; mesh->mMeshBounds.maxZ = -99999999.9f; mesh->mMeshBounds.minX = 99999999.9f; mesh->mMeshBounds.minY = 99999999.9f; mesh->mMeshBounds.minZ = 99999999.9f; mesh->mMeshBounds.radius = 1.0f; mesh->mMeshBounds.scaleFactor = 1.0f; char line[256]=""; while(!feof(f)) { fgets(line,256,f); if (line[0]=='v' && line[1]==' ') { Geometry::Vector3 v3; sscanf(line+2,"%f %f %f",&v3.x,&v3.y,&v3.z); vertices.push_back(v3); } else if (line[0]=='v' && line[1]=='t') { Geometry::Vector2 v2; sscanf(line+2,"%f %f",&v2.x,&v2.y); texcoords.push_back(v2); } else if (line[0]=='v' && line[1]=='n') { Geometry::Vector3 v3; sscanf(line+2,"%f %f %f",&v3.x,&v3.y,&v3.z); normals.push_back(v3); } else if (line[0]=='f') { face_t auxface; auxface.n1=auxface.n2=auxface.n3=auxface.t1=auxface.t2=auxface.t3=auxface.v1=auxface.v2=auxface.v3=0; int n = sscanf(line+2,"%d/%d/%d %d/%d/%d %d/%d/%d", &auxface.v1,&auxface.t1,&auxface.n1, &auxface.v2,&auxface.t2,&auxface.n2, &auxface.v3,&auxface.t3,&auxface.n3); if (n<9) { auxface.n1=auxface.n2=auxface.n3=auxface.t1=auxface.t2=auxface.t3=auxface.v1=auxface.v2=auxface.v3=0; n = sscanf(line+2,"%d//%d %d//%d %d//%d", &auxface.v1,&auxface.n1, &auxface.v2,&auxface.n2, &auxface.v3,&auxface.n3); if (n<6) { auxface.n1=auxface.n2=auxface.n3=auxface.t1=auxface.t2=auxface.t3=auxface.v1=auxface.v2=auxface.v3=0; n = sscanf(line+2,"%d/%d %d/%d %d/%d", &auxface.v1,&auxface.t1, &auxface.v2,&auxface.t2, &auxface.v3,&auxface.t3); if (n<6) { auxface.n1=auxface.n2=auxface.n3=auxface.t1=auxface.t2=auxface.t3=auxface.v1=auxface.v2=auxface.v3=0; n = sscanf(line+2,"%d %d %d", &auxface.v1,&auxface.v2,&auxface.v3); } } } auxface.v1=abs(auxface.v1); auxface.v2=abs(auxface.v2); auxface.v3=abs(auxface.v3); auxface.t1=abs(auxface.t1); auxface.t2=abs(auxface.t2); auxface.t3=abs(auxface.t3); auxface.n1=abs(auxface.n1); auxface.n2=abs(auxface.n2); auxface.n3=abs(auxface.n3); auxface.v1--; auxface.v2--; auxface.v3--; auxface.t1--; auxface.t2--; auxface.t3--; auxface.n1--; auxface.n2--; auxface.n3--; current_faces.push_back(auxface); } else if (line[0]=='g') { if (current_faces.size()>0) faces.push_back(current_faces); current_faces.clear(); } } if (current_faces.size()>0) faces.push_back(current_faces); current_faces.clear(); mesh->mSubMeshCount = faces.size(); bool found_texcoords=!texcoords.empty(); if (normals.empty()) { // calculate face normals for (size_t i=0, inormal=0; imSubMeshCount; i++) { Geometry::SubMesh *submesh = mesh->mSubMesh+i; std::vector & vecfaces = faces[i]; int j=0; for (std::vector::iterator it=vecfaces.begin(); it!=vecfaces.end(); it++,j++,inormal++) { face_t & auxface = *it; auxface.n1 = (int)inormal; auxface.n2 = (int)inormal; auxface.n3 = (int)inormal; Geometry::Vector3 v1,v2,v3,v31,v21,nor; v1 = vertices[auxface.v1]; v2 = vertices[auxface.v2]; v3 = vertices[auxface.v3]; v31 = v3 - v1; v21 = v2 - v1; nor = v21.crossProduct(v31); nor.normalise(); normals.push_back(nor); } } } // fill up the mesh structure with the loaded information VertexArranger vertex_arranger(mesh); mesh->mSubMesh=new Geometry::SubMesh[mesh->mSubMeshCount]; for (size_t i = 0; i < mesh->mSubMeshCount; i++) { Geometry::SubMesh *submesh = mesh->mSubMesh+i; int j=0; const std::vector & vecfaces = faces[i]; std::vector aux_indices; submesh->mSharedVertexBuffer = true; submesh->mIndexCount = vecfaces.size()*3; submesh->mIndex=new Geometry::Index[submesh->mIndexCount]; vertex_arranger.SetCurrentSubMesh((int)i); for (std::vector::const_iterator it=vecfaces.begin(); it!=vecfaces.end(); it++,j++) { const face_t & auxface = *it; vertex_arranger.AddFace(auxface.v1,auxface.v2,auxface.v3, auxface.t1,auxface.t2,auxface.t3, auxface.n1,auxface.n2,auxface.n3); } } vertex_arranger.Arrange(vertices,normals,texcoords); }