OpenGL: Difference between revisions
Levidsmith (talk | contribs) |
Levidsmith (talk | contribs) |
||
Line 274: | Line 274: | ||
I pulled all of that code out into its own function, so now I just simply call loadPNGTexture("filename.png") to load the texture. The function had to be written specific for PNGs, since the RGB/BGR format issue with BMPs. | I pulled all of that code out into its own function, so now I just simply call loadPNGTexture("filename.png") to load the texture. The function had to be written specific for PNGs, since the RGB/BGR format issue with BMPs. | ||
When I tried using my new method, the entire program | When I tried using my new method, the entire program crashed. I found that the reason was because I converted the background from a BMP to a PNG, but I didn't add a transparent layer. Apparently it is REALLY important to make sure you have a transparent layer if you specify RGBA as a parameter to glTexImage2D. | ||
GLuint loadPNGTexture(char *strFile) { | GLuint loadPNGTexture(char *strFile) { |
Revision as of 02:47, 17 February 2010
I am attempting to integrate OpenGL into the code, so that the game uses hardware graphics acceleration. Hopefully, this will improve some of the framerate issues.
This will also allow me to use Fraps to make videos of the game to post to YouTube.
Below, I have documented the process I went through to enable OpenGL, including all of the issues I came across.
Get code to compile with a single line of OpenGL
I can compile a program using #include "SDL_opengl.h", but I am getting errors about missing functions when an OpenGL method is called.
I installed the OpenGL libraries in cygwin, so I'm not sure if those were necessary:
Installing these files may help
http://www.libsdl.org/extras/win32/cygwin/
Found out that I was using the wrong parameters to compile. I should have been using this:
gcc test.c `sdl-config --libs --cflags` -lglut32 -lglu32 -lopengl32
Display a bitmap to the screen
I got a simple square BMP to display in OpenGL:
Added Tux BMP:
Tux on an image background:
One of the vertices was off, which made the background skewed.
Moving Block
Next Step is to get the player block moving
Pseudo Code:
INTEGER playerX INTEGER playerY INTEGER playerVelocityX INTEGER playerVelocityY Setup_SDL Setup_OpenGL Load_Bitmaps GameLoop { While (User hasn't Quit) { IF (User presses up) THEN playerVelocityY = - PLAYER_SPEED IF (User presses down) THEN playerVelocityY = PLAYER_SPEED IF (User presses left) THEN playerVelocityX = - PLAYER_SPEED IF (User presses right) THEN playerVelocityX = PLAYER_SPEED playerX = playerX + playerVelocityX playerY = playerY + playerVelocityY Render_Screen } }
Change BMP to PNG
Next step is to replace the BMP with a PNG
Some "gotchas"
- Add "IMG_Init(IMG_INIT_PNG);" to the program's startup code
- Replace "SDL_LoadBMP" with "IMG_Load"
- Add -lSDL_image on the compile line (Makefile or go script)
- Add required DLLs to the working directory (libpng12-0.dll, zlib1.dll, SDL_image.dll, etc)
- If the PNG will not display, try passing a BMP to IMG_Load to see if it works
Got SDL and OpenGL to accept the PNG image with transparency, but there are display issues:
PNG with transparency disabled, and background color saved. Basic image is correct, but some discoloration.
Got the non-transparent PNG to display correctly. The problem was with the glTeximage2D line. The "format" parameter was set to "GL_BGR" when it should have been "GL_RBG".
Apparently, changing the format parameter to GL_RBG (from GL_BGR) will make BMPs appear discolored (cyan for yellow).
Another interesting note I found was that all textures MUST be a power of 2 (2, 4, 8, 16, 32, 64, 128, 256, ...) in order to work with OpenGL.
Got the transparent PNG image to display correctly. I changed the "format" parameter in the glTeximage2D (noted above) to "GL_RBGA". However, the transparent pixels show up as white instead of the background color.
The image now displays correctly with transparency! I had to change the "internalformat" parameter for glTeximage2D from "3" to "GL_RBGA".
The methods glEnable(GL_ALPHA_TEST); and glAlphaFun(GL_GREATER, 0.5); must also be called to enable transparency.
Now I just need to write a standard method for generating textures, and I think I will be ready to integrate the code into the main game code.
Below is my test code:
#include "SDL.h" #include "SDL_image.h" #include "SDL_opengl.h" #include <stdio.h> void gameLoop(); void drawScene(); int iPlayerX = 0; int iPlayerY = 0; int iPlayerVelX = 0; int iPlayerVelY = 0; GLuint texture; GLuint texture_bkg; int main(int argc, char *argv[]) { SDL_Surface *screen; if ( SDL_Init(SDL_INIT_VIDEO) != 0 ) { printf("Unable to initialize SDL: %s\n", SDL_GetError()); return 1; } SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); screen = SDL_SetVideoMode( 1024, 768, 16, SDL_OPENGL ); IMG_Init(IMG_INIT_JPG|IMG_INIT_PNG); if ( !screen ) { printf("Unable to set video mode: %s\n", SDL_GetError()); return 1; } glClearColor( 0, 0, 0, 0 ); glEnable( GL_TEXTURE_2D ); // Need this to display a texture glViewport( 0, 0, 1024, 768 ); glMatrixMode( GL_PROJECTION ); glLoadIdentity(); glOrtho( 0, 1024, 768, 0, -1, 1 ); glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GREATER, 0.5); SDL_Surface *surface; SDL_Surface *surface_bkg; // if ( (surface = SDL_LoadBMP("image.bmp")) ) { // if ( (surface = SDL_LoadBMP("tux.bmp")) ) { // if ( (surface = IMG_Load("tux.png")) ) { // if ( (surface = SDL_LoadBMP("tux1a.bmp")) ) { // if ( (surface = IMG_Load("tux1a.bmp")) ) { if ( (surface = IMG_Load("tux.png")) ) { glGenTextures( 1, &texture ); glBindTexture( GL_TEXTURE_2D, texture ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, surface->pixels ); } else { printf("SDL could not load image: %s\n", SDL_GetError()); SDL_Quit(); return 1; } if ( surface ) { SDL_FreeSurface( surface ); } surface_bkg = SDL_LoadBMP("bkg.bmp"); glGenTextures(1, &texture_bkg); glBindTexture(GL_TEXTURE_2D, texture_bkg); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); glTexImage2D( GL_TEXTURE_2D, 0, 3, surface_bkg->w, surface_bkg->h, 0, GL_BGR, GL_UNSIGNED_BYTE, surface_bkg->pixels ); SDL_FreeSurface(surface_bkg); gameLoop(); glDeleteTextures( 1, &texture ); IMG_Quit(); SDL_Quit(); return 0; } void drawScene() { glClear( GL_COLOR_BUFFER_BIT ); glBindTexture( GL_TEXTURE_2D, texture_bkg ); glBegin( GL_QUADS ); glTexCoord2i( 0, 0 ); glVertex3f( 0, 0, 0 ); glTexCoord2i( 1, 0 ); glVertex3f( 1024, 0, 0 ); glTexCoord2i( 1, 1 ); glVertex3f( 1024, 768, 0 ); glTexCoord2i( 0, 1 ); glVertex3f( 0, 768, 0 ); glEnd(); glBindTexture( GL_TEXTURE_2D, texture ); glBegin( GL_QUADS ); glTexCoord2i( 0, 0 ); glVertex3f( iPlayerX, iPlayerY, 0 ); glTexCoord2i( 1, 0 ); glVertex3f( iPlayerX + 256, iPlayerY, 0 ); glTexCoord2i( 1, 1 ); glVertex3f( iPlayerX + 256, iPlayerY + 256, 0 ); glTexCoord2i( 0, 1 ); glVertex3f( iPlayerX, iPlayerY + 256, 0 ); glEnd(); SDL_GL_SwapBuffers(); } void gameLoop() { int iKeepLooping; SDL_Event event; iKeepLooping = 1; while (iKeepLooping) { while (SDL_PollEvent( &event) ) { switch(event.type) { case SDL_KEYDOWN: if (event.key.keysym.sym == SDLK_LEFT) { iPlayerVelX = -2; } if (event.key.keysym.sym == SDLK_RIGHT) { iPlayerVelX = 2; } if (event.key.keysym.sym == SDLK_UP) { iPlayerVelY = -2; } if (event.key.keysym.sym == SDLK_DOWN) { iPlayerVelY = 2; } if (event.key.keysym.sym == SDLK_q) { iKeepLooping = 0; } break; case SDL_KEYUP: iPlayerVelX = 0; iPlayerVelY = 0; break; } } iPlayerX += iPlayerVelX; iPlayerY += iPlayerVelY; drawScene(); } }
Adding Other Objects
I added a snowman that simply moves in a horizontal motion and bounces off the window border.
Now I have three OpenGL textures.
Modularizing Code
With the three textures, I had texture initialization code that was repeated three times.
I pulled all of that code out into its own function, so now I just simply call loadPNGTexture("filename.png") to load the texture. The function had to be written specific for PNGs, since the RGB/BGR format issue with BMPs.
When I tried using my new method, the entire program crashed. I found that the reason was because I converted the background from a BMP to a PNG, but I didn't add a transparent layer. Apparently it is REALLY important to make sure you have a transparent layer if you specify RGBA as a parameter to glTexImage2D.
GLuint loadPNGTexture(char *strFile) { SDL_Surface *surface; GLuint giTexture; if ( (surface = IMG_Load(strFile)) ) { glGenTextures( 1, &giTexture ); glBindTexture( GL_TEXTURE_2D, giTexture ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, surface->w, surface->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, surface->pixels ); } if ( surface ) { SDL_FreeSurface( surface ); } return giTexture; }