#include "Main.h"
#include "Ase.h"
// 下面的函数功能是将ASE模型读入到t3DModel模型结构体中
bool CLoadASE::ImportASE(t3DModel *pModel, char *strFileName)
{
char strMessage[255] = {0}; // 用于显示错误信息
// 判断是否是一个合法的模型和文件类型
if(!pModel || !strFileName) return false;
// 以只读方式打开文件,返回文件指针
m_FilePointer = fopen(strFileName, "r");
// 判断文件指针是否正确
if(!m_FilePointer) {
// 如果文件指针不正确,则显示错误信息
sprintf(strMessage, "Unable to find or open the file: %s", strFileName);
MessageBox(NULL, strMessage, "Error", MB_OK);
return false;
}
// 读入文件信息
ReadAseFile(pModel);
// 计算顶点的法向量,用于光照
ComputeNormals(pModel);
// 关闭打开的文件
fclose(m_FilePointer);
return true;
}
// 下面的函数用来读入一个Ase文件
void CLoadASE::ReadAseFile(t3DModel *pModel)
{
tMaterialInfo newMaterial = {0}; // 新材质
t3DObject newObject = {0}; // 新对象
int i = 0;
// 获得ase文件中对象的数量
pModel->numOfObjects = GetObjectCount();
// 获得ase文件中材质的数量
pModel->numOfMaterials = GetMaterialCount();
// 遍历所有的材质
for(i = 0; i < pModel->numOfMaterials; i++)
{
// 在材质链表中添加一个新的材质
pModel->pMaterials.push_back(newMaterial);
// 获得当前材质的材质信息
GetTextureInfo(&(pModel->pMaterials[i]), i + 1);
}
// 遍历所有的对象
for(i = 0; i < pModel->numOfObjects; i++)
{
// 在对象链表中添加一个新的对象
pModel->pObject.push_back(newObject);
// 初始化材质ID,设置为-1
pModel->pObject[i].materialID = -1;
// 将文件指针移动到指定的对象
MoveToObject(i + 1);
// 确定对象的顶点数、面的数量和纹理坐标数量,然后分配足够的内存空间
ReadObjectInfo(&(pModel->pObject[i]), i + 1);
// 读入对象的顶点、面和纹理坐标数据
ReadObjectData(pModel, &(pModel->pObject[i]), i + 1);
}
}
// 下面的函数的功能是获得ase文件中对象的数量
int CLoadASE::GetObjectCount()
{
char strWord[255] = {0};
int objectCount = 0;
// 将文件指针的定位在文件的开始
rewind(m_FilePointer);
// 遍历整个文件
while (!feof(m_FilePointer))
{
// 获得文件中的每个字符串
fscanf(m_FilePointer, "%s", &strWord);
// 判断是否是对象
if (!strcmp(strWord, OBJECT))
{
// 增加对象计数器
objectCount++;
}
else
{
// 进入下一行
fgets(strWord, 100, m_FilePointer);
}
}
// 返回ase文件中的对象数量
return objectCount;
}
// 下面的函数功能是获得ase文件中的材质
int CLoadASE::GetMaterialCount()
{
char strWord[255] = {0};
int materialCount = 0;
// 将文件指针定位于文件开始处
rewind(m_FilePointer);
// 遍历整个文件
while (!feof(m_FilePointer))
{
// 获得文件中的每个字符串
fscanf(m_FilePointer, "%s", &strWord);
// 判断是否是对象的材质数量
if (!strcmp(strWord, MATERIAL_COUNT))
{
// 读入材质数
fscanf(m_FilePointer, "%d", &materialCount);
// 返回材质数
return materialCount;
}
else
{
// 进入下一行
fgets(strWord, 100, m_FilePointer);
}
}
// 如果没有材质,则返回0
return 0;
}
// 获得指定材质的材质信息
void CLoadASE::GetTextureInfo (tMaterialInfo *pTexture, int desiredMaterial)
{
char strWord[255] = {0};
int materialCount= 0;
// 将文件指针定位于文件开始处
rewind(m_FilePointer);
// 遍历整个文件
while (!feof(m_FilePointer))
{
// 获得文件中每个字符串
fscanf(m_FilePointer, "%s", &strWord);
// 判断是否是材质
if (!strcmp(strWord, MATERIAL))
{
// 增加材质计数器
materialCount++;
// 判断材质计数器是否与具体的材质匹配
if(materialCount == desiredMaterial)
break;
}
else
{
// 进入下一行
fgets(strWord, 100, m_FilePointer);
}
}
// 现在进入所需要读入的材质
// 遍历余下的文件,直到结束
while (!feof(m_FilePointer))
{
// 获得文件中的每个字符串
fscanf(m_FilePointer, "%s", &strWord);
// 判断是否是材质标签
if (!strcmp (strWord, MATERIAL))
{
// 新的材质,则返回
return;
}
// 如果是MATERIAL_COLOR标签,需要获得材质的颜色
else if (!strcmp(strWord, MATERIAL_COLOR))
{
// 获得对象材质的RGB颜色
fscanf(m_FilePointer, " %f %f %f", &(pTexture->fColor[0]),
&(pTexture->fColor[1]),
&(pTexture->fColor[2]));
}
// 如果是TEXTURE标签,需要获得纹理名称
else if (!strcmp(strWord, TEXTURE))
{
// 获得纹理的文件名
GetTextureName(pTexture);
}
// 如果是MATERIAL_NAME标签,则需要获得材质的名称
else if (!strcmp(strWord, MATERIAL_NAME))
{
// 获得对象的材质名称
GetMaterialName(pTexture);
}
// 如果是UTILE标签,则需要获得U重复率
else if(!strcmp(strWord, UTILE))
{
// 读入U纹理坐标上的U重复率
pTexture->uTile = ReadFloat();
}
// 如果是VTILE标签,则需要获得V重复率
else if(!strcmp(strWord, VTILE))
{
// 读入V纹理坐标上的V重复率
pTexture->vTile = ReadFloat();
}
// 否则,略过这些数据
else
{
// 进入下一行
fgets (strWord, 100, m_FilePointer);
}
}
}
// 下面的函数功能是将文件指针移到Ase文件中指定的对象
void CLoadASE::MoveToObject (int desiredObject)
{
char strWord[255] = {0};
int objectCount = 0;
// 将文件指针定位的文件的开始
rewind(m_FilePointer);
// 遍历整个文件,直到文件结束
while(!feof(m_FilePointer))
{
// 获得文件每一个字符串
fscanf(m_FilePointer, "%s", &strWord);
// 判断是否是一个对象
if(!strcmp(strWord, OBJECT))
{
// 增加对象计数器
objectCount++;
// 如果是指定的对象
if(objectCount == desiredObject)
return;
}
else
{
// 进入下一行
fgets(strWord, 100, m_FilePointer);
}
}
}
// 下面的函数功能是从Ase文件中读入一个浮点数
float CLoadASE::ReadFloat()
{
float v = 0.0f;
// 读入一个浮点数
fscanf(m_FilePointer, " %f", &v);
// 返回该浮点数
return v;
}
// 下面的函数的功能是读入对象的信息
void CLoadASE::ReadObjectInfo(t3DObject *pObject, int desiredObject)
{
char strWord[255] = {0};
// 将文件指针移动到指定的对象
MoveToObject(desiredObject);
// 直到文件尾才结束
while (!feof(m_FilePointer))
{
// 从文件中读入每个字符串
fscanf(m_FilePointer, "%s", &strWord);
// 如果是顶点数量标签
if (!strcmp(strWord, NUM_VERTEX))
{
// 读入对象的顶点数量
fscanf(m_FilePointer, "%d", &pObject->numOfVerts);
// 分配保存顶点的内存空间
pObject->pVerts = new CVector3 [pObject->numOfVerts];
}
// 如果是面的数目标签
else if (!strcmp(strWord, NUM_FACES))
{
// 读入对象中面的数目
fscanf(m_FilePointer, "%d", &pObject->numOfFaces);
// 分配保存面的内存空间
pObject->pFaces = new tFace [pObject->numOfFaces];
}
// 如果是纹理坐标数目
else if (!strcmp(strWord, NUM_TVERTEX))
{
// 读入对象的纹理坐标数目
fscanf(m_FilePointer, "%d", &pObject->numTexVertex);
// 分配保存UV坐标的内存空间
pObject->pTexVerts = new CVector2 [pObject->numTexVertex];
}
// 如果是对象标签,则进入了下一个对象
else if (!strcmp(strWord, OBJECT))
{
// 返回
return;
}
else
{
// 没有找到任何东西,则进入下一行
fgets(strWord, 100, m_FilePointer);
}
}
}
// 下面的函数功能是读入对象的纹理文件名称
void CLoadASE::GetTextureName(tMaterialInfo *pTexture)
{
// 读入纹理的文件名
fscanf (m_FilePointer, " \"%s", &(pTexture->strFile));
// 在字符串的末尾增加一个NULL字符
pTexture->strFile[strlen (pTexture->strFile) - 1] = '\0';
}
// 下面的函数功能是读入对象的材质名称
void CLoadASE::GetMaterialName(tMaterialInfo *pTexture)
{
// 读入材质名称
fscanf (m_FilePointer, " \"%s", &(pTexture->strName));
// 在字符串的末尾加上NULL字符
pTexture->strName[strlen (pTexture->strName)] = '\0';
}
// 下面的函数功能是读入指定对象的具体数据
void CLoadASE::ReadObjectData(t3DModel *pModel, t3DObject *pObject, int desiredObject)
{
// 读入对象的材质ID
GetData(pModel, pObject, MATERIAL_ID, desiredObject);
// 读入对象的顶点数
GetData(pModel, pObject, VERTEX, desiredObject);
// 读入对�