Lesson 1: Textured Cube
In this tutorial we will explain to you how to make a textured cube using OpenGL and SDL. You will need to have the GNU C Compiler (short gcc) installed. Furthermore you of course need OpenGL and SDL installed. If you are on Ubuntu Linux you can use the commands
sudo apt-get install libsdl*
sudo apt-get install gcc*
Once you have the environment set up, lets get started
First create a directory for your project called /opengl/. Create a file called cube.c using your favorite editor inside this directory.
Paste the following code:
/* * OpenGL Textured Cube * https://talkera.org.cp-in-1.webhostbox.net/opengl/ * http://openglsamples.sf.net * * Compilation trough: * gcc cube.c -lglut -lGL -lGLU -lSDL * */ #include#include #include #include #include "SDL/SDL.h" /* screen width, height, and bit depth */ #define SCREEN_WIDTH 640 #define SCREEN_HEIGHT 480 #define SCREEN_BPP 16 /* Setup useful booleans */ #define TRUE 1 #define FALSE 0 /* This is our SDL surface */ SDL_Surface *surface; /* Used for rotating the cube */ GLfloat rotationXaxis; GLfloat rotationYaxis; GLfloat rotationZaxis; /* Storage For One Texture ( NEW ) */ GLuint texture[1]; /* Release resources and quit */ void Quit( int returnCode ) { SDL_Quit( ); exit( returnCode ); } /* Loads in a bitmap as a GL texture */ int LoadGLTextures( ) { int Status = FALSE; /* Create storage space for the texture */ SDL_Surface *TextureImage[1]; /* Load The Bitmap into Memory */ if ((TextureImage[0] = SDL_LoadBMP("data/texture.bmp"))) { Status = TRUE; glGenTextures( 1, &texture[0] ); glBindTexture( GL_TEXTURE_2D, texture[0] ); glTexImage2D( GL_TEXTURE_2D, 0, 3, TextureImage[0]->w, TextureImage[0]->h, 0, GL_BGR, GL_UNSIGNED_BYTE, TextureImage[0]->pixels ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); } /* Free up some memory */ if ( TextureImage[0] ) SDL_FreeSurface( TextureImage[0] ); return Status; } /* function to reset our viewport after a window resize */ int resizeWindow( int width, int height ) { /* Height / width ration */ GLfloat ratio; /* Protect against a divide by zero */ if ( height == 0 ) height = 1; ratio = ( GLfloat )width / ( GLfloat )height; /* Setup our viewport. */ glViewport( 0, 0, ( GLint )width, ( GLint )height ); /* * change to the projection matrix and set * our viewing volume. */ glMatrixMode( GL_PROJECTION ); glLoadIdentity( ); /* Set our perspective */ gluPerspective( 45.0f, ratio, 0.1f, 100.0f ); /* Make sure we're chaning the model view and not the projection */ glMatrixMode( GL_MODELVIEW ); /* Reset The View */ glLoadIdentity( ); return( TRUE ); } /* function to handle key press events */ void handleKeyPress( SDL_keysym *keysym ) { switch ( keysym->sym ) { case SDLK_ESCAPE: /* ESC key was pressed */ Quit( 0 ); break; case SDLK_F1: /* F1 key was pressed * this toggles fullscreen mode */ SDL_WM_ToggleFullScreen( surface ); break; default: break; } return; } /* OpenGL initialization function */ int initGL( GLvoid ) { /* Load in the texture */ if ( !LoadGLTextures( ) ) return FALSE; /* Enable Texture Mapping ( NEW ) */ glEnable( GL_TEXTURE_2D ); /* Enable smooth shading */ glShadeModel( GL_SMOOTH ); /* Set the background black */ glClearColor( 0.0f, 0.0f, 0.0f, 0.5f ); /* Depth buffer setup */ glClearDepth( 1.0f ); /* Enables Depth Testing */ glEnable( GL_DEPTH_TEST ); /* The Type Of Depth Test To Do */ glDepthFunc( GL_LEQUAL ); /* Really Nice Perspective Calculations */ glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST ); return( TRUE ); } /* Here goes our drawing code */ int drawGLScene( GLvoid ) { /* Clear The Screen And The Depth Buffer */ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); /* Move Into The Screen 5 Units */ glLoadIdentity( ); glTranslatef( 0.0f, 0.0f, -5.0f ); glRotatef( rotationXaxis, 1.0f, 0.0f, 0.0f); /* Rotate On The X Axis */ glRotatef( rotationYaxis, 0.0f, 1.0f, 0.0f); /* Rotate On The Y Axis */ glRotatef( rotationZaxis, 0.0f, 0.0f, 1.0f); /* Rotate On The Z Axis */ /* Select Our Texture */ glBindTexture( GL_TEXTURE_2D, texture[0] ); /* * Draw the cube. A cube consists of six quads, with four coordinates (glVertex3f) * per quad. * */ glBegin(GL_QUADS); /* Front Face */ glTexCoord2f( 0.0f, 1.0f ); glVertex3f( -1.0f, -1.0f, 1.0f ); glTexCoord2f( 1.0f, 1.0f ); glVertex3f( 1.0f, -1.0f, 1.0f ); glTexCoord2f( 1.0f, 0.0f ); glVertex3f( 1.0f, 1.0f, 1.0f ); glTexCoord2f( 0.0f, 0.0f ); glVertex3f( -1.0f, 1.0f, 1.0f ); /* Back Face */ glTexCoord2f( 0.0f, 0.0f ); glVertex3f( -1.0f, -1.0f, -1.0f ); glTexCoord2f( 0.0f, 1.0f ); glVertex3f( -1.0f, 1.0f, -1.0f ); glTexCoord2f( 1.0f, 1.0f ); glVertex3f( 1.0f, 1.0f, -1.0f ); glTexCoord2f( 1.0f, 0.0f ); glVertex3f( 1.0f, -1.0f, -1.0f ); /* Top Face */ glTexCoord2f( 1.0f, 1.0f ); glVertex3f( -1.0f, 1.0f, -1.0f ); glTexCoord2f( 1.0f, 0.0f ); glVertex3f( -1.0f, 1.0f, 1.0f ); glTexCoord2f( 0.0f, 0.0f ); glVertex3f( 1.0f, 1.0f, 1.0f ); glTexCoord2f( 0.0f, 1.0f ); glVertex3f( 1.0f, 1.0f, -1.0f ); /* Bottom Face */ /* Top Right Of The Texture and Quad */ glTexCoord2f( 0.0f, 1.0f ); glVertex3f( -1.0f, -1.0f, -1.0f ); glTexCoord2f( 1.0f, 1.0f ); glVertex3f( 1.0f, -1.0f, -1.0f ); glTexCoord2f( 1.0f, 0.0f ); glVertex3f( 1.0f, -1.0f, 1.0f ); glTexCoord2f( 0.0f, 0.0f ); glVertex3f( -1.0f, -1.0f, 1.0f ); /* Right face */ glTexCoord2f( 0.0f, 0.0f ); glVertex3f( 1.0f, -1.0f, -1.0f ); glTexCoord2f( 0.0f, 1.0f ); glVertex3f( 1.0f, 1.0f, -1.0f ); glTexCoord2f( 1.0f, 1.0f ); glVertex3f( 1.0f, 1.0f, 1.0f ); glTexCoord2f( 1.0f, 0.0f ); glVertex3f( 1.0f, -1.0f, 1.0f ); /* Left Face */ glTexCoord2f( 1.0f, 0.0f ); glVertex3f( -1.0f, -1.0f, -1.0f ); glTexCoord2f( 0.0f, 0.0f ); glVertex3f( -1.0f, -1.0f, 1.0f ); glTexCoord2f( 0.0f, 1.0f ); glVertex3f( -1.0f, 1.0f, 1.0f ); glTexCoord2f( 1.0f, 1.0f ); glVertex3f( -1.0f, 1.0f, -1.0f ); glEnd( ); /* Draw it to the screen */ SDL_GL_SwapBuffers( ); /* Rotate Cube */ rotationXaxis += 0.3f; rotationYaxis += 0.2f; return( TRUE ); } /* https://talkera.org.cp-in-1.webhostbox.net/opengl/ */ int main( int argc, char **argv ) { /* Flags to pass to SDL_SetVideoMode */ int videoFlags; /* main loop variable */ int done = FALSE; /* used to collect events */ SDL_Event event; /* this holds some info about our display */ const SDL_VideoInfo *videoInfo; /* whether or not the window is active */ int isActive = TRUE; /* initialize SDL */ if ( SDL_Init( SDL_INIT_VIDEO ) hw_available ) videoFlags |= SDL_HWSURFACE; else videoFlags |= SDL_SWSURFACE; /* This checks if hardware blits can be done */ if ( videoInfo->blit_hw ) videoFlags |= SDL_HWACCEL; /* Sets up OpenGL double buffering */ SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); /* get a SDL surface */ surface = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, videoFlags ); /* Verify there is a surface */ if ( !surface ) { fprintf( stderr, "Video mode set failed: %s\n", SDL_GetError( ) ); Quit( 1 ); } /* initialize OpenGL */ initGL( ); /* resize the initial window */ resizeWindow( SCREEN_WIDTH, SCREEN_HEIGHT ); /* wait for events */ while ( !done ) { /* handle the events in the queue */ while ( SDL_PollEvent( &event ) ) { switch( event.type ) { case SDL_ACTIVEEVENT: if ( event.active.gain == 0 ) isActive = FALSE; else isActive = TRUE; break; case SDL_VIDEORESIZE: /* handle resize event */ surface = SDL_SetVideoMode( event.resize.w, event.resize.h, 16, videoFlags ); if ( !surface ) { fprintf( stderr, "Could not get a surface after resize: %s\n", SDL_GetError( ) ); Quit( 1 ); } resizeWindow( event.resize.w, event.resize.h ); break; case SDL_KEYDOWN: /* handle key presses */ handleKeyPress( &event.key.keysym ); break; case SDL_QUIT: /* handle quit requests */ done = TRUE; break; default: break; } } /* draw the scene */ if ( isActive ) drawGLScene( ); } /* clean ourselves up and exit */ Quit( 0 ); /* Should never get here */ return( 0 ); }
Then create a directory within it called /data/. Save this texture image into /opengl/data/ as a bitmap called texture.bmp.
Finally, open a terminal, go to the directory /opengl/ and type this command
gcc cube.c -lglut -lGL -lGLU -lSDL
This command compiles the source code above into a binary called a.out. Run the program using the command
./a.out
If you want another program name you could use
gcc cube.c -o cube -lglut -lGL -lGLU -lSDL
Explanation
A cube consists of 6 faces (also referred to as quads or squares). Every face or square has 4 individual points, specified by glVertex3f.
glVertex3f( -1.0f, 1.0f, -1.0f ); glVertex3f( -1.0f, 1.0f, 1.0f ); glVertex3f( 1.0f, 1.0f, 1.0f ); glVertex3f( 1.0f, 1.0f, -1.0f );
The command
glBegin(GL_QUADS);
is necessary to tell OpenGL to draw quads. OpenGL has support for various shapes, such as triangles and quads.
The command
glTranslatef( 0.0f, 0.0f, -5.0f );
set the camera. Thus our camera is at (0,0,-5) and the position of the cube is around (0,0,1). If we would set it to
glTranslatef( 0.0f, 0.0f, -15.0f );
the camera would be more far away, and thus the cube would appear smaller.
The commands
glRotatef( rotationXaxis, 1.0f, 0.0f, 0.0f); /* Rotate On The X Axis */ glRotatef( rotationYaxis, 0.0f, 1.0f, 0.0f); /* Rotate On The Y Axis */ glRotatef( rotationZaxis, 0.0f, 0.0f, 1.0f); /* Rotate On The Z Axis */
rotate the cube around their axis. You will notice the glRotatef function has four parameters. The last three are x, y and z-rotation.
The command
SDL_GL_SwapBuffers( );
is mandatory. It sends all previously given drawing commands to the videocard GPU, thus drawing on screen. The rest of the code is initialization code.