⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 3dsloader.cpp

📁 三维模型数据格式3DS数据的读取。详细分解3DS数据格式
💻 CPP
📖 第 1 页 / 共 3 页
字号:
//----------------------------------------------------------------------------
//
// 版权所有 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 + -