在OpenGL中实现纹理映射是一个繁琐的过程。有时,希望有一个简单的操作,只需调用图像文件的名称即可进行纹理映射,而不需要经过许多阶段的条件实现。
在OpenGL中,通过调用图像文件名称实现纹理映射的程序已经开发出来,这得益于CImage类的应用。演示项目ImgTexture是从标准的MFC Cube Sample项目派生出来的,使用CodeProject的ProjRename程序重命名。
全局过程LoadImgTexture(LPCTSTR fName)和两个相关过程GetImgBitmap(CImage * pImg)和LoadGLTexture(BITMAP * pBm)位于GlobGLTexture.cpp文件中,该文件通过使用菜单命令PROJECT->Add Existing Item...插入到ImgTexture项目中。
纹理映射的过程如下:
GLuint LoadImgTexture(LPCTSTR fName)
{
CImage img;
HRESULT hResult = img.Load(fName);
if (FAILED(hResult)) {
CString fmt;
fmt.Format(_T("Error %d\n%s"), hResult, _com_error(hResult).ErrorMessage());
MessageBox(NULL, fmt + _T("\nin file:\n") + (CString)fName, _T("Error:"), MB_OK | MB_ICONERROR);
return FALSE;
}
CBitmap * pBm = NULL;
if (img.GetBPP() != 24) {
CImage tmg;
tmg.Create(img.GetWidth(), img.GetHeight(), 24);
img.BitBlt(tmg.GetDC(), CPoint(0, 0));
pBm = GetImgBitmap(&tmg);
} else {
pBm = GetImgBitmap(&img);
}
BITMAP BMP;
pBm->GetBitmap(&BMP);
return LoadGLTexture(&BMP);
}
使用标准的CImage过程加载图像文件。默认情况下,图像格式为每像素24位。如果图像格式与默认格式不同,则创建一个每像素24位的环境,并将原始图像复制到新环境中。
CBitmap类依赖于CImage类:
CBitmap * GetImgBitmap(CImage * pImg)
{
if (pImg == NULL) return NULL;
CDC * pDC = new CDC;
if (!pDC->CreateCompatibleDC(CDC::FromHandle(pImg->GetDC()))) return NULL;
CBitmap * pBm = new CBitmap;
pBm->CreateCompatibleBitmap(CDC::FromHandle(pImg->GetDC()), pImg->GetWidth(), pImg->GetHeight());
CBitmap * pBmOld = pDC->SelectObject(pBm);
pImg->BitBlt(pDC->m_hDC, CPoint(0, 0));
pDC->DeleteDC();
return pBm;
}
BITMAP结构依赖于CBitmap类,并使用标准的OpenGL程序实现纹理,格式为GL_BGR_EXT,对应于BITMAP结构中的每像素24位格式:
GLuint LoadGLTexture(BITMAP * pBm)
{
GLuint texi;
glGenTextures(1, &texi);
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
glBindTexture(GL_TEXTURE_2D, texi);
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, pBm->bmWidth, pBm->bmHeight, GL_BGR_EXT, GL_UNSIGNED_BYTE, pBm->bmBits);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
return texi;
}
在原始项目中,CImgTextureView类有一些变化:插入了三个变量:int m_texNum; // 当前纹理名称的顺序号 CWordArray m_globTexture; // 可用纹理名称的数组 int m_view_type; // 视图性能:VIEW_DEFAULT或VIEW_TEXTURE enum VIEW_TYPE { VIEW_DEFAULT, // 原始Cube Sample视图 VIEW_TEXTURE, // 纹理视图 };
原始的CImgTextureView::Init()过程及其相关过程保持不变;在CImgTextureView::OnCreate过程中,出于演示目的,在根目录的Data文件夹中实现了来自图像文件的两条纹理实现:
int CImgTextureView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1) return -1;
Init();
m_globTexture.Add((WORD)LoadImgTexture(_T("Data/MSUN.bmp")));
m_globTexture.Add((WORD)LoadImgTexture(_T("Data/famrt.bmp")));
return 0;
}
在原始的CImgTextureView::DrawScene过程中插入了纹理处理块:
case VIEW_TEXTURE:
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, (GLuint)m_globTexture.GetAt(m_texNum));
glBegin(GL_QUADS);
glColor3f(1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
glTexCoord2f(2.0f, 0.0f); glVertex3f(1.0f, -1.0f, 1.0f);
glTexCoord2f(2.0f, 2.0f); glVertex3f(1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 2.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
glEnd();
glDisable(GL_TEXTURE_2D);
break;
所有后续的菜单和加速器命令都是使用标准AppWizard技术完成的。