用 Targa(TGA) 图像文件,因为它简单并且支持 alpha 通道,它可以使你更容易的创建酷的效果。
TGA 文件与 BMP 文件一样,图像数据都是按 BGR 存储,而 OpenGL 的图像是按 RGB 来使用的。
这里用了一个很好的方法,一次性读入所有的图像数据,然后再进行转换 R 与 B,而不是每次读一个 R,G,B,A,这种读法很省时间。fread(buffer, size, number, file);按块读取文件内容
size 为每次读取几个 byte,如按字节读取,这里使用的一样,size == 1;
number 为一共读取多少个 size 的内容,number = width * height * bytesPerPixel;(整个图像的数据内容)
这个方法只能读取无压缩的 TGA 文件
TGA 开始为 12 字节的内容为描述文件的一般信息,接下来的 6 字节为最重要的信息,文件宽,高,每个像素的位数, 从第 18 个字节开始,就是图像的数据内容。
更重要的一点,这个程序进行了各种出错处理。
#ifndef _TGALOAD_H_
#define _TGALOAD_H_
#include <stdio.h>
typedef struct {
GLubyte* data;
GLuint width;
GLuint height;
GLuint rgbType;
} TextureImage;
GLboolean loadTGA(char* fileName, TextureImage* textureImage) {
GLubyte TGAheader[12]= { 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; // 无压缩的TGA文件头
GLubyte TGAcompare[12]; // 保存读入的文件头信息
GLubyte header[6]; // 保存最有用的图像信息,宽,高,位深
GLuint bytesPerPixel; // 记录每个颜色所占用的字节数
GLuint imageSize; // 记录文件大小
GLuint temp; // 临时变量
FILE *file = fopen(fileName, "rb"); // 打开一个TGA文件
if (file==NULL || // 文件存在么?
fread(TGAcompare, 1, sizeof(TGAcompare), file)!= sizeof(TGAcompare) ||
// 是否包含12个字节的文件头?
memcmp(TGAheader, TGAcompare, sizeof(TGAheader))!= 0 ||
// 是否是我们需要的格式?
fread(header, 1, sizeof(header), file)!= sizeof(header)) {
// 如果是读取下面六个图像信息
if (file == NULL) // 文件不存在返回错误
return false;
else {
fclose(file); // 关闭文件返回错误
return false;
}
}
textureImage->width = header[1] * 256 + header[0]; // 记录文件宽度
textureImage->height = header[3] * 256 + header[2]; // 记录文件高度
if (textureImage->width <= 0 || // 宽度是否小于0
textureImage->height <= 0 || // 高度是否小于0
(header[4] != 24 && header[4] != 32)) { // TGA文件是24/32位?
fclose(file); // 如果失败关闭文件,返回错误
return false;
}
bytesPerPixel = header[4] >> 3; // 记录每个象素所占的字节数
textureImage->rgbType = bytesPerPixel; // 记录每个象素所占的字节数
imageSize = textureImage->width *textureImage->height * bytesPerPixel;
// 计算TGA文件加载所需要的内存大小
textureImage->data = (GLubyte*)malloc(imageSize); // 分配内存去保存TGA数据
if (textureImage->data == NULL || // 系统是否分配了足够的内存?
fread(textureImage->data, 1, imageSize, file)!= imageSize) {
// 是否成功读入内存?
if (textureImage->data != NULL) { // 是否有数据被加载
free(textureImage->data); // 如果是,则释放载入的数据
}
fclose(file); // 关闭文件
return false; // 返回错误
}
for (GLuint i=0; i<GLuint(imageSize); i+=bytesPerPixel) {
// 循环所有的像素
// 交换R和B的值
temp = textureImage->data[i];
textureImage->data[i] = textureImage->data[i + 2];
textureImage->data[i + 2] = temp;
}
fclose(file); // 关闭文件
return true;
}
#endif