OpenGL纹理映射

来源:互联网 发布:文章管理系统cms 编辑:程序博客网 时间:2024/05/01 22:03
 

// BMPLoader.h

#pragma once

#include "stdafx.h"
#define BITMAP_ID 0x4D42

class CBMPLoader
{
public:
CBMPLoader(void);
~CBMPLoader(void);

bool LoadBitmap(const char *filename);      // 装载一个bmp文件
void FreeImage();           // 释放图像数据
bool Load(const char *fileName);       // 载入位图并创建纹理

GLuint ID;             // 生成纹理的ID号
int imageWidth;            // 图像宽度
int imageHeight;           // 图像高度
unsigned char *image;          // 指向图像数据的指针
};

// BMPLoader.cpp

#include "BMPLoader.h"

CBMPLoader::CBMPLoader(void)
{
// 初始化成员值为0
image = NULL;
imageWidth = 0;
imageHeight = 0;
}

CBMPLoader::~CBMPLoader(void)
{
FreeImage();            // 释放图像数据占据的内存
}

// 装载一个位图文件
bool CBMPLoader::LoadBitmap(const char *file)
{
FILE *pFile = NULL;           // 文件指针

// 创建位图文件信息和位图文件头结构
BITMAPINFOHEADER bitmapInfoHeader;
BITMAPFILEHEADER header;

unsigned char textureColors = 0;       // 用于将图像颜色从BGR变换到RGB

// 打开文件,并检查错误
pFile = fopen(file, "rb");
if (pFile == NULL) return false;

// 读入位图文件头信息
fread(&header, sizeof(BITMAPFILEHEADER), 1, pFile);
// 检查该文件是否为位图文件
if (header.bfType != BITMAP_ID)
{
   fclose(pFile);           // 若不是位图文件,则关闭文件并返回
   return false;
}

// 读入位图文件信息
fread(&bitmapInfoHeader, sizeof(BITMAPINFOHEADER), 1, pFile);
// 保存图像的宽度和高度
imageWidth = bitmapInfoHeader.biWidth;
imageHeight = bitmapInfoHeader.biHeight;
// 确保读取数据的大小
if (bitmapInfoHeader.biSizeImage == NULL)
   bitmapInfoHeader.biSizeImage = bitmapInfoHeader.biWidth * bitmapInfoHeader.biHeight * 3;

// 将指针移到数据开始位置
fseek(pFile, header.bfOffBits, SEEK_SET);
// 分配内存
image = new unsigned char[bitmapInfoHeader.biSizeImage];
// 检查内存分配是否成功
if(!image)             // 若分配内存失败则返回
{
   delete[] image;
   fclose(pFile);
   return false;
}

// 读取图像数据
fread(image, 1, bitmapInfoHeader.biSizeImage, pFile);
// 将图像颜色数据格式进行交换,由BGR转换为RGB
for(int index = 0; index < (int)bitmapInfoHeader.biSizeImage; index+=3)
{
   textureColors = image[index];
   image[index] = image[index + 2];
   image[index + 2] = textureColors;
}

fclose(pFile);            // 关闭文件
return true;            // 成功返回
}

// 载入位图文件,并创建纹理
bool CBMPLoader::Load(const char *fileName)
{
if (!LoadBitmap(fileName)) return false;
// 生成纹理对象名称
glGenTextures(1, &ID);
// 创建纹理对象
glBindTexture(GL_TEXTURE_2D, ID);
// 控制滤波
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// 创建纹理
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, imageWidth, imageHeight, GL_RGB, GL_UNSIGNED_BYTE, image);
return true;
}

// 释放内存
void CBMPLoader::FreeImage()
{
// 释放分配的内存
if(image)
{
   delete []image;
   image = NULL;
}
}

// TGALoader.h

#pragma once
#include "stdafx.h"

class CTGALoader
{
public:
CTGALoader(void);
~CTGALoader(void);

bool LoadTGA(const char *file);        // 载入TGA文件
void FreeImage();           // 释放内存
bool Load(const char *fileName);       // 载入TGA文件为纹理

GLuint ID;             // 生成纹理的ID号
int imageWidth;            // 图像宽度
int imageHeight;           // 图像高度
unsigned char *image;          // 指向图像数据的指针
unsigned int type;           // 图象类型GL_RGB 或GL_RGBA
};

// TGALoader.cpp

#include "TGALoader.h"

CTGALoader::CTGALoader(void)
{
// 设置为默认值
image = NULL;
type = 0;
ID = -1;
imageWidth = 0;
imageHeight = 0;
}

CTGALoader::~CTGALoader(void)
{
FreeImage();            // 释放内存
}

// 载入TGA文件
bool CTGALoader::LoadTGA(const char *file)
{
FILE *pfile;
unsigned char tempColor;         // 用于交换颜色分量
unsigned char bitCount;          // 每象素的bit位数
int colorMode;            // 颜色模式
long tgaSize;            // TGA文件大小
unsigned char unCompressHeader[12] = { 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
                // 未压缩TGA文件头
unsigned char tgaHeader[12];        // 文件头
unsigned char header[6];         // 文件头前6个字节

// 检查文件名是否为空
if (file == NULL) return false;

// 打开文件
pfile = fopen(file, "rb");
if (pfile == NULL) 
   return false;

// 读取文件头前12个字节
fread(tgaHeader, 1, sizeof(tgaHeader), pfile);

// 比较文件是否为未压缩文件
if(memcmp(unCompressHeader, tgaHeader, sizeof(unCompressHeader)) != 0)
{
   MessageBox(NULL,"文件类型错误!","错误",MB_OK);
   fclose(pfile);
   return false;
}

// 读取6个字节
fread(header, 1, sizeof(header), pfile);

// 计算图像的宽度和高度
imageWidth = header[1] * 256 + header[0];
imageHeight = header[3] * 256 + header[2];

// 获取每象素的bit位数
bitCount = header[4];
// 计算颜色模式和图像大小
colorMode = bitCount / 8;
tgaSize = imageWidth * imageHeight * colorMode;

// 分配内存
image = new unsigned char[sizeof(unsigned char) * tgaSize];
// 读取数据
fread(image, sizeof(unsigned char), tgaSize, pfile);

// 将BGA格式转化为RGA格式
for(long index = 0; index < tgaSize; index += colorMode)
{
   tempColor = image[index];
   image[index] = image[index + 2];
   image[index + 2] = tempColor;
}

// 关闭文件
fclose(pfile);

// 设置图象类型
if(colorMode == 3) type = GL_RGB;
else type = GL_RGBA;

return true;
}

// 载入TGA文件并创建纹理
bool CTGALoader::Load(const char *fileName)
{
if (LoadTGA(fileName) == false) return false;

// 生成纹理对象名称
glGenTextures(1, &ID);
// 创建纹理对象
glBindTexture(GL_TEXTURE_2D, ID);
// 控制滤波
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,GL_REPEAT);
// 创建纹理
gluBuild2DMipmaps(GL_TEXTURE_2D, type, imageWidth, imageHeight, type, GL_UNSIGNED_BYTE, image);

return true;
}

void CTGALoader::FreeImage()
{
// 释放内存
if(image)
{
   delete []image;
   image = 0;
}
}

// Texture.h

#pragma once
#include "glframe.h"
#include "BMPLoader.h"
#include "TGALoader.h"

class Texture : public GLApplication
{
public:
~Texture(void);

bool Init();            // 执行所有的初始化工作,如果成功函数返回true
void Uninit();            // 执行所有的卸载工作
void Update(DWORD milliseconds);       // 执行所有的更新操作,传入的参数为两次操作经过的时间,以毫秒为单位
void Draw();            // 执行所有的绘制操作

bool    LoadTexture();          // 载入纹理
void    SetLight();           // 设置光源
void    DrawSphere();          // 绘制球体
void    DrawBox();           // 绘制木箱

private:
friend class GLApplication;         // 父类为它的一个友元类,可以用来创建程序的实例
Texture(const char *class_name);       // 构造函数

// 用户自定义的程序变量
CBMPLoader texture1[6];          // 位图载入类
CTGALoader texture2;          // TGA文件载入类
float rot;             // 用于旋转物体
GLUquadricObj *sphere;
};

// Texture.cpp

#include "Texture.h"

Texture::~Texture(void)
{
}

// 创建一个程序的实例
GLApplication * GLApplication::Create(const char *class_name)
{
Texture *test = new Texture(class_name);
return reinterpret_cast<GLApplication *>(test);
}

// 构造函数
Texture::Texture(const char *class_name) : GLApplication(class_name)
{
// 初始化用户自定义的程序变量
rot = 0.0;
}

// 载入纹理数据
bool Texture::LoadTexture()
{
CString str;
// 载入位图文件
for (int i = 0; i < 6; i++)
{
   str.Format("data/%d.bmp", i);
   if (texture1[i].Load(str) == false)
   {
    MessageBox(NULL, "装载BMP文件失败!", "错误", MB_OK);
    return false;          // 如果载入失败则弹出对话框并返回失败
   
   }
}
// 载入TGA文件
if (texture2.Load("data/map.tga") == false)     // 载入TGA文件
{
   MessageBox(NULL, "装载TGA文件失败!", "错误", MB_OK); // 如果载入失败则弹出对话框
   return false;
}

// 启用纹理映射
glEnable(GL_TEXTURE_2D);
return true;
}

// 设置光源
void Texture::SetLight()
{
// 定义光源的属性值
GLfloat LightAmbient[] = { 0.5f, 0.5f, 0.5f, 1.0f }; // 环境光参数
GLfloat LightDiffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f }; // 漫射光参数
GLfloat LightSpecular[] = { 1.0f, 1.0f, 1.0f, 1.0f }; // 镜面光参数
GLfloat LightPosition[] = { 0.0f, 0.0f, 2.0f, 1.0f }; // 光源位置

// 设置光源的属性值
glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient);    // 设置环境光
glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse);    // 设置漫射光
glLightfv(GL_LIGHT1, GL_SPECULAR, LightSpecular);   // 设置漫射光
glLightfv(GL_LIGHT1, GL_POSITION, LightPosition);   // 设置光源位置

// 启用光源
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT1);
}

// 初始化OpenGL
bool Texture::Init()
{
// 载入纹理
if (!LoadTexture()) 
{
   MessageBox(NULL, "载入纹理失败!", "错误", MB_OK);
   return false;
}

glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
glClearDepth(1.0f);
glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST);
glShadeModel(GL_SMOOTH);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);   
ResizeDraw(true);           // 改变OpenGL窗口大小,直接调用子类的函数

sphere = gluNewQuadric();
// 设置光源
SetLight();
return true;            // 成功返回
}

// 用户自定义的卸载函数
void Texture::Uninit()         
{
// 用户自定义的卸载过程
for (int i = 0; i < 6; i++)
{
   texture1[i].FreeImage();        // 释放纹理图像占用的内存
   glDeleteTextures(1, &texture1[i].ID);     // 删除纹理对象
}

texture2.FreeImage();          // 释放纹理图像占用的内存
glDeleteTextures(1, &texture2.ID);       // 删除纹理对象

gluDeleteQuadric(sphere);
}

// 程序更新函数
void Texture::Update(DWORD milliseconds)      
{
if (m_Keys.IsPressed(VK_ESCAPE) == true)     // 按ESC退出
   TerminateApplication();         
if (m_Keys.IsPressed(VK_F1) == true)      // 按F1在窗口和全屏间切换
   ToggleFullscreen();         

rot += milliseconds / 20.0f;
}

// 绘制球体
void Texture::DrawSphere()
{
glPushMatrix();
glTranslatef(2.0f, 0.0f, -10.0f);
glRotatef(rot, 0.0f, 1.0f, 1.0f);

// 指定纹理
glBindTexture(GL_TEXTURE_2D, texture2.ID);
gluQuadricOrientation(sphere, GLU_OUTSIDE);
gluQuadricNormals(sphere, GLU_SMOOTH);
gluQuadricTexture(sphere, GL_TRUE);
gluSphere(sphere, 1.5, 50, 50);
glPopMatrix();
}

// 绘制木箱
void Texture::DrawBox()
{
// 设置材质属性
GLfloat mat_ambient[] = { 0.8f, 0.8f, 0.8f, 1.0f };
GLfloat mat_diffuse[] = { 0.8f, 0.8f, 0.8f, 1.0f };
glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);

glPushMatrix();
glTranslatef(-2.0f, 0.0f, -8.0f);
glRotatef(rot, 1.0f, 1.0f, 0.0f);

// 选择纹理
glBindTexture(GL_TEXTURE_2D, texture1[0].ID);
glBegin(GL_QUADS);
// 前侧面
glNormal3f(0.0f, 0.0f, 1.0f);        // 指定法线指向观察者
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
glEnd();

glBindTexture(GL_TEXTURE_2D, texture1[1].ID);
glBegin(GL_QUADS);
// 后侧面
glNormal3f(0.0f, 0.0f,-1.0f);        // 指定法线背向观察者
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f); 
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); 
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); 
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
glEnd();

glBindTexture(GL_TEXTURE_2D, texture1[2].ID);
glBegin(GL_QUADS);
// 顶面
glNormal3f(0.0f, 1.0f, 0.0f);        // 指定法线向上
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); 
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f); 
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 1.0f); 
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);
glEnd();

glBindTexture(GL_TEXTURE_2D, texture1[3].ID);
glBegin(GL_QUADS);
// 底面
glNormal3f(0.0f,-1.0f, 0.0f);        // 指定法线朝下
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f); 
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, -1.0f); 
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); 
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
glEnd();

glBindTexture(GL_TEXTURE_2D, texture1[4].ID);
glBegin(GL_QUADS);
// 右侧面
glNormal3f(1.0f, 0.0f, 0.0f);        // 指定法线朝右
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f); 
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); 
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); 
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
glEnd();

glBindTexture(GL_TEXTURE_2D, texture1[5].ID);
glBegin(GL_QUADS);
// 左侧面
glNormal3f(-1.0f, 0.0f, 0.0f);        // 指定法线朝左
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f); 
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); 
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); 
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
glEnd();

glPopMatrix();
}

// 绘制函数
void Texture::Draw()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();

// 绘制过程
DrawSphere();
DrawBox();
}

原创粉丝点击