Rotating 2D Sprite: In my previous post i showed how to move a 2D sprite in two dimensional screen using Opengl with SDL. Now in this post i’l show how to rotate a 2D sprite using Opengl with SDL.

In Opengl, rotation can be made about x axis, y axis and z axis. In different axis rotation occurs differently like:

about X axis: like closing your laptop

about Y axis: like turning a page in a book

about Z axis: like the hands of a clock

So to rotate our 2D sprite we use glRotatef(angle,x,y,z). If you want to rotate about x axis the the value of x will be 1.0, y and z will be 0.0. How much angle do you want to rotate your sprite is determined by the value of angle to glRotatef() parameter.

So here is the drawImage() function to draw and rotate the 2D sprite:

void drawImage()
{
// Clear the screen before drawing
glClear( GL_COLOR_BUFFER_BIT );

glTranslatef(300.0,200.0,0.0);

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

glBegin( GL_QUADS );
// Top-left vertex (corner)
glTexCoord2i( 0, 0 );

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

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

// Top-right vertex (corner)
glTexCoord2i( 0, 1 );

glEnd();
glLoadIdentity();
SDL_GL_SwapBuffers();
}

In opengl, rotation happens about origin of the screen i.e(0,0). But we want rotation to happen about the centre of the 2D sprite. So instead of drawing the top left vertex at 0,0 you draw it at -imgWidth / 2, -imgHeight / 2, you draw the bottom right vertex at imgWidth / 2, imgHeight / 2, etc, etc. Our size of the quad is 128*128 as we are mapping the texture of size 128*128 to quad. So we’ll draw our quad as (-64,-64) to (64,64) so that (0,0) is directly at the center of the 2D sprite and when we rotate our sprite then rotation will happen about the center of the 2D sprite.


while( quit == false )
{
if( SDL_PollEvent( &event ) )
{
//If a key was pressed
if( event.type == SDL_KEYDOWN )
{
//Adjust the velocity
switch( event.key.keysym.sym )
{
case SDLK_LEFT:
LEFT=true;
break;
case SDLK_RIGHT:
RIGHT=true;
break;
case SDLK_ESCAPE:
quit=true;
break;
}
}
//If a key was released
else if( event.type == SDL_KEYUP )
{
//Adjust the velocity
switch( event.key.keysym.sym )
{
case SDLK_LEFT:
LEFT=false;
break;
case SDLK_RIGHT:
RIGHT=false;
break;
}
}
}

if(LEFT==true){
spin=spin+2;
if(spin>360.0)
spin=spin-360.0;
drawImage();
}
else if(RIGHT==true){
spin=spin-2;
if(spin>360.0)
spin=spin-360.0;
drawImage();
}

In while loop inside main function we are handling key event. As user presses left arrow key then we increment the angle and redraw the 2D sprite. I have used the same style as in previous posts i.e i have used two bool state variables(LEFT and RIGHT), when user presses left arrow key then LEFT becomes TRUE then angle is updated and 2D sprite is redrawn with rotation.

In this program, when left arrow key is pressed then sprite rotates towards east and when right arrow key is pressed then sprite rotates towards west.

 2D Sprite after rotation

2D Sprite after rotation

Here is the full source code

#include "SDL.h"
#include "SDL_image.h"
#include "SDL_opengl.h"

#include <stdio.h>

GLuint texture=NULL; //this is a handle to our texture object
GLenum texture_format=NULL;
GLint nofcolors;

SDL_Event event;

static GLfloat spin=0.0;
float x=100,y=100;
bool LEFT=false;
bool RIGHT=false;

int loadImage()
{
SDL_Surface *surface; // this surface will tell us the details of the image

if ( (surface = IMG_Load("flower.png")) ) {

// 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");
}

//get number of channels in the SDL surface
nofcolors=surface->format->BytesPerPixel;

//contains an alpha channel
if(nofcolors==4)
{
if(surface->format->Rmask==0x000000ff)
texture_format=GL_RGBA;
else
texture_format=GL_BGRA;
}
else if(nofcolors==3) //no alpha channel
{
if(surface->format->Rmask==0x000000ff)
texture_format=GL_RGB;
else
texture_format=GL_BGR;
}
else
{
printf("warning: the image is not truecolor...this will break ");
}

// 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 );

glTexImage2D( GL_TEXTURE_2D, 0, nofcolors, surface->w, surface->h, 0,
texture_format, GL_UNSIGNED_BYTE, surface->pixels );
}
else {
printf("SDL could not load image.bmp: %s\n", SDL_GetError());
SDL_Quit();
return 1;
}

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

void drawImage()
{
// Clear the screen before drawing
glClear( GL_COLOR_BUFFER_BIT );

glTranslatef(300.0,200.0,0.0);
glRotatef( spin, 0.0, 0.0, 1.0 );

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

glBegin( GL_QUADS );
// Top-left vertex (corner)
glTexCoord2i( 0, 0 );
glVertex3f( -64, -64, 0 );

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

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

// Top-right vertex (corner)
glTexCoord2i( 0, 1 );
glVertex3f( -64, 64, 0 );
glEnd();
glLoadIdentity();

SDL_GL_SwapBuffers();
}

int init()
{
SDL_Surface *screen;

// Slightly different SDL initialization
if ( SDL_Init(SDL_INIT_VIDEO) != 0 ) {
printf("Unable to initialize SDL: %s\n", SDL_GetError());
return 1;
}

SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );

screen = SDL_SetVideoMode( 640, 480, 16, SDL_OPENGL|SDL_FULLSCREEN);
if ( !screen ) {
printf("Unable to set video mode: %s\n", SDL_GetError());
return 1;
}
}

void init_GL()
{
// Set the OpenGL state after creating the context with SDL_SetVideoMode

glClearColor( 0, 0, 0, 0 );

glEnable( GL_TEXTURE_2D ); // Need this to display a texture

glViewport( 0, 0, 640, 480 );

glMatrixMode( GL_PROJECTION );
glLoadIdentity();

glOrtho( 0, 640, 480, 0, -1, 1 );

glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
}

void clean_up()
{
glDeleteTextures( 1, &texture );

SDL_Quit();
}

int main(int argc, char *argv[])
{
//Make sure the program waits for a quit
bool quit = false;

init();
init_GL();
loadImage();
drawImage();

while( quit == false )
{
if( SDL_PollEvent( &event ) )
{
//If a key was pressed
if( event.type == SDL_KEYDOWN )
{
//Adjust the velocity
switch( event.key.keysym.sym )
{
case SDLK_LEFT:
LEFT=true;
break;
case SDLK_RIGHT:
RIGHT=true;
break;
case SDLK_ESCAPE:
quit=true;
break;
}
}
//If a key was released
else if( event.type == SDL_KEYUP )
{
//Adjust the velocity
switch( event.key.keysym.sym )
{
case SDLK_LEFT:
LEFT=false;
break;
case SDLK_RIGHT:
RIGHT=false;
break;
}
}
}

if(LEFT==true){
spin=spin+2;
if(spin>360.0)
spin=spin-360.0;
drawImage();
}
else if(RIGHT==true){
spin=spin-2;
if(spin>360.0)
spin=spin-360.0;
drawImage();
}

}

clean_up();
return 0;
}

So Thats it. I hope this of any help to you and gives u some idea on rotation of 2D sprite using opengl and sdl.

Gracias.