将位图/位数组渲染到 2d 平面的最佳方法(使用 OpenGL)
好吧,这就是我所拥有的。我有一个 1d 位图(或位数组、位集、位串,但我现在将其称为位图),其中包含康威生命生成游戏的活或死状态。 (x, y)
处的单元由 y * map_width + x
处的位表示。
现在我的生命游戏“引擎”正在工作,如果我现在可以渲染一些图形内容那就太好了。我认为 OpenGL 将是一个不错的选择,但我不知道应该如何开始,也不知道是否有任何特定的函数或着色器(我对着色器一无所知)可以有效地将位图渲染为具有黑色和白色像素的二维平面。
如果你现在认为“不,你这个白痴 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);
}
Ok, this is what I have. I have a 1d bitmap (or bitarray, bitset, bitstring, but I'll call it a bitmap for now) containing the live or dead states from a conway game of life generation. The cell at (x, y)
is represented by the bit at y * map_width + x
.
Now I have my game of life "engine" working, it would be nice if I could render some graphical stuff now. I thought OpenGL would be a nice choice for this, but I have no idea how I should start and if there are any specific functions or shaders (I know nothing about shaders) that can efficiently render a bitmap into a 2d plane with black 'n white pixels.
If you now think "no you idiot opengl is bad go with ...", feel free to say it, I'm open for changes.
EDIT
I forgot to say that I use a compact bitarray storing 8 bits per byte and using masking to retrieve those bytes. This is my hand made library thingy:
#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);
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
这是我的 OGL Game of Life 实现中的代码。
这会上传纹理(每次要更新数据时都执行此操作):
game->culture[phase]
是char*
类型的数据数组,大小 < code>width * height(在写入和读取的两个交替数组之间进行相位切换)。由于使用了 GL_LUMINANCE,因此颜色仅为黑色和白色。
另外,你需要用这个设置矩形(每一帧,但我想你已经知道了)
当然你可以使用缓冲区并将“模型”保留在GPU内存中,但这对于只有一个四边形来说并不是真正必要的。
This is code from my OGL Game of Life implementation.
This uploads the texture (do this every time you want to update the data):
game->culture[phase]
is the data array of typechar*
of sizewidth * height
(phase toggles between two alternating arrays that are being written into resp. read from).Because
GL_LUMINANCE
is used, the colors will be only black and white.Also, you need to set up the rectagle with this (every frame, but I guess you already know this)
Of course you could use buffers and keep the "model" in the GPU memory, but that is not really necessary with only one quad.
首先考虑通过在 2 个 OpenGL 纹理之间进行乒乓操作来在 GPU 上进行模拟本身。如果不是一些复杂的优化 - Conway's Life 对于 GPU 来说是一个非常简单的任务。它将需要 2 个帧缓冲区对象和对着色器的一些了解。
Edit-1:片段着色器示例(大脑编译)
顶点着色器是一个简单的传递:
First of all consider doing the simulation itself on GPU by ping-ponging between 2 OpenGL textures. If not some complex optimizations - Conway's Life is a pretty straightforward task for GPU. It will require 2 framebuffer objects and some understanding of shaders.
Edit-1: Example fragment shader (brain-compiled)
The vertex shader is a simple pass-through:
如果您坚持使用 OpenGL,最简单的方法是将位图作为纹理上传,然后渲染使用该纹理映射的四边形。上传位看起来像这样:
假设每个单元格都是一个字节,值
0
表示黑色,0xFF
表示白色。请注意,在某些 OpenGL 版本上,宽度
和高度
必须是 2 的幂。If you stick with OpenGL, the easiest way is to upload your bitmap as a texture, then render a quad mapped with that texture. The uploading bit would look something like this:
This assumes that every cell is a single byte, with value
0
for black and0xFF
for white. Note that, on some OpenGL versions,width
andheight
must be powers of two.旧版本的 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
的参考页以获取解决方法。Old versions of OpenGL provide functionality to draw bitmaps directly without the need for a intermediary texture:
glBitmap
Compared to other methods for drawing imagesglBitmap
is rather slow, but since one uses it only sparingly this is not that bad.http://www.opengl.org/sdk/docs/man/xhtml/glBitmap.xml
Bitmaps are placed using
glRasterPos
orglWindowPos
.http://www.opengl.org/sdk/docs/man/xhtml/glRasterPos.xml
http://www.opengl.org/sdk/docs/man/xhtml/glWindowPos.xml
Bitmaps have a small pitfall: If the raster position set using
glRasterPos
orglWindowPos
is outside the viewport no part of the bitmap gets drawn, even if it reached into the viewport; see the reference page ofglBitmap
for a workaround.