OpenGL, DevIL, C++, How to animate tilesheet?

I’ve made my gif into a tilesheet and can render it just fine. Now I need to know how to make it change the Y coordinate while the program is running to animate it without crashing.


#include "LUtil.h"
#include <IL/il.h>
#include <IL/ilu.h>
#include "LSpriteSheet.h"

int add = 0;
int zoom = 0;
int factor = 0;
int factor2 = 0;
float y = 0.f;
int scroll = 0;
GLfloat gCameraX = 0.f, gCameraY = 0.f, gCameraZ = 0.f;

//Sprite texture

LSpriteSheet gArrowSprites;
LSpriteSheet gGIFSprites;

bool initGL()
{
        //Initialize GLEW
    GLenum glewError = glewInit();
    if( glewError != GLEW_OK )
    {
        printf( "Error initializing GLEW! %s
", glewGetErrorString( glewError ) );
        return false;
    }

    //Make sure OpenGL 2.1 is supported
    if( !GLEW_VERSION_2_1 )
    {
        printf( "OpenGL 2.1 not supported!
" );
        return false;
    }

    //Set the viewport
    glViewport( 0.f, 0.f, SCREEN_WIDTH, SCREEN_HEIGHT );

    //Initialize Projection Matrix
    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();
    glOrtho( 0.0, SCREEN_WIDTH, SCREEN_HEIGHT, 0.0, 5.0, -5.0 );

    //Initialize Modelview Matrix
    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();

    glPushMatrix();

    //Initialize clear color
    glClearColor( 0.f, 0.f, 0.f, 1.f );

    //Enable texturing
    glEnable( GL_TEXTURE_2D );

    glEnable( GL_BLEND );
    glDisable( GL_DEPTH_TEST );
    glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );

    //Check for error
    GLenum error = glGetError();
    if( error != GL_NO_ERROR )
    {
        printf( "Error initializing OpenGL! %s
", gluErrorString(error));
        return false;
    }

    //Initialize DevIL
    ilInit();
    ilClearColour( 255, 255, 255, 000 );

    //Check for error
    ILenum ilError = ilGetError();
    if( ilError != IL_NO_ERROR )
    {
        printf( "Error initializing DevIL! %s
", iluErrorString(ilError) );
        return false;
    }

    return true;
}


bool loadMedia()
{

    //Load texture
    if( !gArrowSprites.loadTextureFromFile( "StillSpriteSheet.png" ) )
    {
        printf( "Unable to load texture!
" );
        return false;
    }
LFRect clip = { 0.f, 0.f, 330.f, 355.f };

	//Top left
	clip.x = 0.f;
	clip.y = 0.f;
	gArrowSprites.addClipSprite( clip );

	//Top right
	clip = {0.f, 0.f, 310.f, 480.f};

	clip.x = 331.f;
	clip.y = 0.f;
	gArrowSprites.addClipSprite( clip );

	clip = {0.f, 0.f, 330.f, 125.f};
	//Bottom left
	clip.x = 0.f;
	clip.y = 355.f;

	gArrowSprites.addClipSprite( clip );

	clip = { 0.f, 0.f, 330.f, 355.f };

	//Top left
	clip.x = 0.f;
	clip.y = 480.f;
	gArrowSprites.addClipSprite( clip );

	//Top right
	clip = {0.f, 0.f, 310.f, 480.f};

	clip.x = 331.f;
	clip.y = 480.f;
	gArrowSprites.addClipSprite( clip );

	clip = {0.f, 0.f, 330.f, 125.f};
	//Bottom left
	clip.x = 0.f;
	clip.y = 835.f;

	gArrowSprites.addClipSprite( clip );
	//Generate VBO
	if( !gArrowSprites.generateDataBuffer() )
	{
	    printf( "Unable to clip sprite sheet!
" );
		return false;
	}
    if( !gGIFSprites.loadTextureFromFile( "TileSheet.png" ) )
    {
        printf( "Unable to load texture!
" );
        return false;
    }

    clip = {0.f, 0.f, 213.f, 214.f};

    clip.x = 0.f;
    clip.y = y;

for (scroll = 0; scroll < 40; ++scroll, clip.y += 214.f, SCREEN_FPS % 10 ){
        glutSwapBuffers();
    if(scroll == 39){
        scroll = 0;
    }
}

	gGIFSprites.addClipSprite( clip );

	if( !gGIFSprites.generateDataBuffer() )
	{
	    printf( "Unable to clip sprite sheet!
" );
		return false;
	}
    return true;
}

void update()
{

}

void render()
{
    //Clear color buffer

    glClear( GL_COLOR_BUFFER_BIT );

    glMatrixMode(GL_MODELVIEW);
    glPopMatrix();

    glPushMatrix();

if(add == 0){
        if(zoom < 101){
        double const f_zoom = 1.0 + 0.1 * zoom;
        glScaled(f_zoom, f_zoom, f_zoom);
        }
        if(zoom < -10){
        double const f_zoom = 1.0 - 0.1 * zoom;
        glScaled(f_zoom, f_zoom, f_zoom);
        }

	glTranslatef( -100.f, 178.f, 0.f );
	gArrowSprites.renderSprite( 0 );

	//Render top right arrow
    glTranslatef( +100.f, -178.f, 0.f );
	glTranslatef( 1240.f, 240.f, 0.f );
	gArrowSprites.renderSprite( 1 );

	//Render bottom left arrow
    glTranslatef( -1240.f, +240.f, 0.f );
	glTranslatef( 620.f, 500.f ,0.f );
	gArrowSprites.renderSprite( 2 );

    glTranslatef( -620.f, -500.f, 0.f );
	glTranslatef( 620.f, 0.f , 0.f );
	gGIFSprites.renderSprite( 0 );

}
	if(add == 1){
        if(zoom < 101){
        double const f_zoom = 1.0 + 0.1 * zoom;
        glScaled(f_zoom, f_zoom, f_zoom);
        }
        if(zoom < -10){
        double const f_zoom = 1.0 - 0.1 * zoom;
        glScaled(f_zoom, f_zoom, f_zoom);
        }

	glTranslatef( -100.f, 178.f, 0.f );
	gArrowSprites.renderSprite( 3 );

    glTranslatef( +100.f, -178.f, 0.f );
	glTranslatef( 1240.f, 240.f, 0.f );
	gArrowSprites.renderSprite( 4 );

    glTranslatef( -1240.f, +240.f, 0.f );
	glTranslatef( 620.f, 500.f ,0.f );
	gArrowSprites.renderSprite( 5 );
	}

	glLoadIdentity();


    glutSwapBuffers();

}
void handleKeys( unsigned char key, int x, int y )
{
    //If the user presses q
   if( key == 'q' && add == 0)
    {
                    add++;
    }
   else if( key == 'q' && add == 1)
    {
        add--;
    }
        //Update the sprite rectangles so the texture change takes effect
        if( key == 27 ) {
            exit(0);
        }
		if(key == 'a') {
		gCameraX += 8.f;
		factor--;
		factor2++;
		}
		else if (key == 'd') {
		gCameraX -= 8.f;
		factor++;
		factor2--;
		}
		else if (key == 'w') {
	    gCameraY += 8.f;
		}
		else if (key == 's') {
		gCameraY -= 8.f;
		}
		else if (key == '+' && zoom != 100) {
        zoom += 1;
        if(factor >= 19) {
        gCameraX -= 64.f;
        }
        if(factor2 >= 33){
            gCameraX += 16.f;
        }
        else{
            gCameraX -= 64.f;
            gCameraY -= 50.f;
        }
		}
		else if (key == '-' && zoom != -9) {
        zoom -= 1;
        if(factor >= 19){
            gCameraX += 64.f;
        }
        if(factor2 >= 33){
        gCameraX -= 32.f;
        }
        else{
        gCameraX += 64.f;
        gCameraY += 50.f;
		}
		}
		    //Take saved matrix off the stack and reset it
    glMatrixMode( GL_MODELVIEW );
    glPopMatrix();
    glLoadIdentity();

    //Move camera to position
    glTranslatef( gCameraX, gCameraY, gCameraZ );

    //Save default matrix again with camera translation
    glPushMatrix();
}

Right now the while loop causes a crash and I assume that it’s because I don’t have an FPS limit on it, but I don’t know how to implement that.
Also I know the loop can run because when I remove the if statement that resets the loop it doesn’t crash but it stops on the last frame.
Any help?

EDIT: Updated the loop.

Update on issue: In the new loop, if 39 is changed to 40 it stops on the last frame. If 39 is kept as it is it will crash while on a black screen.

Sounds like a memory leak.

How can I fix it though?

you just need a clock
then in your main loop, you only call update() and render IF enough time is passed since the last frame
BUT: by default, vsync is on, which means your fps cant get over 60 (frequency of the monitor)
only if you disable vsync, fps can go up to about 3000 or so …



#define FPS_GOAL 60

... 
static double tnow(0), tlast(0), tframe(0);
tnow = m_time.GetTime();    // http://www.cplusplus.com/reference/chrono/high_resolution_clock/now/
tframe = tnow - tlast;
if (tframe < 1.0 / FPS_GOAL)
     continue;
tlast = tnow;

// update(tframe);
// render();

How can I fix it though?
First, confirm it by monitoring how much RAM your application uses while it is running. If you have a leak, it will show up clearly. RAM usage will go up until the app. crashes.

[QUOTE=john_connor;1282613]you just need a clock
then in your main loop, you only call update() and render IF enough time is passed since the last frame
BUT: by default, vsync is on, which means your fps cant get over 60 (frequency of the monitor)
only if you disable vsync, fps can go up to about 3000 or so …



#define FPS_GOAL 60

... 
static double tnow(0), tlast(0), tframe(0);
tnow = m_time.GetTime();    // http://www.cplusplus.com/reference/chrono/high_resolution_clock/now/
tframe = tnow - tlast;
if (tframe < 1.0 / FPS_GOAL)
     continue;
tlast = tnow;

// update(tframe);
// render();

[/QUOTE]

Yeah, that’s what I thought. But where am I supposed to put it? I’ve never made my own clock so I have no idea what to do with it.
Edit: I modified my loop a bit