You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 09:21:35