3ds.cpp

来自「3D赛车游戏源代码-用Visual Studio 2005」· C++ 代码 · 共 446 行

CPP
446
字号
#include "StdAfx.h"
#include "3ds.h"
#include "../opengl/OGLutil.h"
#include <fstream>


//-------------------------------------------------------------------------------
// 文件格式的3D物体定义构造函数
//-------------------------------------------------------------------------------
t3DObject::t3DObject() : numOfVerts(0), numOfFaces(0), numTexVertex(0), 
					bHasTexture(false), pVerts(NULL), pNormals(NULL), 
					pTexVerts(NULL), pFaces(NULL)
{
}

//-------------------------------------------------------------------------------
// 文件格式的3D物体定义析构函数
//-------------------------------------------------------------------------------
t3DObject::~t3DObject()
{
	SAFE_DELETE_ARRAY(pVerts);
	SAFE_DELETE_ARRAY(pNormals);
	SAFE_DELETE_ARRAY(pTexVerts);
	SAFE_DELETE_ARRAY(pFaces);
}

//-------------------------------------------------------------------------------
// 3DS文件载入全局单件对象
//-------------------------------------------------------------------------------
CLoad3DS g_Load3DS;

//-------------------------------------------------------------------------------
// 构造函数
//-------------------------------------------------------------------------------
CLoad3DS::CLoad3DS()
{
}


//-------------------------------------------------------------------------------
// 加载模型
//-------------------------------------------------------------------------------
bool CLoad3DS::Import3DS(t3DModel *pModel, const char *strFileName)
{
	char strMessage[255] = {0};

	m_CurrentChunk = new tChunk;
	m_TempChunk = new tChunk;	
	// Open the 3DS file
	m_FilePointer = fopen(strFileName, "rb");

	// Make sure we have a valid file pointer (we found the file)
	if(!m_FilePointer) 
	{
		sprintf(strMessage, "Unable to find the file: %s!", strFileName);
		MessageBox(NULL, strMessage, "Error", MB_OK);
		CleanUp();
		return false;
	}

	ReadChunk(m_CurrentChunk);

	// Make sure this is a 3DS file
	if (m_CurrentChunk->ID != PRIMARY)
	{
		sprintf(strMessage, "Unable to load PRIMARY chuck from file: %s!", strFileName);
		MessageBox(NULL, strMessage, "Error", MB_OK);
		CleanUp();
		return false;
	}

	
	ProcessNextChunk(pModel, m_CurrentChunk);

	char szPathName[64];
	char szFileName[32];
	bool bHasPath = false;
	char* ptr = strrchr(strFileName, '/');

	if (ptr == NULL)
	{
		ptr = strrchr(strFileName, '\\');
	}

	if (ptr == NULL)
	{
		szPathName[0] = '\0';
	}
	else
	{
		int len = static_cast<int>(ptr - strFileName);
		strncpy(szPathName, strFileName, len);
		szPathName[len] = '\\';
		szPathName[len+1] = '\0';
		bHasPath = true;
	}

	// 为了方便载入纹理,加上模型本身的路径。
	if (bHasPath)
	{
		for (int i=0; i<pModel->numOfMaterials; ++i)
		{
			tMaterialInfo& mat = pModel->pMaterials[i];
			strcpy(szFileName, mat.strFile);
			strcpy(mat.strFile, szPathName);
			strcat(mat.strFile, szFileName);
		}
	}


	CleanUp();

	return true;
}

//-------------------------------------------------------------------------------
// 清空资源
//-------------------------------------------------------------------------------
void CLoad3DS::CleanUp()
{
	fclose(m_FilePointer);		
	SAFE_DELETE(m_CurrentChunk);		
	SAFE_DELETE(m_TempChunk);			
}


//-------------------------------------------------------------------------------
// 处理下一块
//-------------------------------------------------------------------------------
void CLoad3DS::ProcessNextChunk(t3DModel *pModel, tChunk *pPreviousChunk)
{
	t3DObject newObject;			
	tMaterialInfo newTexture;		
	unsigned int version = 0;			
	int buffer[2048] = {0};			

	m_CurrentChunk = new tChunk;						

	while (pPreviousChunk->bytesRead < pPreviousChunk->length)
	{
		// Read next Chunk
		ReadChunk(m_CurrentChunk);

		// Check the chunk ID
		switch (m_CurrentChunk->ID)
		{
		case VERSION:							// This holds the version of the file
			
			m_CurrentChunk->bytesRead += fread(&version, 1, m_CurrentChunk->length - m_CurrentChunk->bytesRead, m_FilePointer);
			break;

		case OBJECTINFO:						// This holds the version of the mesh
			
			//ReadChunk(m_TempChunk);

			
		//	m_TempChunk->bytesRead += fread(buffer, 1, m_TempChunk->length - m_TempChunk->bytesRead, m_FilePointer);			
		//	m_CurrentChunk->bytesRead += m_TempChunk->bytesRead;
			ProcessNextChunk(pModel, m_CurrentChunk);
			break;

		case MATERIAL:							// This holds the material information

			pModel->numOfMaterials++;
			pModel->pMaterials.push_back(newTexture);

			ProcessNextMaterialChunk(pModel, m_CurrentChunk);
			break;

		case OBJECT:							// This holds the name of the object being read
				
			pModel->numOfObjects++;
		
			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 = NULL;
	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:					// This lets us know that we are reading a new object
		
			ProcessNextObjectChunk(pModel, pObject, m_CurrentChunk);
			break;

		case OBJECT_VERTICES:				// This is the objects vertices
			ReadVertices(pObject, m_CurrentChunk);
			break;

		case OBJECT_FACES:					// This is the objects face information
			ReadVertexIndices(pObject, m_CurrentChunk);
			break;

		case OBJECT_MATERIAL:				// This holds the material name that the object has
			
			ReadObjectMaterial(pModel, pObject, m_CurrentChunk);			
			break;

		case OBJECT_UV:						// This holds the UV texture coordinates for the object

			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};					// This is used to read past unwanted data

	// Allocate a new chunk to work with
	m_CurrentChunk = new tChunk;

	// Continue to read these chunks until we read the end of this sub chunk
	while (pPreviousChunk->bytesRead < pPreviousChunk->length)
	{
		// Read the next chunk
		ReadChunk(m_CurrentChunk);

		// Check which chunk we just read in
		switch (m_CurrentChunk->ID)
		{
		case MATNAME:							// This chunk holds the name of the material
			
			// Here we read in the material name
			m_CurrentChunk->bytesRead += fread(pModel->pMaterials[pModel->numOfMaterials - 1].strName, 1, m_CurrentChunk->length - m_CurrentChunk->bytesRead, m_FilePointer);
			break;

		case MATDIFFUSE:						// This holds the R G B color of our object
			ReadColorChunk(&(pModel->pMaterials[pModel->numOfMaterials - 1]), m_CurrentChunk);
			break;
		
		case MATMAP:							// This is the header for the texture info
			
			// Proceed to read in the material information
			ProcessNextMaterialChunk(pModel, m_CurrentChunk);
			break;

		case MATMAPFILE:						// This stores the file name of the material

			// Here we read in the material's file name
			m_CurrentChunk->bytesRead += fread(pModel->pMaterials[pModel->numOfMaterials - 1].strFile, 1, m_CurrentChunk->length - m_CurrentChunk->bytesRead, m_FilePointer);
			break;
		
		default:  

			// Read past the ignored or unknown chunks
			m_CurrentChunk->bytesRead += fread(buffer, 1, m_CurrentChunk->length - m_CurrentChunk->bytesRead, m_FilePointer);
			break;
		}

		// Add the bytes read from the last chunk to the previous chunk passed in.
		pPreviousChunk->bytesRead += m_CurrentChunk->bytesRead;
	}

	// Free the current chunk and set it back to the previous chunk (since it started that way)
	delete m_CurrentChunk;
	m_CurrentChunk = pPreviousChunk;
}



//-------------------------------------------------------------------------------
// 读取文件块
//-------------------------------------------------------------------------------
void CLoad3DS::ReadChunk(tChunk *pChunk)
{
	pChunk->bytesRead = fread(&pChunk->ID, 1, 2, m_FilePointer);

	// Then, we read the length of the chunk which is 4 bytes.
	// This is how we know how much to read in, or read past.
	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) 
	{
		fread(pBuffer + index, 1, 1, m_FilePointer);
	}

	return (int)strlen(pBuffer) + 1;
}


//-------------------------------------------------------------------------------
// 读取颜色块
//-------------------------------------------------------------------------------
void CLoad3DS::ReadColorChunk(tMaterialInfo *pMaterial, tChunk *pChunk)
{
	ReadChunk(m_TempChunk);

	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;					// This is used to read in the current face index

	
	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++)
		{
			// Read the first vertice index for the current face 
			pPreviousChunk->bytesRead += fread(&index, 1, sizeof(index), m_FilePointer);

			if(j < 3)
			{
				// Store the index in our face structure.
				pObject->pFaces[i].vertIndex[j] = index;
			}
		}
	}
}


//-------------------------------------------------------------------------------
// 读取纹理坐标
//-------------------------------------------------------------------------------
void CLoad3DS::ReadUVCoordinates(t3DObject *pObject, tChunk *pPreviousChunk)
{
	pPreviousChunk->bytesRead += fread(&pObject->numTexVertex, 1, 2, m_FilePointer);

	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);

}


//-------------------------------------------------------------------------------
// 读取材质
//-------------------------------------------------------------------------------
void CLoad3DS::ReadObjectMaterial(t3DModel *pModel, t3DObject *pObject, tChunk *pPreviousChunk)
{
	char strMaterial[255] = {0};			// This is used to hold the objects material name
	int buffer[50000] = {0};				// This is used to read past unwanted data

	
	pPreviousChunk->bytesRead += GetString(strMaterial);

	for(int i = 0; i < pModel->numOfMaterials; i++)
	{
		// If the material we just read in matches the current texture name
		if(strcmp(strMaterial, pModel->pMaterials[i].strName) == 0)
		{
			// Set the material ID to the current index 'i' and stop checking
			pObject->materialID = i;

			if(strlen(pModel->pMaterials[i].strFile) > 0) 
			{
				pObject->bHasTexture = true;
			}	
			break;
		}
		else
		{
			pObject->materialID = -1;
		}
	}

	pPreviousChunk->bytesRead += fread(buffer, 1, pPreviousChunk->length - pPreviousChunk->bytesRead, m_FilePointer);
}			

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?