引言
如果您点击了这篇文章,您一定想在您的应用程序中加载 .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 纹理加载器愉快!
====================