Is there anything you have to glEnable for glutBitmapCharacter to work? Because when I use that function, nothing shows up on the screen.

At the moment this is how I'm trying to draw: glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, 'A'); These are the things I've enabled:

glEnable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);

Recommended Answers

All 3 Replies

This is a highly talked about subject.

Its interesting that I very recently tinkered with Font rendering using OpenGL and GLUT. If you don't mind using open source libraries to link to your code, then this code might help you out.

You can copy/paste this code straight into gcc, link the appropriate libraries and it will run. You can use this as a foundation to run your font rendering code.

This was built for linux, but you can adopt it for any OS. The code is as portable as it can be. It supports Unicode at 4 bytes, so you can make your program multi-language. The text is rendered with anti-aliasing, so the quality is very nice. It is also very memory efficient compared to many other call list techniques.

Here are the libraries I use:

Open Source, multi-platform FreeType Library for the Font rendering:

http://freetype.sourceforge.net/index2.html

Open Source, multi-platform Simple DirectMedia Layer Library:

http://www.libsdl.org/

And of course OpenGL with GLUT.

The only thing missing from this example code is the font file, but you use any compatible font.

If you want some more information about some of the techniques used here, refer to this site:

http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=43

/*
 * This code was created by Jeff Molofee '99
 * (ported to Linux/SDL by Ti Leggett '01)
 * (upgraded by N1GHTS '10)
 *
 * If you've found this code useful, please let us know.
 *
 * Visit Jeff at http://nehe.gamedev.net/
 *
 * or for port-specific comments, questions, bugreports etc.
 * email to leggett@eecs.tulane.edu
 *
 * Changes made by N1GHTS:
 *
 * - Added complete support for Wide Character / Unicode text rendering
 * - Reduced the memory footprint of the font texture arrays
 * - Converted to ANSI C from C++ for more portability
 * - Changed the variable and function names to be more descriptive
 * - Changed the method to create new lines
 *
 * Known Bugs:
 *
 * - Rotating the text breaks the vertical orientation of each row of text 
 *
 *
 * This sample code showcases English and Japanese unicode text
 *
 * By default this code will demonstrate japanese katakana. To
 * enable the english demo, uncomment the DEMO_ENGLISH code below.
*/

/* #define  DEMO_ENGLISH */


/* C Standard Library */
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <wchar.h>
#include <math.h>

/* OpenGL Library - For Graphics Processing */
#include <GL/gl.h>
#include <GL/glu.h>

/* FreeType 2 Library - For Font Processing */
#include <ft2build.h>
#include <freetype.h>
#include <ftoutln.h>
#include <fttrigon.h>
#include <ftglyph.h>

/* SDL Library - For Window Processing */
#include <SDL/SDL.h>

/* Character Lists:
 *
 *  A bitmap will be created for each one of these characters. The
 *  order of the characters in this list does not matter. It will
 *  be sorted automatially. In this way, you can eliminate any
 *  specific characters which will not be used or create a custom
 *  character set using characters in different languages.
 *  This can also be useful to extract specific symbol fonts.
 *
 *  The bottom line is that this technique is highly memory efficient
 *  compared to using a single range of characters.
 */
#define  CHARACTERLIST_LANG_US_ENGLISH  L" ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(),.<>/?:;\"'\\|[]{}`~-+="
#define  CHARACTERLIST_LANG_JP_KATAKANA L"゠ァアィイゥウェエォオカガキギクグケゲコゴサザシジスズセゼソゾタダチヂッツヅテデトドナニヌネノハバパヒビピフブプヘベペホボポマミムメモャヤュユョヨラリルレロヮワヰヱヲンヴヵヶヷヸヹヺ・ーヽヾヿ⦆。「」、・ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙゚0123456789. "

#define  DEMO_FONT_FILE   "./ttf-japanese-gothic.ttf"
#define  DEMO_FONT_HEIGHT 19

#ifndef DEMO_ENGLISH
  #define DEMO_CHARACTERLIST   CHARACTERLIST_LANG_JP_KATAKANA
  #define DEMO_TEXT_TO_DISPLAY L"カタカナノニホンゴノレイ\n%7.2f"
#else
  #define DEMO_CHARACTERLIST   CHARACTERLIST_LANG_US_ENGLISH
  #define DEMO_TEXT_TO_DISPLAY L"English Unicode Example\n%7.2f"
#endif

/* screen width, height, and bit depth */
#define SCREEN_WIDTH  640
#define SCREEN_HEIGHT 480
#define SCREEN_BPP     16

/* Define our booleans */
#define TRUE  1
#define FALSE 0

/* Used in the QuickSort function. This value should be fine for any complex character list. */
#define  QS_MAX_LEVELS  300

/* Used in FT_Print() to load formatted text. This value corresponds
 * to the number of characters that will store the final formatted
 * text. If the number of formatted characters is greater than
 * FT_PRINT_BUFFER_SIZE, the formatted text will be truncated.
 */
#define  FT_PRINT_BUFFER_SIZE  512




/* -----------------------------------------------------------------------------------------------
 * Structures and Utility functions
 * -----------------------------------------------------------------------------------------------
 */


/* This holds all of the information related to any
 * freetype font that we want to create.
 */
typedef struct {
    float    Height;            /* Font Height */
    GLuint  *Textures;          /* Texture ID's */
    GLuint   DisplayListID;     /* First Display List ID */
    wchar_t *CharacterList;     /* Sorted Character List */
} FreeType_Font;

/* This function gets the first power of 2 >= the
 * int that we pass it.
 */
inline int NextPowerOfTwo ( int in_Value )
{
    int ReturnValue = 2; // was 1
    while (ReturnValue < in_Value)
        ReturnValue <<= 1;
    return ReturnValue;
}

/* A fast sorting algorithm used in this example to rearrange
 * provided character lists so you don't have to do this
 * manually when creating character lists for your language.
 */
void CharacterListQuickSort(wchar_t *in_CharacterList) {

  wchar_t *arr = in_CharacterList;
  int elements = wcslen(in_CharacterList);

  wchar_t piv, beg[QS_MAX_LEVELS], end[QS_MAX_LEVELS], i=0, L, R, swap ;

  beg[0]=0; end[0]=elements;
  while (i>=0) {
    L=beg[i]; R=end[i]-1;
    if (L<R) {
      piv=arr[L];
      while (L<R) {
        while (arr[R]>=piv && L<R) R--; if (L<R) arr[L++]=arr[R];
        while (arr[L]<=piv && L<R) L++; if (L<R) arr[R--]=arr[L];
      }
      arr[L]=piv; beg[i+1]=L+1; end[i+1]=end[i]; end[i++]=L;
      if (end[i]-beg[i]>end[i-1]-beg[i-1]) {
        swap=beg[i]; beg[i]=beg[i-1]; beg[i-1]=swap;
        swap=end[i]; end[i]=end[i-1]; end[i-1]=swap;
      }
    } else i--;
  }
}

/* Quickly returns an index to the given character in the given font's
 * character list.
 *
 * If the given character is not in the font's character list, it will
 * choose either the first or last character on the list, depending on
 * the value of the character given.
 */
inline int CharacterListQuickSearch(FreeType_Font *in_Font, wchar_t in_Character) {

    int     NumberOfCharacters = wcslen(in_Font->CharacterList)-1,
            t,
            First = 0,
            Last;
    wchar_t TestCharacter;

    for (Last = NumberOfCharacters,
         TestCharacter = in_Font->CharacterList[t = (int)((Last - First) / 2)+First];
         (TestCharacter != in_Character) && (Last != First) ;
         TestCharacter = in_Font->CharacterList[t = (int)((Last - First) / 2)+First] )
       if (in_Character < TestCharacter)
           Last = t - 1;
       else
           First = t + 1;

    return t;

}

/* Create a display list element coresponding to the given character. */
char *CreateDisplayList ( FreeType_Font *in_Font, FT_Face in_FontFace, int in_CharacterIndex ) {
    
    /* The first thing we do is get FreeType to render our character
     * into a bitmap.  This actually requires a couple of FreeType commands: */

    /* Load the Glyph for our character. */
    if(FT_Load_Glyph( in_FontFace, FT_Get_Char_Index( in_FontFace, in_Font->CharacterList[in_CharacterIndex] ), FT_LOAD_DEFAULT ))
	return "FT_Load_Glyph failed \n";

    /* Move the face's glyph into a Glyph object. */
    FT_Glyph Glyph;
    if(FT_Get_Glyph( in_FontFace->glyph, &Glyph ))
        return "FT_Get_Glyph failed \n";

    /* Convert the glyph to a bitmap. */
    FT_Glyph_To_Bitmap( &Glyph, ft_render_mode_normal, 0, 1 );
    FT_BitmapGlyph bitmap_glyph = (FT_BitmapGlyph)Glyph;

    /* This reference will make accessing the bitmap easier */
    FT_Bitmap *bitmap= &bitmap_glyph->bitmap;

    /* Use our helper function to get the widths of
     * the bitmap data that we will need in order to create
     * our texture. */
    int width  = NextPowerOfTwo( bitmap->width );
    int height = NextPowerOfTwo( bitmap->rows );

    /* Allocate memory for the texture data. */
    GLubyte* expanded_data = malloc(sizeof(GLubyte) * 2 * width * height);

    /* Here we fill in the data for the expanded bitmap.
     * Notice that we are using two channel bitmap (one for
     * luminocity and one for alpha), but we assign
     * both luminocity and alpha to the value that we
     * find in the FreeType bitmap.
     * We use the ?: operator so that value which we use
     * will be 0 if we are in the padding zone, and whatever
     * is the the Freetype bitmap otherwise. */
    int j=0, i;
    for(; j < height;j++)
        for(i=0; i < width; i++) {
            expanded_data[2*(i+j*width)] = 255;
            expanded_data[2*(i+j*width)+1] =
                (i>=bitmap->width || j>=bitmap->rows) ?
                0 : bitmap->buffer[i + bitmap->width*j];
        }



    /* Now we just setup some texture paramaters. */
    glBindTexture( GL_TEXTURE_2D, in_Font->Textures[in_CharacterIndex]);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); 

    /* Here we actually create the texture itself, notice
     * that we are using GL_LUMINANCE_ALPHA to indicate that
     * we are using 2 channel data. */
    glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, width, height,
                  0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, expanded_data );

    /* With the texture created, we don't need to expanded data anymore */
    free(expanded_data);

    /* So now we can create the display list */
    glNewList(in_Font->DisplayListID + in_CharacterIndex,GL_COMPILE);

    glBindTexture(GL_TEXTURE_2D, in_Font->Textures[in_CharacterIndex]);

    /* first we need to move over a little so that
     * the character has the right amount of space
     * between it and the one before it. */
    glTranslatef(bitmap_glyph->left,0,0);

    /* Now we move down a little in the case that the
     * bitmap extends past the bottom of the line
     * (this is only true for characters like 'g' or 'y'. */
    glPushMatrix();    /* Allocate some memory to store the texture ids. */
    glTranslatef(0,bitmap_glyph->top-bitmap->rows,0);

    /* Now we need to account for the fact that many of
     * our textures are filled with empty padding space.
     * We figure what portion of the texture is used by
     * the actual character and store that information in
     * the x and y variables, then when we draw the
     * quad, we will only reference the parts of the texture
     * that we contain the character itself. */
    float x=(float)bitmap->width / (float)width,
          y=(float)bitmap->rows  / (float)height;

    /* Here we draw the texturemaped quads.
     * The bitmap that we got from FreeType was not
     * oriented quite like we would like it to be,
     * so we need to link the texture to the quad
     * so that the result will be properly aligned. */
    glBegin(GL_QUADS);
    glTexCoord2d(0,0); glVertex2f(0,bitmap->rows);
    glTexCoord2d(0,y); glVertex2f(0,0);
    glTexCoord2d(x,y); glVertex2f(bitmap->width,0);
    glTexCoord2d(x,0); glVertex2f(bitmap->width,bitmap->rows);
    glEnd();
    glPopMatrix();
    glTranslatef(in_FontFace->glyph->advance.x >> 6 ,0,0);

    /* increment the raster position as if we were a bitmap font.
     * (only needed if you want to calculate text length) */

    /* glBitmap(0,0,0,0,face->glyph->advance.x >> 6,0,NULL); */

    /* Finish the display list */
    glEndList();
    FT_Done_Glyph(Glyph);

    return NULL;
}

char *FreeType_Font_Initialize(FreeType_Font *in_Font, const char * in_FileName, unsigned int in_Height, const wchar_t *in_CharacterList) {

        int NumberOfCharacters = wcslen(in_CharacterList);

    	/* Allocate some memory to store the texture ids. */
	in_Font->Textures      = malloc(sizeof(GLuint) * NumberOfCharacters);
	in_Font->Height        = in_Height;
        in_Font->CharacterList = malloc((sizeof(wchar_t) * NumberOfCharacters) + sizeof(wchar_t));

        /* Make a copy of the character list provided to this function */
        wcscpy(in_Font->CharacterList, in_CharacterList);

        /* The order of the given characters must be sorted so that they are ordered from lowest to highest value.
         * This is done to take advantage of a faster character searching algorithm used in the printing function. */
        CharacterListQuickSort(in_Font->CharacterList);

	/* Create and initilize a freetype font library. */
	FT_Library library;
	if (FT_Init_FreeType( &library ))
		return "FT_Init_FreeType failed \n";

	/* The object in which Freetype holds information on a given
	 * font is called a "face". */
	FT_Face Face;

	/* This is where we load in the font information from the file.
	 * Of all the places where the code might die, this is the most likely,
	 * as FT_New_Face will die if the font file does not exist or is somehow broken. */
	if (FT_New_Face( library, in_FileName, 0, &Face ))
		return "FT_New_Face failed (there is probably a problem with your font file) \n";

	/* For some twisted reason, Freetype measures font size
	 * in terms of 1/64ths of pixels.  Thus, to make a font
	 * h pixels high, we need to request a size of h*64.
	 * (h << 6 is just a prettier way of writting h*64) */
	FT_Set_Char_Size( Face, in_Height << 6, in_Height << 6, 96, 96);

	/* Here we ask opengl to allocate resources for
	 * all the textures and displays lists which we
	 * are about to create. */
	in_Font->DisplayListID = glGenLists(NumberOfCharacters);
	glGenTextures( NumberOfCharacters, in_Font->Textures );

	/* This is where we actually create each of the fonts display lists. */
	unsigned int i=0;
        char *ErrorString;
        for(;i < NumberOfCharacters; i++)
		if ((ErrorString = CreateDisplayList(in_Font, Face, i)) != NULL)
                    return ErrorString;

	/* We don't need the face information now that the display
	 * lists have been created, so we free the assosiated resources. */
	FT_Done_Face(Face);

	/* Ditto for the library. */
	FT_Done_FreeType(library);

        return NULL;
}

void FreeType_Font_Free(FreeType_Font *in_Font) {
	glDeleteLists(in_Font->DisplayListID, 128);
	glDeleteTextures(128, in_Font->Textures);
	free(in_Font->Textures);
}

/* A fairly straight forward function that pushes
 * a projection matrix that will make object world
 * coordinates identical to window coordinates. */
inline void Push_ScreenProjection_Ortho2D() {
    GLint viewport[4];

    glPushAttrib(GL_TRANSFORM_BIT);
    glGetIntegerv(GL_VIEWPORT, viewport);
    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    glLoadIdentity();
    gluOrtho2D(viewport[0],viewport[2],viewport[1],viewport[3]);
    glPopAttrib();
}

/* Pops the projection matrix without changing the current
 * MatrixMode. */
inline void Pop_ScreenProjection_Ortho2D() {
	glPushAttrib(GL_TRANSFORM_BIT);
	glMatrixMode(GL_PROJECTION);
	glPopMatrix();
	glPopAttrib();
}


/* Much like Nehe's glPrint function, but modified to work
 * with freetype fonts. */
void FT_Print(const FreeType_Font *in_Font, float in_X, float in_Y, wchar_t *in_StringFormat, ...)  {

	/* We want a coordinate system where things coresponding to window pixels. */
	Push_ScreenProjection_Ortho2D();

        int     SizeOfBuffer = sizeof(wchar_t) * FT_PRINT_BUFFER_SIZE;

	float   Height = in_Font->Height/0.63f;	  /* We make the height about 1.5* that of */
	wchar_t *Text  = malloc(SizeOfBuffer);    /* Holds Our String */
	va_list ListOfPrintArguments;             /* Pointer To List Of Arguments */

	if (in_StringFormat == NULL)              /* If There's No Text */
	   Text[0] = 0;                           /* Do Nothing */
	else {
	   va_start(ListOfPrintArguments, in_StringFormat);                        /* Parses The String For Variables */
	   vswprintf(Text, SizeOfBuffer, in_StringFormat, ListOfPrintArguments);   /* And Converts Symbols To Actual Numbers */
	   va_end(ListOfPrintArguments);                                           /* Results Are Stored In Text */
	}

	glPushAttrib(GL_LIST_BIT | GL_CURRENT_BIT  | GL_ENABLE_BIT | GL_TRANSFORM_BIT);
	glMatrixMode(GL_MODELVIEW);
	glDisable(GL_LIGHTING);
	glEnable(GL_TEXTURE_2D);
	glDisable(GL_DEPTH_TEST);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	glListBase(in_Font->DisplayListID);

	float modelview_matrix[16];
	glGetFloatv(GL_MODELVIEW_MATRIX, modelview_matrix);

	/* This is where the text display actually happens.
	 * For each line of text we reset the modelview matrix
	 * so that the line's text will start in the correct position.
	 * Notice that we need to reset the matrix, rather than just translating
	 * down by h. This is because when each character is
	 * draw it modifies the current matrix so that the next character
	 * will be drawn immediatly after it. */

	glPushMatrix();
	glLoadIdentity();
	glTranslatef(in_X, in_Y, 0);
	glMultMatrixf(modelview_matrix);

        int      NumberOfCharacters  = wcslen(Text),
                 CurrentLine         = 0;
        wchar_t *LineStart_Ptr = Text;
        int      TextIndex = 0, Line_TextIndex = 0;

        for (; TextIndex < NumberOfCharacters; TextIndex++, Line_TextIndex++) {
           if (Text[TextIndex] == L'\n') {
                       
              glCallLists(Line_TextIndex, GL_UNSIGNED_INT, LineStart_Ptr);

              Text[TextIndex] = 0;
              CurrentLine++;
              LineStart_Ptr += Line_TextIndex + 1;
              Line_TextIndex = 0;
                      
	      glLoadIdentity();
              glTranslatef(in_X, in_Y - (Height * CurrentLine), 0);
              glMultMatrixf(modelview_matrix);

           } else
              Text[TextIndex] = CharacterListQuickSearch((FreeType_Font *)in_Font, Text[TextIndex]);

        }
        glCallLists(Line_TextIndex, GL_UNSIGNED_INT, LineStart_Ptr);

          
        /*  The commented out raster position stuff can be useful if you need to
	 *  know the length of the text that you are creating.
	 *  If you decide to use it make sure to also uncomment the glBitmap command
	 *  in make_dlist(). */

	/* 	glRasterPos2f(0,0); */
	/*	float rpos[4]; */
	/*	glGetFloatv(GL_CURRENT_RASTER_POSITION ,rpos); */
	/*	float len=x-rpos[0]; */

        free(Text);

        glPopMatrix();
	glPopAttrib();

	Pop_ScreenProjection_Ortho2D();
}



/* -----------------------------------------------------------------------------------------------
 * Main Code Starts Here
 * -----------------------------------------------------------------------------------------------
 */

/* This is our font */
FreeType_Font our_font;

/* This is our SDL surface */
SDL_Surface *surface;

GLfloat	cnt1;
GLfloat	cnt2;



/* function to release/destroy our resources and restoring the old desktop */
void Quit( int returnCode )
{
    /* clean up the window */
    SDL_Quit( );

    /* and exit appropriately */
    exit( returnCode );
}

/* 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, ( GLsizei )width, ( GLsizei )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;
}

/* general OpenGL initialization function */
char *Initialize_OpenGL( GLvoid )
{
    /* Enable smooth shading */
    glShadeModel( GL_SMOOTH );

    /* Set the background black */
    glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );

    /* 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 FreeType_Font_Initialize(&our_font, DEMO_FONT_FILE, DEMO_FONT_HEIGHT, DEMO_CHARACTERLIST);
}

/* Here goes our drawing code */
int drawGLScene( GLvoid )
{
 	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);	/* Clear Screen And Depth Buffer */
	
	/* Red text */
	glColor3ub(0xff,0,0);

	glPushMatrix();
	glLoadIdentity();
	glScalef(1+.1*cos(cnt1/15),1+.3*cos(cnt1/15),1);
	glTranslatef(-180,0,0);
        FT_Print(&our_font, 320, 240, DEMO_TEXT_TO_DISPLAY, cnt1);
	glPopMatrix();

	/* Uncomment this to test out print's ability to handle newlines. */
	/* freetype::print(our_font, 320, 200, "Here\nthere\nbe\n\nnewlines\n.", cnt1); */

	cnt1+=0.051f;	/* Increase The First Counter */
	cnt2+=0.005f;	/* Increase The First Counter */

	SDL_GL_SwapBuffers( );

    return( TRUE );
}

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 ) < 0 )
	{
	    fprintf( stderr, "Video initialization failed: %s\n",
		     SDL_GetError( ) );
	    Quit( 1 );
	}

    /* Fetch the video info */
    videoInfo = SDL_GetVideoInfo( );

    if ( !videoInfo )
	{
	    fprintf( stderr, "Video query failed: %s\n",
		     SDL_GetError( ) );
	    Quit( 1 );
	}

    /* the flags to pass to SDL_SetVideoMode */
    videoFlags  = SDL_OPENGL;          /* Enable OpenGL in SDL */
    videoFlags |= SDL_GL_DOUBLEBUFFER; /* Enable double buffering */
    videoFlags |= SDL_HWPALETTE;       /* Store the palette in hardware */
    videoFlags |= SDL_RESIZABLE;       /* Enable window resizing */

    /* This checks to see if surfaces can be stored in memory */
    if ( videoInfo->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 */
    char *ErrorString = Initialize_OpenGL();
    if (ErrorString != NULL)
    {
        fprintf( stderr, "Initialize_OpenGL Failed: %s\n", ErrorString );
	Quit( 1 );
    }

    /* 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:
			    /* Something's happend with our focus
			     * If we lost focus or we are iconified, we
			     * shouldn't draw the screen
			     */
			    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 );
}

Attached is a screenshot of what this code will look like when its running.

Are you SERIOUS!
Use SDL_OpenGL.
You can use SDL_ttf then too, I think.
And sound!

Are you SERIOUS!
Use SDL_OpenGL.
You can use SDL_ttf then too, I think.
And sound!

I would be thrilled to see what specific updates you would recommend.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.