OpenGL не работает при изменении размера буфера

0

Мне нужно обновить массив пикселей на экране каждого кадра. Сначала он работает, но когда я пытаюсь изменить размер экрана, он EXC_BAD_ACCESS 1 и, в конце концов, выдает 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();
}

После изменения размера экран также не отображается должным образом: Изображение 174551

Что вызывает эту проблему? Код компилируется и запускается, вам просто нужно связать GLUT и OpenGL.

Теги:
opengl
exc-bad-access

3 ответа

2
Лучший ответ

Как упоминал @genpfault, OpenGL считывает 4 байта на пиксель вместо вашего предположения 3.

Вместо изменения GL_UNPACK_ALIGNMENT вы также можете изменить свой код на правильное предположение о 4 байтах на пиксель с помощью простой struct:

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

Затем вместо использования магической константы 3 вы можете использовать гораздо более четкий sizeof(struct pixel). Это облегчает чтение и передачу намерения кода, и это не приводит к добавлению дополнительного кода (поскольку структура "эффективно" представляет собой массив из 4 байтов).

  • 0
    Я попытался установить выравнивание распаковки на 1, так что это не должно иметь значения, но я тоже попробую
0

Похоже, вы нашли что-то, что работает, но я не думаю, что проблема была правильно диагностирована. Я считаю, что самая большая проблема заключается в том, как вы инициализируете данные текстуры здесь:

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

Это только устанавливает данные в каждой четвертой строке, а затем только для каждого третьего байта в этих строках. Чтобы инициализировать все данные до белого, вам нужно увеличить число строк (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. Но с 3 байтами на пиксель в формате GL_RGB который вы используете, размер строки составляет всего несколько байт, если количество пикселей кратно 4. Так что для плотно упакованных строк с 3 байтами/пикселем, значение должно быть установлено равным 1.

  • 0
    На самом деле я уже написал программный 3d растеризатор, однако публиковать здесь все это не имеет смысла, так что данные текстуры просто загружают КРАСНЫЙ (byte1 [r], byte2 [g], byte3 [b]) полосовой шаблон для простоты , (который очищается с memset 0 при изменении размера)
0
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, buffer);
                                                         ^^^^^^

GL_UNPACK_ALIGNMENT умолчанию GL_UNPACK_ALIGNMENT 4, а не 1. Таким образом, OpenGL будет читать 4 байта для каждого пикселя, а не 3, которые вы предполагаете.

Установите GL_UNPACK_ALIGNMENT в 1 используя glPixelStorei().

  • 0
    GL_UNPACK_ALIGNMENT - это выравнивание по строке, а не по пикселю, не так ли?
  • 0
    Установка выравнивания распаковки не помогает, но выравнивание данных по 4 байта сработало
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню