📄 load3ds.cpp
字号:
// Load3DS.cpp: implementation of the CLoad3DS class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "Load3DS.h"
// 缓冲区
static int gBuffer[50000] = {0};
// 用来跳过不需要的数据(此程序不需要)
//////////////////////////////////////////////////////////////////////
///// This constructor initializes the tChunk data
//////////////////////////////////////////////////////////////////////
CLoad3DS::CLoad3DS()
{
m_FilePointer = NULL;
}
CLoad3DS::~CLoad3DS()
{
m_FilePointer = NULL;
}
///////////////////////////////// IMPORT 3DS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
/////
///// 打开3ds文件
/////
///////////////////////////////// IMPORT 3DS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
bool CLoad3DS::Import3DS(CLoad3DS::t3DModel *pModel, char *strFileName)
{
char strMessage[255] = {0};
tChunk currentChunk = {0};
int i=0;
// 打开文件
m_FilePointer = fopen(strFileName, "rb");
// 确保文件打开
if(!m_FilePointer)
{
sprintf(strMessage, "找不到文件: %s!", strFileName);
MessageBox(NULL, strMessage, "Error", MB_OK);
return false;
}
// 文件打开后,读取第一个文件块
ReadChunk(¤tChunk);
// 文件标志判断
if (currentChunk.ID != PRIMARY)
{
sprintf(strMessage, "Unable to load PRIMARY chuck from file: %s!", strFileName);
MessageBox(NULL, strMessage, "Error", MB_OK);
return false;
}
// 使用 ProcessNextChunk() 来递归读取内容
// 家在对象
ProcessNextChunk(pModel, ¤tChunk);
// 计算法线
ComputeNormals(pModel);
// 清除
CleanUp();
return true;
}
///////////////////////////////// CLEAN UP \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
/////
///// 清空(关闭文件)
/////
///////////////////////////////// CLEAN UP \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
void CLoad3DS::CleanUp()
{
if (m_FilePointer) {
fclose(m_FilePointer); // Close the current file pointer
m_FilePointer = NULL;
}
}
///////////////////////////////// PROCESS NEXT CHUNK\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
/////
///// 函数读取3ds的各分块,并且进行深层的递归
/////
///////////////////////////////// PROCESS NEXT CHUNK\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
void CLoad3DS::ProcessNextChunk(CLoad3DS::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
tChunk currentChunk = {0}; // The current chunk to load
tChunk tempChunk = {0}; // A temp chunk for holding data
// 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.
while (pPreviousChunk->bytesRead < pPreviousChunk->length)
{
// Read next Chunk
ReadChunk(¤tChunk);
// Check the chunk ID
switch (currentChunk.ID)
{
case VERSION: // This holds the version of the file
// If the file was made in 3D Studio Max, this chunk has an int 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.
// However, if the file wasn't made by 3D Studio Max, we don't 100% what the
// version length will be so we'll simply ignore the value
// Read the file version and add the bytes read to our bytesRead variable
currentChunk.bytesRead += fread(gBuffer, 1, currentChunk.length - currentChunk.bytesRead, m_FilePointer);
// If the file version is over 3, give a warning that there could be a problem
if ((currentChunk.length - currentChunk.bytesRead == 4) && (gBuffer[0] > 0x03)) {
MessageBox(NULL, "This 3DS file is over version 3 so it may load incorrectly", "Warning", MB_OK);
}
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(&tempChunk);
// Get the version of the mesh
tempChunk.bytesRead += fread(gBuffer, 1, tempChunk.length - tempChunk.bytesRead, m_FilePointer);
// Increase the bytesRead by the bytes read from the last chunk
currentChunk.bytesRead += tempChunk.bytesRead;
// Go to the next chunk, which is the object has a texture, it should be MATERIAL, then OBJECT.
ProcessNextChunk(pModel, ¤tChunk);
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->vctMaterials.push_back(newTexture);
// Proceed to the material loading function
ProcessNextMaterialChunk(pModel, ¤tChunk);
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->vctObjects.push_back(newObject);
// Initialize the object and all it's data members
memset(&(pModel->vctObjects[pModel->numOfObjects - 1]), 0, sizeof(t3DObject));
// Get the name of the object and store it, then add the read bytes to our byte counter.
currentChunk.bytesRead += GetString(pModel->vctObjects[pModel->numOfObjects - 1].strName);
// Now proceed to read in the rest of the object information
ProcessNextObjectChunk(pModel, &(pModel->vctObjects[pModel->numOfObjects - 1]), ¤tChunk);
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, currentChunk);
// Read past this chunk and add the bytes read to the byte counter
currentChunk.bytesRead += fread(gBuffer, 1, currentChunk.length - 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.
currentChunk.bytesRead += fread(gBuffer, 1, currentChunk.length - currentChunk.bytesRead, m_FilePointer);
break;
}
// Add the bytes read from the last chunk to the previous chunk passed in.
pPreviousChunk->bytesRead += currentChunk.bytesRead;
}
}
///////////////////////////////// PROCESS NEXT OBJECT CHUNK \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
/////
///// 处理一个对象块
/////
///////////////////////////////// PROCESS NEXT OBJECT CHUNK \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
void CLoad3DS::ProcessNextObjectChunk(CLoad3DS::t3DModel *pModel, CLoad3DS::t3DObject *pObject, CLoad3DS::tChunk *pPreviousChunk)
{
// The current chunk to work with
tChunk currentChunk = {0};
vector<tMatREF*> vctMatIDS;
// Continue to read these chunks until we read the end of this sub chunk
while (pPreviousChunk->bytesRead < pPreviousChunk->length)
{
// Read the next chunk
ReadChunk(¤tChunk);
// Check which chunk we just read
switch (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, ¤tChunk);
break;
case OBJECT_VERTICES: // This is the objects vertices
ReadVertices(pObject, ¤tChunk);
break;
case OBJECT_FACES: // This is the objects face information
ReadVertexIndices(pObject, ¤tChunk);
break;
case OBJECT_MATERIAL: // This holds the material name that the object has
// This chunk holds the name of the material that the object has assigned to it.
// This could either be just a color or a texture map. This chunk also holds
// the faces that the texture is assigned to (In the case that there is multiple
// textures assigned to one object, or it just has a texture on a part of the object.
// Since most of my game objects just have the texture around the whole object, and
// they aren't multitextured, I just want the material name.
// We now will read the name of the material assigned to this object
ReadObjectMaterial(pModel, pObject, ¤tChunk,&vctMatIDS);
break;
case OBJECT_UV: // This holds the UV texture coordinates for the object
// This chunk holds all of the UV coordinates for our object. Let's read them in.
ReadUVCoordinates(pObject, ¤tChunk);
break;
case 0x4111: //TRI_VERTEXOPTIONS:
// Read past the ignored or unknown chunks
currentChunk.bytesRead += fread(gBuffer, 1, currentChunk.length - currentChunk.bytesRead, m_FilePointer);
break;
default:
// Read past the ignored or unknown chunks
currentChunk.bytesRead += fread(gBuffer, 1, currentChunk.length - currentChunk.bytesRead, m_FilePointer);
break;
}
// Add the bytes read from the last chunk to the previous chunk passed in.
pPreviousChunk->bytesRead += currentChunk.bytesRead;
}
if(pPreviousChunk->ID!=OBJECT_MESH) return;
//必须是OBJECT_MESH
int size=vctMatIDS.size();
if(size)
{
pObject->numOfMaterials=size;
pObject->pMaterialREFS=new tMatREF[size];
for(int i=0;i<size;i++)
{
pObject->pMaterialREFS[i]=*(vctMatIDS[i]);
}
vctMatIDS.clear();
}
}
///////////////////////////////// PROCESS NEXT MATERIAL CHUNK \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
/////
///// 处理材料信息,名字,贴图等
/////
///////////////////////////////// PROCESS NEXT MATERIAL CHUNK \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
void CLoad3DS::ProcessNextMaterialChunk(CLoad3DS::t3DModel *pModel, CLoad3DS::tChunk *pPreviousChunk)
{
// The current chunk to work with
tChunk currentChunk = {0};
// Continue to read these chunks until we read the end of this sub chunk
while (pPreviousChunk->bytesRead < pPreviousChunk->length)
{
// Read the next chunk
ReadChunk(¤tChunk);
// Check which chunk we just read in
switch (currentChunk.ID)
{
case MATNAME: // This chunk holds the name of the material
// Here we read in the material name
currentChunk.bytesRead += fread(pModel->vctMaterials[pModel->numOfMaterials - 1].strName, 1, currentChunk.length - currentChunk.bytesRead, m_FilePointer);
break;
//下面读入材料的四要素
case MAT_AMBIENT:
ReadColorChunk(&(pModel->vctMaterials[pModel->numOfMaterials - 1]), ¤tChunk,MAT_AMBIENT);
break;
case MAT_SPECULAR:
ReadColorChunk(&(pModel->vctMaterials[pModel->numOfMaterials - 1]), ¤tChunk,MAT_SPECULAR);
break;
case MAT_EMISSIVE:
ReadColorChunk(&(pModel->vctMaterials[pModel->numOfMaterials - 1]), ¤tChunk,MAT_EMISSIVE);
break;
case MATDIFFUSE: // This holds the R G B color of our object
ReadColorChunk(&(pModel->vctMaterials[pModel->numOfMaterials - 1]), ¤tChunk,MATDIFFUSE);
break;
case MATMAP: // This is the header for the texture info
// Proceed to read in the material information
ProcessNextMaterialChunk(pModel, ¤tChunk);
break;
case MATMAPFILE: // This stores the file name of the material
// Here we read in the material's file name
currentChunk.bytesRead += fread(pModel->vctMaterials[pModel->numOfMaterials - 1].strFile, 1, currentChunk.length - currentChunk.bytesRead, m_FilePointer);
break;
default:
// Read past the ignored or unknown chunks
currentChunk.bytesRead += fread(gBuffer, 1, currentChunk.length - currentChunk.bytesRead, m_FilePointer);
break;
}
// Add the bytes read from the last chunk to the previous chunk passed in.
pPreviousChunk->bytesRead += currentChunk.bytesRead;
}
}
///////////////////////////////// READ CHUNK \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -