/*1* SDL OpenGL Tutorial.2* (c) Michael Vance, 20003* [email protected]4*5* Distributed under terms of the LGPL.6*/78#include <SDL/SDL.h>910#ifdef __EMSCRIPTEN__11#include <GL/gl.h>12#include <GL/glu.h>13#include "emscripten.h"14#else15#include <GL/gl.h>16#include <GL/glu.h>17#endif18#include <stdio.h>19#include <stdlib.h>2021#ifdef __EMSCRIPTEN__22#define emColor4ubv(x)23#else24#define emColor4ubv(x) glColor4ubv(x)25#endif2627static GLboolean should_rotate = GL_TRUE;2829static void quit_tutorial( int code )30{31/*32* Quit SDL so we can release the fullscreen33* mode and restore the previous video settings,34* etc.35*/36SDL_Quit( );3738/* Exit program. */39exit( code );40}4142static void handle_key_down( SDL_keysym* keysym )43{4445/*46* We're only interested if 'Esc' has47* been presssed.48*49* EXERCISE:50* Handle the arrow keys and have that change the51* viewing position/angle.52*/53switch( keysym->sym ) {54case SDLK_ESCAPE:55quit_tutorial( 0 );56break;57case SDLK_SPACE:58should_rotate = !should_rotate;59break;60default:61break;62}6364}6566static void process_events( void )67{68/* Our SDL event placeholder. */69SDL_Event event;7071/* Grab all the events off the queue. */72while( SDL_PollEvent( &event ) ) {7374switch( event.type ) {75case SDL_KEYDOWN:76/* Handle key presses. */77handle_key_down( &event.key.keysym );78break;79case SDL_QUIT:80/* Handle quit requests (like Ctrl-c). */81quit_tutorial( 0 );82break;83}8485}8687}8889static void draw_screen( void )90{91/* Our angle of rotation. */92static float angle = 0.0f;9394/*95* EXERCISE:96* Replace this awful mess with vertex97* arrays and a call to glDrawElements.98*99* EXERCISE:100* After completing the above, change101* it to use compiled vertex arrays.102*103* EXERCISE:104* Verify my windings are correct here ;).105*/106static GLfloat v0[] = { -1.0f, -1.0f, 1.0f };107static GLfloat v1[] = { 1.0f, -1.0f, 1.0f };108static GLfloat v2[] = { 1.0f, 1.0f, 1.0f };109static GLfloat v3[] = { -1.0f, 1.0f, 1.0f };110static GLfloat v4[] = { -1.0f, -1.0f, -1.0f };111static GLfloat v5[] = { 1.0f, -1.0f, -1.0f };112static GLfloat v6[] = { 1.0f, 1.0f, -1.0f };113static GLfloat v7[] = { -1.0f, 1.0f, -1.0f };114static GLubyte red[] = { 255, 0, 0, 255 };115static GLubyte green[] = { 0, 255, 0, 255 };116static GLubyte blue[] = { 0, 0, 255, 255 };117static GLubyte white[] = { 255, 255, 255, 255 };118static GLubyte yellow[] = { 0, 255, 255, 255 };119static GLubyte black[] = { 0, 0, 0, 255 };120static GLubyte orange[] = { 255, 255, 0, 255 };121static GLubyte purple[] = { 255, 0, 255, 0 };122123/* Clear the color and depth buffers. */124glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );125126/* We don't want to modify the projection matrix. */127glMatrixMode( GL_MODELVIEW );128glLoadIdentity( );129130/* Move down the z-axis. */131glTranslatef( 0.0, 0.0, -5.0 );132133/* Rotate. */134glRotatef( angle, 0.0, 1.0, 0.0 );135136if( should_rotate ) {137138if( ++angle > 360.0f ) {139angle = 0.0f;140}141142}143144/* Send our triangle data to the pipeline. */145glBegin( GL_TRIANGLES );146147emColor4ubv( red );148glVertex3fv( v0 );149emColor4ubv( green );150glVertex3fv( v1 );151emColor4ubv( blue );152glVertex3fv( v2 );153154emColor4ubv( red );155glVertex3fv( v0 );156emColor4ubv( blue );157glVertex3fv( v2 );158emColor4ubv( white );159glVertex3fv( v3 );160161emColor4ubv( green );162glVertex3fv( v1 );163emColor4ubv( black );164glVertex3fv( v5 );165emColor4ubv( orange );166glVertex3fv( v6 );167168emColor4ubv( green );169glVertex3fv( v1 );170emColor4ubv( orange );171glVertex3fv( v6 );172emColor4ubv( blue );173glVertex3fv( v2 );174175emColor4ubv( black );176glVertex3fv( v5 );177emColor4ubv( yellow );178glVertex3fv( v4 );179emColor4ubv( purple );180glVertex3fv( v7 );181182emColor4ubv( black );183glVertex3fv( v5 );184emColor4ubv( purple );185glVertex3fv( v7 );186emColor4ubv( orange );187glVertex3fv( v6 );188189emColor4ubv( yellow );190glVertex3fv( v4 );191emColor4ubv( red );192glVertex3fv( v0 );193emColor4ubv( white );194glVertex3fv( v3 );195196emColor4ubv( yellow );197glVertex3fv( v4 );198emColor4ubv( white );199glVertex3fv( v3 );200emColor4ubv( purple );201glVertex3fv( v7 );202203emColor4ubv( white );204glVertex3fv( v3 );205emColor4ubv( blue );206glVertex3fv( v2 );207emColor4ubv( orange );208glVertex3fv( v6 );209210emColor4ubv( white );211glVertex3fv( v3 );212emColor4ubv( orange );213glVertex3fv( v6 );214emColor4ubv( purple );215glVertex3fv( v7 );216217emColor4ubv( green );218glVertex3fv( v1 );219emColor4ubv( red );220glVertex3fv( v0 );221emColor4ubv( yellow );222glVertex3fv( v4 );223224emColor4ubv( green );225glVertex3fv( v1 );226emColor4ubv( yellow );227glVertex3fv( v4 );228emColor4ubv( black );229glVertex3fv( v5 );230231glEnd( );232233/*234* EXERCISE:235* Draw text telling the user that 'Spc'236* pauses the rotation and 'Esc' quits.237* Do it using vetors and textured quads.238*/239240/*241* Swap the buffers. This this tells the driver to242* render the next frame from the contents of the243* back-buffer, and to set all rendering operations244* to occur on what was the front-buffer.245*246* Double buffering prevents nasty visual tearing247* from the application drawing on areas of the248* screen that are being updated at the same time.249*/250SDL_GL_SwapBuffers( );251}252253static void setup_opengl( int width, int height )254{255float ratio = (float) width / (float) height;256257/* Our shading model--Gouraud (smooth). */258glShadeModel( GL_SMOOTH );259260/* Culling. */261glCullFace( GL_BACK );262glFrontFace( GL_CCW );263glEnable( GL_CULL_FACE );264265/* Set the clear color. */266glClearColor( 0, 0, 0, 0 );267268/* Setup our viewport. */269glViewport( 0, 0, width, height );270271/*272* Change to the projection matrix and set273* our viewing volume.274*/275glMatrixMode( GL_PROJECTION );276glLoadIdentity( );277/*278* EXERCISE:279* Replace this with a call to glFrustum.280*/281gluPerspective( 60.0, ratio, 1.0, 1024.0 );282}283284void one_iter();285void one_iter() {286process_events( );287/* Draw the screen. */288draw_screen( );289}290291int main( int argc, char* argv[] )292{293/* Information about the current video settings. */294const SDL_VideoInfo* info = NULL;295/* Dimensions of our window. */296int width = 0;297int height = 0;298/* Color depth in bits of our window. */299int bpp = 0;300/* Flags we will pass into SDL_SetVideoMode. */301int flags = 0;302303/* First, initialize SDL's video subsystem. */304if( SDL_Init( SDL_INIT_VIDEO ) < 0 ) {305/* Failed, exit. */306fprintf( stderr, "Video initialization failed: %s\n",307SDL_GetError( ) );308quit_tutorial( 1 );309}310311/* Let's get some video information. */312info = SDL_GetVideoInfo( );313314if( !info ) {315/* This should probably never happen. */316fprintf( stderr, "Video query failed: %s\n",317SDL_GetError( ) );318quit_tutorial( 1 );319}320321/*322* Set our width/height to 640/480 (you would323* of course let the user decide this in a normal324* app). We get the bpp we will request from325* the display. On X11, VidMode can't change326* resolution, so this is probably being overly327* safe. Under Win32, ChangeDisplaySettings328* can change the bpp.329*/330width = 640;331height = 480;332bpp = info->vfmt->BitsPerPixel;333334/*335* Now, we want to setup our requested336* window attributes for our OpenGL window.337* We want *at least* 5 bits of red, green338* and blue. We also want at least a 16-bit339* depth buffer.340*341* The last thing we do is request a double342* buffered window. '1' turns on double343* buffering, '0' turns it off.344*345* Note that we do not use SDL_DOUBLEBUF in346* the flags to SDL_SetVideoMode. That does347* not affect the GL attribute state, only348* the standard 2D blitting setup.349*/350// SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 5 );351// SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 5 );352// SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 5 );353// SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 );354// SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );355356/*357* We want to request that SDL provide us358* with an OpenGL window, in a fullscreen359* video mode.360*361* EXERCISE:362* Make starting windowed an option, and363* handle the resize events properly with364* glViewport.365*/366flags = SDL_OPENGL;// | SDL_FULLSCREEN;367368/*369* Set the video mode370*/371if( SDL_SetVideoMode( width, height, bpp, flags ) == 0 ) {372/*373* This could happen for a variety of reasons,374* including DISPLAY not being set, the specified375* resolution not being available, etc.376*/377fprintf( stderr, "Video mode set failed: %s\n",378SDL_GetError( ) );379quit_tutorial( 1 );380}381382/*383* At this point, we should have a properly setup384* double-buffered window for use with OpenGL.385*/386setup_opengl( width, height );387388/*389* Now we want to begin our normal app process--390* an event loop with a lot of redrawing.391*/392one_iter(); // just one for testing purposes393394#ifndef __EMSCRIPTEN__395SDL_Delay(2000);396#endif397398/*399* EXERCISE:400* Record timings using SDL_GetTicks() and401* and print out frames per second at program402* end.403*/404405/* Never reached. */406return 0;407}408409410