为啥在 glfw 窗口上没有使用 opengl 显示位图图像?在 C++ 中读取位图图像文件时出现问题

Posted

技术标签:

【中文标题】为啥在 glfw 窗口上没有使用 opengl 显示位图图像?在 C++ 中读取位图图像文件时出现问题【英文标题】:Why is bitmap image not showing with opengl on glfw window? Problem reading bitmap image file in C++为什么在 glfw 窗口上没有使用 opengl 显示位图图像?在 C++ 中读取位图图像文件时出现问题 【发布时间】:2020-08-26 05:40:09 【问题描述】:
#include<GLFW/glfw3.h>
#include<stdio.h>
#include<GL/glu.h>
#include<vector>
using namespace std;

typedef struct __attribute__((__packed__))  
    unsigned short type; 
    unsigned long size; 
    unsigned short reserved1; 
    unsigned short reserved2; 
    unsigned long offsetbits; 
 BITMAPFILEHEADER1;

typedef struct __attribute__((__packed__)) 
    unsigned long size; 
    unsigned long width; 
    unsigned long height; 
    unsigned short planes; 
    unsigned short bitcount;
    unsigned long compression; 
    unsigned long sizeimage; 
    long xpelspermeter; 
    long ypelspermeter; 
    unsigned long colorsused; 
    unsigned long colorsimportant; 
 BITMAPINFOHEADER1;
 
typedef struct  
    unsigned char blue; 
    unsigned char green; 
    unsigned char red; 
 SINGLE_PIXEL1;


void draw_all() 
    FILE *fp;
    unsigned char p;
    int x=0,y=0,c=0;
    float r,g,b;
    float rowsize,pixelarraysize;
    
    int datasize;
    
    BITMAPFILEHEADER1 bitmp;    
    BITMAPINFOHEADER1 bitm; 
    
    glClearColor(1.0,1.0,1.0,0.0);
    glClear(GL_COLOR_BUFFER_BIT);
    
    fp = fopen("free.bmp","rb");//Filename is given 
    
    //fread(&bitmp,14,1,fp);    
    
    //fread(&bitm,40,1,fp);
    printf("sizeheader: %d\n", sizeof(BITMAPFILEHEADER1));  
    fread(&bitmp,sizeof(BITMAPFILEHEADER1),1,fp);   
    
    fread(&bitm,sizeof(BITMAPINFOHEADER1),1,fp);
    
    printf("Type in hexadecimal: %x\n",bitmp.type);
    printf("Size in hexadecimal: %x\n",bitmp.size);
    printf("Reserved1 in hexadecimal: %x\n",bitmp.reserved1);
    printf("Reserved2 in hexadecimal: %x\n",bitmp.reserved2);
    printf("Offsetbits in hexadecimal: %x\n",bitmp.offsetbits); 

    //printf("Width: %x, Height: %x\n",bitm.width,bitm.height);
    printf("Width: %d, Height: %d\n",bitm.width,bitm.height);
    
    printf("Bitcount: %d\n",bitm.bitcount);
    
    glViewport(0,0,bitm.width,bitm.height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(0.0,bitm.width,0.0,bitm.height);
            
    vector<float> v_data;
    int width,height;
    
    width=bitm.width;
    height=bitm.height;
    
    //width=800;
    //height=600;
    
    //rowsize=((24*734+31)/32)*4;
    rowsize=((24*800+31)/32)*4;
    //rowsize=((bitm.bitcount*bitm.width+31)/32)*4;
    pixelarraysize=rowsize*bitm.height;
    
    printf("Rowsize: %f\n",rowsize);
    printf("pixelarraysize: %f\n",pixelarraysize);
    
    //datasize=3*734;
    //datasize=3*800;
    //datasize=3*bitm.width;
    datasize=(bitm.bitcount/8.0)*bitm.width;
    printf("Datasize: %d\n",datasize);
    
    int padding;
    padding = rowsize - (width * 3); 
    //glBegin(GL_POINTS);
    while(!feof(fp))
    
        fread(&p,1,1,fp);
        b = p/255.0;
        fread(&p,1,1,fp);
        g = p/255.0;    
        fread(&p,1,1,fp);
        r = p/255.0;
        
        v_data.push_back(r);
        v_data.push_back(g);
        v_data.push_back(b);
        /*
        glColor3f(r,g,b);       
        glVertex2i(x++,y);
        */
        x++;
        if(x == bitm.width)
        
            //fseek(fp,2,SEEK_CUR);
            fseek(fp,padding,SEEK_CUR);
            x = 0;
            y++;
        
        
       
    //glEnd();
    
    unsigned int texture;
    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);
    
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    
    glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,width,height,0,GL_RGB,GL_FLOAT,&v_data[0]);
        
    glEnable(GL_TEXTURE_2D);
    glActiveTexture(GL_TEXTURE);

    glBegin(GL_QUADS);

    glTexCoord2i(0,0);
    glVertex2i(0,0);
    
    glTexCoord2i(0,1);
    glVertex2i(0,height);
    
    glTexCoord2i(1,1);
    glVertex2i(width,height);
    
    glTexCoord2i(1,0);
    glVertex2i(width,0);

    glEnd();
           
    glFlush();
    fclose(fp); 


int main(void)

    GLFWwindow* window;
    /* Initialize the library */
    if (!glfwInit())
        return -1;
    /* Create a windowed mode window and its OpenGL context */
    window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
    if (!window)
    
        glfwTerminate();
        return -1;
    
    /* Make the window's context current */
    glfwMakeContextCurrent(window);
    /* Loop until the user closes the window */
    draw_all();
    while (!glfwWindowShouldClose(window))
    
        //gladLoadGL();
        /* Render here */
        //draw_all();
        /* Swap front and back buffers */
        glfwSwapBuffers(window);        
        /* Poll for and process events */
        glfwPollEvents();
    
    glfwTerminate();
    return 0;

g++ glfw.cpp -o glfw -lglfw -lGL -lGLU
./glfw

谁能解决读取位图文件(free.bmp)的问题?它没有得到图像的宽度和高度。

【问题讨论】:

【参考方案1】:

rowsize 的计算肯定是错误的。一行中的行数对齐为4:

rowsize=((24*64+31)/32)*4;

rowsize = (bitm.width*3*4+3)/4;

我建议使用STB library 来加载位图。在How to load a bmp on GLUT to use it as a texture?问题的答案中可以找到不同的解决方案。


无论如何,没有必要将纹理图像转换为浮动品脱数据。纹理可以直接加载:

vector<unsigned char> v_data(pixelarraysize);
fread(v_data.data(), 1, pixelarraysize, fp);

// [...]

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_BGR, GL_UNSIGNED_BYTE, &v_data[0]);

不要每帧连续加载纹理。在应用循环之前加载一次纹理:

int width, height;

unsigned int load_texture(const char *filename)

    FILE *fp;
    float rowsize,pixelarraysize;
    BITMAPFILEHEADER1 bitmp;    
    BITMAPINFOHEADER1 bitm; 

    fp = fopen(filename,"rb");//Filename is given 
    printf("sizeheader: %d\n", sizeof(BITMAPFILEHEADER1));  
    fread(&bitmp,sizeof(BITMAPFILEHEADER1),1,fp);   
    fread(&bitm,sizeof(BITMAPINFOHEADER1),1,fp);
    
    printf("Type in hexadecimal: %x\n",bitmp.type);
    printf("Size in hexadecimal: %x\n",bitmp.size);
    printf("Reserved1 in hexadecimal: %x\n",bitmp.reserved1);
    printf("Reserved2 in hexadecimal: %x\n",bitmp.reserved2);
    printf("Offsetbits in hexadecimal: %x\n",bitmp.offsetbits); 

    printf("Width: %d, Height: %d\n",bitm.width,bitm.height);
    printf("Bitcount: %d\n",bitm.bitcount);

    rowsize = (bitm.width*3*4+3)/4;
    pixelarraysize = rowsize*bitm.height;
    
    printf("Rowsize: %f\n",rowsize);
    printf("pixelarraysize: %f\n",pixelarraysize);

    vector<unsigned char> v_data(pixelarraysize);
    fread(v_data.data(), 1, pixelarraysize, fp);
    fclose(fp); 

    width = bitm.width;
    height = bitm.height;

    unsigned int texture;
    glGenTextures(1, &texture);
    
    glActiveTexture(GL_TEXTURE);
    glBindTexture(GL_TEXTURE_2D, texture);
    
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_BGR, GL_UNSIGNED_BYTE, &v_data[0]);
        
    return texture;

void draw_all()

    glClearColor(1.0,1.0,1.0,0.0);
    glClear(GL_COLOR_BUFFER_BIT);
    
    glViewport(0,0,640, 480);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(0.0,640,0.0,480);
             
    glEnable(GL_TEXTURE_2D);
    glBegin(GL_QUADS);

    glTexCoord2i(0,0);
    glVertex2i(0,0);
    
    glTexCoord2i(0,1);
    glVertex2i(0,height);
    
    glTexCoord2i(1,1);
    glVertex2i(width,height);
    
    glTexCoord2i(1,0);
    glVertex2i(width,0);

    glEnd();
           
    glFlush();

int main(void)

    // [...]

    int textureobject = load_texture("free.bmp");
    while (!glfwWindowShouldClose(window))
    
        /* Render here */
        draw_all();
        /* Swap front and back buffers */
        glfwSwapBuffers(window);        
        /* Poll for and process events */
        glfwPollEvents();
    

    // [...]

【讨论】:

以上是关于为啥在 glfw 窗口上没有使用 opengl 显示位图图像?在 C++ 中读取位图图像文件时出现问题的主要内容,如果未能解决你的问题,请参考以下文章

为啥在 GLFW 窗口中使用此代码在我的屏幕上没有绘制立方体?

我的渲染技术进阶之旅glfw库简单介绍

我的渲染技术进阶之旅glfw库简单介绍

我的渲染技术进阶之旅glfw库简单介绍

错误:在 Linux 上使用 OpenGL 编译 C++ 程序时出现“GL/glfw3.h:没有这样的文件或目录”

为啥片段着色器没有附加?