PDA

View Full Version : Problems with getting animation active



Johnny
03-30-2011, 01:52 PM
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.\n",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+20*cos(3.1415926*k/10),the_ball->y+20*sin(3.1415926*k/10),0);
glVertex3f(the_ball->x+20*cos(3.1415926*(k+1)/10),the_ball->y+20*sin(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(&amp;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(&amp;red_ball);
render_ball(&amp;blue_ball);

timer = SDL_AddTimer(20, move_ball, &amp;red_ball);
SDL_Delay(10);
timer2 = SDL_AddTimer(20, move_ball, &amp;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 (&amp;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

marshats
03-31-2011, 08:36 AM
Using two timers may not be the best solution ... take a look at web example. (http://hdrlab.org.nz/articles/amiga-os-articles/minigl-templates/frame-rate-independent-animation-using-sdl-and-opengl-with-frame-rate-limiting/) 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\n", 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(&amp;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();
}

Johnny
03-31-2011, 11:59 AM
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

marshats
03-31-2011, 08:39 PM
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