Лучший способ визуализации растрового изображения / растрового изображения в 2D-плоскости (с OpenGL) - PullRequest
2 голосов
/ 05 марта 2011

Хорошо, это то, что у меня есть.У меня есть 1d растровое изображение (или bitarray, bitset, bitstring, но пока я назову его растровым изображением), содержащее живые или мертвые состояния из игры Конвея о создании жизни.Ячейка в (x, y) представлена ​​битом в y * map_width + x.

Теперь у меня работает «движок» моей игры жизни, было бы неплохо, если бы я мог теперь визуализировать некоторые графические вещи.Я подумал, что OpenGL будет хорошим выбором для этого, но я понятия не имею, как мне начать и есть ли какие-то конкретные функции или шейдеры (я знаю ничего о шейдерах), которые могут эффективно отображать растровое изображение в2D-плоскость с черными и белыми пикселями.

Если вы сейчас думаете, «нет, вы, идиот, opengl - это плохо…», не стесняйтесь говорить, я открыт для изменений.

РЕДАКТИРОВАТЬ

Я забыл сказать, что я использую компактный массив битов, хранящий 8 бит на байт и использующий маскирование для извлечения этих байтов.Это моя ручная библиотека чтоли:

#include <stdint.h> // uint32_t
#include <stdlib.h> // malloc()
#include <string.h> // memset()
#include <limits.h> // CHAR_BIT

typedef uint32_t word_t;
enum {
    WORD_SIZE = sizeof(word_t), // size of one word in bytes
    BITS_PER_WORD = sizeof(word_t) * CHAR_BIT, // size of one word in bits
    MAX_WORD_VALUE = UINT32_MAX // max value of one word
};

typedef struct {
    word_t *words;
    int nwords;
    int nbytes;
} bitmap_t;

inline int WORD_OFFSET(int b) { return b / BITS_PER_WORD; }
inline int BIT_OFFSET(int b) { return b % BITS_PER_WORD; }

inline void setbit(bitmap_t bitmap, int n) { bitmap.words[WORD_OFFSET(n)] |= (1 << BIT_OFFSET(n)); }
inline void flipbit(bitmap_t bitmap, int n) { bitmap.words[WORD_OFFSET(n)] ^= (1 << BIT_OFFSET(n)); }
inline void clearbit(bitmap_t bitmap, int n) { bitmap.words[WORD_OFFSET(n)] &= ~(1 << BIT_OFFSET(n)); }
inline int getbit(bitmap_t bitmap, int n) { return (bitmap.words[WORD_OFFSET(n)] & (1 << BIT_OFFSET(n))) != 0; }

inline void clearall(bitmap_t bitmap) {
    int i;
    for (i = bitmap.nwords - 1; i >= 0; i--) {
        bitmap.words[i] = 0;
    }
}

inline void setall(bitmap_t bitmap) {
    int i;
    for (i = bitmap.nwords - 1; i >= 0; i--) {
        bitmap.words[i] = MAX_WORD_VALUE;
    }
}

bitmap_t bitmap_create(int nbits) {
    bitmap_t bitmap;
    bitmap.nwords = nbits / BITS_PER_WORD + 1;
    bitmap.nbytes = bitmap.nwords * WORD_SIZE;
    bitmap.words = malloc(bitmap.nbytes);

    if (bitmap.words == NULL) { // could not allocate memory
        printf("ERROR: Could not allocate (enough) memory.");
        exit(1);
    }

    clearall(bitmap);
    return bitmap;
}

void bitmap_free(bitmap_t bitmap) {
    free(bitmap.words);
}

Ответы [ 4 ]

2 голосов
/ 05 марта 2011

Это код из моей реализации OGL Game of Life.

Это загружает текстуру (делайте это каждый раз, когда вы хотите обновить данные):

glTexImage2D( GL_TEXTURE_2D, 0, 1, game->width, game->height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, game->culture[game->phase] );

game->culture[phase] isмассив данных типа char* размера width * height (фаза переключается между двумя чередующимися массивами, которые записываются или считываются из).

Поскольку используется GL_LUMINANCE, цвета будут только чернымии белый.

Кроме того, вам нужно настроить прямоугольник с этим (каждый кадр, но я думаю, вы уже знаете это)

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);


    glBegin(GL_QUADS);                                  // Draw A Quad
        glVertex3f(-1.0f, 1.0f, 0.0f);                  // Top Left
        glTexCoord2i( 1, 0 );
        glVertex3f( 1.0f, 1.0f, 0.0f);                  // Top Right
        glTexCoord2i( 1, 1 );
        glVertex3f( 1.0f,-1.0f, 0.0f);                  // Bottom Right
        glTexCoord2i( 0, 1 );
        glVertex3f(-1.0f,-1.0f, 0.0f);                  // Bottom Left
        glTexCoord2i( 0, 0 );
    glEnd();

Конечно, вы можете использовать буферы и сохранить«модель» в памяти графического процессора, но это не является действительно необходимым только с одним квадом.

1 голос
/ 07 марта 2011

Прежде всего подумайте о том, чтобы выполнить симуляцию на GPU, используя пинг-понг между двумя текстурами OpenGL.Если не какие-то сложные оптимизации - Conway's Life - довольно простая задача для GPU.Для этого потребуются 2 объекта кадрового буфера и некоторое понимание шейдеров.

Edit-1: Пример фрагментного шейдера (скомпилированный с мозгом)

#version 130
uniform sampler2D input;
out float life;
void main() {
    ivec2 tc = ivec2(gl_FragCoord);
    float orig = texelFetch(input,tc,0);
    float sum = orig+
        texelFetchOffset(input,tc,0,ivec2(-1,0))+
        texelFetchOffset(input,tc,0,ivec2(+1,0))+
        texelFetchOffset(input,tc,0,ivec2(0,-1))+
        texelFetchOffset(input,tc,0,ivec2(0,+1))+
        texelFetchOffset(input,tc,0,ivec2(-1,-1))+
        texelFetchOffset(input,tc,0,ivec2(-1,+1))+
        texelFetchOffset(input,tc,0,ivec2(+1,-1))+
        texelFetchOffset(input,tc,0,ivec2(+1,+1));
    if(sum<1.9f)
        life = 0.0f;
    else if(sum<2.1f)
        life = orig;
    else life = 1.0f;
}

Вершинный шейдер - это простой проход:1006 *

#version 130
in vec2 vertex;
void main() {
   gl_Position = vec4(vertex,0.0,1.0);
}
0 голосов
/ 06 марта 2011

Старые версии OpenGL предоставляют функциональность для непосредственного рисования растровых изображений без необходимости использовать промежуточную текстуру: glBitmap По сравнению с другими методами для рисования изображений glBitmap довольно медленный, но поскольку его используют только экономно, это не так уж плохо .

http://www.opengl.org/sdk/docs/man/xhtml/glBitmap.xml

Растровые изображения размещаются с использованием glRasterPos или glWindowPos.

http://www.opengl.org/sdk/docs/man/xhtml/glRasterPos.xml http://www.opengl.org/sdk/docs/man/xhtml/glWindowPos.xml

Битовые карты имеют небольшую ловушку: если положение растра, установленное с помощью glRasterPos или glWindowPos, находится вне области просмотра, никакая часть растрового изображения не рисуется, даже если она достигла области просмотра; см. страницу справки glBitmap для обхода проблемы.

0 голосов
/ 05 марта 2011

Если вы придерживаетесь OpenGL, самый простой способ - загрузить свое растровое изображение в качестве текстуры, а затем визуализировать четырехугольник, сопоставленный с этой текстурой.Бит загрузки будет выглядеть примерно так:

glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, data);

Предполагается, что каждая ячейка представляет собой один байт со значением 0 для черного и 0xFF для белого.Обратите внимание, что в некоторых версиях OpenGL width и height должны иметь степень двойки.

...