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

📄 imageload.cpp

📁 在程序中根据3D地形的高度图动态地生成光照图,其中已包含了3D地形混合纹理生成的代码,使用C++和OpenGL进行编写.
💻 CPP
字号:
#include "ImageLoad.h"

//-----------------------------------------
// 函数名称:ImageLoad::ImageLoad - public
// 描述:缺省构造函数
// 参数;None
// 返回:None
//-----------------------------------------
ImageLoad::ImageLoad():m_strTexturePath(),
m_uiTextureID(0),m_FileType(INVALID),m_pTextureSurface(NULL),
m_pData(NULL),m_iWidth(0),m_iHeight(0){}

//--------------------------------------------
// 函数名称:ImageLoad::CopyCnotrol - private
// 描述:拷贝控制辅助函数
// 参数;rhs - 用于进行复制的对象
// 返回:None
//--------------------------------------------
GLvoid ImageLoad::CopyCnotrol(const ImageLoad &rhs)
{
	// 根据被复制ImageLoad的m_pTextureSurface的情况进行合理地复制
	if (rhs.m_pTextureSurface != NULL)
	{
		SDL_Surface *pTempSurface = new SDL_Surface(*(rhs.m_pTextureSurface));	// 复制SDL表面
		delete m_pTextureSurface;
		m_pTextureSurface  = pTempSurface;
	}
	else
	{
		delete m_pTextureSurface;
		m_pTextureSurface = NULL;
	}

	if (rhs.m_pData != NULL)
	{
		size_t length = _mbsnlen( rhs.m_pData, sizeof(rhs.m_pData) ) + 1;	// 保存字符的长度
		GLubyte *pTemp = new GLubyte[length];	// 分配内存 
		_mbsncpy(pTemp, rhs.m_pData, length);	// 复制数据
		delete [] m_pData;
		m_pData = pTemp;
	}
	else
	{
		delete [] m_pData;
		m_pData = NULL;
	}
}

//----------------------------------------
// 函数名称:ImageLoad::ImageLoad - public
// 描述:复制构造函数
// 参数;rhs - 用于进行复制的对象
// 返回:None
//----------------------------------------
ImageLoad::ImageLoad(const ImageLoad &rhs):m_strTexturePath(rhs.m_strTexturePath),
m_uiTextureID(rhs.m_uiTextureID),m_FileType(rhs.m_FileType),m_iWidth(rhs.m_iWidth),
m_iHeight(rhs.m_iHeight)
{
	m_pTextureSurface = NULL;	// 兼容代码,使得可调用
	m_pData = NULL;				// CopyCnotrol避免代码重复
	CopyCnotrol(rhs);
}

//-----------------------------------------------
// 函数名称:ImageLoad::operator =操作符 - public
// 描述:"="操作符
// 参数;rhs - 用于进行赋值的对象
// 返回:ImageLoad &类对象自身的引用
//-----------------------------------------------
ImageLoad &ImageLoad::operator =(const ImageLoad &rhs)
{
	m_strTexturePath = rhs.m_strTexturePath;
	m_uiTextureID = rhs.m_uiTextureID;
	m_FileType = rhs.m_FileType;
	m_iWidth = rhs.m_iWidth;
	m_iHeight = rhs.m_iHeight;
	CopyCnotrol(rhs);
	return *this;
}

//-----------------------------------------------
// 函数名称:ImageLoad::CheckFileType - private
// 描述:检测纹理文件类型
// 参数;None
// 返回:GL_FALSE - 纹理文件类型是符号要求的
//		GL_TRUE - 纹理文件类型是不符号要求的
//-----------------------------------------------
GLboolean ImageLoad::CheckFileType()
{
	string strExtent = m_strTexturePath.substr(m_strTexturePath.size() - 3);
	strExtent[0] = toupper(strExtent[0]);
	strExtent[1] = toupper(strExtent[1]);
	strExtent[2] = toupper(strExtent[2]);
	if (strExtent == "BMP")
	{
		m_FileType = BMP;
	}
	else if (strExtent == "TGA")
	{
		m_FileType = TGA;
	}
	else if (strExtent == "JPG")
	{
		m_FileType = JPG;
	}
	else if (strExtent == "PCX")
	{
		m_FileType = PCX;
	}
	else
	{
		cout << "纹理文件类型不符合要求!" << endl;
		return GL_FALSE;
	}

	return GL_TRUE;
}

//-------------------------------------------
// 函数名称:ImageLoad::LoadTexture - private
// 描述:载入纹理文件
// 参数;None
// 返回:GL_TRUE - 成功栽入纹理
//		GL_FALSE - 载入纹理失败
//-------------------------------------------
GLboolean ImageLoad::LoadTexture()
{
	// 根据纹理文件的类型载入纹理
	if (m_FileType == PCX)
	{
		if (LoadPcxTexture() != GL_TRUE)
		{
			cout << "载入PCX纹理失败!" << endl;
			return GL_FALSE;
		}
	}
	else	// 纹理文件类型为Bmp,Tga,Jpg
	{
		m_pTextureSurface = IMG_Load(m_strTexturePath.c_str());
		if (m_pTextureSurface == NULL)
		{
			cout << "载入Bmp,Tga,Jpg纹理失败!" << endl;
			return GL_FALSE;
		}

		// 调整图像数据,使其能正确显示 
		if (m_FileType == BMP || m_FileType == TGA)
		{
			// 颜色模式:colorMode -> 3 = BGR, 4 = BGRA
			GLint iPixComponent = m_pTextureSurface->format->BitsPerPixel/8;
			GLint iImageSize = m_pTextureSurface->w * m_pTextureSurface->h * iPixComponent;        // 得到图像的大小

			// 位图像数据分配内存
			GLubyte *m_pData = static_cast<GLubyte*> (m_pTextureSurface->pixels); 

			// 将BGR转换为RGB,以使得OpenGL可以读此图像数据
			GLubyte ubTemp;	
			for (int i = 0; i < iImageSize; i += iPixComponent)
			{
				ubTemp = m_pData[i];
				m_pData[i] = m_pData[i + 2];
				m_pData[i + 2] = ubTemp;
			}
		}
	}

	return GL_TRUE;
}

//----------------------------------------------
// 函数名称:ImageLoad::LoadPcxTexture - private
// 描述:载入Pcx纹理文件
// 参数;None
// 返回:GL_TRUE - 生成Pcx纹理成功
//		GL_FALSE - 生成Pcx纹理失败
//----------------------------------------------
GLboolean ImageLoad::LoadPcxTexture()
{
	GLint i,j;	// 循环索引临时变量
	FILE *pFile = NULL;
	GLint iTemp = 0;
	GLint iIndex = 0;
	GLint iRepeatNumber = 0;
	GLubyte ubMinX = 0;
	GLubyte ubMinY = 0;
	GLubyte ubMaxX = 0;
	GLubyte ubMaxY = 0;

	pFile = fopen(m_strTexturePath.c_str(), "rb");
	if(pFile == NULL)
	{
		return GL_FALSE;
	}

	// 读取第一个字符
	iTemp = getc(pFile);						

	// 测试它是10
	if(iTemp != 10)
	{
		fclose(pFile);
		return GL_FALSE;
	}

	// 再读取一个符
	iTemp = getc(pFile);					

	// 测试它是5
	if(iTemp != 5)
	{
		fclose(pFile);
		return GL_FALSE;
	}

	// 读取两个不需要的字符
	fgetc(pFile);
	fgetc(pFile);

	// 读取一个字符,左移8位,位与然后赋值
	ubMinX = fgetc(pFile); ubMinX |= fgetc(pFile) << 8;	
	ubMinY = fgetc(pFile); ubMinY |= fgetc(pFile) << 8;
	ubMaxX = fgetc(pFile); ubMaxX |= fgetc(pFile) << 8;
	ubMaxY = fgetc(pFile); ubMaxY |= fgetc(pFile) << 8;

	// 得到纹理宽度和高度(以字节为单位)
	m_iWidth = ubMaxX - ubMinX + 1; 
	m_iHeight = ubMaxY - ubMinY + 1;

	// 为纹理数据分配内存
	m_pData = new GLubyte[m_iWidth*m_iHeight];

	// 跳过文件头
	fseek(pFile, 128, SEEK_SET);

	// Read in the image.  We are reading in color indexes and using that to look up the
	// color values from the palette that we will read in later.
	while(iIndex < (m_iWidth*m_iHeight))
	{
		// Read in a character.
		iTemp = getc(pFile);

		// Test if it is > than 0xbf...
		if(iTemp > 0xbf)
		{
			// If so we calculate the number of repeats this color repeats in a row.
			iRepeatNumber = 0x3f & iTemp;

			// Read in the color index value.
			iTemp = getc(pFile);

			// For the number of times this color repeats save its color index.
			for(i = 0; i < iRepeatNumber; ++i)
			{
				m_pData[iIndex++] = iTemp;
			}
		}
		else
		{
			// Else save the color index.
			m_pData[iIndex++] = iTemp;
		}

		// Flush the stream.
		fflush(stdout);
	}

	// 异常处理
	GLubyte *pPalette = NULL;
	GLubyte *unscaledImage = NULL;
	try
	{
		// Allocate memory for the pallete.
		pPalette = new GLubyte[768];
		// Allocate some temp data for the unscaled image.
		unscaledImage = new GLubyte[m_iWidth*m_iHeight*4];
	}
	catch (...)
	{
		fclose(pFile);
		delete [] pPalette;	
		delete [] unscaledImage;	
		CleanUp();	// 释放资源
		throw;		// 继续抛出异常
	}

	// Move the file pointer so we can get the palette.  The palette is the last bit of data.
	fseek(pFile, -769, SEEK_END);

	// Read in a character.
	iTemp = getc(pFile);

	// This must be a 12 or there is an error.
	if(iTemp != 12)
	{
		fclose(pFile);
		delete [] pPalette;
		delete [] m_pData;
		m_pData = NULL;
		return GL_FALSE;
	}

	// Else we read in the palette.
	for(i = 0; i < 768; ++i)
	{
		iTemp = getc(pFile);
		pPalette[i] = iTemp;
	}

	// Close the file.
	fclose(pFile);

	// Create the image by grabing the colors from the palette.
	for(i = 0; i < m_iHeight; ++i)
	{
		for(j = 0; j < m_iWidth; ++j)
		{
			unscaledImage[4*(i*m_iWidth + j) + 0] = pPalette[3*m_pData[i*m_iWidth + j] + 0];
			unscaledImage[4*(i*m_iWidth + j) + 1] = pPalette[3*m_pData[i*m_iWidth + j] + 1];
			unscaledImage[4*(i*m_iWidth + j) + 2] = pPalette[3*m_pData[i*m_iWidth + j] + 2];
			unscaledImage[4*(i*m_iWidth + j) + 3] = static_cast<GLubyte> (255);
		}
	}

	// Delete what is in the image.
	if(m_pData != NULL)
	{
		delete [] pPalette;
		delete [] m_pData;
		m_pData = unscaledImage;
	}

	return GL_TRUE;
}

//----------------------------------------------
// 函数名称:ImageLoad::GenerateTexture - public
// 描述:生成纹理
// 参数;texturePath - 纹理文件路径
// 返回:GL_TRUE - 生成纹理成功
//		GL_FALSE - 生成纹理失败
//----------------------------------------------
GLboolean ImageLoad::GenerateTexture(const string &texturePath)
{
	// 记录纹理文件路径
	m_strTexturePath = texturePath;

	// 检测纹理文件类型
	if (CheckFileType() != GL_TRUE)
	{
		return GL_FALSE;
	}

	// 载入纹理
	if (LoadTexture() != GL_TRUE)
	{
		return GL_FALSE;
	}

	// 分配纹理对象
	glGenTextures(1, &m_uiTextureID);            

	// 载入纹理数据并设置参数
	glBindTexture(GL_TEXTURE_2D, m_uiTextureID);
	// 设置纹理过滤器
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	// 设置纹理环境
	glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE);
	// 生成纹理

	// 根据纹理文件的类型来生成纹理
	if (m_FileType == BMP || m_FileType == JPG)
	{
		gluBuild2DMipmaps(GL_TEXTURE_2D,GL_RGB, m_pTextureSurface->w, m_pTextureSurface->h, 
			GL_RGB, GL_UNSIGNED_BYTE, (GLubyte*) m_pTextureSurface->pixels);
	}
	else if (m_FileType == PCX)	// 纹理文件类型为PCX
	{
		gluBuild2DMipmaps(GL_TEXTURE_2D,GL_RGBA, m_iWidth, m_iHeight, 
			GL_RGBA, GL_UNSIGNED_BYTE, m_pData);
	}
	else	// 纹理文件类型为TGA
	{
		gluBuild2DMipmaps(GL_TEXTURE_2D,GL_RGBA, m_pTextureSurface->w, m_pTextureSurface->h, 
			GL_RGBA, GL_UNSIGNED_BYTE, (GLubyte*) m_pTextureSurface->pixels);
	}

	return GL_TRUE;
}

//-------------------------------------
// 函数名称:ImageLoad::CleanUp - public
// 描述:释放资源
// 参数;None
// 返回:None
//-------------------------------------
GLvoid ImageLoad::CleanUp()
{
	// 释放内存
	if (m_pTextureSurface !=NULL)
	{
		SDL_FreeSurface(m_pTextureSurface);
		m_pTextureSurface = NULL;
	}

	if (m_uiTextureID != 0)
	{
		glDeleteTextures(1,&m_uiTextureID);
		m_uiTextureID = 0;
	}

	if (m_pData != NULL)
	{
		delete [] m_pData;
		m_pData = NULL;
	}

	// 设置相关成员数据
	m_strTexturePath = "";
	m_FileType = INVALID;
	m_iWidth = m_iHeight = 0;
}

//-------------------------------------------------
// 名称:ImageLoad::SetPositionPixelColor - public
// 描述:设置指定位置纹理像素的颜色值
// 参数;x,y - 指定纹利像素的位置
//		red,green,blue - 为此纹理像素所设置的颜色值
// 返回:None
//-------------------------------------------------
GLvoid ImageLoad::SetPositionPixelColor(GLint x, GLint y, GLubyte red, GLubyte green, GLubyte blue)
{
	// 只对Bmp,Tga,Jpg纹理进行次操作
	if (m_FileType == PCX)
	{
		// 错误信息:不可针对PCX文件进行此操作
		return;
	}

	// 设置指定位置的纹理颜色
	if (m_pTextureSurface != NULL && x < m_pTextureSurface->w && y < m_pTextureSurface->h)
	{
		// 因为使用SDL载入的纹理颜色数据是倒过来的,所以作设置位置调整
		GLubyte ubBpp = m_pTextureSurface->format->BitsPerPixel/8;	// 得到每此纹理每像素使用的字节数
		GLubyte *surfaceData = static_cast<GLubyte*> (m_pTextureSurface->pixels);
		surfaceData[ (m_pTextureSurface->w*(m_pTextureSurface->h - y - 1) + x)*ubBpp ] = red;
		surfaceData[ (m_pTextureSurface->w*(m_pTextureSurface->h - y - 1) + x)*ubBpp + 1] = green;
		surfaceData[ (m_pTextureSurface->w*(m_pTextureSurface->h - y - 1) + x)*ubBpp + 2 ] = blue;
	}
}

//-------------------------------------------------
// 名称:ImageLoad::GetPositionPixelColor - public
// 描述:返回指定位置纹理像素的颜色值
// 参数;x,y - 指定纹利像素的位置
//		red,green,blue - 记录此纹理像素所设置的颜色值
// 返回:None
//-------------------------------------------------
GLvoid ImageLoad::GetPositionPixelColor(GLint x, GLint y, GLubyte &red, GLubyte &green, GLubyte &blue) const
{
	// 只对Bmp,Tga,Jpg纹理进行次操作
	if (m_FileType == PCX)
	{
		// 错误信息:不可针对PCX文件进行此操作
		return;
	}

	// 设置指定位置的纹理颜色
	if (m_pTextureSurface != NULL && x < m_pTextureSurface->w && y < m_pTextureSurface->h)
	{
		// 因为使用SDL载入的纹理颜色数据是倒过来的,所以作设置位置调整
		GLubyte ubBpp = m_pTextureSurface->format->BitsPerPixel/8;	// 得到每此纹理每像素使用的字节数
		GLubyte *surfaceData = static_cast<GLubyte*> (m_pTextureSurface->pixels);
		red = surfaceData[ (m_pTextureSurface->w*(m_pTextureSurface->h - y - 1) + x)*ubBpp ];
		green = surfaceData[ (m_pTextureSurface->w*(m_pTextureSurface->h - y - 1) + x)*ubBpp + 1 ];
		blue = surfaceData[ (m_pTextureSurface->w*(m_pTextureSurface->h - y - 1) + x)*ubBpp + 2 ];
	}
}

//-------------------------------------
// 名称:ImageLoad::GetWidth - public
// 描述:返回纹理宽度
// 参数;None
// 返回:GLint - 纹理宽度
//-------------------------------------
GLint ImageLoad::GetWidth() const
{
	if (m_FileType != PCX)
	{
		return m_pTextureSurface->w;
	}
	else
	{
		return m_iWidth;
	}
}

//------------------------------------
// 名称:ImageLoad::GetHeight - public
// 描述:返回纹理高度
// 参数;None
// 返回:GLint - 纹理高度
//------------------------------------
GLint ImageLoad::GetHeight() const
{
	if (m_FileType != PCX)
	{
		return m_pTextureSurface->h;
	}
	else
	{
		return m_iHeight;
	}
}

⌨️ 快捷键说明

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