Guest User

Raytrace6.cpp

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