用 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