SDL + OpenGL Sprite Loading Problem

Member
Posts: 30
Joined: 2006.05
Post: #1
I've recently started learning to use SDL with OpenGL for graphics, and when compiling and running tutorial code made to load BMPs in SDL and blit them with OpenGL, I have encountered a strange situation - I can load an image using SDL, but when I check its width to see if it is a power of two (not sure why the tutorial does so...), and the width is 128, it tells me the width is only 96 px. and therefore throws an error.

In addition, if I ignore that and continue, I get a white rectangle rather than an image.

I know the image is being found... the error "Could not load image" does not appear.

Please help... code below. Sorry for the long listing...

Code:
#include <stdio.h>
#include <string.h>

#include "main.h"

#include "SDL.h"
#include "SDL_OpenGL.h"

#define SCREEN_WIDTH 1024
#define SCREEN_HEIGHT 768

#if defined(__MACOSX__)
char* RSRC_PREFIX = "TestOne.app/Contents/Resources/";
#else
char* RSRC_PREFIX = "";
#endif

#if defined(WIN32) && !defined(GL_BGR)
#define GL_BGR GL_BGR_EXT
#endif

using namespace std;

SDL_Surface* drawContext;

GLuint image1;

int counter = 0;

int main(int argc, char *argv[])
{
    if (SDL_Init(SDL_INIT_EVERYTHING) != 0)
    {
        fprintf(stderr, "Unable to initialize SDL: %s\n", SDL_GetError());
        return 1;
    }
    atexit(SDL_Quit);
    
    // Create a double-buffered draw context
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
    
    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);
    
    Uint32 flags;
    flags = SDL_OPENGL | SDL_FULLSCREEN;
    drawContext = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, 0, flags);
    
    InitGLForScreen(SCREEN_WIDTH, SCREEN_HEIGHT);
        
    gluOrtho2D(0.0, 4.0, 0.0, 3.0);
    
    if (LoadImages() == 1) {
        fprintf(stderr, "Images failed to load.\n");
        return 1;
    }
    
    GameLoop();
    
    FreeAll();
    
    return 0;
}

/*
void HandleUserEvents(SDL_Event* event)
{
    switch (event->user.code) {
        case RUN_GAME_LOOP:
            GameLoop();
            break;
            
        default:
            break;
    }
}
*/

void GameLoop()
{
    SDL_Event event;
    bool done = false;
    while(!done) {
        while(SDL_PollEvent(&event) != 0) {
            switch(event.type) {
                /*
                case SDL_USEREVENT:
                    HandleUserEvents(&event);
                    break;
                */
                    
                case SDL_KEYDOWN:
                    done = true;
                    // Handle any key presses here.
                    break;
                    
                /*
                case SDL_MOUSEBUTTONDOWN:
                    // Handle mouse clicks here.
                    break;
                    
                case SDL_QUIT:
                    break;
                */
                    
                default:
                    break;
            }
        }
        
        // Clear screen
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        
        // Enable texturing
        glEnable(GL_TEXTURE_2D);
        
        // Draw to screen
        if (image1 == NULL) {
            fprintf(stderr, "image1 is still null\n");
        }
        DrawImage(image1, 200.0f + counter, 200.0f + counter, 300.0f + counter, 300.0f + counter);
        
        // Disable texturing
        glDisable(GL_TEXTURE_2D);
        
        // Flip
        SDL_GL_SwapBuffers();
        
        counter++;
    }
}

void InitGLForScreen(int width, int height) {
    glViewport(0, 0, width, height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    
    glOrtho(0.0f, width, height, 0.0f, -1.0f, 1.0f);
    
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    
    glClearColor(0.0f,0.0f,0.0f,0.5f);
    glClearDepth(1.0f);
    glDepthFunc(GL_LEQUAL);
    glEnable(GL_DEPTH_TEST);
    glShadeModel(GL_SMOOTH);
    glDisable(GL_CULL_FACE);
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
}

int LoadImages() {
    char file[100];
    strcpy(file, RSRC_PREFIX);
    strcat(file, "testbmp.bmp");
    if (LoadGLTexture(image1, file) == 1) {
        return 1;
    }
    return 0;
}

int LoadGLTexture(GLuint& image, char* path) {
    
    if (image == NULL) {
        fprintf(stderr, "image is null #0\n");
    }
    
    SDL_Surface *temp;      //This will help get the pixel data for our texture
    
    if ( (temp = SDL_LoadBMP(path)) ) {
        //Check that the image is square (width equal to height)
        if (temp->w != temp->h) {
            fprintf(stderr, "Image is not square...\n");
            return 1;
        }    
        
        //Check that the image's width is valid and then check that the image's width is a power of 2
        if (temp->w < 1) {
            fprintf(stderr, "Image is of valid width...\n");
            return 1;
        } else if ((temp->w & (temp->w - 1)) != 0) {
            fprintf(stderr, "Image width is not a power of 2. Width = %i\n", temp->w);
            return 1;
        }
        
        
        if (image == NULL) {
            fprintf(stderr, "image is null #1\n");
        }
        
        //Create the texture
        glGenTextures(1, &image);
        
        //Load the texture
        glBindTexture(GL_TEXTURE_2D, image);
        
        //Generate the texture
        glTexImage2D(GL_TEXTURE_2D, 0, 3, temp->w, temp->h, 0, GL_BGR, GL_UNSIGNED_BYTE, temp->pixels);
        
        if (image == NULL) {
            fprintf(stderr, "image is null #2\n");
        }
        
        //Use nearest filtering, very good
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    } else {
        fprintf(stderr, "Unable to load bitmap: %s\n", SDL_GetError());
        return 1;
    }    
    
    //Free up our temp surface if it was ever used
    if (temp) { SDL_FreeSurface(temp); }
    
    return 0;
}

int DrawImage (GLuint& image, float x1, float y1, float x2, float y2) {
    //Load the texture
    glBindTexture(GL_TEXTURE_2D, image);
    
    glBegin(GL_QUADS);
    //Top-left vertex (corner)
    glTexCoord2i(0,0);
    glVertex3f(x1, y1, 0.0f);
    
    //Bottom-left vertex (corner)
    glTexCoord2i(1,0);
    glVertex3f(x2, y1, 0.0f);
    
    //Bottom-right vertex (corner)
    glTexCoord2i(1,1);
    glVertex3f(x2, y2, 0.0f);
    
    //Top-right vertex (corner)
    glTexCoord2i(0,1);
    glVertex3f(x1, y2, 0.0f);
    glEnd();
    
    return 0;
}

void FreeAll() {
    glDeleteTextures(1, &image1);
}
Quote this message in a reply
Moderator
Posts: 771
Joined: 2003.04
Post: #2
Quote:but when I check its width to see if it is a power of two (not sure why the tutorial does so...),

It is a requirement of OpenGL textures when using GL_TEXTURE_2D. An alternative is to use rectangle textures, which are not limited to PoT sizes. If you try to use a NPoT texture with GL_TEXTURE_2D, the texture will end up white, as you found out.

Note that the code checks that the image is square, this is not required (texture sizes like 128x64, for instance, work just fine)
Quote this message in a reply
Member
Posts: 20
Joined: 2006.06
Post: #3
PowerMacX Wrote:It is a requirement of OpenGL textures when using GL_TEXTURE_2D. An alternative is to use rectangle textures, which are not limited to PoT sizes. If you try to use a NPoT texture with GL_TEXTURE_2D, the texture will end up white, as you found out.

Note that the code checks that the image is square, this is not required (texture sizes like 128x64, for instance, work just fine)
Though it should be noted that more and more modern cards are being released with support for non-power of two textutes. (I know because that bit me once on a device with non-power of two support.)
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #4
GeForce 6xxx, 7xxx and derivatives (Eg. Quadro 4500) have full support for non-power-of-two textures (ARB_texture_non_power_of_two), though not yet on Mac OS X. Even then, the support comes at a steep performance price. No ATI cards yet support this feature.

The more restrictive ARB_texture_rectangle (which you can't accidentally use) is available on anything better than a Rage 128.
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  OpenGL Alpha Channel Problem Moganza 1 2,890 Jan 19, 2013 08:25 AM
Last Post: sealfin
  Sprite game with OpenGL/GLKit InvisibleMoustache 6 8,191 Oct 10, 2012 09:20 AM
Last Post: OneSadCookie
  Sprite transparency in OpenGL? Guest! 26 28,915 Feb 17, 2012 09:24 AM
Last Post: Skorche
  iPad, OpenGL ES, and XCode Instruments problem! Bandit 0 3,834 Dec 13, 2010 01:21 PM
Last Post: Bandit
  OpenGL ES Loading images techy 4 3,813 Dec 24, 2009 02:01 PM
Last Post: techy