?? 3dsloader.cpp
字號:
//========================================================
/**
* @file 3DSLoader.h
*
* 項目描述: 3DS文件載入
* 文件描述: 3DS文件載入類
* 適用平臺: Windows98/2000/NT/XP
*
* 作者: WWBOSS
* 電子郵件: wwboss123@gmail.com
* 創建日期: 2006-12-06
* 修改日期: 2006-12-12
*
*/
//========================================================
#include "3DSLoader.h"
#include "CBMPLoader.h"
/** 構造函數 */
C3DSLoader::C3DSLoader()
{
m_CurrentChunk = new tChunk; /**< 為當前塊分配空間 */
m_TempChunk = new tChunk; /**< 為臨時塊分配空間 */
m_3DModel.numOfObjects = 0;
m_3DModel.numOfMaterials = 0;
for (int i=0; i<MAX_TEXTURES; i++)
m_textures[i] = 0;
}
/** 釋放內存并關閉文件 */
void C3DSLoader::CleanUp()
{
fclose(m_FilePointer); /**< 關閉文件 */
delete m_CurrentChunk; /**< 釋放當前塊 */
delete m_TempChunk; /**< 釋放臨時塊 */
}
/** 析構函數 */
C3DSLoader::~C3DSLoader()
{
m_3DModel.numOfObjects = 0;
m_3DModel.numOfMaterials = 0;
m_3DModel.pObject.clear();
m_3DModel.pMaterials.clear();
glDeleteTextures(MAX_TEXTURES, m_textures);
}
/** 初時化3DS文件 */
void C3DSLoader::Init(char *filename)
{
/** 將3ds文件裝入到模型結構體中 */
Import3DS(&m_3DModel, filename);
for(int i =0; i<m_3DModel.numOfMaterials;i++)
{
if(strlen(m_3DModel.pMaterials[i].strFile)>0) /**< 判斷是否是一個文件名 */
LoadTexture(m_3DModel.pMaterials[i].strFile,m_textures, i);/**< 使用紋理文件名稱來裝入位圖 */
/** 設置材質的紋理ID */
m_3DModel.pMaterials[i].texureId = i;
}
}
/** 顯示3ds模型 */
void C3DSLoader::Draw()
{
glPushAttrib(GL_CURRENT_BIT); /**< 保存現有顏色屬實性 */
glDisable(GL_TEXTURE_2D);
/**< 遍歷模型中所有的對象 */
for(int i = 0; i < m_3DModel.numOfObjects; i++)
{
if(m_3DModel.pObject.size() <= 0)
break; /**< 如果對象的大小小于0,則退出 */
t3DObject *pObject = &m_3DModel.pObject[i];/**< 獲得當前顯示的對象 */
if(pObject->bHasTexture) /**< 判斷該對象是否有紋理映射 */
{
glEnable(GL_TEXTURE_2D); /**< 打開紋理映射 */
glBindTexture(GL_TEXTURE_2D, m_textures[pObject->materialID]);
}
else
glDisable(GL_TEXTURE_2D); /**< 關閉紋理映射 */
glColor3ub(255, 255, 255);
/** 開始繪制 */
glBegin(GL_TRIANGLES);
for(int j = 0; j < pObject->numOfFaces; j++) /**< 遍歷所有的面 */
{for(int tex = 0; tex < 3; tex++) /**< 遍歷三角形的所有點 */
{
int index = pObject->pFaces[j].vertIndex[tex]; /**< 獲得面對每個點的索引 */
glNormal3f(pObject->pNormals[index].x,pObject->pNormals[index].y,
pObject->pNormals[index].z); /**< 給出法向量 */
if(pObject->bHasTexture) /**< 如果對象具有紋理 */
{
if(pObject->pTexVerts) /**< 確定是否有UVW紋理坐標 */
glTexCoord2f(pObject->pTexVerts[index].x,pObject->pTexVerts[index].y);
}
else
{
if(m_3DModel.pMaterials.size() && pObject->materialID>= 0)
{
BYTE *pColor = m_3DModel.pMaterials[pObject->materialID].color;
glColor3ub(pColor[0],pColor[1],pColor[2]);
}
}
glVertex3f(pObject->pVerts[index].x,pObject->pVerts[index].y,pObject->pVerts[index].z);
}
}
glEnd(); /**< 繪制結束 */
}
glEnable(GL_TEXTURE_2D);
glPopAttrib(); /**< 恢復前一屬性 */
}
/** 轉載紋理 */
void C3DSLoader::LoadTexture(char* filename, GLuint textureArray[], GLuint textureID)
{
if(!filename)
return;
/** 載入位圖 */
if(!m_BMPTexture.LoadBitmap(filename))
{
MessageBox(NULL,"載入位圖失敗!","錯誤",MB_OK);
exit(0);
}
glGenTextures(1,&m_textures[textureID]);
glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
glBindTexture(GL_TEXTURE_2D, m_textures[textureID]);
/** 控制濾波 */
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR_MIPMAP_LINEAR);
/** 創建紋理 */
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, m_BMPTexture.imageWidth, m_BMPTexture.imageHeight, GL_RGB,
GL_UNSIGNED_BYTE, m_BMPTexture.image);
}
/** 載入3DS文件到模型結構中 */
bool C3DSLoader::Import3DS(t3DModel *pModel, char *strFileName)
{
char strMessage[255] = {0};
/** 打開一個3ds文件 */
m_FilePointer = fopen(strFileName, "rb");
/**< 檢查文件指針 */
if(!m_FilePointer)
{
sprintf(strMessage, "找不到文件: %s!", strFileName);
MessageBox(NULL, strMessage, "Error", MB_OK);
return false;
}
/** 將文件的第一塊讀出并判斷是否是3ds文件 */
ReadChunk(m_CurrentChunk);
/** 確保是3ds文件 */
if (m_CurrentChunk->ID != PRIMARY)
{
MessageBox(NULL, "不能加載主塊!", "Error", MB_OK);
return false;
}
/** 遞歸讀出對象數據 */
ReadNextChunk(pModel, m_CurrentChunk);
/** 計算頂點的法線 */
ComputeNormals(pModel);
/** 釋放內存空間 */
CleanUp();
return true;
}
/** 讀入一個字符串 */
int C3DSLoader::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;
}
/** 讀入塊的ID號和它的字節長度 */
void C3DSLoader::ReadChunk(tChunk *pChunk)
{
// 讀入塊的ID號 */
pChunk->bytesRead = fread(&pChunk->ID, 1, 2, m_FilePointer);
/** 讀入塊占用的長度 */
pChunk->bytesRead += fread(&pChunk->length, 1, 4, m_FilePointer);
}
/** 讀出3ds文件的主要部分 */
void C3DSLoader::ReadNextChunk(t3DModel *pModel, tChunk *pPreChunk)
{
t3DObject newObject = {0}; /**< 用來添加到對象鏈表 */
tMatInfo newTexture = {0}; /**< 用來添加到材質鏈表 */
unsigned int version = 0; /**< 保存文件版本 */
int buffer[50000] = {0}; /**< 用來跳過不需要的數據 */
m_CurrentChunk = new tChunk; /**< 為新的塊分配空間 */
/** 繼續讀入子塊 */
while (pPreChunk->bytesRead < pPreChunk->length)
{
/** 讀入下一個塊 */
ReadChunk(m_CurrentChunk);
/** 判斷塊的ID號 */
switch (m_CurrentChunk->ID)
{
/** 文件版本號 */
case VERSION:
/** 讀入文件的版本號 */
m_CurrentChunk->bytesRead += fread(&version, 1, m_CurrentChunk->length - m_CurrentChunk->bytesRead, m_FilePointer);
/** 如果文件版本號大于3,給出一個警告信息 */
if (version > 0x03)
MessageBox(NULL, " 該3DS文件版本大于3.0,可能不能正確讀取", "警告", 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;
/** 進入下一個塊 */
ReadNextChunk(pModel, m_CurrentChunk);
break;
/** 材質信息 */
case MATERIAL:
/** 材質的數目遞增 */
pModel->numOfMaterials++;
/** 在紋理鏈表中添加一個空白紋理結構 */
pModel->pMaterials.push_back(newTexture);
/** 進入材質裝入函數 */
ReadNextMatChunk(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);
/** 進入其余的對象信息的讀入 */
ReadNextObjChunk(pModel, &(pModel->pObject[pModel->numOfObjects - 1]), m_CurrentChunk);
break;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -