调整缓冲区大小时OpenGL失败

时间:2014-08-11 20:02:13

标签: c++ c opengl exc-bad-access

我需要每帧更新一个像素数组到屏幕。它最初工作,但是当我尝试调整屏幕大小时,它会出现故障并最终抛出EXC_BAD_ACCESS 1。我已经检查过每个帧之前缓冲区是否分配了正确的大小,但它似乎不会影响结果。

#include <stdio.h>
#include <stdlib.h>
#include <GLUT/GLUT.h>

unsigned char *buffer = NULL;
int width = 400, height = 400;
unsigned int screenTexture;

void Display()
{
    for (int y = 0; y < height; y+=4) {
        for (int x = 0; x < width; x++) {
            buffer[(x + y * width) * 3] = 255;
        }
    }

    glClear(GL_COLOR_BUFFER_BIT);
    glEnable(GL_TEXTURE_2D);
    // This function results in EXC_BAD_ACCESS 1, although the buffer is always correctly allocated
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, buffer);

    glViewport(0, 0, width, height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, width, height, 0, 0, 1);
    glMatrixMode(GL_MODELVIEW);

    glBegin (GL_QUADS);
    glTexCoord2f(0,0); glVertex2i(0,    0);
    glTexCoord2f(1,0); glVertex2i(width,0);
    glTexCoord2f(1,1); glVertex2i(width,height);
    glTexCoord2f(0,1); glVertex2i(0,    height);
    glEnd ();

    glFlush();
    glutPostRedisplay();
}

void Resize(int w, int h)
{
    width = w;
    height = h;
    buffer = (unsigned char *)realloc(buffer, sizeof(unsigned char) * width * height * 3);

    if (!buffer) {
        printf("Error Reallocating buffer\n");
        exit(1);
    }
}

int main(int argc, char **argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
    glutInitWindowSize(width, height);
    glutCreateWindow("Rasterizer");
    glutDisplayFunc(Display);
    glutReshapeFunc(Resize);

    glGenTextures(1, &screenTexture);
    glBindTexture(GL_TEXTURE_2D, screenTexture);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
    glDisable(GL_DEPTH_TEST);

    buffer = (unsigned char *)malloc(sizeof(unsigned char) * width * height * 3);

    glutMainLoop();
}

调整大小后屏幕无法正常显示: enter image description here

是什么导致了这个问题?代码编译并运行,您只需链接GLUT和OpenGL。

3 个答案:

答案 0 :(得分:2)

正如@genpfault所提到的,OpenGL每个像素读取4个字节,而不是假设3个。

您也可以通过简单的GL_UNPACK_ALIGNMENT将代码更改为每像素4个字节的正确假设,而不是更改struct

struct pixel {
    unsigned char r, g, b;
    unsigned char unused;
};

然后,您可以使用更清晰的sizeof(struct pixel),而不是使用魔术常数3。这使得更容易阅读和传达代码的意图,并且它不会产生任何额外的代码(因为结构是&#34;有效&#34; 4字节的数组)。

答案 1 :(得分:0)

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, buffer);
                                                         ^^^^^^

GL_UNPACK_ALIGNMENT默认为4,而不是1。因此OpenGL将为每个像素读取 4 字节,而不是您所假设的3个字节。

使用GL_UNPACK_ALIGNMENT1设置为glPixelStorei()

答案 2 :(得分:0)

听起来你发现了一些有效的东西,但我认为问题没有得到正确的诊断。我认为最大的问题在于你在这里初始化纹理数据:

for (int y = 0; y < height; y+=4) {
    for (int x = 0; x < width; x++) {
        buffer[(x + y * width) * 3] = 255;
    }
}

这仅在每第4行设置数据,然后仅在这些行中的每第3个字节设置数据。要将所有数据初始化为白色,您需要将行号(y)递增1而不是4,并在循环中设置所有3个组件:

for (int y = 0; y < height; y++) {
    for (int x = 0; x < width; x++) {
        buffer[(x + y * width) * 3    ] = 255;
        buffer[(x + y * width) * 3 + 1] = 255;
        buffer[(x + y * width) * 3 + 2] = 255;
    }
}

您还需要将GL_UNPACK_ALIGNMENT设置为1:

glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

这可以控制行对齐(不是像素对齐,如其他几个答案所示)。 GL_UNPACK_ALIGNMENT的默认值为4.但是如果您使用的GL_RGB格式为每像素3个字节,则如果像素数为多个,则行的大小仅为4个字节的倍数因此,对于具有3个字节/像素的紧密排列的行,该值需要设置为1。

相关问题