引言
如果您點選了這篇文章,您一定想在您的應用程式中載入 .bmp 檔案。
雖然 .bmp 檔案體積可能很大,但它們在許多應用程式中仍被廣泛使用,並且在網際網路上文件齊全。
現在網上有很多關於如何實現此功能的教程,但它們大多使用 C 語言的方式。這將是一個 C++ 教程,
而不是 C 語言教程。
====================
需要了解的內容
本教程假定您正在使用 Windows,但它不使用特定於 Windows 的函式。您可以輕鬆編寫自己的結構。維基百科對點陣圖標頭檔案有相當好的描述。
本教程還使用了 OpenGL,但移植到 DirectX 應該不難。
此外,我們有一個新型別。Uint8 本質上是
unsigned char
。為此,我們還需要包含 fstream。
====================
教程
好了,我們開始吧。我們將有一個函式,該函式返回一個 GLuint 作為我們的紋理。
該函式接受 2 個引數。
int LoadBMP(const char* location, GLuint &texture);
第一個是檔案的位置。第二個是對紋理無符號整數的引用,這是生成的紋理的 ID。
好了,現在進入實際程式碼。我們首先宣告四個指標,並將它們設定為 nullptr(或者您也可以使用 NULL)。
1 2 3 4 5 6
|
Uint8* datBuff[2] = {nullptr, nullptr}; // Header buffers
Uint8* pixels = nullptr; // Pixels
BITMAPFILEHEADER* bmpHeader = nullptr; // Header
BITMAPINFOHEADER* bmpInfo = nullptr; // Info
|
它們非常自明。
我們使用 fstream 開啟一個檔案,然後檢查它是否已開啟。
1 2 3 4 5 6 7 8
|
// The file... We open it with it's constructor
std::ifstream file(location, std::ios::binary);
if(!file)
{
std::cout << "Failure to open bitmap file.\n";
return 1;
}
|
現在,我們為標頭檔案分配記憶體,透過資料緩衝區獲取值。
1 2 3 4 5 6
|
// Allocate byte memory that will hold the two headers
datBuff[0] = new Uint8[sizeof(BITMAPFILEHEADER)];
datBuff[1] = new Uint8[sizeof(BITMAPINFOHEADER)];
file.read((char*)datBuff[0], sizeof(BITMAPFILEHEADER));
file.read((char*)datBuff[1], sizeof(BITMAPINFOHEADER));
|
一旦我們載入了資料,我們就將載入的資料構造到標頭檔案中。
1 2 3
|
// Construct the values from the buffers
bmpHeader = (BITMAPFILEHEADER*) datBuff[0];
bmpInfo = (BITMAPINFOHEADER*) datBuff[1];
|
由於我們已經載入了這些,所以我們檢查檔案是否是 BMP 檔案。
1 2 3 4 5 6
|
// Check if the file is an actual BMP file
if(bmpHeader->bfType != 0x4D42)
{
std::cout << "File \"" << location << "\" isn't a bitmap file\n";
return 2;
}
|
分配畫素記憶體,然後跳轉到畫素資料開始的位置並讀取。
1 2 3 4 5 6
|
// First allocate pixel memory
pixels = new Uint8[bmpInfo->biSizeImage];
// Go to where image data starts, then read in image data
file.seekg(bmpHeader->bfOffBits);
file.read((char*)pixels, bmpInfo->biSizeImage);
|
由於點陣圖將畫素儲存為 BGR,因此我們將其轉換為 RGB。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
// We're almost done. We have our image loaded, however it's not in the right format.
// .bmp files store image data in the BGR format, and we have to convert it to RGB.
// Since we have the value in bytes, this shouldn't be to hard to accomplish
Uint8 tmpRGB = 0; // Swap buffer
for (unsigned long i = 0; i < bmpInfo->biSizeImage; i += 3)
{
tmpRGB = pixels[i];
pixels[i] = pixels[i + 2];
pixels[i + 2] = tmpRGB;
}
// Set width and height to the values loaded from the file
GLuint w = bmpInfo->biWidth;
GLuint h = bmpInfo->biHeight;
|
現在我們用 OpenGL 生成紋理。如果您使用 DirectX,請忽略此步驟,並使用您建立紋理的任何方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
|
/*******************GENERATING TEXTURES*******************/
glGenTextures(1, texture); // Generate a texture
glBindTexture(GL_TEXTURE_2D, texture); // Bind that texture temporarily
GLint mode = GL_RGB; // Set the mode
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// Create the texture. We get the offsets from the image, then we use it with the image's
// pixel data to create it.
glTexImage2D(GL_TEXTURE_2D, 0, mode, w, h, 0, mode, GL_UNSIGNED_BYTE, pixels);
// Unbind the texture
glBindTexture(GL_TEXTURE_2D, NULL);
// Output a successful message
std::cout << "Texture \"" << location << "\" successfully loaded.\n";
// Delete the two buffers.
delete[] datBuff[0];
delete[] datBuff[1];
delete[] pixels;
return 0; // Return success code
|
就是這樣。請評價這篇文章。
祝您使用新的 BMP 紋理載入器愉快!
====================