3

Ok.. brand new to C++ (I mean super new). I understand a lot of PHP and javascript so I understand basic code structure and such. Right now, I'm just trying to get a hold of C++ concepts. I can produce a square and move it around using a tutorial I found online. Don't mind the square size vs the texture(its 175x55 and it is in the root directory[texture.bmp]).However I am attempting to get a texture on and I get an error. I am using SDL and openGL. The error I get is:

"Unhandled exception at 0x0020fee9 in Test1.exe: 0x0000005: Access violation reading location 0x00139000"

I have looked online and from what I understand something is getting called out of order(from all the results I found online). I think..

My code is as follows:

//The headers
#include "SDL.h"
#include "SDL_opengl.h"
#include "stdio.h"
#pragma comment( lib, "opengl32.lib" )
#pragma comment( lib, "glu32.lib" )

//Screen attributes
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
const int SCREEN_BPP = 32;

//The frame rate
const int FRAMES_PER_SECOND = 60;

//The attributes of the square
const int SQUARE_WIDTH = 20;
const int SQUARE_HEIGHT = 20;

//Event handler
SDL_Event event;

//The square
class Square
{
    private:
    //The offsets
    int x, y;

    //The velocity of the square
    int xVel, yVel;

    public:
    //Initializes
    Square();

    //Handles key presses
    void handle_input();

    //Moves the square
    void move();

    //Shows the square on the screen
    void show();

    void getTexture();
};

//The timer
class Timer
{
    private:
    //The clock time when the timer started
    int startTicks;

    //The ticks stored when the timer was paused
    int pausedTicks;

    //The timer status
    bool paused;
    bool started;

    public:
    //Initializes variables
    Timer();

    //The various clock actions
    void start();
    void stop();
    void pause();
    void unpause();

    //Gets the timer's time
    int get_ticks();

    //Checks the status of the timer
    bool is_started();
    bool is_paused();
};

bool init_GL()
{
    //Set clear color
    glClearColor( 0, 0, 0, 0 );

    //Set projection
    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();
    glOrtho( 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, -1, 1 );

    //Initialize modelview matrix
    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();

    //If there was any errors
    if( glGetError() != GL_NO_ERROR )
    {
        return false;
    }

    //If everything initialized
    return true;
}

bool init()
{
    //Initialize SDL
    if( SDL_Init( SDL_INIT_EVERYTHING ) < 0 )
    {
        return false;
    }

    //Create Window
    if( SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_OPENGL ) == NULL )
    {
        return false;
    }

    //Initialize OpenGL
    if( init_GL() == false )
    {
        return false;
    }

    //Set caption
    SDL_WM_SetCaption( "OpenGL Test", NULL );

    return true;
}

void clean_up()
{
    //Quit SDL
    SDL_Quit();
}

Square::Square()
{
    //Initialize offsets
    x = 0;
    y = 0;

    //Initialize velocity
    xVel = 0;
    yVel = 0;
}

void Square::handle_input()
{
    //If a key was pressed
    if( event.type == SDL_KEYDOWN )
    {
        //Adjust the velocity
        switch( event.key.keysym.sym )
        {
            case SDLK_UP: yVel -= SQUARE_HEIGHT / 2; break;
            case SDLK_DOWN: yVel += SQUARE_HEIGHT / 2; break;
            case SDLK_LEFT: xVel -= SQUARE_WIDTH / 2; break;
            case SDLK_RIGHT: xVel += SQUARE_WIDTH / 2; break;
        }
    }
    //If a key was released
    else if( event.type == SDL_KEYUP )
    {
        //Adjust the velocity
        switch( event.key.keysym.sym )
        {
            case SDLK_UP: yVel += SQUARE_HEIGHT / 2; break;
            case SDLK_DOWN: yVel -= SQUARE_HEIGHT / 2; break;
            case SDLK_LEFT: xVel += SQUARE_WIDTH / 2; break;
            case SDLK_RIGHT: xVel -= SQUARE_WIDTH / 2; break;
        }
    }
}

void Square::move()
{
    //Move the square left or right
    x += xVel;

    //If the square went too far
    if( ( x < 0 ) || ( x + SQUARE_WIDTH > SCREEN_WIDTH ) )
    {
        //Move back
        x -= xVel;
    }

    //Move the square up or down
    y += yVel;

    //If the square went too far
    if( ( y < 0 ) || ( y + SQUARE_HEIGHT > SCREEN_HEIGHT ) )
    {
        //Move back
        y -= yVel;
    }
}

void getTexture()
{
    GLuint texture; // Texture object handle

    SDL_Surface *surface; // Gives us the information to make the texture

    if ( (surface = SDL_LoadBMP("image.bmp")) ) { 

        // Check that the image's width is a power of 2
        if ( (surface->w & (surface->w - 1)) != 0 ) {
            printf("warning: image.bmp's width is not a power of 2\n");
        }

        // Also check if the height is a power of 2
        if ( (surface->h & (surface->h - 1)) != 0 ) {
            printf("warning: image.bmp's height is not a power of 2\n");
        }

        // Have OpenGL generate a texture object handle for us
        glGenTextures( 1, &texture );

        // Bind the texture object
        glBindTexture( GL_TEXTURE_2D, texture );

        // Set the texture's stretching properties
        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );

        // Edit the texture object's image data using the information SDL_Surface gives us
        glTexImage2D( GL_TEXTURE_2D, 0, 3, surface->w, surface->h, 0, 
                      GL_BGR, GL_UNSIGNED_BYTE, surface->pixels );
    }     

    // Free the SDL_Surface only if it was successfully created
    if ( surface ) { 
        SDL_FreeSurface( surface );
    }

    // Bind the texture to which subsequent calls refer to
    glBindTexture( GL_TEXTURE_2D, texture );

}

void Square::show()
{
    //Move to offset
    glTranslatef( x, y, 0 );

    //Start quad
    glBegin( GL_QUADS );
        // Top-left vertex (corner)
        glTexCoord2i( 0, 0 );
        glVertex3f( 100, 100, 0 );

        // Bottom-left vertex (corner)
        glTexCoord2i( 1, 0 );
        glVertex3f( 228, 100, 0 );

        // Bottom-right vertex (corner)
        glTexCoord2i( 1, 1 );
        glVertex3f( 228, 228, 0 );

        // Top-right vertex (corner)
        glTexCoord2i( 0, 1 );
        glVertex3f( 100, 228, 0 );
    glEnd();

    //Reset
    glLoadIdentity();
}

Timer::Timer()
{
    //Initialize the variables
    startTicks = 0;
    pausedTicks = 0;
    paused = false;
    started = false;
}

void Timer::start()
{
    //Start the timer
    started = true;

    //Unpause the timer
    paused = false;

    //Get the current clock time
    startTicks = SDL_GetTicks();
}

void Timer::stop()
{
    //Stop the timer
    started = false;

    //Unpause the timer
    paused = false;
}

void Timer::pause()
{
    //If the timer is running and isn't already paused
    if( ( started == true ) && ( paused == false ) )
    {
        //Pause the timer
        paused = true;

        //Calculate the paused ticks
        pausedTicks = SDL_GetTicks() - startTicks;
    }
}

void Timer::unpause()
{
    //If the timer is paused
    if( paused == true )
    {
        //Unpause the timer
        paused = false;

        //Reset the starting ticks
        startTicks = SDL_GetTicks() - pausedTicks;

        //Reset the paused ticks
        pausedTicks = 0;
    }
}

int Timer::get_ticks()
{
    //If the timer is running
    if( started == true )
    {
        //If the timer is paused
        if( paused == true )
        {
            //Return the number of ticks when the timer was paused
            return pausedTicks;
        }
        else
        {
            //Return the current time minus the start time
            return SDL_GetTicks() - startTicks;
        }
    }

    //If the timer isn't running
    return 0;
}

bool Timer::is_started()
{
    return started;
}

bool Timer::is_paused()
{
    return paused;
}

int main( int argc, char *argv[] )
{
    //Quit flag
    bool quit = false;

    //Initialize
    if( init() == false )
    {
        return 1;
    }

    //Our square object
    Square square;

    getTexture();

    //The frame rate regulator
    Timer fps;

    //Wait for user exit
    while( quit == false )
    {
        //Start the frame timer
        fps.start();

        //While there are events to handle
        while( SDL_PollEvent( &event ) )
        {
            //Handle key presses
            square.handle_input();

            if( event.type == SDL_QUIT )
            {
                quit = true;
            }
        }

        //Move the square
        square.move();

        //Clear the screen
        glClear( GL_COLOR_BUFFER_BIT );

        //Show the square
        square.show();

        //Update screen
        SDL_GL_SwapBuffers();

        //Cap the frame rate
        if( fps.get_ticks() < 1000 / FRAMES_PER_SECOND )
        {
            SDL_Delay( ( 1000 / FRAMES_PER_SECOND ) - fps.get_ticks() );
        }
    }

    //Clean up
    clean_up();

    return 0;
}

You can paste this into MS Visual C++ 2010 ( What I'm using ). Please give me suggestions if its better to do it differently or any other suggestions you may have. Thank you.

Mat
  • 202,337
  • 40
  • 393
  • 406
ALF
  • 47
  • 1
  • 7
  • 1
    New to C++? I'm obliged to recommend [a good introductory C++ book](http://stackoverflow.com/q/388242/46642). :) – R. Martinho Fernandes Dec 22 '11 at 02:38
  • 5
    Have you tried using a debugger to figure out exactly where the exception is being thrown? – David Brown Dec 22 '11 at 02:40
  • "Disassembly" in Visual C says: 0020FEE9 movzx ebx,byte ptr [esi+2]. Not sure if that helps or not. – ALF Dec 22 '11 at 02:56
  • @ALF: which source line does that correspond to? – sarnold Dec 22 '11 at 02:57
  • @sarnold Thats the problem.. It compiles without errors. Its when I run it that the error comes up.(doesn't say which line) – ALF Dec 22 '11 at 02:59
  • 2
    If you're new to C++, the *last* thing you need to be doing is graphics programming. Try to understand how C++ works *first*. Graphics is not a task for a beginning programmer. – Nicol Bolas Dec 22 '11 at 03:01
  • @ALF: Are you running it in Visual Studio? It should break on that line, giving you a call stack and everything. – Nicol Bolas Dec 22 '11 at 03:01
  • @Nicol: I find it helps to learn a language if you've got an actual problem to work on. One can only play around with pretend shapes or cars or something for so long... – sarnold Dec 22 '11 at 03:07
  • compiled and ran for me on linux .. moved the square around a bit .. no exceptions .. no texture showing though .. tried in 'gdb' debugger .. didn't see any exceptions. I found it needed a full path to load the bitmap and it needed to be without RLE encoding, but still didn't display it. (I used a 64x64 pic of tux). – matiu Dec 22 '11 at 03:27
  • You should use the debugger to investigate which line actually causes the error. – Kos Dec 22 '11 at 10:23

2 Answers2

1

It appears you're calling glBindTexture() twice on the same texture; I can't say that's the source of the problem, but I think you should probably delete the second instance (where texture might be uninitialized if the if() branch wasn't taken).

sarnold
  • 102,305
  • 22
  • 181
  • 238
  • Nice catch. Calling it twice on the same texture is not problematic (it's redundant, but shouldn't be an issue). And sadly, calling it with an indeterminate value will also work. Before OpenGL 3 (as is the case here), using a texture object handle that was not generated does generate it automatically. So, it may be causing some issues, but I don't think it would cause an exception. +1 anyway. – R. Martinho Fernandes Dec 22 '11 at 03:12
  • Since it's just an integer, doing _real_ "indeterminate" checks would be too much to do anyhow, but it could at least make sure that the value is one that was handed out earlier. (How often does mapping a texture really happen that removing error checks for performance makes sense?) Thanks for the warning. :) – sarnold Dec 22 '11 at 03:19
1

I can not really reproduce your problem. The program executes just fine, and with adding a glEnable(GL_TEXTURE_2D) it even shows a textures square. Note that you should not to input handling in the object's classes, but by a dedicated input handler, that delegates the input events' outcomes to the objects. And this is not Java, you don't have to put everything in a class, especially with libraries like SDL which are class agnostic. getTextures was declared a member function in your code, but not defined one.

After making those 4 changes the code in http://pastebin.com/c58Hmw9Z executes as expected. BTW: Since OpenGL-2 textures may have arbitrary resolutions.

datenwolf
  • 159,371
  • 13
  • 185
  • 298
  • OK, From what you have helped me with, it looks like something is not configured correctly. When I push f10( Run to Cursor) and it takes me to WinMainCRTStartup(void)? I tried disabling /GS but I'm still getting the exact same error. – ALF Dec 22 '11 at 17:26
  • Thank you. Had to restart the project configuring everything and re-downloaded all the dlls. At some point I must have changed something.. not sure though. – ALF Dec 22 '11 at 17:46