3ds.cpp
来自「3D赛车游戏源代码-用Visual Studio 2005」· C++ 代码 · 共 446 行
CPP
446 行
#include "StdAfx.h"
#include "3ds.h"
#include "../opengl/OGLutil.h"
#include <fstream>
//-------------------------------------------------------------------------------
// 文件格式的3D物体定义构造函数
//-------------------------------------------------------------------------------
t3DObject::t3DObject() : numOfVerts(0), numOfFaces(0), numTexVertex(0),
bHasTexture(false), pVerts(NULL), pNormals(NULL),
pTexVerts(NULL), pFaces(NULL)
{
}
//-------------------------------------------------------------------------------
// 文件格式的3D物体定义析构函数
//-------------------------------------------------------------------------------
t3DObject::~t3DObject()
{
SAFE_DELETE_ARRAY(pVerts);
SAFE_DELETE_ARRAY(pNormals);
SAFE_DELETE_ARRAY(pTexVerts);
SAFE_DELETE_ARRAY(pFaces);
}
//-------------------------------------------------------------------------------
// 3DS文件载入全局单件对象
//-------------------------------------------------------------------------------
CLoad3DS g_Load3DS;
//-------------------------------------------------------------------------------
// 构造函数
//-------------------------------------------------------------------------------
CLoad3DS::CLoad3DS()
{
}
//-------------------------------------------------------------------------------
// 加载模型
//-------------------------------------------------------------------------------
bool CLoad3DS::Import3DS(t3DModel *pModel, const char *strFileName)
{
char strMessage[255] = {0};
m_CurrentChunk = new tChunk;
m_TempChunk = new tChunk;
// 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);
MessageBox(NULL, strMessage, "Error", MB_OK);
CleanUp();
return false;
}
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);
MessageBox(NULL, strMessage, "Error", MB_OK);
CleanUp();
return false;
}
ProcessNextChunk(pModel, m_CurrentChunk);
char szPathName[64];
char szFileName[32];
bool bHasPath = false;
char* ptr = strrchr(strFileName, '/');
if (ptr == NULL)
{
ptr = strrchr(strFileName, '\\');
}
if (ptr == NULL)
{
szPathName[0] = '\0';
}
else
{
int len = static_cast<int>(ptr - strFileName);
strncpy(szPathName, strFileName, len);
szPathName[len] = '\\';
szPathName[len+1] = '\0';
bHasPath = true;
}
// 为了方便载入纹理,加上模型本身的路径。
if (bHasPath)
{
for (int i=0; i<pModel->numOfMaterials; ++i)
{
tMaterialInfo& mat = pModel->pMaterials[i];
strcpy(szFileName, mat.strFile);
strcpy(mat.strFile, szPathName);
strcat(mat.strFile, szFileName);
}
}
CleanUp();
return true;
}
//-------------------------------------------------------------------------------
// 清空资源
//-------------------------------------------------------------------------------
void CLoad3DS::CleanUp()
{
fclose(m_FilePointer);
SAFE_DELETE(m_CurrentChunk);
SAFE_DELETE(m_TempChunk);
}
//-------------------------------------------------------------------------------
// 处理下一块
//-------------------------------------------------------------------------------
void CLoad3DS::ProcessNextChunk(t3DModel *pModel, tChunk *pPreviousChunk)
{
t3DObject newObject;
tMaterialInfo newTexture;
unsigned int version = 0;
int buffer[2048] = {0};
m_CurrentChunk = new tChunk;
while (pPreviousChunk->bytesRead < pPreviousChunk->length)
{
// Read next Chunk
ReadChunk(m_CurrentChunk);
// Check the chunk ID
switch (m_CurrentChunk->ID)
{
case VERSION: // This holds the version of the file
m_CurrentChunk->bytesRead += fread(&version, 1, m_CurrentChunk->length - m_CurrentChunk->bytesRead, m_FilePointer);
break;
case OBJECTINFO: // This holds the version of the mesh
//ReadChunk(m_TempChunk);
// m_TempChunk->bytesRead += fread(buffer, 1, m_TempChunk->length - m_TempChunk->bytesRead, m_FilePointer);
// m_CurrentChunk->bytesRead += m_TempChunk->bytesRead;
ProcessNextChunk(pModel, m_CurrentChunk);
break;
case MATERIAL: // This holds the material information
pModel->numOfMaterials++;
pModel->pMaterials.push_back(newTexture);
ProcessNextMaterialChunk(pModel, m_CurrentChunk);
break;
case OBJECT: // This holds the name of the object being read
pModel->numOfObjects++;
pModel->pObject.push_back(newObject);
memset(&(pModel->pObject[pModel->numOfObjects - 1]), 0, sizeof(t3DObject));
m_CurrentChunk->bytesRead += GetString(pModel->pObject[pModel->numOfObjects - 1].strName);
ProcessNextObjectChunk(pModel, &(pModel->pObject[pModel->numOfObjects - 1]), m_CurrentChunk);
break;
case EDITKEYFRAME:
m_CurrentChunk->bytesRead += fread(buffer, 1, m_CurrentChunk->length - m_CurrentChunk->bytesRead, m_FilePointer);
break;
default:
m_CurrentChunk->bytesRead += fread(buffer, 1, m_CurrentChunk->length - m_CurrentChunk->bytesRead, m_FilePointer);
break;
}
pPreviousChunk->bytesRead += m_CurrentChunk->bytesRead;
}
delete m_CurrentChunk;
m_CurrentChunk = NULL;
m_CurrentChunk = pPreviousChunk;
}
//-------------------------------------------------------------------------------
// 处理下一个物体块
//-------------------------------------------------------------------------------
void CLoad3DS::ProcessNextObjectChunk(t3DModel *pModel, t3DObject *pObject, tChunk *pPreviousChunk)
{
int buffer[50000] = {0};
m_CurrentChunk = new tChunk;
while (pPreviousChunk->bytesRead < pPreviousChunk->length)
{
ReadChunk(m_CurrentChunk);
switch (m_CurrentChunk->ID)
{
case OBJECT_MESH: // This lets us know that we are reading a new object
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
ReadObjectMaterial(pModel, pObject, m_CurrentChunk);
break;
case OBJECT_UV: // This holds the UV texture coordinates for the object
ReadUVCoordinates(pObject, m_CurrentChunk);
break;
default:
m_CurrentChunk->bytesRead += fread(buffer, 1, m_CurrentChunk->length - m_CurrentChunk->bytesRead, m_FilePointer);
break;
}
pPreviousChunk->bytesRead += m_CurrentChunk->bytesRead;
}
delete m_CurrentChunk;
m_CurrentChunk = pPreviousChunk;
}
//-------------------------------------------------------------------------------
// 处理下一个材质块
//-------------------------------------------------------------------------------
void CLoad3DS::ProcessNextMaterialChunk(t3DModel *pModel, 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 in
switch (m_CurrentChunk->ID)
{
case MATNAME: // This chunk holds the name of the material
// Here we read in the material name
m_CurrentChunk->bytesRead += fread(pModel->pMaterials[pModel->numOfMaterials - 1].strName, 1, m_CurrentChunk->length - m_CurrentChunk->bytesRead, m_FilePointer);
break;
case MATDIFFUSE: // This holds the R G B color of our object
ReadColorChunk(&(pModel->pMaterials[pModel->numOfMaterials - 1]), m_CurrentChunk);
break;
case MATMAP: // This is the header for the texture info
// Proceed to read in the material information
ProcessNextMaterialChunk(pModel, m_CurrentChunk);
break;
case MATMAPFILE: // This stores the file name of the material
// Here we read in the material's file name
m_CurrentChunk->bytesRead += fread(pModel->pMaterials[pModel->numOfMaterials - 1].strFile, 1, m_CurrentChunk->length - m_CurrentChunk->bytesRead, m_FilePointer);
break;
default:
// Read past the ignored or unknown chunks
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;
}
//-------------------------------------------------------------------------------
// 读取文件块
//-------------------------------------------------------------------------------
void CLoad3DS::ReadChunk(tChunk *pChunk)
{
pChunk->bytesRead = fread(&pChunk->ID, 1, 2, m_FilePointer);
// Then, we read the length of the chunk which is 4 bytes.
// This is how we know how much to read in, or read past.
pChunk->bytesRead += fread(&pChunk->length, 1, 4, m_FilePointer);
}
//-------------------------------------------------------------------------------
// 获取字符串
//-------------------------------------------------------------------------------
int CLoad3DS::GetString(char *pBuffer)
{
int index = 0;
fread(pBuffer, 1, 1, m_FilePointer);
while (*(pBuffer + index++) != 0)
{
fread(pBuffer + index, 1, 1, m_FilePointer);
}
return (int)strlen(pBuffer) + 1;
}
//-------------------------------------------------------------------------------
// 读取颜色块
//-------------------------------------------------------------------------------
void CLoad3DS::ReadColorChunk(tMaterialInfo *pMaterial, tChunk *pChunk)
{
ReadChunk(m_TempChunk);
m_TempChunk->bytesRead += fread(pMaterial->color, 1, m_TempChunk->length - m_TempChunk->bytesRead, m_FilePointer);
pChunk->bytesRead += m_TempChunk->bytesRead;
}
//-------------------------------------------------------------------------------
// 读取顶点索引
//-------------------------------------------------------------------------------
void CLoad3DS::ReadVertexIndices(t3DObject *pObject, tChunk *pPreviousChunk)
{
unsigned short index = 0; // This is used to read in the current face index
pPreviousChunk->bytesRead += fread(&pObject->numOfFaces, 1, 2, m_FilePointer);
pObject->pFaces = new tFace [pObject->numOfFaces];
memset(pObject->pFaces, 0, sizeof(tFace) * pObject->numOfFaces);
for(int i = 0; i < pObject->numOfFaces; i++)
{
for(int j = 0; j < 4; j++)
{
// Read the first vertice index for the current face
pPreviousChunk->bytesRead += fread(&index, 1, sizeof(index), m_FilePointer);
if(j < 3)
{
// Store the index in our face structure.
pObject->pFaces[i].vertIndex[j] = index;
}
}
}
}
//-------------------------------------------------------------------------------
// 读取纹理坐标
//-------------------------------------------------------------------------------
void CLoad3DS::ReadUVCoordinates(t3DObject *pObject, tChunk *pPreviousChunk)
{
pPreviousChunk->bytesRead += fread(&pObject->numTexVertex, 1, 2, m_FilePointer);
pObject->pTexVerts = new CVector2 [pObject->numTexVertex];
pPreviousChunk->bytesRead += fread(pObject->pTexVerts, 1, pPreviousChunk->length - pPreviousChunk->bytesRead, m_FilePointer);
}
//-------------------------------------------------------------------------------
// 读取顶点
//-------------------------------------------------------------------------------
void CLoad3DS::ReadVertices(t3DObject *pObject, tChunk *pPreviousChunk)
{
pPreviousChunk->bytesRead += fread(&(pObject->numOfVerts), 1, 2, m_FilePointer);
pObject->pVerts = new CVector3 [pObject->numOfVerts];
memset(pObject->pVerts, 0, sizeof(CVector3) * pObject->numOfVerts);
pPreviousChunk->bytesRead += fread(pObject->pVerts, 1, pPreviousChunk->length - pPreviousChunk->bytesRead, m_FilePointer);
}
//-------------------------------------------------------------------------------
// 读取材质
//-------------------------------------------------------------------------------
void CLoad3DS::ReadObjectMaterial(t3DModel *pModel, t3DObject *pObject, tChunk *pPreviousChunk)
{
char strMaterial[255] = {0}; // This is used to hold the objects material name
int buffer[50000] = {0}; // This is used to read past unwanted data
pPreviousChunk->bytesRead += GetString(strMaterial);
for(int i = 0; i < pModel->numOfMaterials; i++)
{
// If the material we just read in matches the current texture name
if(strcmp(strMaterial, pModel->pMaterials[i].strName) == 0)
{
// Set the material ID to the current index 'i' and stop checking
pObject->materialID = i;
if(strlen(pModel->pMaterials[i].strFile) > 0)
{
pObject->bHasTexture = true;
}
break;
}
else
{
pObject->materialID = -1;
}
}
pPreviousChunk->bytesRead += fread(buffer, 1, pPreviousChunk->length - pPreviousChunk->bytesRead, m_FilePointer);
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?