Keos3DSLoader.cpp

Go to the documentation of this file.
00001 /*
00002  * This source file is part of KEOS (Free 3D Engine)
00003  * For the latest info, see http://www.keosengine.org/
00004  * E-mails : thierry.vouriot@keosengine.org, yeri@keosengine.org
00005  *
00006  * This program is free software; you can redistribute it and/or modify it under
00007  * the terms of the GNU Lesser General Public License as published by the Free Software
00008  * Foundation; either version 2 of the License, or (at your option) any later
00009  * version.
00010  *
00011  * This program is distributed in the hope that it will be useful, but WITHOUT
00012  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00013  * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU Lesser General Public License along with
00016  * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
00017  * Place - Suite 330, Boston, MA 02111-1307, USA, or go to
00018  * http://www.gnu.org/copyleft/lesser.txt.
00019  *
00020  */
00021 #include "Keos3DSLoader.h"
00022 #include "KeosRenderSystem.h"
00023 #include "KeosLogger.h"
00024 #include "KeosMesh.h"
00025 #include "KeosString.h"
00026 #include "KeosUtil.h"
00027 #include <fstream>
00028 
00029 namespace Keos
00030 {
00031   //=======================================================================
00032   // C3DSLoader implementation
00033   //=======================================================================
00034 
00035   //-----------------------------------------------------------------------
00036   C3DSLoader::C3DSLoader()
00037   {
00038     m_pTexCoords = NULL;
00039     m_pVertices = NULL;
00040 
00041     m_nNumTexVertex = 0;
00042     m_nObjectWithMultMaterial = 0;
00043   }
00044 
00045   //-----------------------------------------------------------------------
00046   CMesh* C3DSLoader::LoadFromFile(const String& strFilename)
00047   {
00048     m_CurrentChunk = new TChunk;    // Initialize and allocate our current chunk
00049     m_TempChunk = new TChunk;     // Initialize and allocate a temporary chunk
00050 
00051     // Open the 3DS file
00052     m_FilePointer = fopen(strFilename.c_str(), "rb");
00053 
00054     ILogger::Log("Load of the mesh : %s", strFilename.c_str());
00055 
00056     // Make sure we have a valid file pointer (we found the file)
00057     if (!m_FilePointer)
00058       LOADINGFAILED_EXCEPT(strFilename, "Unable to find the file !", "C3DSLoader::LoadFromFile");
00059 
00060     // Once we have the file open, we need to read the very first data chunk
00061     // to see if it's a 3DS file.  That way we don't read an invalid file.
00062     // If it is a 3DS file, then the first chunk ID will be equal to PRIMARY (some hex num)
00063 
00064     // Read the first chuck of the file to see if it's a 3DS file
00065     ReadChunk(m_CurrentChunk);
00066 
00067     // Make sure this is a 3DS file
00068     if (m_CurrentChunk->ID != CHUNK_PRIMARY)
00069       LOADINGFAILED_EXCEPT(strFilename, "The file is not a valid model 3DS !", "C3DSLoader::LoadFromFile");
00070 
00071     CMesh* pMesh = new CMesh();
00072 
00073     // Now we actually start reading in the data.  ProcessNextChunk() is recursive
00074     ProcessNextChunk(pMesh, m_CurrentChunk);
00075 
00076     // Clean up after everything
00077     CleanUp();
00078 
00079     // Calculate normals
00080     pMesh->ComputeNormals();
00081 
00082     return pMesh;
00083   }
00084 
00085   //-----------------------------------------------------------------------
00086   void C3DSLoader::CleanUp()
00087   {
00088     fclose(m_FilePointer);      // Close the current file pointer
00089     delete m_CurrentChunk;      // Free the current chunk
00090     delete m_TempChunk;       // Free our temporary chunk
00091   }
00092 
00093   //-----------------------------------------------------------------------
00094   void C3DSLoader::ProcessNextChunk(CMesh *pMesh, TChunk *pPreviousChunk)
00095   {
00096     unsigned int version = 0;     // This will hold the file version
00097     int buffer[50000] = {0};     // This is used to read past unwanted data
00098     char strBuffer[256] = {0};
00099 
00100     m_CurrentChunk = new TChunk;    // Allocate a new chunk
00101 
00102     // Below we check our chunk ID each time we read a new chunk.  Then, if
00103     // we want to extract the information from that chunk, we do so.
00104     // If we don't want a chunk, we just read past it.
00105 
00106     // Continue to read the sub chunks until we have reached the length.
00107     // After we read ANYTHING we add the bytes read to the chunk and then check
00108     // check against the length.
00109     while (pPreviousChunk->bytesRead < pPreviousChunk->length)
00110     {
00111       // Read next Chunk
00112       ReadChunk(m_CurrentChunk);
00113 
00114       // Check the chunk ID
00115       switch (m_CurrentChunk->ID)
00116       {
00117         case CHUNK_VERSION:       // This holds the version of the file
00118 
00119           // This chunk has an unsigned short that holds the file version.
00120           // Since there might be new additions to the 3DS file format in 4.0,
00121           // we give a warning to that problem.
00122 
00123           // Read the file version and add the bytes read to our bytesRead variable
00124           m_CurrentChunk->bytesRead += fread(&version, 1, m_CurrentChunk->length - m_CurrentChunk->bytesRead, m_FilePointer);
00125 
00126           // If the file version is over 3, give a warning that there could be a problem
00127           if (version > 0x03)
00128             ILogger::Log("WARNING - This 3DS file is over version 3 so it may load incorrectly");
00129           break;
00130 
00131         case CHUNK_OBJECTINFO:      // This holds the version of the mesh
00132 
00133           // This chunk holds the version of the mesh.  It is also the head of the MATERIAL
00134           // and OBJECT chunks.  From here on we start reading in the material and object info.
00135 
00136           // Read the next chunk
00137           ReadChunk(m_TempChunk);
00138 
00139           // Get the version of the mesh
00140           m_TempChunk->bytesRead += fread(&version, 1, m_TempChunk->length - m_TempChunk->bytesRead, m_FilePointer);
00141 
00142           // Increase the bytesRead by the bytes read from the last chunk
00143           m_CurrentChunk->bytesRead += m_TempChunk->bytesRead;
00144 
00145           // Go to the next chunk, which is the object has a texture, it should be MATERIAL, then OBJECT.
00146           ProcessNextChunk(pMesh, m_CurrentChunk);
00147           break;
00148 
00149         case CHUNK_MATERIAL:       // This holds the material information
00150         {
00151           // This chunk is the header for the material info chunks
00152 
00153           // Add a empty material to mesh material list.
00154           CMaterial* pMaterial = new CMaterial();
00155           pMesh->GetMaterialList().push_back(pMaterial);
00156 
00157           // Proceed to the material loading function
00158           ProcessNextMaterialChunk(pMesh, m_CurrentChunk);
00159         }
00160         break;
00161 
00162         case CHUNK_OBJECT:       // This holds the name of the object being read
00163 
00164           // This chunk is the header for the object info chunks.  It also
00165           // holds the name of the object.
00166 
00167           // Get the name of the object and store it, then add the read bytes to our byte counter.
00168           m_CurrentChunk->bytesRead += GetString(strBuffer);
00169 
00170           // Now proceed to read in the rest of the object information
00171           ProcessNextObjectChunk(pMesh, strBuffer, m_CurrentChunk);
00172 
00173           break;
00174 
00175         case CHUNK_EDITKEYFRAME:
00176 
00177           // Not supported
00178           //ProcessNextKeyFrameChunk(pMesh, m_CurrentChunk);
00179 
00180           // Read past this chunk and add the bytes read to the byte counter
00181           m_CurrentChunk->bytesRead += fread(buffer, 1, m_CurrentChunk->length - m_CurrentChunk->bytesRead, m_FilePointer);
00182           break;
00183 
00184         default:
00185 
00186           // If we didn't care about a chunk, then we get here.  We still need
00187           // to read past the unknown or ignored chunk and add the bytes read to the byte counter.
00188           m_CurrentChunk->bytesRead += fread(buffer, 1, m_CurrentChunk->length - m_CurrentChunk->bytesRead, m_FilePointer);
00189           break;
00190       }
00191 
00192       // Add the bytes read from the last chunk to the previous chunk passed in.
00193       pPreviousChunk->bytesRead += m_CurrentChunk->bytesRead;
00194     }
00195 
00196     // Free the current chunk and set it back to the previous chunk (since it started that way)
00197     delete m_CurrentChunk;
00198     m_CurrentChunk = pPreviousChunk;
00199   }
00200 
00201   //-----------------------------------------------------------------------
00202   void C3DSLoader::ProcessNextObjectChunk(CMesh *pMesh, char* strObjectName, TChunk *pPreviousChunk)
00203   {
00204     int buffer[50000] = {0};     // This is used to read past unwanted data
00205 
00206     // Allocate a new chunk to work with
00207     m_CurrentChunk = new TChunk;
00208 
00209     // Continue to read these chunks until we read the end of this sub chunk
00210     while (pPreviousChunk->bytesRead < pPreviousChunk->length)
00211     {
00212       // Read the next chunk
00213       ReadChunk(m_CurrentChunk);
00214 
00215       // Check which chunk we just read
00216       switch (m_CurrentChunk->ID)
00217       {
00218         case CHUNK_OBJECT_MESH:     // This lets us know that we are reading a new object
00219         {
00220           // We found a new object, so let's read in it's info using recursion
00221           ProcessNextObjectChunk(pMesh, strObjectName, m_CurrentChunk);
00222 
00223           // Create the index buffers
00224           // For each different material, we create a new TGeom struct
00225           std::vector<TGeom*> GeomList;
00226           TGeom* CurrentGeom;
00227           std::map<int, uint> MaterialSet;
00228           std::map<int, uint>::const_iterator SetIter;
00229           uint nNumDiffMat = 0;
00230           for (uint i = 0; i < m_Faces.size(); ++i)
00231           {
00232             // Search if this material has already been used
00233             SetIter = MaterialSet.find(m_Faces[i].materialID);
00234             if (SetIter == MaterialSet.end())
00235             {
00236               // Add a new TGeom
00237               MaterialSet[m_Faces[i].materialID] = nNumDiffMat;
00238               GeomList.push_back(new TGeom);
00239               CurrentGeom = GeomList[nNumDiffMat];
00240               nNumDiffMat++;
00241             }
00242             // Get the TGeom for this material
00243             else CurrentGeom = GeomList[SetIter->second];
00244 
00245             CurrentGeom->materialID = m_Faces[i].materialID;
00246 
00247             // Addition in the index buffer
00248             CurrentGeom->Indicies.push_back(m_Faces[i].vertIndex[0]);
00249             CurrentGeom->Indicies.push_back(m_Faces[i].vertIndex[1]);
00250             CurrentGeom->Indicies.push_back(m_Faces[i].vertIndex[2]);
00251           }
00252 
00253           // Create the vertex buffer
00254           TVertexList Vertices;
00255           Vertices.reserve(m_nNumVerts);
00256           for (int i = 0; i < m_nNumVerts; ++i)
00257           {
00258             // Recovery of the information on the current point
00259             CMeshGeom::TVertex v;
00260             v.Position.x  = m_pVertices[i].x;
00261             v.Position.y  = m_pVertices[i].y;
00262             v.Position.z  = m_pVertices[i].z;
00263 
00264             v.Normal      = TVector3F(0.0, 0.0, 0.0);
00265             if (GeomList[0]->materialID != -1)
00266               v.Color = Renderer->ConvertColor(pMesh->GetMaterial(GeomList[0]->materialID)->GetDiffuseColor());
00267             else v.Color = Renderer->ConvertColor(CColor::White);
00268 
00269             if (i < m_nNumTexVertex)
00270               v.TexCoords = m_pTexCoords[i];
00271             else v.TexCoords = TVector2F(0, 0);
00272 
00273             // Addition in the vertex buffer
00274             Vertices.push_back(v);
00275           }
00276 
00277           KEOS_DELETE_ARRAY(m_pTexCoords);
00278           KEOS_DELETE_ARRAY(m_pVertices);
00279           m_nNumTexVertex = 0;
00280 
00281 #if KEOS_MESH_SHARED_VERTEX_BUFFER
00282           // If this object has more than one material
00283           if (GeomList.size() > 1)
00284           {
00285             // Test if there is only one object with multiple materials
00286             if (m_nObjectWithMultMaterial >= 1)
00287               ILogger::Log("WARNING - This 3DS model has more than one object with multiple materials, the loader may not support this correctly !");
00288             m_nObjectWithMultMaterial++;
00289 
00290             // Create a shared vertex buffer in the mesh class
00291             // We create a shared vertex buffer only for the first object with multiple materials
00292 
00293             if (m_nObjectWithMultMaterial == 1)
00294               pMesh->CreateSharedVertexBuffer(&Vertices[0], (int)Vertices.size());
00295           }
00296 #endif
00297 
00298           // We create one MeshGeom for one TGeom struct
00299           for (uint i = 0; i < GeomList.size(); i++)
00300           {
00301             CurrentGeom = GeomList[i];
00302 
00303             // Create MeshGeom
00304             CMeshGeom *pMeshGeom;
00305 #if KEOS_MESH_SHARED_VERTEX_BUFFER
00306             if (m_nObjectWithMultMaterial == 1)
00307               pMeshGeom = new CMeshGeom(&(CurrentGeom->Indicies[0]), (int)CurrentGeom->Indicies.size());
00308             else
00309 #endif
00310               pMeshGeom = new CMeshGeom(&Vertices[0], (int)Vertices.size(), &(CurrentGeom->Indicies[0]), (int)CurrentGeom->Indicies.size());
00311 
00312             // Add MeshGeom to the mesh
00313             pMesh->AddMeshGeom(pMeshGeom, String(strObjectName) + CStringConverter::ToString((int)i));
00314 
00315             // Set the material index of the MeshGeom
00316             pMeshGeom->SetMaterialIndex(CurrentGeom->materialID);
00317           }
00318           std::for_each(GeomList.begin(), GeomList.end(), Delete());
00319 
00320         }
00321         break;
00322 
00323         case CHUNK_OBJECT_VERTICES:    // This is the objects vertices
00324           ReadVertices(m_CurrentChunk);
00325           break;
00326 
00327         case CHUNK_OBJECT_FACES:     // This is the objects face information
00328           ReadVertexIndices(m_CurrentChunk);
00329           break;
00330 
00331         case CHUNK_OBJECT_MATERIAL:    // This holds the material name that the object has
00332           ReadObjectMaterial(pMesh, m_CurrentChunk);
00333           break;
00334 
00335         case CHUNK_OBJECT_UV:      // This holds the UV texture coordinates for the object
00336 
00337           // This chunk holds all of the UV coordinates for our object.  Let's read them in.
00338           ReadUVCoordinates(m_CurrentChunk);
00339           break;
00340 
00341         default:
00342 
00343           // Read past the ignored or unknown chunks
00344           m_CurrentChunk->bytesRead += fread(buffer, 1, m_CurrentChunk->length - m_CurrentChunk->bytesRead, m_FilePointer);
00345           break;
00346       }
00347 
00348       // Add the bytes read from the last chunk to the previous chunk passed in.
00349       pPreviousChunk->bytesRead += m_CurrentChunk->bytesRead;
00350     }
00351 
00352     // Free the current chunk and set it back to the previous chunk (since it started that way)
00353     delete m_CurrentChunk;
00354     m_CurrentChunk = pPreviousChunk;
00355   }
00356 
00357   //-----------------------------------------------------------------------
00358   void C3DSLoader::ProcessNextMaterialChunk(CMesh *pMesh, TChunk *pPreviousChunk)
00359   {
00360     int buffer[50000] = {0};     // This is used to read past unwanted data
00361     char  strBuffer[255];
00362 
00363     // Allocate a new chunk to work with
00364     m_CurrentChunk = new TChunk;
00365 
00366     // Continue to read these chunks until we read the end of this sub chunk
00367     while (pPreviousChunk->bytesRead < pPreviousChunk->length)
00368     {
00369       // Read the next chunk
00370       ReadChunk(m_CurrentChunk);
00371 
00372       CMaterial* pMaterial = pMesh->GetMaterialList()[pMesh->GetLastAddedMaterialIndex()];
00373 
00374       // Check which chunk we just read in
00375       switch (m_CurrentChunk->ID)
00376       {
00377         case CHUNK_MATNAME:       // This chunk holds the name of the material
00378 
00379           // Here we read in the material name
00380           m_CurrentChunk->bytesRead += fread(strBuffer, 1, m_CurrentChunk->length - m_CurrentChunk->bytesRead, m_FilePointer);
00381           pMaterial->SetName(strBuffer);
00382           break;
00383 
00384         case CHUNK_MATDIFFUSE:      // This holds the R G B color of our object
00385           ReadColorChunk(pMaterial, m_CurrentChunk);
00386           break;
00387 
00388         case CHUNK_MATMAP:       // This is the header for the texture info
00389 
00390           // Proceed to read in the material information
00391           ProcessNextMaterialChunk(pMesh, m_CurrentChunk);
00392           break;
00393 
00394         case CHUNK_MATMAPFILE:      // This stores the file name of the material
00395 
00396           // Here we read in the material's file name
00397           m_CurrentChunk->bytesRead += fread(strBuffer, 1, m_CurrentChunk->length - m_CurrentChunk->bytesRead, m_FilePointer);
00398           pMaterial->CreateTexture(String(strBuffer));
00399 
00400           // We flip the image texture, because else the texture coordinates are false
00401           // I don't know why ?
00402           pMaterial->GetTexture()->GetPixels().Flip();
00403           pMaterial->GetTexture()->Update();
00404           break;
00405 
00406         default:
00407 
00408           // Read past the ignored or unknown chunks
00409           m_CurrentChunk->bytesRead += fread(buffer, 1, m_CurrentChunk->length - m_CurrentChunk->bytesRead, m_FilePointer);
00410           break;
00411       }
00412 
00413       // Add the bytes read from the last chunk to the previous chunk passed in.
00414       pPreviousChunk->bytesRead += m_CurrentChunk->bytesRead;
00415     }
00416 
00417     // Free the current chunk and set it back to the previous chunk (since it started that way)
00418     delete m_CurrentChunk;
00419     m_CurrentChunk = pPreviousChunk;
00420   }
00421 
00422   //-----------------------------------------------------------------------
00423   void C3DSLoader::ReadChunk(TChunk *pChunk)
00424   {
00425     // This reads the chunk ID which is 2 bytes.
00426     // The chunk ID is like OBJECT or MATERIAL.  It tells what data is
00427     // able to be read in within the chunks section.
00428     pChunk->bytesRead = fread(&pChunk->ID, 1, 2, m_FilePointer);
00429 
00430     // Then, we read the length of the chunk which is 4 bytes.
00431     // This is how we know how much to read in, or read past.
00432     pChunk->bytesRead += fread(&pChunk->length, 1, 4, m_FilePointer);
00433   }
00434 
00435   //-----------------------------------------------------------------------
00436   size_t C3DSLoader::GetString(char *pBuffer)
00437   {
00438     int index = 0;
00439 
00440     // Read 1 byte of data which is the first letter of the string
00441     fread(pBuffer, 1, 1, m_FilePointer);
00442 
00443     // Loop until we get NULL
00444     while (*(pBuffer + index++) != 0)
00445     {
00446 
00447       // Read in a character at a time until we hit NULL.
00448       fread(pBuffer + index, 1, 1, m_FilePointer);
00449     }
00450 
00451     // Return the string length, which is how many bytes we read in (including the NULL)
00452     return strlen(pBuffer) + 1;
00453   }
00454 
00455   //-----------------------------------------------------------------------
00456   void C3DSLoader::ReadColorChunk(CMaterial *pMaterial, TChunk *pChunk)
00457   {
00458     // Read the color chunk info
00459     ReadChunk(m_TempChunk);
00460 
00461     unsigned char color[4];
00462     // Read in the R G B color (3 bytes - 0 through 255)
00463     m_TempChunk->bytesRead += fread(color, 1, m_TempChunk->length - m_TempChunk->bytesRead, m_FilePointer);
00464     pMaterial->SetDiffuseColor(CColor(color[0], color[1], color[2]));
00465 
00466     // Add the bytes read to our chunk
00467     pChunk->bytesRead += m_TempChunk->bytesRead;
00468   }
00469 
00470   //-----------------------------------------------------------------------
00471   void C3DSLoader::ReadVertexIndices(TChunk *pPreviousChunk)
00472   {
00473     unsigned short index = 0;     // This is used to read in the current face index
00474 
00475     // In order to read in the vertex indices for the object, we need to first
00476     // read in the number of them, then read them in.  Remember,
00477     // we only want 3 of the 4 values read in for each face.  The fourth is
00478     // a visibility flag for 3D Studio Max that doesn't mean anything to us.
00479 
00480     // Read in the number of faces that are in this object (int)
00481     int nNumOfFaces = 0;
00482     pPreviousChunk->bytesRead += fread(&nNumOfFaces, 1, 2, m_FilePointer);
00483 
00484     // Initialize
00485     m_Faces.clear();
00486     TFace Face = {0};
00487     Face.materialID = -1;
00488 
00489     // Go through all of the faces in this object
00490     for (int i = 0; i < nNumOfFaces; i++)
00491     {
00492       // Next, we read in the A then B then C index for the face, but ignore the 4th value.
00493       // The fourth value is a visibility flag for 3D Studio Max, we don't care about this.
00494       for (int j = 0; j < 4; j++)
00495       {
00496         // Read the first vertice index for the current face
00497         pPreviousChunk->bytesRead += fread(&index, 1, sizeof(index), m_FilePointer);
00498 
00499         if (j < 3)
00500         {
00501           // Store the index in our face structure.
00502           Face.vertIndex[j] = index;
00503         }
00504       }
00505       m_Faces.push_back(Face);
00506     }
00507   }
00508 
00509   //-----------------------------------------------------------------------
00510   void C3DSLoader::ReadUVCoordinates(TChunk *pPreviousChunk)
00511   {
00512     // In order to read in the UV indices for the object, we need to first
00513     // read in the amount there are, then read them in.
00514 
00515     // Read in the number of UV coordinates there are (int)
00516     m_nNumTexVertex = 0;
00517     pPreviousChunk->bytesRead += fread(&m_nNumTexVertex, 1, 2, m_FilePointer);
00518 
00519     // Allocate memory to hold the UV coordinates
00520     m_pTexCoords = new TVector2F [m_nNumTexVertex];
00521 
00522     // Read in the texture coodinates (an array 2 float)
00523     pPreviousChunk->bytesRead += fread(m_pTexCoords, 1, pPreviousChunk->length - pPreviousChunk->bytesRead, m_FilePointer);
00524   }
00525 
00526   //-----------------------------------------------------------------------
00527   void C3DSLoader::ReadVertices(TChunk *pPreviousChunk)
00528   {
00529     // Like most chunks, before we read in the actual vertices, we need
00530     // to find out how many there are to read in.  Once we have that number
00531     // we then fread() them into our vertice array.
00532 
00533     // Read in the number of vertices (int)
00534     m_nNumVerts = 0;
00535     pPreviousChunk->bytesRead += fread(&m_nNumVerts, 1, 2, m_FilePointer);
00536 
00537     // Allocate the memory for the verts and initialize the structure
00538     m_pVertices = new TVector3F [m_nNumVerts];
00539     memset(m_pVertices, 0, sizeof(TVector3F) * m_nNumVerts);
00540 
00541     // Read in the array of vertices (an array of 3 floats)
00542     pPreviousChunk->bytesRead += fread(m_pVertices, 1, pPreviousChunk->length - pPreviousChunk->bytesRead, m_FilePointer);
00543 
00544     // Now we should have all of the vertices read in.  Because 3D Studio Max
00545     // Models with the Z-Axis pointing up (strange and ugly I know!), we need
00546     // to flip the y values with the z values in our vertices.  That way it
00547     // will be normal, with Y pointing up.  If you prefer to work with Z pointing
00548     // up, then just delete this next loop.  Also, because we swap the Y and Z
00549     // we need to negate the Z to make it come out correctly.
00550 
00551     // Go through all of the vertices that we just read and swap the Y and Z values
00552     /*for(int i = 0; i < pObject->numOfVerts; i++)
00553     {
00554      // Store off the Y value
00555      float fTempY = pObject->pVerts[i].y;
00556 
00557      // Set the Y value to the Z value
00558      pObject->pVerts[i].y = pObject->pVerts[i].z;
00559 
00560      // Set the Z value to the Y value, 
00561      // but negative Z because 3D Studio max does the opposite.
00562      pObject->pVerts[i].z = -fTempY;
00563     }*/
00564   }
00565 
00566   //-----------------------------------------------------------------------
00567   void C3DSLoader::ReadObjectMaterial(CMesh *pMesh, TChunk *pPreviousChunk)
00568   {
00569     char strMaterial[255] = {0};   // This is used to hold the objects material name
00570     int buffer[50000] = {0};    // This is used to read past unwanted data
00571     int nMaterialIndex = -1;    // Index in the model material list
00572 
00573     // *What is a material?*  - A material is either the color or the texture map of the object.
00574     // It can also hold other information like the brightness, shine, etc... Stuff we don't
00575     // really care about.  We just want the color, or the texture map file name really.
00576 
00577     // Here we read the material name that is assigned to the current object.
00578     // strMaterial should now have a string of the material name, like "Material #2" etc..
00579     pPreviousChunk->bytesRead += GetString(strMaterial);
00580 
00581     // Now that we have a material name, we need to go through all of the materials
00582     // and check the name against each material.  When we find a material in our material
00583     // list that matches this name we just read in, then we assign the materialID
00584     // of the object to that material index.  You will notice that we passed in the
00585     // model to this function.  This is because we need the number of textures.
00586 
00587     // Go through all of the textures
00588     for (uint i = 0; i < pMesh->GetMaterialsCount(); i++)
00589     {
00590       // If the material we just read in matches the current texture name
00591       if (strcmp(strMaterial, pMesh->GetMaterialList()[i]->GetName().c_str()) == 0)
00592       {
00593         // Set the material ID to the current index 'i' and stop checking
00594         nMaterialIndex = i;
00595         break;
00596       }
00597       else
00598       {
00599         // Set the ID to -1 to show there is no material for this object
00600         nMaterialIndex = -1;
00601       }
00602     }
00603 
00604     // Read the number of faces which use this material
00605     ushort iNumFaces = 0;
00606     pPreviousChunk->bytesRead += fread(&iNumFaces, 1, 2, m_FilePointer);
00607 
00608     ushort* pFaceAssignedThisMaterial = new ushort[iNumFaces];
00609     memset(pFaceAssignedThisMaterial, 0, sizeof(ushort) * iNumFaces);
00610 
00611     // Read in the array of ushort
00612     pPreviousChunk->bytesRead += fread(pFaceAssignedThisMaterial, 1, iNumFaces * sizeof(ushort), m_FilePointer);
00613 
00614     // We assign for each face the corresponding material
00615     for (int i = 0; i < iNumFaces; i++)
00616     {
00617       int iIndex = pFaceAssignedThisMaterial[i];
00618       m_Faces[iIndex].materialID = nMaterialIndex;
00619     }
00620 
00621     KEOS_DELETE_ARRAY(pFaceAssignedThisMaterial);
00622 
00623     // Read past the rest of the chunk since we don't care about shared vertices
00624     // You will notice we subtract the bytes already read in this chunk from the total length.
00625     pPreviousChunk->bytesRead += fread(buffer, 1, pPreviousChunk->length - pPreviousChunk->bytesRead, m_FilePointer);
00626   }
00627 }

Generated on Fri Mar 9 14:29:01 2007 for Keos by  doxygen 1.5.1-p1