Guest User

rt_raytrace.cpp

a guest
Jan 16th, 2014
123
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // linux:
  2. // compile using:
  3. // > g++ g++ -O3 -msse4 -I/usr/include/SDL/ rt_raytrace.cpp -o out.elf -L/usr/lib -lSDL
  4. // run using:
  5. // > ./out.elf
  6.  
  7. // include Simple Direct-media Layer
  8. #include <SDL/SDL.h>
  9.  
  10. #ifdef _MSC_VER
  11. #pragma comment( lib, "SDL.lib" )
  12. #include <intrin.h>
  13. #endif
  14.  
  15. #include <math.h>
  16.  
  17. // setup some basic data types
  18. typedef   signed long long s64;
  19. typedef unsigned long long u64;
  20. typedef unsigned int       u32;
  21. typedef   signed int       s32;
  22. typedef   signed short     s16;
  23. typedef unsigned char      byte;
  24. typedef   signed long long fp64;
  25.  
  26. // ---- ----- ---- ---- ---- ---- ---- ---- FRAMEWORK SPECIFICS
  27. namespace framework
  28. {
  29.     #define _threading
  30.  
  31.     // number of threads alive
  32.     volatile long threads   = 0;
  33.  
  34.     // true while program is running
  35.     volatile bool active    = true;
  36.  
  37.     // the title name for this application
  38.     const char *app_name    = "Raytrace Demo";
  39.  
  40.     // size of the video buffer
  41.     const int vidSize       = 512;
  42.  
  43.     // pixel size
  44.     const int vidScale      = 1;
  45.  
  46.     // video buffer
  47.     u32 *video              = NULL;
  48.      
  49.     // number of pixels in the video buffer
  50.     const int nPixels       = vidSize * vidSize;
  51.  
  52.     // calculated real SDL video buffer size
  53.     const int scrRes        = vidSize * vidScale;
  54.  
  55.     // the real SDL video buffer
  56.     SDL_Surface *screen     = NULL;
  57.  
  58.     // rate onTick is called in FPS
  59.     const int tickFPS       = 60;
  60.  
  61.     // mouse position
  62.     int mousex              = 0;
  63.     int mousey              = 0;
  64.  
  65. }; // namespace framework
  66. using namespace framework;
  67.  
  68. // ---- ----- ---- ---- ---- ---- ---- ---- MATH HELPER FUNCTIONS
  69. namespace mathHelper
  70. {
  71.     static u32 randSeed = 0xBABEFACE;
  72.  
  73.     static s64 absi( s64 a )
  74.     {
  75.         if ( a < 0 ) return -a;
  76.         else         return  a;
  77.     }
  78.  
  79.     static s64 maxi( s64 a, s64 b )
  80.     {
  81.         if ( a > b ) return a;
  82.         else         return b;
  83.     }
  84.  
  85.     static s64 mini( s64 a, s64 b )
  86.     {
  87.         if ( a < b ) return a;
  88.         else         return b;
  89.     }
  90.  
  91.     inline u32 randi( void )
  92.     {
  93.         randSeed *= 1103515245;
  94.         randSeed += 12345;
  95.         return (randSeed >> 15) & 0xFFFF;
  96.     }
  97.  
  98.     inline u32 scale( u32 a, byte scale )
  99.     {
  100.         return (a * scale) >> 8;
  101.     }
  102.  
  103. }; // namespace mathHelper
  104. using namespace mathHelper;
  105.  
  106. // ---- ----- ---- ---- ---- ---- ---- ---- DRAWING HELPER FUNCTIONS
  107. namespace videoHelper
  108. {
  109.     inline void plot( int x, int y, u32 drawColour )
  110.     {
  111.         bool out  = x < 0;
  112.              out |= y < 0;
  113.              out |= x >= vidSize;
  114.              out |= y >= vidSize;
  115.         if ( out ) return;
  116.         video[ x + y * vidSize ] = drawColour;
  117.     }
  118.  
  119.     u32 randColour( void )
  120.     {
  121.         return ((randi()&0xFF) << 16 ) | ((randi()&0xFF) << 8 ) | ((randi()&0xFF) );
  122.     }
  123.  
  124. }; // namesapce videoHelper
  125. using namespace videoHelper;
  126.  
  127. // ---- ----- ---- ---- ---- ---- ---- ---- DEMO CODE ( the good stuff )
  128. namespace demo
  129. {  
  130. #if 0
  131.     inline float isqrtf( float number )
  132.     {
  133.         long i;
  134.         float x2, y;
  135.         const float threehalfs = 1.5F;
  136.  
  137.         x2 = number * 0.5F;
  138.         y  = number;
  139.         i  = * ( long * ) &y;                       // evil floating point bit level hacking
  140.         i  = 0x5f3759df - ( i >> 1 );               // what the fuck?
  141.         y  = * ( float * ) &i;
  142.         y  = y * ( threehalfs - ( x2 * y * y ) );   // 1st iteration
  143.         y  = y * ( threehalfs - ( x2 * y * y ) );   // 2nd iteration, this can be removed
  144.         return y;
  145.     }
  146. #else
  147. inline float isqrtf( float number )
  148. {
  149.     return 1.0f / sqrtf( number );
  150. }
  151. #endif
  152.  
  153.     struct vec3
  154.     {
  155.         float x, y, z;
  156.  
  157.         vec3( )
  158.             : x( 0 ), y( 0 ), z( 0 )
  159.         {
  160.         }
  161.  
  162.         vec3( float _tx, float _ty, float _tz )
  163.             : x( _tx ), y( _ty ), z( _tz )
  164.         {
  165.         }
  166.  
  167.         void fnorm( void )
  168.         {
  169.             float d = isqrtf( x*x + y*y + z*z );
  170.             x *= d;
  171.             y *= d;
  172.             z *= d;
  173.         }
  174.  
  175.         vec3 project( vec3 &a )
  176.         {
  177.             return (*this) * ((a * (*this)) / length( ));
  178.         }
  179.  
  180.         vec3 operator - ( const vec3 &a ) const
  181.         {
  182.             return vec3( x - a.x, y - a.y, z - a.z );
  183.         }
  184.  
  185.         vec3 operator + ( const vec3 &a ) const
  186.         {
  187.             return vec3( x + a.x, y + a.y, z + a.z );
  188.         }
  189.  
  190.         float operator * ( const vec3 &a ) const
  191.         {
  192.             return x*a.x + y*a.y + z*a.z;
  193.         }
  194.  
  195.         vec3 operator * ( const float s ) const
  196.         {
  197.             return vec3( x*s, y*s, z*s );
  198.         }
  199.  
  200.         float length( void )
  201.         {
  202.             return sqrt( lengthSqr() );
  203.         }
  204.  
  205.         float lengthSqr( void ) const
  206.         {
  207.             return x*x + y*y + z*z;
  208.         }
  209.  
  210.         static vec3 findNormal( const vec3 &s, const vec3 &d )
  211.         {
  212.             vec3 n = d - s;
  213.             n.fnorm( );
  214.             return n;
  215.         }
  216.  
  217.         static float lengthSqr( const vec3 &s, const vec3 &d )
  218.         {
  219.             return (d.x-s.x)*(d.x-s.x) + (d.y-s.y)*(d.y-s.y) + (d.z-s.z)*(d.z-s.z);
  220.         }
  221.  
  222.         static vec3 reflect( const vec3 &n, const vec3 &r )
  223.         {
  224.             return r - n * ( 2 * (r * n) );
  225.         }
  226.  
  227.     };
  228.  
  229.     struct sSphere
  230.     {
  231.         sSphere( )
  232.             : origin( 0, 0, 0 ), radius( 0 )
  233.         {
  234.         }
  235.  
  236.         sSphere( const vec3 &center, float r )
  237.             : origin( center ), radius( r ), material( 0 )
  238.         {
  239.         }
  240.  
  241.         sSphere( const vec3 &center, float r, u32 m )
  242.             : origin( center ), radius( r ), material( m )
  243.         {
  244.         }
  245.  
  246.         vec3   origin;
  247.         float radius;
  248.         u32    material;
  249.     };
  250.  
  251.     struct sPlane
  252.     {
  253.         vec3  normal;
  254.         float offset;
  255.         u32   material;
  256.     };
  257.  
  258.     struct sRay
  259.     {  
  260.         sRay( )
  261.         {
  262.         }
  263.  
  264.         sRay( const vec3 &a )
  265.             : origin( ), normal( a )
  266.         {
  267.         }
  268.  
  269.         sRay( const vec3 &a, const vec3 &b )
  270.         {
  271.             origin = a;
  272.             normal = b - a;
  273.             normal.fnorm( );
  274.         }
  275.  
  276.         vec3 origin;
  277.         vec3 normal;
  278.     };
  279.  
  280.     const int nSpheres = 3;
  281.     const float lightRadius = 4.0f;
  282.     vec3 light( 0,-120, 256+128 );
  283.  
  284.     sSphere spheres[ nSpheres ] =
  285.     {
  286.         sSphere( vec3(   0, 128.f - 128.f, 420        ), 10.f, 0 ),
  287.         sSphere( vec3(  32, 128.f -  64.f, 512.f-96.f ), 64.f, 1 ),
  288.         sSphere( vec3( -32, 128.f -  32.f, 310        ), 32.f, 0 )
  289.     };
  290.  
  291.     sPlane planes[] =
  292.     {
  293.         { vec3( 0,-1, 0), 128.0f, 0 },
  294.         { vec3( 0, 1, 0), 128.0f, 0 },
  295.         { vec3( 0, 0,-1), 512.0f, 0 },
  296.         { vec3( 0, 0, 1),-256.0f, 0 },
  297.         { vec3( 1, 0, 0), 128.0f, 0 },
  298.         { vec3(-1, 0, 0), 128.0f, 0 }
  299.     };
  300.    
  301.    
  302.     bool useShadows = true;
  303.  
  304.     //
  305.     // precise ray intersection test
  306.     //
  307.     bool intersect( sRay &ray, sSphere &sphere, vec3 &ipoint )
  308.     {
  309.         float t1 = -1;
  310.         float t2 = -1;
  311.         float discriminant;
  312.         float t = -1;
  313.         //temporary == e-c
  314.         vec3 temp = ray.origin - sphere.origin;
  315.         float b = 2 * (ray.normal * temp);
  316.         float a = ray.normal * ray.normal;
  317.         float c = temp * temp - (sphere.radius * sphere.radius);
  318.         float disc;
  319.         disc = b*b - 4*a*c;
  320.         if ( disc < 0 )
  321.             return false;
  322.         else
  323.         {
  324.             discriminant = 1.0f / isqrtf( disc );
  325.             t1 = (-b+discriminant)/(2*a);
  326.             t2 = (-b-discriminant)/(2*a);  
  327.  
  328.             if (t2 > 0)
  329.             {
  330.                 ipoint = ray.origin + ray.normal * t2;
  331.                 return true;
  332.             }
  333.             if ( t1 > 0 )
  334.             {
  335.                 ipoint = ray.origin + ray.normal * t1;
  336.                 return true;
  337.             }
  338.         }
  339.         return false;
  340.     }
  341.    
  342.     bool intersect( sRay &ray, sPlane &plane, vec3 &ipoint )
  343.     {
  344.         if ( ray.normal * plane.normal > 0 )
  345.             return false;
  346.  
  347.         float t = - ( ray.origin * plane.normal + plane.offset ) / ( ray.normal * plane.normal );
  348.         ipoint = ray.origin + ray.normal * t;
  349.  
  350.         return (t > 0);
  351.     }
  352.    
  353.     void rayShoot( sRay &ray, vec3 &xpoint, vec3 &normal, u32 &material, float &min )
  354.     {
  355.         min = 99999999.f;
  356.         vec3  ipoint;
  357.  
  358.         // sphere intersections
  359.         for ( int i=0; i<nSpheres; i++ )
  360.         {
  361.             sSphere &sphere = spheres[ i ];
  362.             if ( intersect( ray, sphere, ipoint ) )
  363.             {
  364.                 float dst = (ipoint-ray.origin).lengthSqr( );
  365.                 if ( dst < min /*|| min < 0.0f*/ )
  366.                 {
  367.                     xpoint      = ipoint;
  368.                     float irad  = 1.0f / sphere.radius;
  369.                     min         = dst;
  370.                     normal      = (ipoint - sphere.origin);
  371.                     normal.x   *= irad;
  372.                     normal.y   *= irad;
  373.                     normal.z   *= irad;
  374.                     material    = sphere.material;
  375.                 }
  376.             }
  377.         }
  378.  
  379.         // plane intersections
  380.         for ( int i=0; i<6; i++ )
  381.         {
  382.             sPlane &plane = planes[i];
  383.             if ( intersect( ray, plane, ipoint ) )
  384.             {
  385.                 float dst = (ipoint-ray.origin).lengthSqr( );
  386.                 if ( dst < min /*|| min < 0.0f*/ )
  387.                 {
  388.                     xpoint   = ipoint;
  389.                     min      = dst;
  390.                     normal   = plane.normal;
  391.                     material = plane.material;
  392.                 }
  393.             }
  394.         }
  395.  
  396.     }
  397.  
  398.     void incWrap( float &x, float y )
  399.     {
  400.         const float _2PI = 6.28318530718f;
  401.         if ( (x+=y) > _2PI ) x -= _2PI;
  402.     }
  403.  
  404.     // rand -1 -> +1 - uniform dist
  405.     inline
  406.     float jitter( void )
  407.     {
  408.         static s32 seed = 0xfacebabe;
  409.         const float fact =  4.6566129e-010f * lightRadius;
  410.         seed *= 87103;
  411.         return (float)seed * fact;
  412.     }
  413.  
  414.     int renderRegion( void *arg )
  415.     {
  416.         float hvs = vidSize / 2.0;
  417.  
  418.         SDL_Rect *rect = (SDL_Rect*)arg;
  419.  
  420.         int x1 = rect->x;
  421.         int x2 = rect->x + rect->w;
  422.         int y1 = rect->y;
  423.         int y2 = rect->y + rect->h;
  424.        
  425.         u32 drawColour = 0;
  426.  
  427. #ifdef _threading
  428.         while ( active )
  429.         {
  430. #endif
  431.             for ( int y=y1; y<y2; y++ )
  432.             {
  433.                 for ( int x=x1; x<x2; x++ )
  434.                 {
  435.                     float atten = 1.0f;
  436.  
  437.                     vec3 lpos( light.x, light.y, light.z );
  438. //                  vec3 lpos( light.x + jitter(), light.y, light.z + jitter() );
  439.  
  440.                     sRay ray( vec3( x-hvs, y-hvs, hvs*2 ) );
  441.                     ray.normal.fnorm( );
  442.  
  443.                     vec3  ipoint;
  444.                     vec3  normal;
  445.                     float dist;
  446.                     u32   material = 0;
  447.  
  448.                     rayShoot( ray, ipoint, normal, material, dist );
  449.  
  450.                     if ( material == 1 )
  451.                     {
  452.                         ray.normal = vec3::reflect( normal, ray.normal );
  453.                         ray.origin = ipoint + ray.normal;
  454.                    
  455.                         atten = ray.normal * normal;
  456.                         if ( atten < 0 ) atten = 0;
  457.  
  458.                         rayShoot( ray, ipoint, normal, material, dist );
  459.                     }
  460.                    
  461.  
  462.                     //
  463.                     // dot product lighting
  464.                     //
  465.                     vec3 lightNorm = vec3::findNormal( ipoint, light );
  466.                     float dplight = normal * lightNorm;
  467.                     if ( dplight < 0.0f )
  468.                         dplight = 0.0f;
  469.                     else
  470.                     {
  471.                         atten *= 1.0f / (vec3::lengthSqr( ipoint, light ) * 0.0001f);
  472.                         if ( atten > 1.0f )
  473.                             atten = 1.0f;
  474.                     }
  475.  
  476.                     u32 dp3 = (u32)( dplight * 255 * atten );
  477.                     drawColour = dp3 | (dp3 << 8) | (dp3 << 16);
  478.  
  479.                     //
  480.                     // shadows
  481.                     //
  482.  
  483.                     // distance from intersection point to light
  484.                     float ldist = vec3::lengthSqr( ipoint, lpos );
  485.  
  486.                     // trace from light to interection point
  487.                     sRay lightRay( lpos, ipoint );
  488.                     u32   colour = 0;
  489.                     float mdist  = 0;
  490.  
  491.                     vec3 t1;
  492.                     vec3 t2;
  493.                     rayShoot( lightRay, t1, t2, colour, mdist );
  494.  
  495.                     if ( useShadows )
  496.                     {
  497.                         if ( ldist-1 > mdist )
  498.                             drawColour = (drawColour>>3) & 0x1f1f1f;
  499.                     }
  500.  
  501.                     plot( x, y, drawColour );
  502.                 }
  503.             }
  504. #ifdef _threading
  505.         } // while ( active )
  506. #endif
  507.  
  508. #ifdef _threading
  509. #ifdef _MSC_VER
  510.         _InterlockedDecrement( &threads );
  511. #else
  512.         __sync_fetch_and_sub( &threads, 1 );
  513. #endif
  514. #endif
  515.         return 1;
  516.     }
  517.  
  518.     void onTick( void )
  519.     {
  520.         static float t=0.0f; incWrap( t, 0.012346f );
  521.         static float g=0.0f; incWrap( g, 0.024243f );
  522.  
  523.         // move sphere
  524.         spheres[0].origin.x = sin( (float)t ) * 64.f;
  525.         spheres[0].origin.y =-sin( (float)g ) * 8.f- 32 ;
  526.         spheres[0].origin.z = cos( (float)t ) * 64 + (128 + 256);
  527.  
  528. #ifndef _threading
  529.         SDL_Rect r1 = { 0, 0, vidSize, vidSize };
  530.         renderRegion( &r1 );
  531. #endif
  532.  
  533.         // move light
  534.         light.x = sin( g ) * 64;
  535.         light.y = sin( t ) * 16 - 96;
  536.         light.z = cos( g ) * 32 + (256+64);
  537.     }
  538.  
  539.     void app_createThread( int x, int y, int w, int h )
  540.     {
  541.         SDL_Rect *r = new SDL_Rect;
  542.         r->x = x;
  543.         r->y = y;
  544.         r->w = w;
  545.         r->h = h;
  546.  
  547.         if ( SDL_CreateThread( renderRegion, (void*)r ) )
  548.         {
  549. #ifdef _threading
  550. #ifdef _MSC_VER
  551.             _InterlockedIncrement( &threads );
  552. #else
  553.             __sync_fetch_and_add( &threads, 1 );
  554. #endif
  555. #endif
  556.         }
  557.     }
  558.  
  559.     void onInit( void )
  560.     {
  561. #ifdef _threading
  562.         int hvs = vidSize / 2;
  563.         app_createThread( 0  ,   0, hvs, hvs );
  564.         app_createThread( hvs,   0, hvs, hvs );
  565.         app_createThread( 0  , hvs, hvs, hvs );
  566.         app_createThread( hvs, hvs, hvs, hvs );
  567. #endif
  568.     }
  569.  
  570.     void onKeyHit( SDLKey key )
  571.     {
  572.         switch ( key )
  573.         {
  574.         case ( SDLK_SPACE ):
  575.             useShadows = !useShadows;
  576.         }
  577.     }
  578.  
  579. }; // namespace demo
  580. using namespace demo;
  581.  
  582. // ---- ----- ---- ---- ---- ---- ---- ---- FRAMEWORK FUNCIONS
  583. namespace framework
  584. {
  585.     static bool app_init( void )
  586.     {
  587.         if ( SDL_Init( SDL_INIT_VIDEO ) != 0 )
  588.             return false;
  589.  
  590.         SDL_WM_SetCaption( app_name, NULL );
  591.  
  592.         screen = SDL_SetVideoMode( scrRes, scrRes, 32, 0 );
  593.         if ( screen == NULL )
  594.             return false;
  595.  
  596.         if ( vidScale == 1 )    video = (u32*)screen->pixels;
  597.         else                    video = new u32[ nPixels ];
  598.  
  599.         return true;
  600.     }
  601.  
  602.     static void blit_2x( void )
  603.     {
  604.         //
  605.         const int stride = screen->w;
  606.  
  607.         u32 *dst = (u32*) screen->pixels;
  608.  
  609.         int a = 0;
  610.  
  611.         for ( int i=0; i<nPixels; i++ )
  612.         {
  613.             u32 colour = video[ i ];
  614.            
  615.             // x4 pixel write
  616.             dst[0       ] = colour;
  617.             dst[1       ] = colour;
  618.             dst[  stride] = colour;
  619.             dst[1+stride] = colour;
  620.  
  621.             dst += 2;
  622.             if ( a++ >= vidSize )
  623.             {
  624.                 a = 0;
  625.                 // add on ONE stride not two since one length
  626.                 // has already been walked
  627.                 dst += stride;
  628.             }
  629.         }
  630.     }
  631.  
  632.     static void app_draw( void )
  633.     {
  634.         if ( vidScale <= 1 )
  635.             return;
  636.  
  637.         if ( vidScale == 2 )
  638.         {
  639.             blit_2x( );
  640.             return;
  641.         }
  642.  
  643.         for ( int i=0; i<nPixels; i++ )
  644.         {
  645.             SDL_Rect rect =
  646.             {
  647.                 (i % vidSize) * vidScale,
  648.                 (i / vidSize) * vidScale,
  649.                                 vidScale,
  650.                                 vidScale
  651.             };
  652.             SDL_FillRect( screen, &rect, video[ i ] );
  653.         }
  654.     }
  655.  
  656.     static bool app_tick( void )
  657.     {
  658.         SDL_Event event;
  659.         while ( SDL_PollEvent( &event ) )
  660.         {
  661.             switch ( event.type )
  662.             {
  663.             case ( SDL_QUIT ):
  664.                 active = false;
  665.                 break;
  666.             case ( SDL_KEYUP ):
  667.                 {
  668.                     if ( event.key.keysym.sym == SDLK_ESCAPE )
  669.                     {
  670.                         active = false;
  671.                     }
  672.                     else
  673.                         onKeyHit( event.key.keysym.sym );
  674.                 }
  675.                 break;
  676.             }
  677.         }
  678.         return active;
  679.     }
  680.  
  681.     static void app_quit( void )
  682.     {
  683.         //
  684.         if ( video != NULL )
  685.             if ( video != screen->pixels )
  686.                 delete [] video;
  687.         video = NULL;
  688.         //
  689.         if ( screen != NULL )
  690.             SDL_FreeSurface( screen );
  691.         //
  692.         SDL_Quit( );
  693.     }
  694.  
  695. }; // namespace framework
  696.  
  697. #ifdef _MSC_VER
  698. // windows entry point
  699. int __stdcall WinMain( int, int, int, int )
  700. #else
  701. int main( int argc, char** args )
  702. #endif
  703. {
  704.     // start up SDL
  705.     atexit( app_quit );
  706.     if (! app_init( ) )
  707.         return 1;
  708.     // get keyboard access
  709.     u32 keyCount = 0;
  710.     byte *keys = SDL_GetKeyState( (int*) &keyCount );
  711.     // seed the random
  712.     randSeed ^= SDL_GetTicks( );
  713.     // call the on initialize function 
  714.     onInit( );
  715.     //
  716.     int oldTicks = SDL_GetTicks( );
  717.     // work out the tick threshold in milliseconds
  718.     const int tickThresh = 1000 / tickFPS;
  719.     //
  720.     while ( app_tick( ) )
  721.     {
  722.         int diff = SDL_GetTicks() - oldTicks;
  723.  
  724.         if ( diff < 10  )
  725.             SDL_Delay( 10 );
  726.  
  727.         if ( diff > 500 )
  728.         {
  729.             oldTicks += diff;
  730.             continue;
  731.         }
  732.  
  733.         while ( diff > tickThresh )
  734.         {
  735.             // grab the mouse state
  736.             SDL_GetMouseState( &mousex, &mousey );
  737.             // tick the application
  738.             onTick( );
  739.             app_draw( );
  740.             SDL_Flip( screen );
  741.             // progress the tick count
  742.             oldTicks += tickThresh;
  743.             diff     -= tickThresh;
  744.         }
  745.     }
  746.  
  747.     //
  748.     while ( threads > 0 )
  749.         SDL_Delay( 100 );
  750.  
  751.     return 0;
  752. }
RAW Paste Data