📄 lesson2.cpp
字号:
delete m_CurrentChunk; // 释放当前块
delete m_TempChunk; // 释放临时块
}
// 下面的函数读出3ds文件的主要部分
void CLoad3DS::ProcessNextChunk(t3DModel *pModel, tChunk *pPreviousChunk)
{
t3DObject newObject = {0}; // 用来添加到对象链表
tMaterialInfo newTexture = {0}; // 用来添加到材质链表
unsigned int version = 0; // 保存文件版本
int buffer[50000] = {0}; // 用来跳过不需要的数据
m_CurrentChunk = new tChunk; // 为新的块分配空间
// 下面每读一个新块,都要判断一下块的ID,如果该块是需要的读入的,则继续进行
// 如果是不需要读入的块,则略过
// 继续读入子块,直到达到预定的长度
while (pPreviousChunk->bytesRead < pPreviousChunk->length)
{
// 读入下一个块
ReadChunk(m_CurrentChunk);
// 判断块的ID号
switch (m_CurrentChunk->ID)
{
case VERSION: // 文件版本号
// 在该块中有一个无符号短整型数保存了文件的版本
// 读入文件的版本号,并将字节数添加到bytesRead变量中
m_CurrentChunk->bytesRead += fread(&version, 1, m_CurrentChunk->length - m_CurrentChunk->bytesRead, m_FilePointer);
// 如果文件版本号大于3,给出一个警告信息
if (version > 0x03)
MessageBox(NULL, "This 3DS file is over version 3 so it may load incorrectly", "Warning", MB_OK);
break;
case OBJECTINFO: // 网格版本信息
// 读入下一个块
ReadChunk(m_TempChunk);
// 获得网格的版本号
m_TempChunk->bytesRead += fread(&version, 1, m_TempChunk->length - m_TempChunk->bytesRead, m_FilePointer);
// 增加读入的字节数
m_CurrentChunk->bytesRead += m_TempChunk->bytesRead;
// 进入下一个块
ProcessNextChunk(pModel, m_CurrentChunk);
break;
case MATERIAL: // 材质信息
// 材质的数目递增
pModel->numOfMaterials++;
// 在纹理链表中添加一个空白纹理结构
pModel->pMaterials.push_back(newTexture);
// 进入材质装入函数
ProcessNextMaterialChunk(pModel, m_CurrentChunk);
break;
case OBJECT: // 对象的名称
// 该块是对象信息块的头部,保存了对象了名称
// 对象数递增
pModel->numOfObjects++;
// 添加一个新的tObject节点到对象链表中
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 = 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: // 正读入的是一个新块
// 使用递归函数调用,处理该新块
ProcessNextObjectChunk(pModel, pObject, m_CurrentChunk);
break;
case OBJECT_VERTICES: // 读入是对象顶点
ReadVertices(pObject, m_CurrentChunk);
break;
case OBJECT_FACES: // 读入的是对象的面
ReadVertexIndices(pObject, m_CurrentChunk);
break;
case OBJECT_MATERIAL: // 读入的是对象的材质名称
// 该块保存了对象材质的名称,可能是一个颜色,也可能是一个纹理映射。同时在该块中也保存了
// 纹理对象所赋予的面
// 下面读入对象的材质名称
ReadObjectMaterial(pModel, pObject, m_CurrentChunk);
break;
case OBJECT_UV: // 读入对象的UV纹理坐标
// 读入对象的UV纹理坐标
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}; // 用于读入不需要的数据
// 给当前块分配存储空间
m_CurrentChunk = new tChunk;
// 继续读入这些块,知道该子块结束
while (pPreviousChunk->bytesRead < pPreviousChunk->length)
{
// 读入下一块
ReadChunk(m_CurrentChunk);
// 判断读入的是什么块
switch (m_CurrentChunk->ID)
{
case MATNAME: // 材质的名称
// 读入材质的名称
m_CurrentChunk->bytesRead += fread(pModel->pMaterials[pModel->numOfMaterials - 1].strName, 1, m_CurrentChunk->length - m_CurrentChunk->bytesRead, m_FilePointer);
break;
case MATDIFFUSE: // 对象的R G B颜色
ReadColorChunk(&(pModel->pMaterials[pModel->numOfMaterials - 1]), m_CurrentChunk);
break;
case MATMAP: // 纹理信息的头部
// 进入下一个材质块信息
ProcessNextMaterialChunk(pModel, m_CurrentChunk);
break;
case MATMAPFILE: // 材质文件的名称
// 读入材质的文件名称
m_CurrentChunk->bytesRead += fread(pModel->pMaterials[pModel->numOfMaterials - 1].strFile, 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 = pPreviousChunk;
}
// 下面函数读入块的ID号和它的字节长度
void CLoad3DS::ReadChunk(tChunk *pChunk)
{
// 读入块的ID号,占用了2个字节。块的ID号象OBJECT或MATERIAL一样,说明了在块中所包含的内容
pChunk->bytesRead = fread(&pChunk->ID, 1, 2, m_FilePointer);
// 然后读入块占用的长度,包含了四个字节
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) {
// 读入一个字符直到NULL
fread(pBuffer + index, 1, 1, m_FilePointer);
}
// 返回字符串的长度
return strlen(pBuffer) + 1;
}
// 下面的函数读入RGB颜色
void CLoad3DS::ReadColorChunk(tMaterialInfo *pMaterial, tChunk *pChunk)
{
// 读入颜色块信息
ReadChunk(m_TempChunk);
// 读入RGB颜色
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; // 用于读入当前面的索引
// 读入该对象中面的数目
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++)
{
// 读入当前面的第一个点
pPreviousChunk->bytesRead += fread(&index, 1, sizeof(index), m_FilePointer);
if(j < 3)
{
// 将索引保存在面的结构中
pObject->pFaces[i].vertIndex[j] = index;
}
}
}
}
// 下面的函数读入对象的UV坐标
void CLoad3DS::ReadUVCoordinates(t3DObject *pObject, tChunk *pPreviousChunk)
{
// 为了读入对象的UV坐标,首先需要读入UV坐标的数量,然后才读入具体的数据
// 读入UV坐标的数量
pPreviousChunk->bytesRead += fread(&pObject->numTexVertex, 1, 2, m_FilePointer);
// 分配保存UV坐标的内存空间
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);
// 现在已经读入了所有的顶点。
// 因为3D Studio Max的模型的Z轴是指向上的,因此需要将y轴和z轴翻转过来。
// 具体的做法是将Y轴和Z轴交换,然后将Z轴反向。
// 遍历所有的顶点
for(int i = 0; i < pObject->numOfVerts; i++)
{
// 保存Y轴的值
float fTempY = pObject->pVerts[i].y;
// 设置Y轴的值等于Z轴的值
pObject->pVerts[i].y = pObject->pVerts[i].z;
// 设置Z轴的值等于-Y轴的值
pObject->pVerts[i].z = -fTempY;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -