Aros/Developer/SDL
Introduction
editSDL_Init SDL_SetVideoMode SDL_Surface SDL_Rect SDL_PollEvent SDL_EventType SDL_FreeSurface SDL_Quit
Many SDL games work by polling (ie reading all the time) the event queue.
https://wiki.libsdl.org/SDL_PollEvent
The example code shows the ugly. while(1) { SDL_PollEvent(...); }
It kills any CPU class.
Better main loop would be with SDL_WaitEvent/SDL_WaitEventTimeout
https://wiki.libsdl.org/SDL_WaitEvent https://wiki.libsdl.org/SDL_WaitEventTimeout
At least, those calls shouldn't eat all the CPU.
C initialisation of SDL
editC++ initialisation of SDL
edit#include <SDL/SDL.h>
#include "Application.h"
//Extern'd in Application.h; Used as forefront to access everything we create =D
Application* pApp;
int main(int args, char* argv[])
{
//Create the application on the heap for actual use
pApp = new Application();
//Initialize the application. If something fails, return -1 (I like -1 for errors)
if(pApp->Init() != true)
{
return -1;
}
//This should successfully run our application
//Should go through Input, Logic, and Rendering
pApp->Run();
//This will clean up everything, deallocating dynamically allocated memory
//Uninitializing SDL, etc.
pApp->Quit();
//Out of habit, I always check to make sure a pointer has a value (other than NULL)
//Before I deallocate it. I also ALWAYS set it to NULL immediately after.
//Good habit to get into because it is preventative for memory leaks
if(pApp)
{
delete pApp;
pApp = NULL;
}
//Lastly, end the application, returning 0 to indicate that nothing went wrong
return 0;
}
#ifndef APPLICATION_H_INCLUDED
#define APPLICATION_H_INCLUDED
#include <SDL/SDL.h>
class Application
{
private:
//We'll keep adding here as we go along
bool m_bDone;
public:
Application();
~Application();
bool Init();
void Run();
void TakeInput(SDL_Event* pEvent);
void Update();
void Render();
void Quit();
};
//We'll use this global pointer to access things like the window later on
extern Application* pApp;
#endif // APPLICATION_H_INCLUDED
#include "Application.h"
Application::Application()
{
//Standard constructor we'll use to initialize variables with default values
//The program just started, we certainly are not done yet!
m_bDone = false;
}
Application::~Application()
{
//Here, we'll deallocate any dynamically allocated memory we may have missed
}
bool Application::Init()
{
//Initialize SDL and return false if anything goes wrong
//We'll add more initializations here for anything else we use
if(SDL_Init(SDL_INIT_EVERYTHING) != 0)
{
return false;
}
//Lastly return true to indicate that the initialization was successful
return true;
}
void Application::Run()
{
//This function implements our loop
//Any calls that should be made each frame should be put in this loop
//the m_bDone variable will track whether the program is ready to exit
while(!m_bDone)
{
m_bDone = true;
}
}
void Application::TakeInput(SDL_Event* pEvent)
{
//We'll use this function to take input from the user and act upon it
}
void Application::Update()
{
//This is where all the magic happens!
//After receiving input, this is where we act on that input
//and actually make things happen =D
}
void Application::Render()
{
//Here, we will draw our images to the screen
}
void Application::Quit()
{
//Uninitialize SDL, we'll also deallocate any memory we dynamically allocate
SDL_Quit();
}
2D platformer pseudo code
editgame loop while( SDL_PollEvent( &event ) ) { myHero.handle_input(); //If the user has Xed out the window if( event.type == SDL_QUIT ) { //Quit the program quit = true; } } myHero.move( blahbox ); //Set the camera myHero.set_camera(); handle_input() if( event.type == SDL_KEYDOWN ) { if( SDLK_LEFT ) { xForce -= HERO_WIDTH / 2; } if( SDLK_RIGHT ){ xForce += HERO_WIDTH / 2; } } else if( event.type == SDL_KEYUP ) { if( SDLK_LEFT ) { xForce = 0; } if( SDLK_RIGHT ) { xForce = 0; } } move() void Hero::move(SDL_Rect blahbox) { //Move the dot left or right if( xForce != 0 ) { xAcc = xForce / HERO_MASS; } if( xForce == 0 ) { xVel = xAcc = 0; } xVel = xVel + xAcc; box.x = box.x + xVel; //If the dot went too far to the left or right or touched a wall if( ( box.x < 0 ) || ( box.x + HERO_WIDTH > LEVEL_WIDTH ) || check_collision( box, blahbox) ) { //move back box.x = box.x - xVel; } } what i was going for is force is applied when a key is pressed, acceleration = Force / Mass Velocity = Velocity + Acceleration etc...
Game Routines
edit/* Here's the include */ #include "SDL.h" SDL_Surface* screen; void startGame() { /* Load my picture */ SDL_Surface* pic = SDL_LoadBMP("mypic.bmp"); /* Here's where I'll draw it */ SDL_Rect destRect; if(pic != NULL) { destRect.x = screen->w/2 - pic->w/2; destRect.y = screen->h/2 - pic->h/2; } /* Here are two rectangles */ /* I initialize rect.x, rect.y, rect.w, and rect.h all at once */ SDL_Rect rect1 = {40, 40, 300, 200}; SDL_Rect rect2 = {200, 100, 160, 160}; /* Start the main loop */ SDL_Event event; Uint8 done = 0; while (!done) { /* Check for events */ while (SDL_PollEvent(&event)) { if(event.type == SDL_QUIT) { done = 1; } if(event.type == SDL_KEYDOWN) { if(event.key.keysym.sym == SDLK_ESCAPE) { done = 1; } } } /* Clear the screen */ SDL_FillRect(screen, NULL, 0x000000); /* Red rectangle */ SDL_FillRect(screen, &rect1, SDL_MapRGB(screen->format, 200, 0, 0)); /* White rectangle */ SDL_FillRect(screen, &rect2, SDL_MapRGB(screen->format, 255, 255, 255)); /* Draw my picture */ SDL_BlitSurface(pic, NULL, screen, &destRect); /* Send all this to the monitor */ SDL_Flip(screen); } /* Free up the picture memory */ SDL_FreeSurface(pic); return; } int main(int argc, char *argv[]) { /* Initialize SDL */ if( SDL_Init(SDL_INIT_VIDEO) < 0 ) return 0; /* Initialize the screen surface */ screen = SDL_SetVideoMode(400, 300, 32, SDL_SWSURFACE); if ( screen == NULL ) return 0; /* Now do whatever we want! */ startGame(); SDL_Quit(); return 0; }
If SDL failed
if( SDL_Init( SDL_INIT_VIDEO ) == -1 ) { fprintf(stderr, "Failed to initialize SDL. [%s]\n", SDL_GetError()); exit(1); }
SDL_Surface *screen = SDL_SetVideoMode(640, 480, 32, SDL_SWSURFACE); if( screen == NULL ) { fprintf(stderr, "Failed to set video mode. [%s]\n", SDL_GetError()); exit(1); }
SDL_Event evt; bool done = false; while( !done ) { while( SDL_PollEvent( &evt ) ) { switch( evt.type ) { case SDL_QUIT: done = true; break; case SDL_KEYUP: if( evt.key.keysym.sym == SDLK_ESCAPE ) done = true; break; default: break; } } }
#include <sdl.h> int main( int argc, char **argv) { SDL_Event evt; bool done = false; // initialize SDL if( SDL_Init( SDL_INIT_VIDEO ) == -1 ) { fprintf(stderr, "Failed to initialize SDL. [%s]\n", SDL_GetError()); exit(1); } // create a software surface/window SDL_Surface *screen = SDL_SetVideoMode(640, 480, 32, SDL_SWSURFACE); if( screen == NULL ) { fprintf(stderr, "Failed to set video mode. [%s]\n", SDL_GetError()); exit(1); } // main game loop while( !done ) { // check for events generated from SDL while( SDL_PollEvent( &evt ) ) { switch( evt.type ) { case SDL_QUIT: done = true; break; case SDL_KEYUP: if( evt.key.keysym.sym == SDLK_ESCAPE ) done = true; break; default: break; } } } SDL_Quit(); return 0; }
Uint32 color1 = SDL_MapRGB(screen->format, 0x00, 0x00, 0xFF); Uint32 color2 = SDL_MapRGB(screen->format, 0x00, 0xFF, 0x00); Uint32 currentColor = color1;
case SDL_KEYUP: if( evt.key.keysym.sym == SDLK_ESCAPE ) done = true; else if( evt.key.keysym.sym == SDLK_SPACE ) { currentColor = ( currentColor == color1 ) ? color2 : color1; SDL_FillRect( screen, NULL, currentColor); SDL_UpdateRect(screen, 0, 0, 0, 0); } break;
case SDL_KEYDOWN: printf( "KEYDOWN: %c\n", evt.key.keysym.unicode); break;
Sound
edit//SDL_Mixer #include <SDL/SDL_mixer.h> // Mix_Chuck* effect1; Mix_Chuck* effect2; Mix_Music* music; Mix_OpenAudio(22050,MIX_DEFAULT_FORMAT,2,4096); music=Mix_LoadMUS("sound.wav"); effect1=Mix_LoadWAV("sound.wav"); effect2=Mix_LoadWAV("sound2.wav"); screen=SDL_SetVideoMode(x,y,res,SDL_SWSURFACE); //in events loop Mix_PlayMusic(music-1); case SDL_KEYDOWN: switch(event.key,keysym.sym) { case SDLK_1: Mix_PlayChannel(-1,effect1,0); case SDLK_1: Mix_PlayChannel(-1,effect2,0); } //close Mix_FreeChuck(effect2); Mix_FreeChuck(effect1); Mix_FreeMusic(music); Mix_CloseAudio; SDL_QUIT();
Animation
edit//This program is made by thecplusplusguy from YouTube for demonstration purposes. //Feel free to read, learn, or modify the source as you wish, LGPL licence, I guess. //http://www.youtube.com/user/thecplusplusguy //keep this header comment for advertisement :) //compile in case of Windows normally, in case of Linux normally as well, so: //g++ particle.cpp -lSDL //Code::blocks: build and run #include <SDL/SDL.h> #include <iostream> #include <vector> //to store the particles (I like std::vector :D) #include <cstdlib> //for the random numbers #include <ctime> class particle{ //represent 1 particle float x,y,xvel,yvel; //position && speed Uint32 endTime; //death time Uint8 color; //color public: particle(float X,float Y,float Xvel,float Yvel,int life,Uint8 Color); void move(); void show(); bool isDead(); //true if the particle dead else false }; particle::particle(float X,float Y,float Xvel,float Yvel,int life,Uint8 Color) { //initialize the variables, nothing new x=X; y=Y; xvel=Xvel; yvel=Yvel; endTime=SDL_GetTicks()+life; //the end time, is the current time + the time, while the particle lives color=Color; } void particle::move() { //move x+=xvel; y+=yvel; //if it is outside of the screen, set it back to the edge of the screen if(x<0) x=0; if(y<0) y=0; if(x>SDL_GetVideoSurface()->w) x=SDL_GetVideoSurface()->w-1; if(y>SDL_GetVideoSurface()->h) y=SDL_GetVideoSurface()->h-1; } void particle::show() { //just set the pixel to the current color at the current position (pixel manipulation tutorial) Uint8* pixels=(Uint8*)SDL_GetVideoSurface()->pixels; Uint8* pixel=pixels+(int)y*SDL_GetVideoSurface()->pitch+(int)x; *pixel=color; } bool particle::isDead() { //read above, what it does return (SDL_GetTicks()>=endTime || x==0 || y==0 || x==SDL_GetVideoSurface()->w-1 || y==SDL_GetVideoSurface()->h-1); } //the particle engine will store all of the particle, and their initialize position class particleEngine{ std::vector<particle*> particles; //this vector represent all of the particle int x,y,maxparticle; public: particleEngine(int maxpart,int X, int Y); ~particleEngine(); //need for deallocate allocated space void refresh(); //move && show the particles }; particleEngine::particleEngine(int maxpart,int X, int Y) { x=X; y=Y; maxparticle=maxpart; for(int i=0;i<maxparticle;i++) //create maxparticle number of particles with random values both for position, velocity, life, color particles.push_back(new particle(x+rand()%6-3,y+rand()%6-3,rand()%10+(float)rand()/(float)RAND_MAX-5,rand()%10+(float)rand()/(float)RAND_MAX-5,500+rand()%1000,rand()%255)); } particleEngine::~particleEngine() { //deallocate all reserved memory for(int i=0;i<maxparticle;i++) delete particles[i]; } void particleEngine::refresh() { for(int i=0;i<maxparticle;i++) { if(particles[i]->isDead()) //if dead { delete particles[i]; //delete the earlier one and create a new particles[i]=new particle(x+rand()%6-3,y+rand()%6-3,rand()%10+(float)rand()/(float)RAND_MAX-5,rand()%10+(float)rand()/(float)RAND_MAX-5,500+rand()%2000,rand()%255); }else{ //else particles[i]->move(); //move && show particles[i]->show(); } } } int main(int argc,char** argv) { //this should be familiar to you SDL_Init(SDL_INIT_EVERYTHING); SDL_Surface* screen; screen=SDL_SetVideoMode(640,480,8,SDL_SWSURFACE); bool running=true; const int FPS=30; //make the FPS bigger, for quicker animation Uint32 start; srand(time(0)); //seed the random number generator particleEngine ps(5000,screen->w/2,screen->h/2); //create the particles while(running) { start=SDL_GetTicks(); SDL_Event event; while(SDL_PollEvent(&event)) { switch(event.type) { case SDL_QUIT: running=false; break; } } SDL_FillRect(screen,&screen->clip_rect,SDL_MapRGB(screen->format,0x00,0x00,0x00)); //clear the screen //logic ps.refresh(); //refresh the particles SDL_Flip(screen); if(1000/FPS>SDL_GetTicks()-start) SDL_Delay(1000/FPS-(SDL_GetTicks()-start)); } SDL_Quit(); return 0; }
References
editlibSDL.a libSDL_gfx.a libSDLGL.a libSDL_image.a libSDL_mixer.a libSDL_net.a libSDL_sound.a libSDL_ttf.a
SDL uses event-based input. All SDL apps are handling events by themselves. Therefore, every SDL app starts a busy loop on AROS, using as much of CPU time as possible. It seems also that the SDL software is badly written and most of the code uses event pooling (instead of waiting for events) and small delays, like here. It also seems, many programmers do not care at all if a SDL game consumes 100% of cpu time even in idle state.
st=SDL_GetAppState(); if ((st==SDL_APPACTIVE) || (! st) ) SDL_Delay(1000) else SDL_Delay(0) PollEvents... ...
Colors in SDL are usually stored in Uint32 variables. This type (and others) is defined by SDL so that you can be sure that you get exactly 32 bits on every different platform/OS, rather than the ambiguous 'unsigned int'. On a 32-bit surface, each color component gets 8 bits. If I write a hexidecimal constant like so: 0x50a600ff, and the pixel format is ARGB, then my components would be alpha = 0x50 (80), red = 0xa6 (166), green = 0x00 (0), and blue = 0xff (255). There you can see that color components range from 0 to 255 (256 values). These components can each be stored in Uint8 variables.
SDL uses the standard coordinate axes for computer graphics. The point (0, 0) is in the upper left-hand corner of the screen. The x coordinate increases to the right, and the y coordinate increases downward. This does have a small side-effect that the coordinate system is left-handed (angles are measured clockwise).
It pays to wrap certain things in your own functions. For example, you can write a function that draws an image to the screen, taking just the surface pointer and coordinates. Found it very easy to wrap both keyboard and joystick handling into one function, so my game accepts either input method for a particular player and the code to use it is nice and clean.
openGL
editOLD STYLE OpenGL 1.1 - Immediate mode: glBegin(), glEnd(), glVertex() etc
NEW STYLE OpenGL2 3 4 - Vertex Arrays
OpenGL 2, 3 and 4 - Shaders and co
editglColor() - Even if often used with immediate mode, this is ok for setting a constant color for further vertices to draw.
glNormal(), glTexCoord() - As with glColor(), although it's quite rare to set these to a constant value.
glTranslate(), glLoadMatrix(), glMultMatrix() etc. - These are the way to do transformations.
glMatrixMode() - Used to change which matrix to apply changes to. Don't do glFrustum(), glOrtho(), gluPerspective() or similar each frame (unless its arguments change). In most cases,this belongs to your reshape function.
NOTE: all of the previous functionality is deprecated, and done quite differently in "modern" OpenGL
glEnableClientState(), glVertexPointer() (and equivalent for normals, texcoords, color), glDrawArrays(), glDrawElements() - While deprecated, the "idea" is generally the same (but used functions different) with modern OpenGL. Give OpenGL a pointer to elements, which it will draw. Of course you want to use VBO (upload the data to graphics ram) when possible. You can do this with few #ifdef's if you want to compile your code also for platforms that already support it.
GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN - These are still around in every OpenGL (or OpenGL ES) implementation. Use freely.
NOTE: all previous functionality (except immediate mode) works with OpenGL ES1. OpenGL ES2 uses shaders extensively, and it's not possible to write code that works both on TinyGL or OpenGL1 and OpenGL ES2 without using lots of #ifdefs or similar, assuming you do something more complex than clear the screen with the specified color.
GL_QUADS, GL_QUAD_STRIP, GL_POLYGON - AVOID. Deprecated, and missing from both OpenGL ES1 and ES2. Use indexed GL_TRIANGLES or GL_TRIANGLE_STRIP instead.
http://www.amigacoding.de/index.php?topic=456.0
http://www.amigacoding.de/index.php?topic=494.0
VBOs (Vertx Buffer Objects) with texture atlases (create one big texture with all your textures in it uing Texture Arrays) - use multiple VBOs, one for each texture atlas -
shaders
use the OpenGL state machine more optimally. Switching between shaders and textures are often more expensive than actual draw calls, so one has to design the code in such a way that this switching is minimised, e.g. perform all the draw calls that need a specific shader and texture before switching to another shader and/or texture.
http://forum.unity3d.com/threads/63149-After-playing-minecraft...
lighting
shadows
reflections
bump/parallax mapping
OpenGL 1 - old
editAVIOD below
//pcguy
#include <iostream>
#include <SDL/SDL.h>
#include <GL/gl.h>
#include <GL/glu.h>
void init()
{
glClearColor(0.0,0.0,0.0,1.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0,640.0/480.0,1.0,500.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void display()
{
glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_TRIANGLES);
glVertex3f(0.0,2.0,-5.0);
glVertex3f(-2.0,-2.0,-5.0);
glVertex3f(2.0,-2.0,-5.0);
glEnd();
}
int main()
{
SDL_Init(SDL_INIT_EVERYTHING);
SDL_Surface* screen=SDL_SetVideoMode(640,480,32,SDL_SWSURFACE|SDL_OPENGL);
bool running=true;
Uint32 start;
SDL_Event event;
init();
while(running)
{
start=SDL_GetTicks();
while(SDL_PollEvent(&event))
{
switch(event.type)
{
case SDL_QUIT:
running=false;
break;
}
}
display();
SDL_GL_SwapBuffers();
if(1000/30>(SDL_GetTicks()-start))
SDL_Delay(1000/30-(SDL_GetTicks()-start));
}
SDL_Quit();
return 0;
}
int main( int argc, char **argv) { // graphics properties const int width = 640; // width of the game window const int height = 480; // height of the game window const float fov = 45.0f; // field of view (degrees) const float nearClip = 1.0f; // near clip plane (don't set to zero) const float farClip = 100.0f; // far clip plane // initialize SDL if( SDL_Init( SDL_INIT_VIDEO ) == -1 ) { fprintf(stderr, "Failed to initialize SDL. [%s]\n", SDL_GetError()); exit(1); } // set desired OpenGL attributes prior to selecting a video mode SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 ); // use 16 bits for depth buffer SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); // enable double buffering // create an OpenGL surface/window SDL_Surface *screen = SDL_SetVideoMode(width, height, 32, SDL_OPENGL); if( screen == NULL ) { fprintf(stderr, "Failed to set video mode. [%s]\n", SDL_GetError()); exit(1); } // initialize OpenGL if( SetupOpenGL( width, height, fov, nearClip, farClip) == -1 ) { fprintf( stderr, "Failed to setup OpenGL.\n" ); exit(1); } // main game loop bool done = false; while( !done ) { RenderScene(); if( ProcessInput() ) done = true; } SDL_Quit(); return 0; }
int SetupOpenGL( int width, int height, float fov, float nearClip, float farClip ) { glClearColor( 0.0f, 0.0f, 0.0f, 0.0f ); float ar = (GLfloat)width / height; // display aspect ratio // setup projection matrix glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(fov, ar, nearClip, farClip); // setup model view matrix glMatrixMode(GL_MODELVIEW); glLoadIdentity(); // setup depth buffer glClearDepth(1.0f); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); // misc. GL settings glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); glShadeModel(GL_SMOOTH); glViewport( 0, 0, width, height ); return 0; }
Render
editvoid RenderScene( void ) { // render everything for the current frame glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); // move off center so the quad is visible glTranslatef(-1.0f, 0.0f, -5.0f); // draw quad as red glColor3f( 1.0f, 0.0, 0.0 ); // render the quad glBegin(GL_QUADS); glVertex3f(-1.0f, 1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 0.0f); glVertex3f( 1.0f,-1.0f, 0.0f); glVertex3f(-1.0f,-1.0f, 0.0f); glEnd(); // update display SDL_GL_SwapBuffers(); }
Input
editbool ProcessInput( void ) { // runs the input processing loop // returns true if any input has requested the application to exit SDL_Event evt; bool exitFlag = false; // check for events generated from SDL while( SDL_PollEvent( &evt ) ) { switch( evt.type ) { case SDL_QUIT: exitFlag = true; break; case SDL_KEYUP: if( evt.key.keysym.sym == SDLK_ESCAPE ) exitFlag = true; break; default: break; } } return exitFlag; }
#include <windows.h> #include <gl\gl.h> #include <gl\glu.h> #include <sdl.h> #include <sdl_opengl.h> // function prototypes int SetupOpenGL( int width, int height, float fov, float nearClip, float farClip ); void RenderScene( void ); bool ProcessInput( void ); int main( int argc, char **argv) { // graphics properties const int width = 640; // width of the game window const int height = 480; // height of the game window const float fov = 45.0f; // field of view (degrees) const float nearClip = 1.0f; // near clip plane (don't set to zero) const float farClip = 100.0f; // far clip plane // initialize SDL if( SDL_Init( SDL_INIT_VIDEO ) == -1 ) { fprintf(stderr, "Failed to initialize SDL. [%s]\n", SDL_GetError()); exit(1); } // set desired OpenGL attributes prior to selecting a video mode SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 ); // use 16 bits for depth buffer SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); // enable double buffering // create an OpenGL surface/window SDL_Surface *screen = SDL_SetVideoMode(width, height, 32, SDL_OPENGL); if( screen == NULL ) { fprintf(stderr, "Failed to set video mode. [%s]\n", SDL_GetError()); exit(1); } // initialize OpenGL if( SetupOpenGL( width, height, fov, nearClip, farClip) == -1 ) { fprintf( stderr, "Failed to setup OpenGL.\n" ); exit(1); } // main game loop bool done = false; while( !done ) { RenderScene(); if( ProcessInput() ) done = true; } SDL_Quit(); return 0; } int SetupOpenGL( int width, int height, float fov, float nearClip, float farClip ) { glClearColor( 0.0f, 0.0f, 0.0f, 0.0f ); float ar = (GLfloat)width / height; // display aspect ratio // setup projection matrix glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(fov, ar, nearClip, farClip); // setup model view matrix glMatrixMode(GL_MODELVIEW); glLoadIdentity(); // setup depth buffer glClearDepth(1.0f); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); // misc. GL settings glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); glShadeModel(GL_SMOOTH); glViewport( 0, 0, width, height ); return 0; } void RenderScene( void ) { // render everything for the current frame glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); // move off center so the quad is visible glTranslatef(-1.0f, 0.0f, -5.0f); // draw quad as red glColor3f( 1.0f, 0.0, 0.0 ); // render the quad glBegin(GL_QUADS); glVertex3f(-1.0f, 1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 0.0f); glVertex3f( 1.0f,-1.0f, 0.0f); glVertex3f(-1.0f,-1.0f, 0.0f); glEnd(); // update display SDL_GL_SwapBuffers(); } bool ProcessInput( void ) { // runs the input processing loop // returns true if any input has requested the application to exit SDL_Event evt; bool exitFlag = false; // check for events generated from SDL while( SDL_PollEvent( &evt ) ) { switch( evt.type ) { case SDL_QUIT: exitFlag = true; break; case SDL_KEYUP: if( evt.key.keysym.sym == SDLK_ESCAPE ) exitFlag = true; break; default: break; } } return exitFlag; }
Lighting
edit// // // glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); //position of light source float pos[]={-2.0,2.0,3.0,1.0}; glLightfv(GL_LIGHT0,GL_POSITION,pos); //diffused float dif[]={1.0,1.0,1.0,1.0}; glLightfv(GL_LIGHT0,GL_DIFFUSE,dif); //ambient light float amb[]={0.2,0.2,0.2,1.0}; glLightfv(GL_LIGHT0,GL_AMBIENT,amb);
Animation
edit//http://www.youtube.com/user/thecplusplusguy //load animation main.cpp #include "functions.h" #include "objloader.h" #include "text.h" float angle=0.0; int cube; objloader obj; bool mousein=false; coordinate spherecenter(0.0,0.0,0.0); coordinate raystart(0.0,0.0,0.0); text* tex; std::vector<unsigned int> frames; int curframe=0; void init() { glClearColor(0.5,0.5,0.5,1.0); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45,640.0/480.0,1.0,500.0); glMatrixMode(GL_MODELVIEW); glEnable(GL_DEPTH_TEST); cube=obj.load("test10.obj"); std::vector<unsigned int> chars; char tmp[40]; for(int i=0;i<26;i++) { sprintf(tmp,"font/%d.obj",i); unsigned int tmp2=obj.load(tmp); chars.push_back(tmp2); } tex=new text(0.9,0.8,chars); // cube=loadObject("test.obj"); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); float col[]={1.0,1.0,1.0,1.0}; glLightfv(GL_LIGHT0,GL_DIFFUSE,col); initskybox(); loadAnimation(frames,"anim/anim",250,obj); } coordinate p1(-5.0,5.0,-5.0); coordinate p2(5.0,5.0,-5.0); coordinate p3(5.0,-5.0,-5.0); coordinate p4(-5.0,-5.0,-5.0); /* */ void display() { glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glLoadIdentity(); Control(0.2,0.2,mousein); drawSkybox(50.0); UpdateCamera(); float pos[]={-1.0,1.0,-2.0,1.0}; glLightfv(GL_LIGHT0,GL_POSITION,pos); // glTranslatef(0.0,0.0,-4.0); // glRotatef(angle,1,1,1); glDisable(GL_LIGHTING); // if(raysphere(spherecenter.x,spherecenter.y,spherecenter.z,0.0,0.0,1.0,raystart.x, raystart.y,raystart.z,1.0)) if(rayplane(0.0,0.0,1.0,raystart.x,raystart.y,raystart.z,0.0,0.0,-1.0,p1,p2,p3,p4)) glColor3f(1.0,0.0,0.0); else glColor3f(1.0,1.0,1.0); //xs+t*xd glBegin(GL_LINES); glVertex3f(raystart.x,raystart.y,raystart.z); glVertex3f(raystart.x+100*0,raystart.y+100*0,raystart.z+100*-1); glEnd(); glBegin(GL_QUADS); glVertex3f(-5.0,5.0,-5.0); glVertex3f(5.0,5.0,-5.0); glVertex3f(5.0,-5.0,-5.0); glVertex3f(-5.0,-5.0,-5.0); glColor3f(0,0,0); glVertex3f(-10.0,0.0,-10.0); glVertex3f(-10.0,-5.0,10.0); glVertex3f(10.0,-5.0,10.0); glVertex3f(10.0,0.0,-10.0); glEnd(); glEnable(GL_LIGHTING); glCallList(cube); tex->drawText(coordinate(10,0,0),coordinate(angle,0,0),"HELLO\nWORLD\nFROM\nOPENGL"); glTranslatef(-20,0,0); glCallList(frames[curframe]); curframe++; if(curframe>249) curframe=0; std::cout << curframe << std::endl; glColor3f(1.0,1.0,1.0); } coordinate p5(-10.0,0,-10.0); coordinate p6(-10.0,-5.0,10.0); coordinate p7(10.0,-5.0,10.0); coordinate p8(10.0,0,-10.0); int main() { SDL_Init(SDL_INIT_EVERYTHING); SDL_Surface* screen=SDL_SetVideoMode(640,480,32,SDL_SWSURFACE|SDL_OPENGL); bool running=true; Uint32 start; SDL_Event event; init(); bool b[4]={0,0,0,0}; while(running) { start=SDL_GetTicks(); while(SDL_PollEvent(&event)) { switch(event.type) { case SDL_QUIT: running=false; break; case SDL_MOUSEBUTTONDOWN: mousein=true; SDL_ShowCursor(SDL_DISABLE); break; case SDL_KEYDOWN: if(event.key.keysym.sym==SDLK_p) { mousein=false; SDL_ShowCursor(SDL_ENABLE); break; } if(event.key.keysym.sym==SDLK_ESCAPE) { running=false; break; } switch(event.key.keysym.sym) { case SDLK_UP: b[0]=1; break; case SDLK_LEFT: b[1]=1; break; case SDLK_DOWN: b[2]=1; break; case SDLK_RIGHT: b[3]=1; break; } break; case SDL_KEYUP: switch(event.key.keysym.sym) { case SDLK_UP: b[0]=0; break; case SDLK_LEFT: b[1]=0; break; case SDLK_DOWN: b[2]=0; break; case SDLK_RIGHT: b[3]=0; break; } break; } } if(b[0]) raystart.y+=0.3; if(b[1]) raystart.x-=0.3; if(b[2]) raystart.y-=0.3; if(b[3]) raystart.x+=0.3; display(); SDL_GL_SwapBuffers(); angle+=0.5; if(angle>360) angle-=360; coordinate cameraPos=camPos(); if(spheresphere(cameraPos,2.0,coordinate(0,0,0),1.0)) std::cout << "collision\n"; sphereplane(cameraPos,coordinate(0,0,1),p1,p2,p3,p4,2.0); sphereplane(cameraPos,coordinate(0,0.9701425,0.242535625),p5,p6,p7,p8,2.0); moveTo(cameraPos); if(1000/30>(SDL_GetTicks()-start)) SDL_Delay(1000/30-(SDL_GetTicks()-start)); } SDL_Quit(); killskybox(); delete tex; return 0; }
Collision
edit//http://www.youtube.com/user/thecplusplusguy //watch the video for explonation //ray-sphere and ray-plane collision detection. //if you find a bug, let me know #include "functions.h" #include "objloader.h" float angle=0.0; int cube; objloader obj; bool mousein=false; coordinate spherecenter(0.0,0.0,0.0); coordinate raystart(0.0,0.0,0.0); void init() { glClearColor(0.5,0.5,0.5,1.0); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45,640.0/480.0,1.0,500.0); glMatrixMode(GL_MODELVIEW); glEnable(GL_DEPTH_TEST); cube=obj.load("test10.obj"); // cube=loadObject("test.obj"); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); float col[]={1.0,1.0,1.0,1.0}; glLightfv(GL_LIGHT0,GL_DIFFUSE,col); initskybox(); } coordinate p1(-5.0,5.0,-5.0); coordinate p2(5.0,5.0,-5.0); coordinate p3(5.0,-5.0,-5.0); coordinate p4(-5.0,-5.0,-5.0); /* */ void display() { glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glLoadIdentity(); Control(0.2,0.2,mousein); drawSkybox(50.0); UpdateCamera(); float pos[]={-1.0,1.0,-2.0,1.0}; glLightfv(GL_LIGHT0,GL_POSITION,pos); // glTranslatef(0.0,0.0,-4.0); // glRotatef(angle,1,1,1); glDisable(GL_LIGHTING); // if(raysphere(spherecenter.x,spherecenter.y,spherecenter.z,0.0,0.0,1.0,raystart.x, raystart.y,raystart.z,1.0)) if(rayplane(0.0,0.0,1.0,raystart.x,raystart.y,raystart.z,0.0,0.0,-1.0,p1,p2,p3,p4)) glColor3f(1.0,0.0,0.0); else glColor3f(1.0,1.0,1.0); //xs+t*xd glBegin(GL_LINES); glVertex3f(raystart.x,raystart.y,raystart.z); glVertex3f(raystart.x+100*0,raystart.y+100*0,raystart.z+100*-1); glEnd(); glBegin(GL_QUADS); glVertex3f(-5.0,5.0,-5.0); glVertex3f(5.0,5.0,-5.0); glVertex3f(5.0,-5.0,-5.0); glVertex3f(-5.0,-5.0,-5.0); glEnd(); glEnable(GL_LIGHTING); glCallList(cube); glColor3f(1.0,1.0,1.0); } int main() { SDL_Init(SDL_INIT_EVERYTHING); SDL_Surface* screen=SDL_SetVideoMode(640,480,32,SDL_SWSURFACE|SDL_OPENGL); bool running=true; Uint32 start; SDL_Event event; init(); bool b[4]={0,0,0,0}; while(running) { start=SDL_GetTicks(); while(SDL_PollEvent(&event)) { switch(event.type) { case SDL_QUIT: running=false; break; case SDL_MOUSEBUTTONDOWN: mousein=true; SDL_ShowCursor(SDL_DISABLE); break; case SDL_KEYDOWN: if(event.key.keysym.sym==SDLK_p) { mousein=false; SDL_ShowCursor(SDL_ENABLE); break; } if(event.key.keysym.sym==SDLK_ESCAPE) { running=false; break; } switch(event.key.keysym.sym) { case SDLK_UP: b[0]=1; break; case SDLK_LEFT: b[1]=1; break; case SDLK_DOWN: b[2]=1; break; case SDLK_RIGHT: b[3]=1; break; } break; case SDL_KEYUP: switch(event.key.keysym.sym) { case SDLK_UP: b[0]=0; break; case SDLK_LEFT: b[1]=0; break; case SDLK_DOWN: b[2]=0; break; case SDLK_RIGHT: b[3]=0; break; } break; } } if(b[0]) raystart.y+=0.3; if(b[1]) raystart.x-=0.3; if(b[2]) raystart.y-=0.3; if(b[3]) raystart.x+=0.3; display(); SDL_GL_SwapBuffers(); angle+=0.5; if(angle>360) angle-=360; if(1000/30>(SDL_GetTicks()-start)) SDL_Delay(1000/30-(SDL_GetTicks()-start)); } SDL_Quit(); killskybox(); return 0; }