Problems with getting animation active

Hi Forum,

I am using OpenGL / SDL on a Linux machine, I compile with gcc and I want to make a simple animation.

I have SDL as window manager and have successfully installed two timers that repeatedly call a function that updates my data. The function that updates the data (the position of my objects that I want to move) thereafter calls a function called “render_ball” (it’s a ball I wanna move) and the function render_ball calls glBegin and glEnd and then SDL_GL_SwapBuffers().

But no luck! My objects are frozen even though the coordinates of them change. I have been searching a very long time on the web and I have found numerous references to many functions with many different flags with relevant names such as SDL_DOUBLEBUF, SDL_GL_DOUBLEBUFFERING, etc, and I am trying very hard to combine everything into a working program, but I keep failing. Is there anyone who knows of a good synopsis of how to accomplish this. I’d rather not use GLUT but stick with SDL since I want to later incorporate sound and such.

Here’s the code:

<code>
#include <SDL/SDL.h>
#include <stdio.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <math.h>

void init(SDL_Surface ** screen)
{

/The following code does the initialization for Audio and Video/
int i_error=SDL_Init( SDL_INIT_EVERYTHING );

/*If initialization is unsuccessful, then quit */
if(i_error==-1)
exit(1);

atexit(SDL_Quit);

SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );

*screen = SDL_SetVideoMode(640, 480, 24, SDL_HWSURFACE | SDL_DOUBLEBUF | SDL_OPENGL );

if ( *screen == NULL )
{
fprintf(stderr, "Couldn’t set 640x480x8 video mode: %s.
",SDL_GetError());
exit(1);
}

glClearColor(0, 0, 0, 0);
glClearDepth(1.0f);
glViewport(0, 0, 640, 480);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 640, 480, 0, 1, -1);
glMatrixMode(GL_MODELVIEW);
glEnable(GL_TEXTURE_2D);
glLoadIdentity();

}

struct ball
{
int startx, starty;
int destx, desty;
float x, y;
float dx, dy;
float r, g, b;
SDL_Surface * screen;
};

void render_ball(struct ball * the_ball)
{
int k;

glFlush();

glBegin(GL_LINES);
glColor3f(the_ball->r,the_ball->g,the_ball->b);
for(k=0;k<20;k++)
{
glVertex3f(the_ball->x+20cos(3.1415926k/10),the_ball->y+20sin(3.1415926k/10),0);
glVertex3f(the_ball->x+20cos(3.1415926(k+1)/10),the_ball->y+20sin(3.1415926(k+1)/10),0);
}
glEnd();

SDL_GL_SwapBuffers();

}

float myabs(float x) { if(x>0)return x; else return -x; }

Uint32 move_ball(Uint32 interval, void * param)
{
struct ball * the_ball = (struct ball *) param;

if( myabs(the_ball->x - the_ball->destx) > myabs(the_ball->dx) )
the_ball->x += the_ball->dx;

if( myabs(the_ball->y - the_ball->desty) > myabs(the_ball->dy) )
the_ball->y += the_ball->dy;

render_ball(the_ball);

return interval;
}

int main(int argc,char* argv[])
{
SDL_Surface *screen;
SDL_Surface *ball_bmp;

int k;

struct ball red_ball, blue_ball;

SDL_TimerID timer, timer2;

int done;

init(&screen);

//This could be put in an init function:
red_ball.startx=50; red_ball.starty=50; red_ball.destx=50; red_ball.desty=50;
red_ball.x = (float)red_ball.startx; red_ball.y = (float)red_ball.starty;
red_ball.dx = 0.0; red_ball.dy = 0.0;
red_ball.r = 1; red_ball.g = 0; red_ball.b = 0;
red_ball.screen = screen;

blue_ball.startx=100; blue_ball.starty=50; blue_ball.destx=100; blue_ball.desty=50;
blue_ball.x = (float)blue_ball.startx; blue_ball.y = (float)blue_ball.starty;
blue_ball.dx = 0.0; blue_ball.dy = 0.0;
blue_ball.r = 0; blue_ball.g = 0; blue_ball.b = 1;
blue_ball.screen = screen;

render_ball(&red_ball);
render_ball(&blue_ball);

timer = SDL_AddTimer(20, move_ball, &red_ball);
SDL_Delay(10);
timer2 = SDL_AddTimer(20, move_ball, &blue_ball);

/Handle the keyboards events here. Catch the SDL_Quit event to exit/
done = 0;
while (!done)
{
SDL_Event event;

/* Check for events */
while (SDL_PollEvent (&event))
{
  switch (event.type)
  {
    case SDL_KEYDOWN:
      break;

    case SDL_MOUSEBUTTONDOWN: 
    {
      switch(event.button.button) 
      {
        case SDL_BUTTON_LEFT: 
        {
          
          red_ball.destx = event.button.x;
          red_ball.desty = event.button.y;

          red_ball.dx = (red_ball.destx - red_ball.x)/50.0;
          red_ball.dy = (red_ball.desty - red_ball.y)/50.0;

          break;
        }

        case SDL_BUTTON_RIGHT:
        {
          blue_ball.destx = event.button.x;
          blue_ball.desty = event.button.y;

          blue_ball.dx = (blue_ball.destx - blue_ball.x)/50.0;
          blue_ball.dy = (blue_ball.desty - blue_ball.y)/50.0;

          break;
        }

      }
    }
    break;

    case SDL_QUIT:
      done = 1;
      break;

    default:
      break;

  }
} 

}
}

</code>

Thank you
Johnny

Using two timers may not be the best solution … take a look at web example. showing how to do smooth animations. Putting all your rendering into one function rather than multiple timer callbacks is more robust.

The code there compiles on linux with


gcc -O3 -Wall -gstabs -DMINIGL `sdl-config --cflags`  SDL-GL-animate.c `sdl-config --libs` -lGL -lGLU

and is repeated here for convenience


/** A template for SDL based OpenGL applications that perform frame-rate independent animation.
 *
 * Unaltered, template draws an animated triangle. It indicates where
 * to add your own code in order to create your own SDL based OpenGL
 * application.
 *
 * IMPORTANT: It is recommended that you use the GLUT-animate template for
 * serious work instead as it is more versatile. However, this one is easier
 * to understand for beginners.
 *
 * by Hans de Ruiter
 *
 * License:
 * This source code can be used and/or modified without restrictions.

 * It is provided as is and the author disclaims all warranties, expressed 

 * or implied, including, without limitation, the warranties of

 * merchantability and of fitness for any purpose. The user must assume the

 * entire risk of using the Software.
 */

#ifdef _WIN32
#include <windows.h> 
#endif

#include "SDL.h"
#include <GL/gl.h>
#include <GL/glu.h>

#define WINDOW_TITLE "SDL-GL-animate Template"

#define WIDTH 640
#define HEIGHT 480

// The minimum time between frames (for frame-rate limiting)
#define MIN_FRAMETIME_MSECS 33

// rotation rate in degrees per second
#define ROTRATE 45.0f

static GLfloat rot = 0.0f;

// Global variables for measuring time (in milli-seconds)
int startTime;
int prevTime;

// ----- Function Prototypes -----
static void init(int w, int h);
static void reshape(GLsizei w, GLsizei h);
static void animate(int milliseconds);
static void render();


// ---- Function Implementations -----

int main(int argc, char** argv)
{
	SDL_Surface *screen;
	int done;
	Uint8 *keys;

	// Initialize
	SDL_Init(SDL_INIT_VIDEO);

	// Enable double-buffering
	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);

	// Create a OpenGL window
	screen = SDL_SetVideoMode(WIDTH, HEIGHT, 0, SDL_OPENGL | SDL_RESIZABLE);
	if( ! screen ) 
	{
		printf("Couldn't set %dx%d GL video mode: %s
", WIDTH, HEIGHT, SDL_GetError());
		SDL_Quit();
		exit(2);
	}
	SDL_WM_SetCaption(WINDOW_TITLE, WINDOW_TITLE);

	// ##### INSERT ANY ARGUMENT (PARAMETER) PARSING CODE HERE

	// Initialize the OpenGL context
	init(screen->w, screen->h);

	// Initialize the time variables
	startTime = SDL_GetTicks();
	prevTime = startTime;

	// The main loop
	done = 0;
	while(!done) 
	{
		SDL_Event event;

		// Rotates the triangle (this could be replaced with custom processing code)
		int currTime = SDL_GetTicks();
		int timeElapsed = currTime - prevTime;
		if(timeElapsed < MIN_FRAMETIME_MSECS)
		{
			// Not enough time has elapsed. Let's limit the frame rate
			SDL_Delay(MIN_FRAMETIME_MSECS - timeElapsed);
			currTime = SDL_GetTicks();
			timeElapsed = currTime - prevTime;
		}
		prevTime = currTime;
		animate(timeElapsed);

		// Respond to any events that occur
		while(SDL_PollEvent(&event))
		{
			switch(event.type) 
			{
			case SDL_VIDEORESIZE:
				screen = SDL_SetVideoMode(event.resize.w, event.resize.h, 0,
									SDL_OPENGL|SDL_RESIZABLE);
				if(screen)
				{
					reshape(screen->w, screen->h);
				} 
				else 
				{
					; // Oops, we couldn't resize for some reason. This should never happen
				}
				break;

			case SDL_QUIT:
				done = 1;
				break;

			// ##### INSERT CODE TO HANDLE ANY OTHER EVENTS HERE #####
			}
		}

		// Check for escape
		keys = SDL_GetKeyState(NULL);
		if( keys[SDLK_ESCAPE] ) {
			done = 1;
		}
	
		// Draw the screen
		render();
	}

  // Clean up and quit
  SDL_Quit();
  return 0;
}

static void init(int w, int h)
{
	// Set up the OpenGL state
	// ##### REPLACE WITH YOUR OWN OPENGL INIT CODE HERE #####
    glClearColor(0.0, 0.0, 0.0, 0.0);
	reshape(w, h);

	glEnable(GL_DEPTH_TEST);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	// ##### END OF INIT CODE #####
}

static void reshape(GLsizei w, GLsizei h)
{
	// Respond to a window resize event

	// ##### REPLACE WITH YOUR OWN RESHAPE CODE #####
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

	// Calculate the aspect ratio of the screen, and set up the
	// projection matrix (i.e., update the camera)
	gluPerspective(45.0f,(GLfloat)w/(GLfloat)h,0.1f,100.0f);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
	// ##### END OF RESHAPE CODE #####
}

static void animate(int milliseconds)
{
	// Moves objects to where they would be after the specified number of milliseconds

	// ##### REPLACE WITH YOUR OWN GAME/APP MAIN CODE HERE #####

	// Rotate the triangle
	rot += ROTRATE * milliseconds / 1000;

	// ##### END OF GAME/APP MAIN CODE #####
}

static void render()
{
	// Render the screen

	// ##### REPLACE THIS WITH YOUR OWN RENDERING CODE #####

	// Clear the screen
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	// Move and rotate the triangle
	glLoadIdentity();
	glTranslatef(0.0f,0.0f,-3.0f);
	glRotatef(rot, 0.0, 0.0, 1.0);

	// Draws a triangle
	glBegin(GL_TRIANGLES);
	glColor3f(1.0, 0.0, 0.0);
	glVertex3f(-1.0, -1.0, 0.0);
	glColor3f(0.0, 1.0, 0.0);
	glVertex3f(1.0, -1.0, 0.0);
	glColor3f(0.0, 0.0, 1.0);
	glVertex3f(0.0, 1.0, 0.0);
	glEnd();
	// ##### END OF RENDER CODE #####

	// Swap the buffers (if double-buffered) to show the rendered image
    SDL_GL_SwapBuffers();
}

Thank you very much. I have also solved the problem with a complete rewrite with much better structure than before. I would be very interested in seeing the GLUT-template that is recommended for more serious work, could you please post that one too?

I’ll post my newer solution soon also, but I think I want to delve into why it didn’t work first. I’m preparing the newer (working one) for a presentation that I am giving soon. It would be very interesting to include the GLUT-aspects in that presentation also. Right now I asked for a solution without GLUT because I am a beginner and I will do the presentation for beginners also.

Again, many thanks.

Johnny

On linux you can extract the lha files. For example after downloading the GLUT example just run


lha -x  GLUT-animate-template.lha

and compile with


g++ GLUT-animate.c  -lglut -lGLU