3

I'm trying to load an image into my game. It's being written in C++, with SDL and OpenGL, and the SDL_Image framework. I've gotten the image in, and have rotated/inverted it to my needs, but there are two main problems.

Firstly, the image's colors are completely inverted. (ie blue -> red) I have the format to either 'GL_RGB' or 'GL_RGBA,' depending on the bytes per pixel. I've tried with PNGs, JPEGs, and BMPs, but their all the same. I'm lost! --Thanks to datenwolf for correcting my silly mistakes!

Secondly, the image draws once, and that's it. It doesn't get redrawn on the other buffer, it just gets displayed once and then is gone as soon as the next frame is drawn.

GLuint loadTexture()
{
SDL_Surface* image = IMG_Load( "/Users/<My name>/Pictures/pacman board.jpeg" );

SDL_DisplayFormatAlpha(image);

unsigned object(0);

glGenTextures(1, &object);

glBindTexture(GL_TEXTURE_2D, object);

glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);


int Mode = NULL;

if(image->format->BytesPerPixel == 3) {Mode = GL_RGB;}
else if(image->format->BytesPerPixel == 4) {Mode = GL_RGBA;}

glTexImage2D(GL_TEXTURE_2D, 0, Mode, image->w, image->h, 0, Mode, GL_UNSIGNED_BYTE, image->pixels);

SDL_FreeSurface(image);
return object;
}

int main(int argc, char * argv[])
{
SDL_Init(SDL_INIT_EVERYTHING);

SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);

SDL_WM_SetCaption("HI", NULL);
SDL_SetVideoMode(600, 600, 32, SDL_OPENGL);

glClearColor(0,0,0,1);
glViewport(0, 0, 600, 600);

glShadeModel(GL_SMOOTH);

glMatrixMode(GL_PROJECTION);
glLoadIdentity();

unsigned int pad_texture = 0;
pad_texture = loadTexture();


//---MAIN LOOP---\\

bool isRunning = true;
SDL_Event event;
while (isRunning)
{
    while (SDL_PollEvent(&event))
    {
        if (event.type == SDL_QUIT) { isRunning = false; }
        if (event.type == SDL_KEYUP && event.key.keysym.sym == SDLK_ESCAPE) {isRunning = false;}   
    }


    glClear(GL_COLOR_BUFFER_BIT);
    gluOrtho2D(0, 600, 0, 600); // For some reason, I prefer having '0,0' at the bottom left.

    glPushMatrix();

    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D,pad_texture);

    glBegin(GL_QUADS);

    glTexCoord2d(0, 1); glVertex2f(0, 0);
    glTexCoord2d(1, 1); glVertex2f(600, 0);
    glTexCoord2d(1, 0); glVertex2f(600, 600);
    glTexCoord2d(0, 0); glVertex2f(0, 600);
    glEnd();

    glDisable(GL_TEXTURE_2D);

    glPopMatrix(); //Stop drawing

    SDL_GL_SwapBuffers();   
}
SDL_Quit();    
return 0;
}
Matt Reynolds
  • 787
  • 2
  • 9
  • 22

1 Answers1

2

Most image file formats have the pixel data in BGR or BGRA order. If you load such image data using a RGB ordering the blue and red channel will be swapped, of course.

OpenGL does offer those pixel formats as well, since version 1.4. You'll have to either use a extension wrapper like GLEW or fetch and install a current glext.h to get access to the new format tokens. Have a look at http://www.opengl.org/sdk/docs/man/xhtml/glTexImage2D.xml for the complete list of supported formats in OpenGL-3 core and later. For older OpenGL, namely OpenGL-1.4 to OpenGL-2.1 look at http://www.opengl.org/sdk/docs/man2/xhtml/glTexImage2D.xml

Update

That your image shows only once is due to the following:

while (isRunning)
{
    /*...*/

    glClear(GL_COLOR_BUFFER_BIT);
    gluOrtho2D(0, 600, 0, 600); // For some reason, I prefer having '0,0' at the bottom left.

gluOrtho2D multiplies on top whats already on the matrix. Which is what gluOrtho2D did in the previous iteration. Also you left the matrix mode in a "dangling" state. As a general rule you should always freshly setup the whole OpenGL drawing state (viewport, clear color, clear depth, all the matrices) at the beginning of each drawing iteration. In your case

while (isRunning)
{
    /*...*/

    glViewport(0, 0, win_width, win_height);

    glClearColor(0,0,0,1);
    glClear(GL_COLOR_BUFFER_BIT);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, win_width, 0, win_height, -1, 1); // gluOrtho2D is the most useless wrapper ever..., just put a -1, 1 as additional parameters to glOrtho

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glShadeModel(GL_SMOOTH);
Community
  • 1
  • 1
datenwolf
  • 159,371
  • 13
  • 185
  • 298
  • I've tried that before, substituting the format in the `if`s with `GL_RGB` and `GL_RGBA`, and strangely the only thing I get is a white square before the other problem whisks it away. – Matt Reynolds Apr 06 '13 at 16:29
  • @TheWalkingCactus: You get the "white" texture because glTexImage will bail out with an invalid value error (always check glGetError!). You're using the same format token for `internal format` and `format`, which works for GL_RGB(A). But reading the reference carefully yields, that for a BGR(A) format, only the `format` parameter, *but not* the `internal format` parameter must be set this way. Read the documentation for the sets of allowed tokens in each parameter. `internal format` tells OpenGL the kind of and precision of the data to use internally. `format` tells it, how `data` is arranged. – datenwolf Apr 06 '13 at 16:35
  • Oh, I see. That worked great! now, the texture loads properly, but only for one frame. Oh well, it's a start. Thanks again!! – Matt Reynolds Apr 06 '13 at 16:47
  • By the way, @datenwolf, the only reason I haven't marked this answer as 'Accepted' is because I still have that other problem... so although your answer was AMAZING, I won't mark it as accepted (yet). Sorry :( – Matt Reynolds Apr 07 '13 at 01:53
  • @TheWalkingCactus: The other problem is, because you do the classical newbie mistake: You separated projection matrix setup from the drawing code, and wrongly that is in your case. Let me update my answer. – datenwolf Apr 07 '13 at 10:08
  • Thanks, let me give it a whirl and tell you how it goes! – Matt Reynolds Apr 07 '13 at 10:45