OpenGL中替代glaux加载指定位置24位BMP的方案咨询
不依赖glaux的BMP加载渲染实现
以下是纯标准C++实现的替代方案,无需第三方库,完全匹配你原iShowBMP的功能:
#include <fstream> #include <cstdint> // 处理结构体字节对齐,避免读取BMP头时出错 #pragma pack(push, 1) typedef struct { uint16_t bfType; uint32_t bfSize; uint16_t bfReserved1; uint16_t bfReserved2; uint32_t bfOffBits; } BITMAPFILEHEADER; typedef struct { uint32_t biSize; int32_t biWidth; int32_t biHeight; uint16_t biPlanes; uint16_t biBitCount; uint32_t biCompression; uint32_t biSizeImage; int32_t biXPelsPerMeter; int32_t biYPelsPerMeter; uint32_t biClrUsed; uint32_t biClrImportant; } BITMAPINFOHEADER; #pragma pack(pop) void loadAndDrawBMP(int x, int y, const char* filename, int ignoreColor) { std::ifstream file(filename, std::ios::binary); if (!file.is_open()) { return; // 文件打不开直接返回 } BITMAPFILEHEADER fileHeader; BITMAPINFOHEADER infoHeader; // 读取文件头和信息头 file.read(reinterpret_cast<char*>(&fileHeader), sizeof(BITMAPFILEHEADER)); file.read(reinterpret_cast<char*>(&infoHeader), sizeof(BITMAPINFOHEADER)); // 检查是否是24位无压缩BMP if (fileHeader.bfType != 0x4D42 || infoHeader.biBitCount != 24 || infoHeader.biCompression != 0) { file.close(); return; } int width = infoHeader.biWidth; int height = abs(infoHeader.biHeight); // 高度取绝对值,处理正向存储的情况 bool isTopDown = infoHeader.biHeight < 0; // 判断BMP是否是从上到下存储 // BMP每行像素数据是4的倍数,计算行间距 int stride = (width * 3 + 3) / 4 * 4; uint8_t* bmpData = new uint8_t[stride * height]; // 跳转到像素数据位置 file.seekg(fileHeader.bfOffBits); file.read(reinterpret_cast<char*>(bmpData), stride * height); file.close(); // 生成RGBA像素数据 uint8_t* rgbaData = new uint8_t[width * height * 4]; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { // 计算当前像素在BMP数据中的位置 int bmpY = isTopDown ? y : height - 1 - y; int bmpIdx = bmpY * stride + x * 3; // BMP存储是BGR顺序,转为RGB uint8_t blue = bmpData[bmpIdx]; uint8_t green = bmpData[bmpIdx + 1]; uint8_t red = bmpData[bmpIdx + 2]; // 组合成RGB整数,和ignoreColor比较 int rgb = (red << 16) | (green << 8) | blue; uint8_t alpha = (rgb == ignoreColor) ? 0 : 255; // 填充RGBA数据 int rgbaIdx = (y * width + x) * 4; rgbaData[rgbaIdx] = red; rgbaData[rgbaIdx + 1] = green; rgbaData[rgbaIdx + 2] = blue; rgbaData[rgbaIdx + 3] = alpha; } } // 绘制到GLUT窗口指定位置 glRasterPos2f(x, y); glDrawPixels(width, height, GL_RGBA, GL_UNSIGNED_BYTE, rgbaData); // 释放内存 delete[] bmpData; delete[] rgbaData; }
关键说明
- 字节对齐处理:用
#pragma pack确保结构体按1字节对齐,避免因编译器默认对齐导致的BMP头读取错误 - BMP格式兼容:支持24位无压缩BMP,自动处理BMP的上下存储方向(多数BMP是从下到上存储,这里会翻转成OpenGL需要的从上到下)
- 透明处理:和原函数逻辑一致,当像素RGB值与
ignoreColor完全匹配时,将Alpha通道设为0(完全透明),否则设为255(完全不透明) - 内存安全:所有动态分配的内存都在函数结束前释放,避免内存泄漏
- Code::Blocks适配:仅依赖标准C++库和OpenGL/GLUT头文件,无需额外配置第三方库
使用方法
直接替换原代码中iShowBMP的调用为loadAndDrawBMP即可,参数完全一致:
// 示例:在(100, 100)位置加载test.bmp,忽略洋红色(0xFF00FF) loadAndDrawBMP(100, 100, "test.bmp", 0xFF00FF);
注意事项
- 确保传入的BMP是24位无压缩格式,宽高为2的幂次(符合你的项目要求)
ignoreColor的格式是0xRRGGBB(比如红色是0xFF0000),和原函数的参数格式一致- 如果需要每帧加载,建议在每帧开始前确保OpenGL状态正确(比如没有绑定纹理、颜色模式正确等)
内容的提问来源于stack exchange,提问作者Preetom Saha Arko
相关产品推荐
相关产品推荐

