📄 3ds.cpp
字号:
//***********************************************************************//// //// - "Talk to me like I'm a 3 year old!" Programming Lessons - //// //// $Author: DigiBen digiben@gametutorials.com //// //// $Program: 3DS Loader //// //// $Description: Demonstrates how to load a .3ds file format //// //// $Date: 10/6/01 //// ////***********************************************************************//# include <math.h>#include "3ds.h"// This file handles all of the code needed to load a .3DS file.// Basically, how it works is, you load a chunk, then you check// the chunk ID. Depending on the chunk ID, you load the information// that is stored in that chunk. If you do not want to read that information,// you read past it. You know how many bytes to read past the chunk because// every chunk stores the length in bytes of that chunk.///////////////////////////////// CLOAD3DS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*////////// This constructor initializes the tChunk data////////////////////////////////////// CLOAD3DS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*CLoad3DS::CLoad3DS(){ m_CurrentChunk = new tChunk; // Initialize and allocate our current chunk m_TempChunk = new tChunk; // Initialize and allocate a temporary chunk}///////////////////////////////// IMPORT 3DS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*////////// This is called by the client to open the .3ds file, read it, then clean up////////////////////////////////////// IMPORT 3DS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*bool CLoad3DS::Import3DS(t3DModel *pModel, char *strFileName){ char strMessage[255] = {0}; pModel->numOfMaterials = pModel->numOfObjects = 0; // Open the 3DS file m_FilePointer = fopen(strFileName, "rb"); // Make sure we have a valid file pointer (we found the file) if(!m_FilePointer) { sprintf(strMessage, "Unable to find the file: %s!", strFileName); cout << strMessage << endl; exit(1); } // Once we have the file open, we need to read the very first data chunk // to see if it's a 3DS file. That way we don't read an invalid file. // If it is a 3DS file, then the first chunk ID will be equal to PRIMARY (some hex num) // Read the first chuck of the file to see if it's a 3DS file ReadChunk(m_CurrentChunk); // Make sure this is a 3DS file if (m_CurrentChunk->ID != PRIMARY) { sprintf(strMessage, "Unable to load PRIMARY chuck from file: %s!", strFileName); cout << strMessage << endl; exit(1); } // Now we actually start reading in the data. ProcessNextChunk() is recursive // Begin loading objects, by calling this recursive function ProcessNextChunk(pModel, m_CurrentChunk); // After we have read the whole 3DS file, we want to calculate our own vertex normals. ComputeNormals(pModel); // Clean up after everything CleanUp(); return true;}///////////////////////////////// CLEAN UP \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*////////// This function cleans up our allocated memory and closes the file////////////////////////////////////// CLEAN UP \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*void CLoad3DS::CleanUp(){ fclose(m_FilePointer); // Close the current file pointer delete m_CurrentChunk; // Free the current chunk delete m_TempChunk; // Free our temporary chunk}///////////////////////////////// PROCESS NEXT CHUNK\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*////////// This function reads the main sections of the .3DS file, then dives deeper with recursion////////////////////////////////////// PROCESS NEXT CHUNK\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*void CLoad3DS::ProcessNextChunk(t3DModel *pModel, tChunk *pPreviousChunk){ t3DObject newObject = {0}; // This is used to add to our object list tMaterialInfo newTexture = {0}; // This is used to add to our material list unsigned int version = 0; // This will hold the file version int buffer[50000] = {0}; // This is used to read past unwanted data m_CurrentChunk = new tChunk; // Allocate a new chunk // Below we check our chunk ID each time we read a new chunk. Then, if // we want to extract the information from that chunk, we do so. // If we don't want a chunk, we just read past it. // Continue to read the sub chunks until we have reached the length. // After we read ANYTHING we add the bytes read to the chunk and then check // check against the length. //int count = 0; while (pPreviousChunk->bytesRead < pPreviousChunk->length) { // if(count++ > 20) exit(1); // Read next Chunk ReadChunk(m_CurrentChunk); // Check the chunk ID switch (m_CurrentChunk->ID) { case VERSION: // This holds the version of the file // This chunk has an unsigned short that holds the file version. // Since there might be new additions to the 3DS file format in 4.0, // we give a warning to that problem. // Read the file version and add the bytes read to our bytesRead variable m_CurrentChunk->bytesRead += fread(&version, 1, m_CurrentChunk->length - m_CurrentChunk->bytesRead, m_FilePointer); if(SDL_BYTEORDER == SDL_BIG_ENDIAN) { version = SDL_SwapLE32(version); } // If the file version is over 3, give a warning that there could be a problem if (version > 0x03) cout << "This 3DS file is over version 3 so it may load incorrectly" << endl; break; case OBJECTINFO: // This holds the version of the mesh // This chunk holds the version of the mesh. It is also the head of the MATERIAL // and OBJECT chunks. From here on we start reading in the material and object info. // Read the next chunk ReadChunk(m_TempChunk); // Get the version of the mesh m_TempChunk->bytesRead += fread(&version, 1, m_TempChunk->length - m_TempChunk->bytesRead, m_FilePointer); if(SDL_BYTEORDER == SDL_BIG_ENDIAN) { version = SDL_SwapLE32(version); } // Increase the bytesRead by the bytes read from the last chunk m_CurrentChunk->bytesRead += m_TempChunk->bytesRead; // Go to the next chunk, which is the object has a texture, it should be MATERIAL, then OBJECT. ProcessNextChunk(pModel, m_CurrentChunk); break; case MATERIAL: // This holds the material information // This chunk is the header for the material info chunks // Increase the number of materials pModel->numOfMaterials++; // Add a empty texture structure to our texture list. // If you are unfamiliar with STL's "vector" class, all push_back() // does is add a new node onto the list. I used the vector class // so I didn't need to write my own link list functions. pModel->pMaterials.push_back(newTexture); // Proceed to the material loading function ProcessNextMaterialChunk(pModel, m_CurrentChunk); break; case OBJECT: // This holds the name of the object being read // This chunk is the header for the object info chunks. It also // holds the name of the object. // Increase the object count pModel->numOfObjects++; // Add a new tObject node to our list of objects (like a link list) pModel->pObject.push_back(newObject); // Initialize the object and all it's data members memset(&(pModel->pObject[pModel->numOfObjects - 1]), 0, sizeof(t3DObject)); // Get the name of the object and store it, then add the read bytes to our byte counter. m_CurrentChunk->bytesRead += GetString(pModel->pObject[pModel->numOfObjects - 1].strName); // Now proceed to read in the rest of the object information ProcessNextObjectChunk(pModel, &(pModel->pObject[pModel->numOfObjects - 1]), m_CurrentChunk); break; case EDITKEYFRAME: // Because I wanted to make this a SIMPLE tutorial as possible, I did not include // the key frame information. This chunk is the header for all the animation info. // In a later tutorial this will be the subject and explained thoroughly. //ProcessNextKeyFrameChunk(pModel, m_CurrentChunk); // Read past this chunk and add the bytes read to the byte counter m_CurrentChunk->bytesRead += fread(buffer, 1, m_CurrentChunk->length - m_CurrentChunk->bytesRead, m_FilePointer); break; default: // If we didn't care about a chunk, then we get here. We still need // to read past the unknown or ignored chunk and add the bytes read to the byte counter. m_CurrentChunk->bytesRead += fread(buffer, 1, m_CurrentChunk->length - m_CurrentChunk->bytesRead, m_FilePointer); break; } // Add the bytes read from the last chunk to the previous chunk passed in. pPreviousChunk->bytesRead += m_CurrentChunk->bytesRead; } // Free the current chunk and set it back to the previous chunk (since it started that way) delete m_CurrentChunk; m_CurrentChunk = pPreviousChunk;}///////////////////////////////// PROCESS NEXT OBJECT CHUNK \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*////////// This function handles all the information about the objects in the file////////////////////////////////////// PROCESS NEXT OBJECT CHUNK \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*void CLoad3DS::ProcessNextObjectChunk(t3DModel *pModel, t3DObject *pObject, tChunk *pPreviousChunk){ int buffer[50000] = {0}; // This is used to read past unwanted data // Allocate a new chunk to work with m_CurrentChunk = new tChunk; // Continue to read these chunks until we read the end of this sub chunk while (pPreviousChunk->bytesRead < pPreviousChunk->length) { // Read the next chunk ReadChunk(m_CurrentChunk); // Check which chunk we just read switch (m_CurrentChunk->ID) { case OBJECT_MESH: // This lets us know that we are reading a new object // We found a new object, so let's read in it's info using recursion ProcessNextObjectChunk(pModel, pObject, m_CurrentChunk); break; case OBJECT_VERTICES: // This is the objects vertices ReadVertices(pObject, m_CurrentChunk); break; case OBJECT_FACES: // This is the objects face information ReadVertexIndices(pObject, m_CurrentChunk); break; case OBJECT_MATERIAL: // This holds the material name that the object has
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -