// include Simple Direct-media Layer #include #pragma comment( lib, "SDL.lib" ) #include // setup some basic data types typedef signed long long s64; typedef unsigned long long u64; typedef unsigned int u32; typedef signed int s32; typedef signed short s16; typedef unsigned char byte; typedef signed long long fp64; // ---- ----- ---- ---- ---- ---- ---- ---- FRAMEWORK SPECIFICS namespace framework { // the title name for this application const char *app_name = "Raytrace Demo"; // size of the video buffer const int vidSize = 512; // pixel size const int vidScale = 1; // video buffer u32 *video = NULL; // number of pixels in the video buffer const int nPixels = vidSize * vidSize; // calculated real SDL video buffer size const int scrRes = vidSize * vidScale; // the real SDL video buffer SDL_Surface *screen = NULL; // rate onTick is called in FPS const int tickFPS = 45; // mouse position int mousex = 0; int mousey = 0; }; // namespace framework using namespace framework; // ---- ----- ---- ---- ---- ---- ---- ---- MATH HELPER FUNCTIONS namespace mathHelper { static u32 randSeed = 0xBABEFACE; static s64 absi( s64 a ) { if ( a < 0 ) return -a; else return a; } static s64 maxi( s64 a, s64 b ) { if ( a > b ) return a; else return b; } static s64 mini( s64 a, s64 b ) { if ( a < b ) return a; else return b; } inline u32 randi( void ) { randSeed *= 1103515245; randSeed += 12345; return (randSeed >> 15) & 0xFFFF; } inline u32 scale( u32 a, byte scale ) { return (a * scale) >> 8; } }; // namespace mathHelper using namespace mathHelper; // ---- ----- ---- ---- ---- ---- ---- ---- FIXED POINT HELPER FUNCTIONS namespace fixedPointHelper { const fp64 fp_1 = 0x10000; fp64 fp_mul( fp64 a, fp64 b ) { return (a * b) >> 16; } fp64 fp_div( fp64 a, fp64 b ) { return (a << 16) / b; } fp64 fp_ceil( fp64 a ) { return (a | 0xFFFF) + 1; } fp64 fp_floor( fp64 a ) { return a & (~0xFFFF); } fp64 fp_fract( fp64 a ) { return a & 0xFFFF; } fp64 fp_ifract( fp64 a ) { return 0xFFFF - (a & 0xFFFF); } int fp_to_int( fp64 a ) { return (int) (a >> 16); } fp64 int_to_fp( int a ) { return (a << 16); } fp64 fp_rand( int max ) { return ((randi() % max) << 16) | (randi() & 0xFFFF); } }; // namespace fixedPointHelper using namespace fixedPointHelper; // ---- ----- ---- ---- ---- ---- ---- ---- DRAWING HELPER FUNCTIONS namespace videoHelper { static u32 drawColour = 0xFFFFFF; inline void plot( int x, int y ) { bool out = x < 0; out |= y < 0; out |= x >= vidSize; out |= y >= vidSize; if ( out ) return; video[ x + y * vidSize ] = drawColour; } inline u32 readPixel( int x, int y ) { bool out = x < 0; out |= y < 0; out |= x >= vidSize; out |= y >= vidSize; if ( out ) return 0; return video[ x + y * vidSize ]; } void circle( s32 x0, s32 y0, s32 radius ) { s32 error = 1 - radius; s32 errorY = 1; s32 errorX = -2 * radius; s32 x = radius, y = 0; plot(x0, y0 + radius); plot(x0, y0 - radius); plot(x0 + radius, y0); plot(x0 - radius, y0); while(y < x) { if (error > 0) { x--; errorX += 2; error += errorX; } { y++; errorY += 2; error += errorY; } plot(x0 + x, y0 + y); plot(x0 - x, y0 + y); plot(x0 + x, y0 - y); plot(x0 - x, y0 - y); plot(x0 + y, y0 + x); plot(x0 - y, y0 + x); plot(x0 + y, y0 - x); plot(x0 - y, y0 - x); } } void line( s32 X0, s32 Y0, s32 X1, s32 Y1 ) { s32 incrementVal = 0; s32 shortLen = Y1 - Y0; s32 longLen = X1 - X0; bool yLonger = false; s32 decInc = 0; s32 endVal = 0; s32 j = 0; if ( absi( shortLen ) > absi( longLen ) ) { int swap = shortLen; shortLen = longLen; longLen = swap; yLonger = true; } endVal = longLen; if ( longLen < 0 ) { incrementVal = -1; longLen = -longLen; } else incrementVal = 1; if ( longLen == 0 ) decInc = 0; else decInc = (shortLen << 16) / longLen; if ( yLonger ) { for ( s32 i=0; i!=endVal; i+=incrementVal ) { plot( X0 + (j >> 16), Y0 + i ); j += decInc; } } else { for ( s32 i=0; i!=endVal; i+=incrementVal ) { plot( X0 + i, Y0 + (j >> 16) ); j += decInc; } } } u32 randColour( void ) { return ((randi()&0xFF) << 16 ) | ((randi()&0xFF) << 8 ) | ((randi()&0xFF) ); } }; // namesapce videoHelper using namespace videoHelper; // ---- ----- ---- ---- ---- ---- ---- ---- DEMO CODE ( the good stuff ) namespace demo { struct vec3 { float x, y, z; vec3( ) : x( 0 ), y( 0 ), z( 0 ) { } vec3( float _tx, float _ty, float _tz ) : x( _tx ), y( _ty ), z( _tz ) { } void normalize( void ) { float d = 1.0f / sqrtf( x*x + y*y + z*z ); x *= d; y *= d; z *= d; } vec3 operator - ( const vec3 &a ) { return vec3( x - a.x, y - a.y, z - a.z ); } vec3 operator + ( const vec3 &a ) { return vec3( x + a.x, y + a.y, z + a.z ); } float operator * ( const vec3 &a ) { return x*a.x + y*a.y + z*a.z; } vec3 operator * ( const float s ) { return vec3( x*s, y*s, z*s ); } float lengthSqr( void ) { return x*x + y*y + z*z; } }; struct sSphere { sSphere( ) : origin( 0, 0, 0 ), radius( 0 ) { } sSphere( float x, float y, float z, float r ) : origin( x, y, z ), radius( r ) { } sSphere( float x, float y, float z, float r, u32 c ) : origin( x, y, z ), radius( r ), colour( c ) { } vec3 origin; float radius; u32 colour; }; struct sPlane { vec3 normal; float offset; }; struct sRay { vec3 origin; vec3 normal; }; bool intersect( sRay &ray, sSphere &sphere, vec3 &ipoint ) { vec3 EO = sphere.origin - ray.origin; float v = EO * ray.normal; float disc = sphere.radius * sphere.radius; disc -= (EO*EO) - (v*v); if ( disc < 0.0 ) return false; float d = sqrtf( disc ); ipoint = ray.origin + ray.normal * (v-d); return true; } bool intersect( sRay &ray, sPlane &plane, vec3 &ipoint ) { float t = - ( ray.origin * plane.normal + plane.offset ) / ( ray.normal * plane.normal ); ipoint = ray.origin + ray.normal * t; return (t > 0); } const int nSpheres = 3; sSphere spheres[ nSpheres ] = { sSphere( 0, 32, 315, 96, randColour( ) ), sSphere( -128, -32, 512, 48, randColour( ) ), sSphere( 0, -64, 256, 64, randColour( ) ) }; sPlane floor = { vec3( 0,-1, 0), 96.0f }; void onInit( void ) { /* for ( int i=0; i _2PI ) x -= _2PI; } float t = 0.0; void onTick( void ) { float hvs = vidSize / 2.0; for ( int y=0; ypixels; else video = new u32[ nPixels ]; return true; } static void blit_2x( void ) { // const int stride = screen->w; u32 *dst = (u32*) screen->pixels; int a = 0; for ( int i=0; i= vidSize ) { a = 0; // add on ONE stride not two since one length // has already been walked dst += stride; } } } static void app_draw( void ) { if ( vidScale <= 1 ) return; if ( vidScale == 2 ) { blit_2x( ); return; } for ( int i=0; ipixels ) delete [] video; video = NULL; // if ( screen != NULL ) SDL_FreeSurface( screen ); // SDL_Quit( ); } }; // namespace framework // windows entry point int __stdcall WinMain( int, int, int, int ) { // start up SDL atexit( app_quit ); if (! app_init( ) ) return 1; // get keyboard access u32 keyCount = 0; byte *keys = SDL_GetKeyState( (int*) &keyCount ); // seed the random randSeed ^= SDL_GetTicks( ); // call the on initialize function onInit( ); // int oldTicks = SDL_GetTicks( ); // work out the tick threshold in milliseconds const int tickThresh = 1000 / tickFPS; // while ( app_tick( ) ) { int diff = SDL_GetTicks() - oldTicks; if ( diff < 10 ) SDL_Delay( 10 ); if ( diff > 500 ) { oldTicks += diff; continue; } while ( diff > tickThresh ) { // grab the mouse state SDL_GetMouseState( &mousex, &mousey ); // tick the application onTick( ); app_draw( ); SDL_Flip( screen ); // progress the tick count oldTicks += tickThresh; diff -= tickThresh; } } return 0; }