Mercurial > sdl-ios-xcode
diff test/testgl2.c @ 1914:051df511279c
Added a test program framework for easy initialization.
Started work on multi-window OpenGL demo
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Tue, 18 Jul 2006 07:49:51 +0000 |
parents | |
children | a228436a2404 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/testgl2.c Tue Jul 18 07:49:51 2006 +0000 @@ -0,0 +1,770 @@ +#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); + saved_alpha = surface->format->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) { + SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1); + } + 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) { + SDL_GL_GetAttribute(SDL_GL_ACCELERATED_VISUAL, &value); + printf("SDL_GL_ACCELERATED_VISUAL: requested 1, got %d\n", 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 = 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 = 0; + 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; + } + 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] [-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 */