📄 3dsloader.cpp
字号:
//----------------------------------------------------------------------------
//
// 版权所有 Copyright (c) 2003
// Leon Lee
// Leon8086 in CSDN
//
// 允许在不必征得作者的同意的情况下使用、拷贝、分发该代码,或将将该代码使用
// 于除了商业用途之外的其他用途,但请将以上这些说明放置于所有的拷贝之上。
// 未征得作者同意,请勿将该代码用于商业用途。
//
// 允许在该代码基础上进行修改,或在此基础上进行二次开发,但请保持本说明,保证所进行的
// 修改是在本版权说明允许的范围之内的,并保证所开发代码也遵循上述版权说明。
//----------------------------------------------------------------------------
//---------------------------------------------------
// CGL3DSLoader类定义
//---------------------------------------------------
#if defined _WIN32
#include <windows.h>
#else
typedef unsigned long DWORD;
typedef unsigned short WORD;
typedef unsigned char BYTE;
typedef long HRESULT;
#endif
//some symbols(most of them are std::list ect.) are more than 255 chars,
//it will course a c4786 warning
//I don't know how to deal with it, so just disable the warning
#pragma warning (disable:4786)
#include "GLTypeDef.h"
#include "GL3DSLoader.h"
#define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } }
#define SAFE_DELETE_ARRAY(p){ if(p) { delete[] (p); (p)=NULL; } }
const long GL3DSLOADER_OK = 0x00000000;
const long GL3DSLOADER_ERR = 0x80000000;
const DWORD MESH_USINGTEXCOORD = 0x00000001;
const long GL3DSLOADERERR_CANNOTOPENFILE = GL3DSLOADER_ERR | 0x00000001;
const long GL3DSLOADERERR_NOT3DSFILE = GL3DSLOADER_ERR | 0x00000002;
const long GL3DSLOADERERR_IOERROR = GL3DSLOADER_ERR | 0x00000003;
using namespace std;
static const float PI=3.1415926536f;
//constructor & destructor
//no comment here
CGL3DSLoader::CGL3DSLoader( )
{
m_dwObjectNum = 0;
m_dwTextureNum = 0;
m_dwMaterialNum = 0;
m_lpstrName = NULL;
m_lpstrTexture = NULL;
m_lplpVertex = NULL;
m_lplpTexcoord = NULL;
m_lplpFaceIndex = NULL;
m_lpVertexNum = NULL;
m_lpFaceNum = NULL;
m_lpFlags = NULL;
m_lpMaterial = NULL;
m_lpFaceMaterialNum = NULL;
m_lplpFaceMaterialID = NULL;
m_lplpFaceMaterialBegin = NULL;
m_lplpFaceMaterialEnd = NULL;
m_IsOK = false;
}
CGL3DSLoader::~CGL3DSLoader( )
{
Cleanup();
}
CGL3DSLoader::CGL3DSLoader( string filename )
{
m_dwObjectNum = 0;
m_dwTextureNum = 0;
m_dwMaterialNum = 0;
m_lpstrName = NULL;
m_lpstrTexture = NULL;
m_lplpVertex = NULL;
m_lplpTexcoord = NULL;
m_lplpFaceIndex = NULL;
m_lpVertexNum = NULL;
m_lpFaceNum = NULL;
m_lpFlags = NULL;
m_lpMaterial = NULL;
m_lpFaceMaterialNum = NULL;
m_lplpFaceMaterialID = NULL;
m_lplpFaceMaterialBegin = NULL;
m_lplpFaceMaterialEnd = NULL;
m_IsOK = false;
Create( filename );
}
CGL3DSLoader::MATERIALDATA::MATERIALDATA( )
:strName("")
,strTexture("")
{
fOffsetU = 0.0f;
fTilingU = 1.0f;
fOffsetV = 0.0f;
fTilingV = 1.0f;
fRotationW = 0.0f;
pAmbient[0] = 0.0f;
pAmbient[1] = 0.0f;
pAmbient[2] = 0.0f;
pAmbient[3] = 0.0f;
pDiffuse[0] = 1.0f;
pDiffuse[1] = 1.0f;
pDiffuse[2] = 1.0f;
pDiffuse[3] = 1.0f;
pSpecular[0] = 1.0f;
pSpecular[1] = 1.0f;
pSpecular[2] = 1.0f;
pSpecular[3] = 1.0f;
}
CGL3DSLoader::MESHDATA::MESHDATA( )
:vtxCenter( 0, 0, 0 )
,strName("")
{
lpVertex = NULL;
lpTexcoord = NULL;
lpTriangles = NULL;
dwVertexNum = 0;
dwFaceNum = 0;
dwFlags = 0;
lpMaterialName
= NULL;
lpFaceMaterialNum
= NULL;
lplpFaceMaterialIndex
= NULL;
dwMaterialNum
= 0;
lpMaterialID
= NULL;
strName = "";
};
CGL3DSLoader::MESHDATA::~MESHDATA()
{
for( DWORD i=0; i<dwMaterialNum; i++ )
SAFE_DELETE_ARRAY( lplpFaceMaterialIndex[i] );
SAFE_DELETE_ARRAY( lplpFaceMaterialIndex );
SAFE_DELETE_ARRAY( lpFaceMaterialNum );
SAFE_DELETE_ARRAY( lpMaterialName );
SAFE_DELETE_ARRAY( lpVertex );
SAFE_DELETE_ARRAY( lpTexcoord );
SAFE_DELETE_ARRAY( lpTriangles );
SAFE_DELETE_ARRAY( lpMaterialID );
};
//----------------------------------------------------
//Function Name : Cleanup
//Desc : 清对象
//Input :NUL
//Output : NUL
//----------------------------------------------------
void CGL3DSLoader::Cleanup(void)
{
SAFE_DELETE_ARRAY( m_lpstrName );
SAFE_DELETE_ARRAY( m_lpstrTexture );
if( m_lplpVertex )
for( DWORD i=0; i<m_dwObjectNum; i++ )
SAFE_DELETE_ARRAY( m_lplpVertex[i] );
if( m_lplpTexcoord )
for( DWORD i=0; i<m_dwObjectNum; i++ )
SAFE_DELETE_ARRAY( m_lplpTexcoord[i] );
if( m_lplpFaceIndex )
for( DWORD i=0; i<m_dwObjectNum; i++ )
SAFE_DELETE_ARRAY( m_lplpFaceIndex[i] );
SAFE_DELETE_ARRAY( m_lplpVertex );
SAFE_DELETE_ARRAY( m_lplpTexcoord );
SAFE_DELETE_ARRAY( m_lplpFaceIndex );
SAFE_DELETE_ARRAY( m_lpFaceNum );
SAFE_DELETE_ARRAY( m_lpVertexNum );
SAFE_DELETE_ARRAY( m_lpFlags );
SAFE_DELETE_ARRAY( m_lpFaceMaterialNum );
SAFE_DELETE_ARRAY( m_lpMaterial );
if( m_lplpFaceMaterialID )
for( DWORD i=0; i<m_dwObjectNum; i++ )
SAFE_DELETE_ARRAY( m_lplpFaceMaterialID[i] );
SAFE_DELETE_ARRAY( m_lplpFaceMaterialID );
if( m_lplpFaceMaterialBegin )
for( DWORD i=0; i<m_dwObjectNum; i++ )
SAFE_DELETE_ARRAY( m_lplpFaceMaterialBegin[i] );
SAFE_DELETE_ARRAY( m_lplpFaceMaterialBegin );
if( m_lplpFaceMaterialEnd )
for( DWORD i=0; i<m_dwObjectNum; i++ )
SAFE_DELETE_ARRAY( m_lplpFaceMaterialEnd[i] );
SAFE_DELETE_ARRAY( m_lplpFaceMaterialEnd );
m_dwObjectNum = 0;
m_dwTextureNum = 0;
m_dwMaterialNum = 0;
m_IsOK = false;
}
//----------------------------------------------------
//Function Name : Seek3DSChunk
//Desc : 从当前位置开始定位ID为wID块
//Input :file : 用于定位的fstream文件对象的引用
// : wID : 指定的块ID
// : dwLength : 寻找范围,0表示以当前位置到文件尾
//Output : 指定块被找到返回该块的长度(不包括块头),否则返回0
//Notice : 当前文件指针必须指向某个块的块头(保证所有块都能被找到)
// 找到该块时文件指针指向ID和Length之后的
// 第一个字节(==offset(块头)+6Bytes)
// 否则将回到初始时的位置
// file的完备性由使用者保证
//----------------------------------------------------
DWORD CGL3DSLoader::Seek3DSChunk( fstream& file, WORD wID, DWORD dwLength )
{
WORD wIDRead = 0;
DWORD dwBlockLength = 0;
DWORD dwTemp = file.tellg();
file.seekg( 0, ios::end );
DWORD dwLengthToEnd = (DWORD)file.tellg() - dwTemp;
file.seekg( dwTemp, ios::beg );
if( dwLength > dwLengthToEnd || (!dwLength) )
dwLength = dwLengthToEnd;
int iCounter = dwLength;
DWORD dwBeginPos = file.tellg();
DWORD dwReadCount = 0;
//当处于寻找范围内,执行循环。
//此处的文件操作均未使用异常检测
while( iCounter > 0 )
{
//读取块ID
file.read( (char*)&wIDRead, sizeof(wIDRead) );
iCounter -= sizeof(wIDRead);
//读取块长度
file.read( (char*)&dwBlockLength, sizeof(dwBlockLength) );
iCounter -= sizeof(dwBlockLength);
if( iCounter <= 0 || file.eof() )
{
file.seekg( dwBeginPos, ios::beg );
return 0;
}
if( wID != wIDRead )
{
//如果不是指定块,跳向下一块
DWORD dwOffset = dwBlockLength - sizeof(wID) - sizeof(dwBlockLength);
iCounter -= dwOffset;
if( iCounter <= 0 )
break;
file.seekg( dwOffset, ios::cur );
if( file.eof() )
break;
}
else
//否则返回块的长度
return dwBlockLength - sizeof( dwBlockLength ) - sizeof( wID );
}
//若找不到则返回初始位置
file.seekg( dwBeginPos, ios::beg );
return 0;
}
//----------------------------------------------------
//Function Name : Read3DSFaceListChunk
//Desc : 从当前位置开始读取面块
//Input :file : 用于定位的fstream文件对象的引用
// : dwLength : 块大小
// : lpData : 用于填充数据的对象
//Output : 成功返回true,否则返回false
//Notice : 当前文件指针必须指向面块的数据部分(不包括块头)
// file,lpData的完备性由使用者保证
//----------------------------------------------------
bool CGL3DSLoader::Read3DSFaceListChunk( fstream& file, DWORD dwLength, CGL3DSLoader::MESHDATA* lpData )
{
int iCount = dwLength;
DWORD dwReadCount =0;
//面列表拷贝
WORD wNum;
DWORD dwBeginPos = file.tellg();
file.read( (char*)&wNum, sizeof(wNum) );
iCount -= sizeof(wNum);
if( file.eof() || iCount < 0 )
{
file.seekg( dwBeginPos, ios::beg );
return false;
}
//面的数目
lpData->dwFaceNum = wNum;
WORD* pwFace = new WORD[wNum*4];
//读取所有面
file.read( (char*)pwFace, sizeof(WORD)*wNum*4 );
iCount -= sizeof(WORD)*wNum*4;
if( file.eof() || iCount < 0 )
{
file.seekg( dwBeginPos, ios::beg );
SAFE_DELETE_ARRAY( pwFace );
return false;
}
list<string> listName;
list<DWORD*> listFaceIndex;
list<DWORD> listFaceNum;
lpData->lpTriangles = new MESHTRIANGLEINDEX[wNum];
//拷贝面数据
for( int i=0; i<(int)wNum; i++ )
lpData->lpTriangles[i] = MESHTRIANGLEINDEX( pwFace[i*4], pwFace[i*4+1], pwFace[i*4+2] );
//释放中间变量
SAFE_DELETE_ARRAY(pwFace);
while( iCount>0 && !(file.eof()) )
{
//继续寻找子块
WORD wID1;
DWORD dwBlockLength1;
//读取块名
file.read( (char*)&wID1, sizeof(wID1) );
iCount -= sizeof(wID1);
file.read( (char*)&dwBlockLength1, sizeof( dwBlockLength1) );
iCount -= sizeof(dwBlockLength1);
//仅处理面材质块
if( wID1 == CHUNK_FACEMAT )
{
//以NULL Terminated string表示使用的材质
char name[200];
memset( name, 1,sizeof(char)*200 );
file.read( name, 1 );
iCount --;
for( DWORD i=0; name[i]!=0; i++ )
{
file.read( name+i+1, 1 );
iCount --;
}
//纪录每个材质
listName.push_back( string(name) );
WORD wFaceNum;
file.read( (char*)&wFaceNum, sizeof(wFaceNum) );
iCount -= sizeof(wFaceNum);
WORD* pTemp = new WORD[wFaceNum];
DWORD* pFaceList = new DWORD[wFaceNum];
file.read( (char*)pTemp, sizeof(WORD)*wFaceNum );
iCount -= sizeof(WORD)*wFaceNum;
for( i=0; i<wFaceNum; i++ )
pFaceList[i] = pTemp[i];
delete []pTemp;
//纪录关联到每个材质的面的索引
listFaceIndex.push_back( pFaceList );
//和数目
listFaceNum.push_back( wFaceNum );
lpData->dwMaterialNum ++;
}
else
{
file.seekg( dwBlockLength1 - sizeof(wID1) - sizeof(dwBlockLength1), ios::cur );
iCount -= dwBlockLength1 - sizeof(wID1) - sizeof(dwBlockLength1);
}
}
//拷贝材质数据到MESHDATA对象
lpData->lpFaceMaterialNum = new DWORD[lpData->dwMaterialNum];
lpData->lplpFaceMaterialIndex = new DWORD*[lpData->dwMaterialNum];
lpData->lpMaterialName = new string[lpData->dwMaterialNum];
for( DWORD j = 0; j < lpData->dwMaterialNum; j++ )
{
//面数目
lpData->lpFaceMaterialNum[j] = listFaceNum.front();
listFaceNum.pop_front();
//面索引数组
lpData->lplpFaceMaterialIndex[j] = listFaceIndex.front();
listFaceIndex.pop_front();
//对应材质的名称
lpData->lpMaterialName[j] = listName.front();
listName.pop_front( );
}
file.seekg( dwBeginPos + dwLength, ios::beg );
return true;
}
//----------------------------------------------------
//Function Name : Read3DSObjectChunk
//Desc : 从当前位置开始读取物体块
//Input :file : 用于定位的fstream文件对象的引用
// : dwLength : 块大小
//Output : 如果该物体是网格对象,返回一个描述该对象的MESHDATA结构指针,否则返回NULL
//Notice : 当前文件指针必须指向物体块的数据部分(不包括块头)
// file的完备性由使用者保证,返回指针由使用者释放
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -