Jump to content

Aros/Developer/SDL

From Wikibooks, open books for an open world
Navbar for the Aros wikibook
Aros User
Aros User Docs
Aros User FAQs
Aros User Applications
Aros User DOS Shell
Aros/User/AmigaLegacy
Aros Dev Docs
Aros Developer Docs
Porting Software from AmigaOS/SDL
For Zune Beginners
Zune .MUI Classes
For SDL Beginners
Aros Developer BuildSystem
Specific platforms
Aros x86 Complete System HCL
Aros x86 Audio/Video Support
Aros x86 Network Support
Aros Intel AMD x86 Installing
Aros Storage Support IDE SATA etc
Aros Poseidon USB Support
x86-64 Support
Motorola 68k Amiga Support
Linux and FreeBSD Support
Windows Mingw and MacOSX Support
Android Support
Arm Raspberry Pi Support
PPC Power Architecture
misc
Aros Public License

Introduction

[edit | edit source]
SDL_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

[edit | edit source]

C++ initialisation of SDL

[edit | edit source]
#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

[edit | edit source]
game 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 | edit source]
/* 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 | edit source]
//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 | edit source]
//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

[edit | edit source]

Comprehensive Tutorials

SDL OpenGL and LUA

Tutorials

C++ Tutorial

Alpha Blending

Tutorials

2D Engine

SDL audio input examples

Programming Forum

libSDL.a
libSDL_gfx.a
libSDLGL.a
libSDL_image.a
libSDL_mixer.a
libSDL_net.a
libSDL_sound.a
libSDL_ttf.a

Stepped Tutorials Tetris,

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

[edit | edit source]

OLD 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

[edit | edit source]

glColor() - 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

[edit | edit source]

AVIOD 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

[edit | edit source]
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();
}

Input

[edit | edit source]
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;
}
#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 | edit source]

//

//

//

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 | edit source]
//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 | edit source]
//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;	
}