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

📄 3dsloader.cpp

📁 通过vc++编程实现3DS格式的模型载入
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//========================================================
/**
*  @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 + -