So - according to many sites, it is supposedly easy to use OpenGL to blit a raw bitmap to the screen using textures. And after many hours, I can say that Yes - it is indeed conceptually easy - but there is a lot of setup needed to actually make it work.
The following code assumes that your OpenGL implementation can work with arbitrary size textures (which is the case on modern graphics cards) AND that your raw bitmap does not exceed the size of the texture (which is 8192x8192 on modern graphics cards).
Initialization
First you need a bit of init code. This only needs to be called once in your application:
glEnable(GL_TEXTURE_2D);
Again, once in the code you allocate a texture and store the handle in a variable that can be accessed from your drawing function
GLuint _tex;
glGenTextures(1, &_tex);
Pixel buffer representation
In the following we assume that an array of pixels exist of size _xdim*_ydim and that each pixel is represented by a uint32_t number. A pixel takes the form 0xAARRGGBB, so to pack the three colors rgb from 8 bit integers you can use the following macro:
#define PIXEL(r,g,b) ((b) | (g << 8) | (r << 16) | (0xff << 24))
By convention the upper left corner of a pixel array is index 0, and the data is stored row major, i.e. the index is given by y*_xdim+x where x,y is the pixel coordinate.
Drawing code
The actual drawing happens (after setting the current context) using the following steps - note that they need to be carried out for each redraw:
First the context is cleared:
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
Then the viewport is set to the size of the window showing the bitmap (typically same size as the bitmap):
glViewport(0, 0, (GLint)width, (GLint)height);
The projection matrix is set:
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
then an orthorgonal view is set up. This view uses logical coordinates, so we define the left side
to be value 0, the right side to be 1, and then the bottom to be 1 and top to be 0. This is opposite normal OpenGL coordinates, but makes the image not show up upside down. z axis is defined to be between -1 and 1.
glOrtho(0.0, 1.0, 1.0, 0.0, -1, 1);
After this the Model View matrix is set up:
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
Now we are finally able to do actual drawing. We bind the texture allocated initially to provide a destination for the pixel data, and disable mipmaps by setting the filter:
glBindTexture(GL_TEXTURE_2D, _tex);
glTexParameteri(GL_TEXTURE_2D,
GL_TEXTURE_MIN_FILTER, GL_LINEAR);
Then we load the pixels into the texture:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, _xdim, _ydim, 0,
GL_BGRA, GL_UNSIGNED_BYTE, pixels);
and we draw the texture onto a quad spanning the entire logical coordinate system set up above. Note that order is important in that the vertices need to be drawn counterclockwise:
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(0, 0, 0);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(1, 0, 0);
glTexCoord2f(1.0f, 1.0f);
glVertex3f(1, 1, 0);
glTexCoord2f(0.0f,1.0f);
glVertex3f(0, 1, 0);
glEnd();
Finally we unbind the texture:
glBindTexture(GL_TEXTURE_2D, 0);
Then the GL buffer needs to be made current, however this is platform specific. in wxWindows this is a call to Swapbuffers();
22 easy steps later, and you have a rendered pixel array.
Ingen kommentarer:
Send en kommentar