view test/testgl.c @ 5067:61d53410eb41

Fixed bug #859 CREATE_SUBDIRS helps a lot if browsing HTML documentation in a file browser. ALWAYS_DETAILED_SEC makes sure everything has at least the automatic documentation like function prototype and source references. STRIP_FROM_PATH allows you to include only the relevant portions of the files' paths, cleaning up both the file list and directory tree, though you need to change the path listed here to match wherever you put SDL. ALIASES avoids some warnings generated by C:\source\svn.libsdl.org\trunk\SDL\src\joystick\darwin\10.3.9-FIX\IOHIDLib.h. It seems Apple uses a few commands which are not normally supported by Doxygen. BUILTIN_STL_SUPPORT adds support for parsing code which makes use of the standard template library. There isn't a lot of C++ in SDL (some in bwindow at least), but this still seems like a good idea. TYPEDEF_HIDES_STRUCT means that for code like this: typedef struct A {int B;} C; C is documented as a structure containing B instead of a typedef mapped to A. EXTRACT_ALL, EXTRACT_PRIVATE, EXTRACT_STATIC, EXTRACT_LOCAL_METHODS, EXTRACT_ANON_NSPACES and INTERNAL_DOCS make sure that _everything_ is documented. CASE_SENSE_NAMES = NO avoids potential conflicts when building documentation on case insensitive file systems like NTFS and FAT32. WARN_NO_PARAMDOC lets you know when you have documented some, but not all, of the parameters of a function. This is useful when you're working on adding such documentation since it makes partially documented functions easier to spot. WARN_LOGFILE writes warnings to a seperate file instead of mixing them in with stdout. When not running in quiet mode, these warnings can be hard to spot without this flag. I added *.h.in and *.h.default to FILE_PATTERNS to generate documentation for config.h.in and config.h.default. RECURSIVE tells doxygen to look not only in the input directory, but also in subfolders. EXCLUDE avoids documenting things like test programs, examples and templates which need to be documented separately. I've used EXCLUDE_PATTERNS to exclude non-source subdirectories that often find their way into source folders (such as obj or .svn). EXAMPLE_PATH lists directories doxygen will search to find included example code. So far, SDL doesn't really use this feature, but I've listed some likely locations. SOURCE_BROWSER adds syntax highlighted source code to the HTML output. USE_HTAGS is nice, but not available on Windows. INLINE_SOURCES adds the body of a function to it's documentation so you can quickly see exactly what it does. ALPHABETICAL_INDEX generates an alphabetical list of all structures, functions, etc., which makes it much easier to find what you're looking for. IGNORE_PREFIX skips the SDL_ prefix when deciding which index page to place an item on so you don't have everything show up under "S". HTML_DYNAMIC_SECTIONS hides the includes/included by diagrams by default and adds JavaScript to allow the user to show and hide them by clicking a link. ENUM_VALUES_PER_LINE = 1 makes enums easier to read by placing each value on it's own line. GENERATE_TREEVIEW produces a two frame index page with a navigation tree on the left. I have LaTeX and man pages turned off to speed up doxygen, you may want to turn them back on yourself. I added _WIN32=1 to PREDEFINED to cause SDL to output documentation related to Win32 builds of SDL. Normally, doxygen gets confused since there are multiple definitions for various structures and formats that vary by platform. Without this doxygen can produce broken documentation or, if you're lucky, output documentation only for the dummy drivers, which isn't very useful. You need to pick a platform. GENERATE_TAGFILE produces a file which can be used to link other doxygen documentation to the SDL documentation. CLASS_DIAGRAMS turns on class diagrams even when dot is not available. HAVE_DOT tells doxygen to try to use dot to generate diagrams. TEMPLATE_RELATIONS and INCLUDE_GRAPH add additional diagrams to the documentation. DOT_MULTI_TARGETS speeds up dot. OUTPUT_DIRECTORY, INPUT and other paths reflect the fact that this Doxyfile is intended to process src as well as include and is being run from a separate subdirectory. Doxygen produces several temporary files while it's running and if interrupted, can leave those files behind. It's easier to clean up if there aren't a hundred or so files in the same folder. I typically run doxygen in SDL/doxy and set the output directory to '.'. Since doxygen puts it's output in subfolders by type, this keeps things pretty well organised. You could use '../doc' instead and get the same results.
author Sam Lantinga <slouken@libsdl.org>
date Fri, 21 Jan 2011 12:57:01 -0800
parents 27ab20a36eba
children
line wrap: on
line source

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>

#include "SDL.h"

#ifdef __MACOS__
#define HAVE_OPENGL
#endif

#ifdef HAVE_OPENGL

#include "SDL_opengl.h"

/* Undefine this if you want a flat cube instead of a rainbow cube */
#define SHADED_CUBE

/* Define this to be the name of the logo image to use with -logo */
#define LOGO_FILE	"icon.bmp"

static SDL_Surface *global_image = NULL;
static GLuint global_texture = 0;
static GLuint cursor_texture = 0;

/**********************************************************************/

void
HotKey_ToggleFullScreen(void)
{
    SDL_Surface *screen;

    screen = SDL_GetVideoSurface();
    if (SDL_WM_ToggleFullScreen(screen)) {
        printf("Toggled fullscreen mode - now %s\n",
               (screen->flags & SDL_FULLSCREEN) ? "fullscreen" : "windowed");
    } else {
        printf("Unable to toggle fullscreen mode\n");
    }
}

void
HotKey_ToggleGrab(void)
{
    SDL_GrabMode mode;

    printf("Ctrl-G: toggling input grab!\n");
    mode = SDL_WM_GrabInput(SDL_GRAB_QUERY);
    if (mode == SDL_GRAB_ON) {
        printf("Grab was on\n");
    } else {
        printf("Grab was off\n");
    }
    mode = SDL_WM_GrabInput(!mode);
    if (mode == SDL_GRAB_ON) {
        printf("Grab is now on\n");
    } else {
        printf("Grab is now off\n");
    }
}

void
HotKey_Iconify(void)
{
    printf("Ctrl-Z: iconifying window!\n");
    SDL_WM_IconifyWindow();
}

int
HandleEvent(SDL_Event * event)
{
    int done;

    done = 0;
    switch (event->type) {
    case SDL_ACTIVEEVENT:
        /* See what happened */
        printf("app %s ", event->active.gain ? "gained" : "lost");
        if (event->active.state & SDL_APPACTIVE) {
            printf("active ");
        } else if (event->active.state & SDL_APPMOUSEFOCUS) {
            printf("mouse ");
        } else if (event->active.state & SDL_APPINPUTFOCUS) {
            printf("input ");
        }
        printf("focus\n");
        break;


    case SDL_KEYDOWN:
        if (event->key.keysym.sym == SDLK_ESCAPE) {
            done = 1;
        }
        if ((event->key.keysym.sym == SDLK_g) &&
            (event->key.keysym.mod & KMOD_CTRL)) {
            HotKey_ToggleGrab();
        }
        if ((event->key.keysym.sym == SDLK_z) &&
            (event->key.keysym.mod & KMOD_CTRL)) {
            HotKey_Iconify();
        }
        if ((event->key.keysym.sym == SDLK_RETURN) &&
            (event->key.keysym.mod & KMOD_ALT)) {
            HotKey_ToggleFullScreen();
        }
        printf("key '%s' pressed\n", SDL_GetKeyName(event->key.keysym.sym));
        break;
    case SDL_QUIT:
        done = 1;
        break;
    }
    return (done);
}

void
SDL_GL_Enter2DMode()
{
    SDL_Surface *screen = SDL_GetVideoSurface();

    /* Note, there may be other things you need to change,
       depending on how you have your OpenGL state set up.
     */
    glPushAttrib(GL_ENABLE_BIT);
    glDisable(GL_DEPTH_TEST);
    glDisable(GL_CULL_FACE);
    glEnable(GL_TEXTURE_2D);

    /* This allows alpha blending of 2D textures with the scene */
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    glViewport(0, 0, screen->w, screen->h);

    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    glLoadIdentity();

    glOrtho(0.0, (GLdouble) screen->w, (GLdouble) screen->h, 0.0, 0.0, 1.0);

    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
    glLoadIdentity();

    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
}

void
SDL_GL_Leave2DMode()
{
    glMatrixMode(GL_MODELVIEW);
    glPopMatrix();

    glMatrixMode(GL_PROJECTION);
    glPopMatrix();

    glPopAttrib();
}

/* Quick utility function for texture creation */
static int
power_of_two(int input)
{
    int value = 1;

    while (value < input) {
        value <<= 1;
    }
    return value;
}

GLuint
SDL_GL_LoadTexture(SDL_Surface * surface, GLfloat * texcoord)
{
    GLuint texture;
    int w, h;
    SDL_Surface *image;
    SDL_Rect area;
    Uint32 saved_flags;
    Uint8 saved_alpha;

    /* Use the surface width and height expanded to powers of 2 */
    w = power_of_two(surface->w);
    h = power_of_two(surface->h);
    texcoord[0] = 0.0f;         /* Min X */
    texcoord[1] = 0.0f;         /* Min Y */
    texcoord[2] = (GLfloat) surface->w / w;     /* Max X */
    texcoord[3] = (GLfloat) surface->h / h;     /* Max Y */

    image = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 32,
#if SDL_BYTEORDER == SDL_LIL_ENDIAN     /* OpenGL RGBA masks */
                                 0x000000FF,
                                 0x0000FF00, 0x00FF0000, 0xFF000000
#else
                                 0xFF000000,
                                 0x00FF0000, 0x0000FF00, 0x000000FF
#endif
        );
    if (image == NULL) {
        return 0;
    }

    /* Save the alpha blending attributes */
    saved_flags = surface->flags & (SDL_SRCALPHA | SDL_RLEACCELOK);
    SDL_GetSurfaceAlphaMod(surface, &saved_alpha);
    if ((saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA) {
        SDL_SetAlpha(surface, 0, 0);
    }

    /* Copy the surface into the GL texture image */
    area.x = 0;
    area.y = 0;
    area.w = surface->w;
    area.h = surface->h;
    SDL_BlitSurface(surface, &area, image, &area);

    /* Restore the alpha blending attributes */
    if ((saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA) {
        SDL_SetAlpha(surface, saved_flags, saved_alpha);
    }

    /* Create an OpenGL texture for the image */
    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexImage2D(GL_TEXTURE_2D,
                 0,
                 GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, image->pixels);
    SDL_FreeSurface(image);     /* No longer needed */

    return texture;
}

void
DrawLogoCursor(void)
{
    static GLfloat texMinX, texMinY;
    static GLfloat texMaxX, texMaxY;
    static int w, h;
    int x, y;

    if (!cursor_texture) {
        SDL_Surface *image;
        GLfloat texcoord[4];

        /* Load the image (could use SDL_image library here) */
        image = SDL_LoadBMP(LOGO_FILE);
        if (image == NULL) {
            return;
        }
        w = image->w;
        h = image->h;

        /* Convert the image into an OpenGL texture */
        cursor_texture = SDL_GL_LoadTexture(image, texcoord);

        /* Make texture coordinates easy to understand */
        texMinX = texcoord[0];
        texMinY = texcoord[1];
        texMaxX = texcoord[2];
        texMaxY = texcoord[3];

        /* We don't need the original image anymore */
        SDL_FreeSurface(image);

        /* Make sure that the texture conversion is okay */
        if (!cursor_texture) {
            return;
        }
    }

    /* Move the image around */
    SDL_GetMouseState(&x, &y);
    x -= w / 2;
    y -= h / 2;

    /* Show the image on the screen */
    SDL_GL_Enter2DMode();
    glBindTexture(GL_TEXTURE_2D, cursor_texture);
    glBegin(GL_TRIANGLE_STRIP);
    glTexCoord2f(texMinX, texMinY);
    glVertex2i(x, y);
    glTexCoord2f(texMaxX, texMinY);
    glVertex2i(x + w, y);
    glTexCoord2f(texMinX, texMaxY);
    glVertex2i(x, y + h);
    glTexCoord2f(texMaxX, texMaxY);
    glVertex2i(x + w, y + h);
    glEnd();
    SDL_GL_Leave2DMode();
}

void
DrawLogoTexture(void)
{
    static GLfloat texMinX, texMinY;
    static GLfloat texMaxX, texMaxY;
    static int x = 0;
    static int y = 0;
    static int w, h;
    static int delta_x = 1;
    static int delta_y = 1;

    SDL_Surface *screen = SDL_GetVideoSurface();

    if (!global_texture) {
        SDL_Surface *image;
        GLfloat texcoord[4];

        /* Load the image (could use SDL_image library here) */
        image = SDL_LoadBMP(LOGO_FILE);
        if (image == NULL) {
            return;
        }
        w = image->w;
        h = image->h;

        /* Convert the image into an OpenGL texture */
        global_texture = SDL_GL_LoadTexture(image, texcoord);

        /* Make texture coordinates easy to understand */
        texMinX = texcoord[0];
        texMinY = texcoord[1];
        texMaxX = texcoord[2];
        texMaxY = texcoord[3];

        /* We don't need the original image anymore */
        SDL_FreeSurface(image);

        /* Make sure that the texture conversion is okay */
        if (!global_texture) {
            return;
        }
    }

    /* Move the image around */
    x += delta_x;
    if (x < 0) {
        x = 0;
        delta_x = -delta_x;
    } else if ((x + w) > screen->w) {
        x = screen->w - w;
        delta_x = -delta_x;
    }
    y += delta_y;
    if (y < 0) {
        y = 0;
        delta_y = -delta_y;
    } else if ((y + h) > screen->h) {
        y = screen->h - h;
        delta_y = -delta_y;
    }

    /* Show the image on the screen */
    SDL_GL_Enter2DMode();
    glBindTexture(GL_TEXTURE_2D, global_texture);
    glBegin(GL_TRIANGLE_STRIP);
    glTexCoord2f(texMinX, texMinY);
    glVertex2i(x, y);
    glTexCoord2f(texMaxX, texMinY);
    glVertex2i(x + w, y);
    glTexCoord2f(texMinX, texMaxY);
    glVertex2i(x, y + h);
    glTexCoord2f(texMaxX, texMaxY);
    glVertex2i(x + w, y + h);
    glEnd();
    SDL_GL_Leave2DMode();
}

int
RunGLTest(int argc, char *argv[],
          int logo, int logocursor, int slowly, int bpp, float gamma,
          int noframe, int fsaa, int sync, int accel)
{
    int i;
    int rgb_size[3];
    int w = 640;
    int h = 480;
    int done = 0;
    int frames;
    Uint32 start_time, this_time;
    float color[8][3] = { {1.0, 1.0, 0.0},
    {1.0, 0.0, 0.0},
    {0.0, 0.0, 0.0},
    {0.0, 1.0, 0.0},
    {0.0, 1.0, 1.0},
    {1.0, 1.0, 1.0},
    {1.0, 0.0, 1.0},
    {0.0, 0.0, 1.0}
    };
    float cube[8][3] = { {0.5, 0.5, -0.5},
    {0.5, -0.5, -0.5},
    {-0.5, -0.5, -0.5},
    {-0.5, 0.5, -0.5},
    {-0.5, 0.5, 0.5},
    {0.5, 0.5, 0.5},
    {0.5, -0.5, 0.5},
    {-0.5, -0.5, 0.5}
    };
    Uint32 video_flags;
    int value;

    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
        fprintf(stderr, "Couldn't initialize SDL: %s\n", SDL_GetError());
        exit(1);
    }

    /* See if we should detect the display depth */
    if (bpp == 0) {
        if (SDL_GetVideoInfo()->vfmt->BitsPerPixel <= 8) {
            bpp = 8;
        } else {
            bpp = 16;           /* More doesn't seem to work */
        }
    }

    /* Set the flags we want to use for setting the video mode */
    video_flags = SDL_OPENGL;
    for (i = 1; argv[i]; ++i) {
        if (strcmp(argv[i], "-fullscreen") == 0) {
            video_flags |= SDL_FULLSCREEN;
        }
    }

    if (noframe) {
        video_flags |= SDL_NOFRAME;
    }

    /* Initialize the display */
    switch (bpp) {
    case 8:
        rgb_size[0] = 3;
        rgb_size[1] = 3;
        rgb_size[2] = 2;
        break;
    case 15:
    case 16:
        rgb_size[0] = 5;
        rgb_size[1] = 5;
        rgb_size[2] = 5;
        break;
    default:
        rgb_size[0] = 8;
        rgb_size[1] = 8;
        rgb_size[2] = 8;
        break;
    }
    SDL_GL_SetAttribute(SDL_GL_RED_SIZE, rgb_size[0]);
    SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, rgb_size[1]);
    SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, rgb_size[2]);
    SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
    if (fsaa) {
        SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
        SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, fsaa);
    }
    if (accel >= 0) {
        SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, accel);
    }
    if (SDL_SetVideoMode(w, h, bpp, video_flags) == NULL) {
        fprintf(stderr, "Couldn't set GL mode: %s\n", SDL_GetError());
        SDL_Quit();
        exit(1);
    }
    if (sync) {
        SDL_GL_SetSwapInterval(1);
    } else {
        SDL_GL_SetSwapInterval(0);
    }

    printf("Screen BPP: %d\n", SDL_GetVideoSurface()->format->BitsPerPixel);
    printf("\n");
    printf("Vendor     : %s\n", glGetString(GL_VENDOR));
    printf("Renderer   : %s\n", glGetString(GL_RENDERER));
    printf("Version    : %s\n", glGetString(GL_VERSION));
    printf("Extensions : %s\n", glGetString(GL_EXTENSIONS));
    printf("\n");

    SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &value);
    printf("SDL_GL_RED_SIZE: requested %d, got %d\n", rgb_size[0], value);
    SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &value);
    printf("SDL_GL_GREEN_SIZE: requested %d, got %d\n", rgb_size[1], value);
    SDL_GL_GetAttribute(SDL_GL_BLUE_SIZE, &value);
    printf("SDL_GL_BLUE_SIZE: requested %d, got %d\n", rgb_size[2], value);
    SDL_GL_GetAttribute(SDL_GL_DEPTH_SIZE, &value);
    printf("SDL_GL_DEPTH_SIZE: requested %d, got %d\n", bpp, value);
    SDL_GL_GetAttribute(SDL_GL_DOUBLEBUFFER, &value);
    printf("SDL_GL_DOUBLEBUFFER: requested 1, got %d\n", value);
    if (fsaa) {
        SDL_GL_GetAttribute(SDL_GL_MULTISAMPLEBUFFERS, &value);
        printf("SDL_GL_MULTISAMPLEBUFFERS: requested 1, got %d\n", value);
        SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &value);
        printf("SDL_GL_MULTISAMPLESAMPLES: requested %d, got %d\n", fsaa,
               value);
    }
    if (accel >= 0) {
        SDL_GL_GetAttribute(SDL_GL_ACCELERATED_VISUAL, &value);
        printf("SDL_GL_ACCELERATED_VISUAL: requested %d, got %d\n", accel,
               value);
    }
    if (sync) {
        printf("Buffer swap interval: requested 1, got %d\n",
               SDL_GL_GetSwapInterval());
    }

    /* Set the window manager title bar */
    SDL_WM_SetCaption("SDL GL test", "testgl");

    /* Set the gamma for the window */
    if (gamma != 0.0) {
        SDL_SetGamma(gamma, gamma, gamma);
    }

    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    glOrtho(-2.0, 2.0, -2.0, 2.0, -20.0, 20.0);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glEnable(GL_DEPTH_TEST);

    glDepthFunc(GL_LESS);

    glShadeModel(GL_SMOOTH);

    /* Loop until done. */
    start_time = SDL_GetTicks();
    frames = 0;
    while (!done) {
        GLenum gl_error;
        char *sdl_error;
        SDL_Event event;

        /* Do our drawing, too. */
        glClearColor(0.0, 0.0, 0.0, 1.0);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        glBegin(GL_QUADS);

#ifdef SHADED_CUBE
        glColor3fv(color[0]);
        glVertex3fv(cube[0]);
        glColor3fv(color[1]);
        glVertex3fv(cube[1]);
        glColor3fv(color[2]);
        glVertex3fv(cube[2]);
        glColor3fv(color[3]);
        glVertex3fv(cube[3]);

        glColor3fv(color[3]);
        glVertex3fv(cube[3]);
        glColor3fv(color[4]);
        glVertex3fv(cube[4]);
        glColor3fv(color[7]);
        glVertex3fv(cube[7]);
        glColor3fv(color[2]);
        glVertex3fv(cube[2]);

        glColor3fv(color[0]);
        glVertex3fv(cube[0]);
        glColor3fv(color[5]);
        glVertex3fv(cube[5]);
        glColor3fv(color[6]);
        glVertex3fv(cube[6]);
        glColor3fv(color[1]);
        glVertex3fv(cube[1]);

        glColor3fv(color[5]);
        glVertex3fv(cube[5]);
        glColor3fv(color[4]);
        glVertex3fv(cube[4]);
        glColor3fv(color[7]);
        glVertex3fv(cube[7]);
        glColor3fv(color[6]);
        glVertex3fv(cube[6]);

        glColor3fv(color[5]);
        glVertex3fv(cube[5]);
        glColor3fv(color[0]);
        glVertex3fv(cube[0]);
        glColor3fv(color[3]);
        glVertex3fv(cube[3]);
        glColor3fv(color[4]);
        glVertex3fv(cube[4]);

        glColor3fv(color[6]);
        glVertex3fv(cube[6]);
        glColor3fv(color[1]);
        glVertex3fv(cube[1]);
        glColor3fv(color[2]);
        glVertex3fv(cube[2]);
        glColor3fv(color[7]);
        glVertex3fv(cube[7]);
#else /* flat cube */
        glColor3f(1.0, 0.0, 0.0);
        glVertex3fv(cube[0]);
        glVertex3fv(cube[1]);
        glVertex3fv(cube[2]);
        glVertex3fv(cube[3]);

        glColor3f(0.0, 1.0, 0.0);
        glVertex3fv(cube[3]);
        glVertex3fv(cube[4]);
        glVertex3fv(cube[7]);
        glVertex3fv(cube[2]);

        glColor3f(0.0, 0.0, 1.0);
        glVertex3fv(cube[0]);
        glVertex3fv(cube[5]);
        glVertex3fv(cube[6]);
        glVertex3fv(cube[1]);

        glColor3f(0.0, 1.0, 1.0);
        glVertex3fv(cube[5]);
        glVertex3fv(cube[4]);
        glVertex3fv(cube[7]);
        glVertex3fv(cube[6]);

        glColor3f(1.0, 1.0, 0.0);
        glVertex3fv(cube[5]);
        glVertex3fv(cube[0]);
        glVertex3fv(cube[3]);
        glVertex3fv(cube[4]);

        glColor3f(1.0, 0.0, 1.0);
        glVertex3fv(cube[6]);
        glVertex3fv(cube[1]);
        glVertex3fv(cube[2]);
        glVertex3fv(cube[7]);
#endif /* SHADED_CUBE */

        glEnd();

        glMatrixMode(GL_MODELVIEW);
        glRotatef(5.0, 1.0, 1.0, 1.0);

        /* Draw 2D logo onto the 3D display */
        if (logo) {
            DrawLogoTexture();
        }
        if (logocursor) {
            DrawLogoCursor();
        }

        SDL_GL_SwapBuffers();

        /* Check for error conditions. */
        gl_error = glGetError();

        if (gl_error != GL_NO_ERROR) {
            fprintf(stderr, "testgl: OpenGL error: %d\n", gl_error);
        }

        sdl_error = (char *)SDL_GetError();

        if (sdl_error[0] != '\0') {
            fprintf(stderr, "testgl: SDL error '%s'\n", sdl_error);
            SDL_ClearError();
        }

        /* Allow the user to see what's happening */
        if (slowly) {
            SDL_Delay(20);
        }

        /* Check if there's a pending event. */
        while (SDL_PollEvent(&event)) {
            done |= HandleEvent(&event);
        }
        ++frames;
    }

    /* Print out the frames per second */
    this_time = SDL_GetTicks();
    if (this_time != start_time) {
        printf("%2.2f FPS\n",
               ((float) frames / (this_time - start_time)) * 1000.0);
    }

    if (global_image) {
        SDL_FreeSurface(global_image);
        global_image = NULL;
    }
    if (global_texture) {
        glDeleteTextures(1, &global_texture);
        global_texture = 0;
    }
    if (cursor_texture) {
        glDeleteTextures(1, &cursor_texture);
        cursor_texture = 0;
    }

    /* Destroy our GL context, etc. */
    SDL_Quit();
    return (0);
}

int
main(int argc, char *argv[])
{
    int i, logo, logocursor = 0;
    int numtests;
    int bpp = 0;
    int slowly;
    float gamma = 0.0;
    int noframe = 0;
    int fsaa = 0;
    int accel = -1;
    int sync = 0;

    logo = 0;
    slowly = 0;
    numtests = 1;
    for (i = 1; argv[i]; ++i) {
        if (strcmp(argv[i], "-twice") == 0) {
            ++numtests;
        }
        if (strcmp(argv[i], "-logo") == 0) {
            logo = 1;
        }
        if (strcmp(argv[i], "-logocursor") == 0) {
            logocursor = 1;
        }
        if (strcmp(argv[i], "-slow") == 0) {
            slowly = 1;
        }
        if (strcmp(argv[i], "-bpp") == 0) {
            bpp = atoi(argv[++i]);
        }
        if (strcmp(argv[i], "-gamma") == 0) {
            gamma = (float) atof(argv[++i]);
        }
        if (strcmp(argv[i], "-noframe") == 0) {
            noframe = 1;
        }
        if (strcmp(argv[i], "-fsaa") == 0) {
            ++fsaa;
        }
        if (strcmp(argv[i], "-accel") == 0) {
            accel = atoi(argv[++i]);
        }
        if (strcmp(argv[i], "-sync") == 0) {
            ++sync;
        }
        if (strncmp(argv[i], "-h", 2) == 0) {
            printf
                ("Usage: %s [-twice] [-logo] [-logocursor] [-slow] [-bpp n] [-gamma n] [-noframe] [-fsaa] [-accel n] [-sync] [-fullscreen]\n",
                 argv[0]);
            exit(0);
        }
    }
    for (i = 0; i < numtests; ++i) {
        RunGLTest(argc, argv, logo, logocursor, slowly, bpp, gamma,
                  noframe, fsaa, sync, accel);
    }
    return 0;
}

#else /* HAVE_OPENGL */

int
main(int argc, char *argv[])
{
    printf("No OpenGL support on this system\n");
    return 1;
}

#endif /* HAVE_OPENGL */