Advertisement
bubblesppf

BVH_SAH

Jun 13th, 2011
534
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 56.21 KB | None | 0 0
  1. #define DEFINE_VARS
  2. #include "OnlineHelpKeys.h"
  3. #include <list>
  4. #include <math.h>
  5. #include <stdio.h>
  6. #include <assert.h>
  7. #include <sys/stat.h>
  8. #include <stdlib.h>
  9. #include <stdio.h>
  10.  
  11. #include <iostream>
  12. #include <algorithm>
  13. #include <vector>
  14. #include <cfloat>
  15. #include <string>
  16.  
  17. #include <cstdio>
  18. #include <cstdlib>
  19. #include <sstream>
  20. #include <fstream>
  21. #include <cfloat>
  22. //using SDL
  23. #include <SDL.h>
  24.  
  25. //using LIB3DS
  26. #include <types.h>
  27. #include <material.h>
  28. #include <mesh.h>
  29. #include <file.h>
  30. #include <map>
  31. using namespace std;
  32.  
  33. #define AMBIENT     96.f
  34. #define BVH_STACK_SIZE 32
  35. #define MAX_RAY_DEPTH       3
  36.  
  37. #define DIFFUSE     128.f
  38. #define SPECULAR    192.f
  39.  
  40. // Ray intersections of a distance <=NUDGE_FACTOR (from the origin) don't count
  41. #define NUDGE_FACTOR     1e-5f
  42. // Maximum allowed depth of BVH
  43. // Checked at BVH build time, no runtime crash possible, see below
  44. #define BVH_STACK_SIZE 32
  45. #define TRI_MAGIC   0xDEADBEEF
  46. #define TRI_MAGICNORMAL 0xDEADC0DE
  47. #define DEBUG_LOG_BVH
  48.  
  49. using namespace std;
  50.  
  51. #define WIDTH       800
  52. #define HEIGHT      600
  53. #define SCREEN_DIST (HEIGHT*2)
  54.  
  55. #define PROGRESS_REPORT
  56. #ifdef  PROGRESS_REPORT
  57. #define REPORT(x) x
  58. #define REPORTPRM(x) x,
  59. #else
  60. #define REPORT(x)
  61. #define REPORTPRM(x)
  62. #endif
  63. using std::string;
  64. unsigned g_reportCounter = 0;
  65. typedef float coord;
  66.  
  67. struct Float3
  68. {
  69.    float X, Y Z;
  70.    Float3(float x=0, float y=0, float z=0)
  71.         :
  72.    X(x), Y(y), Z(z){}
  73.    
  74.    Float3(const Float3& rhs)
  75.         :
  76.    X(rhs.X), Y(rhs.Y), Z(rhs.Z){}
  77.  
  78.    inline Float3& operator+=(const Float3& rhs)
  79.    {    X += rhs.X; Y += rhs.Y; Z += rhs.Z; return *this; }
  80.  
  81.    inline Float3& operator-=(const Float3& rhs)
  82.     {X -= rhs.X; Y -= rhs.Y; Z -= rhs.Z; return *this;}
  83.  
  84.    inline Float3& operator*=(const float& rhs)
  85.     {X *= rhs; Y *= rhs; Z *= rhs; return *this;}
  86.  
  87.    inline Float3& operator/=(const float& rhs)
  88.     {X /= rhs; Y /= rhs; Z /= rhs; return *this;}
  89.  
  90.    inline bool operator!=(const Float3& rhs)
  91.     {return X!=rhs.X || Y!=rhs.Y || Z!=rhs.Z; }
  92.  
  93.    inline Float3 operator*(float rhs) const
  94.     {return Float3(X*rhs, Y*rhs, Z*rhs);   }
  95.  
  96.    inline Float3 operator+(Float3& rhs) const
  97.     {return Float3(X+rhs.X, Y+rhs.Y, Z+rhs.Z);}
  98.  
  99.    inline Float3 operator-(Float3& rhs) const
  100.     {return Float3(X-rhs.X, Y-rhs.Y, Z-rhs.Z);   }
  101.      
  102.    inline void assignSmaller(const Float3& rhs)
  103.    {  X = std::min(X, rhs.X); Y = std::min(Y, rhs.Y); Z = std::min(Z, rhs.Z);   }
  104.    
  105.    inline void assignBigger(const Float3& rhs)
  106.     { X = std::max(X, rhs.X); Y = std::max(Y, rhs.Y); Z = std::max(Z, rhs.Z);}
  107.    
  108.    inline float length()
  109.     {return sqrt(X*X +Y*Y + Z*Z); }
  110.  
  111.    inline float lengthsq()
  112.     {return X*X +Y*Y + Z*Z; }
  113.  
  114.    inline void Normalize()
  115.     {   float norm = length();
  116.     X/= norm; Y/= norm; Z/= norm;   }
  117. };
  118.  
  119. struct Vertex : public Float3
  120. {
  121.     Float3 n;
  122.     unsigned _ambientOcclusionCoeff;
  123.  
  124.     Vertex(float x, float y, float z, float nx, float ny, float nz, unsigned char amb=60)
  125.     :
  126.     Float3(x,y,z), n(nx,ny,nz), _ambientOcclusionCoeff(amb){}
  127.        
  128. };
  129.  
  130. struct Pixel {
  131.     float _b, _g, _r;
  132.     Pixel(float r=0.f, float g=0.f, float b=0.f)
  133.     :
  134.     _b(b), _g(g), _r(r) {}
  135.  
  136.     Pixel& operator+=(const Pixel& rhs) { _b += rhs._b; _g += rhs._g; _r += rhs._r; return *this; }
  137.     Pixel& operator-=(const Pixel& rhs) { _b -= rhs._b; _g -= rhs._g; _r -= rhs._r; return *this; }
  138.     Pixel& operator*=(const float& rhs) { _b =  rhs*_b; _g  = rhs*_g; _r  = rhs*_r; return *this; }
  139.     Pixel& operator/=(const float& rhs) { _b =  _b/rhs; _g  = _g/rhs; _r  = _r/rhs; return *this; }
  140.  
  141.     Pixel operator+(const Pixel& rhs) {
  142.     float r = _r+rhs._r; if (r<0.f) r=0.f; if (r>255.f) r=255.f;
  143.     float g = _g+rhs._g; if (g<0.f) g=0.f; if (g>255.f) g=255.f;
  144.     float b = _b+rhs._b; if (b<0.f) b=0.f; if (b>255.f) b=255.f;
  145.     return Pixel(r,g,b);
  146.     }
  147.     Pixel operator*(const float& rhs) { return Pixel(rhs*_r, rhs*_g, rhs*_b); }
  148. };
  149.  
  150. struct Screen
  151. {
  152.     static SDL_Surface *_surface;
  153.     float _Zbuffer[HEIGHT][WIDTH];
  154.     const struct Scene& _scene;
  155.  
  156.     public:
  157.  
  158.     Screen(const struct Scene& scene)
  159.     :
  160.     _scene(scene)
  161.     {
  162.     if ( SDL_Init(SDL_INIT_VIDEO) < 0 )
  163.     {
  164.         std::cerr << "Couldn't initialize SDL: " <<  SDL_GetError() << std::endl;
  165.         exit(0);
  166.     }
  167.  
  168.     // Clean up on exit
  169.     atexit(SDL_Quit);
  170.  
  171.     // We ask for 32bit surface...
  172.     _surface = SDL_SetVideoMode( WIDTH, HEIGHT, 32, SDL_HWSURFACE | SDL_DOUBLEBUF | SDL_HWACCEL | SDL_ASYNCBLIT);
  173.     if (!_surface)
  174.     // ...and if that fails, we settle for a software-emulation of 16bit
  175.     _surface = SDL_SetVideoMode( WIDTH, HEIGHT, 16, SDL_SWSURFACE | SDL_DOUBLEBUF);
  176.  
  177.     if (!_surface)
  178.     {
  179.        std::cerr << "Couldn't set video mode: " << SDL_GetError() << std::endl;
  180.        exit(0);
  181.     }
  182.  
  183.     if ( SDL_MUSTLOCK(_surface) )
  184.     {
  185.        if ( SDL_LockSurface(_surface) < 0 )
  186.        {
  187.         std::cerr << "Couldn't lock _surface: " << SDL_GetError() << std::endl;
  188.         exit(0);
  189.        }
  190.     }
  191. ClearScreen();
  192. ClearZbuffer();
  193. }
  194.  
  195. ~Screen()
  196. {
  197.     if ( SDL_MUSTLOCK(_surface) )
  198.     SDL_UnlockSurface(_surface);
  199. }
  200.  
  201. void ClearScreen()
  202. {
  203.     Uint32 color = SDL_MapRGB(_surface->format, 0, 0, 0);
  204.     SDL_FillRect(_surface, NULL, color);
  205. }
  206.  
  207. void ClearZbuffer()
  208. {
  209.     memset(reinterpret_cast<void*>(&_Zbuffer[0][0]), 0x0, sizeof(_Zbuffer));
  210. }
  211.  
  212.     // Almost verbatim copy from www.libsdl.org "Introduction" section
  213. void DrawPixel(int y, int x, Uint32 color)
  214.     {
  215.     switch (_surface->format->BytesPerPixel)
  216.     {
  217.         case 1:
  218.         { /* Assuming 8-bpp */
  219.           Uint8 *bufp;
  220.  
  221.           bufp = (Uint8 *)_surface->pixels + y*_surface->pitch + x;
  222.           *bufp = color;
  223.             }
  224.         break;
  225.  
  226.         case 2:
  227.              { /* Probably 15-bpp or 16-bpp */
  228.         Uint16 *bufp;
  229.  
  230.         bufp = (Uint16 *)_surface->pixels + y*_surface->pitch/2 + x;
  231.         *bufp = color;
  232.          }
  233.         break;
  234.  
  235.         case 3:
  236.               { /* Slow 24-bpp mode, usually not used */
  237.         Uint8 *bufp;
  238.  
  239.         bufp = (Uint8 *)_surface->pixels + y*_surface->pitch + x;
  240.         *(bufp+_surface->format->Rshift/8) =
  241.             ((color & _surface->format->Rmask) >> _surface->format->Rshift) << _surface->format->Rloss;
  242.         *(bufp+_surface->format->Gshift/8) =
  243.             ((color & _surface->format->Gmask) >> _surface->format->Gshift) << _surface->format->Gloss;
  244.         *(bufp+_surface->format->Bshift/8) =
  245.             ((color & _surface->format->Bmask) >> _surface->format->Bshift) << _surface->format->Bloss;
  246.          }
  247.         break;
  248.  
  249.         case 4:
  250.          { /* Probably 32-bpp */
  251.         Uint32 *bufp;
  252.  
  253.         bufp = (Uint32 *)_surface->pixels + y*_surface->pitch/4 + x;
  254.         *bufp = color;
  255.         }
  256.         break;
  257.     }
  258.     }
  259.  
  260. void ShowScreen(bool raytracerOutput=false)
  261. {
  262.     if (!raytracerOutput)
  263.       { //  to add the "Press H for help" when not benchmarking
  264.     extern bool g_benchmark;
  265.     if (!g_benchmark)
  266.     {
  267.       unsigned char *pData = onlineHelpKeysImage;
  268.        for(int h=0; h<OHELPH; h++)
  269.           for(int w=0; w<OHELPW; w++)
  270.         {
  271.                pData++;
  272.            unsigned char c = *pData++;
  273.            pData++;
  274.            if (c<200)
  275.            DrawPixel(h + 20,WIDTH-20-OHELPW + w,
  276.                 SDL_MapRGB(_surface->format, 255-c, 255-c, 255-c));
  277.         }
  278.            
  279.          }
  280.      }
  281.      if ( SDL_MUSTLOCK(_surface) ) {SDL_UnlockSurface(_surface);}
  282.        
  283.      if (raytracerOutput)
  284.     SDL_UpdateRect(_surface, 0, 0, 0, 0);
  285.      else
  286.         SDL_Flip(_surface);
  287.      
  288.      if ( SDL_MUSTLOCK(_surface) )
  289.     {
  290.        if ( SDL_LockSurface(_surface) < 0 )
  291.         {
  292.            std::cerr << "Couldn't lock _surface: " << SDL_GetError() << std::endl;
  293.            exit(0);
  294.         }
  295.     }
  296. }
  297.  
  298. };
  299. SDL_Surface *Screen::_surface = NULL;
  300.  
  301. struct Triangle
  302. {
  303.     const Vertex *_vertexA, *_vertexB, *_vertexC;
  304.     Float3 centroid, n;
  305.  
  306.     // Color:
  307.     Pixel _colorf;
  308.     // precomputed for SDL surface
  309.     Uint32 _color;
  310.  
  311.     // Should we backface cull this triangle?
  312.     bool _twoSided;
  313.  
  314.     // Raytracing intersection pre-computed cache:
  315.     float _d, _d1, _d2, _d3;
  316.     Float3 _e1, _e2, _e3, _bottom, _top;
  317.    
  318.     Triangle(
  319.     const Vertex *vertexA,
  320.         const Vertex *vertexB,
  321.     const Vertex *vertexC,
  322.     unsigned r, unsigned g, unsigned b,
  323.     bool twosided = false, bool triNormalProvided = false,
  324.     Float3 triNormal =Float3(0.,0.,0.));
  325. };
  326.  
  327. Triangle::Triangle(
  328.     const Vertex *vertexA,
  329.         const Vertex *vertexB,
  330.     const Vertex *vertexC,
  331.     unsigned r, unsigned g, unsigned b,
  332.     bool twosided , bool triNormalProvided,
  333.     Float3 triNormal)
  334.         :
  335.         _vertexA(vertexA), _vertexB(vertexB), _vertexC(vertexC),
  336.  
  337.         centroid((vertexA->X + vertexB->X + vertexC->X)/3.0f,
  338.          (vertexA->Y + vertexB->Y + vertexC->Y)/3.0f,
  339.          (vertexA->Z + vertexB->Z + vertexC->Z)/3.0f),
  340.  
  341.     _colorf((float)r,(float)g,(float)b), // For use in all other cases
  342.         _color(SDL_MapRGB(Screen::_surface->format, r,g,b)), // For use with DrawPixel
  343.         _twoSided(twosided),
  344.     _bottom(FLT_MAX,FLT_MAX, FLT_MAX), // Will be updated after centering in Loader
  345.         _top(-FLT_MAX, -FLT_MAX,-FLT_MAX) // Will be updated after centering in Loader
  346.     {// this is where the debugger takes me to//
  347.         if (!triNormalProvided)
  348.         {
  349.            n = Float3((vertexA->n.X + vertexB->n.X + vertexC->n.X)/3.0f,
  350.                   (vertexA->n.Y + vertexB->n.Y + vertexC->n.Y)/3.0f,
  351.                   (vertexA->n.Z + vertexB->n.Z + vertexC->n.Z)/3.0f);
  352.            n.Normalize();
  353.         }
  354.         else {n = triNormal;}
  355. }
  356.  
  357. struct Bound{
  358.     Float3 minBound;
  359.     Float3 maxBound;
  360.     Float3 center;
  361.     float dia;
  362. }b;
  363.  
  364. struct Camera {
  365.     Float3 From;
  366.     Float3 At;
  367.     Float3 Up;
  368. };
  369.  
  370. Camera Cam =  {Float3(0.0f,1.0f/3.0f,2.0f),
  371.            Float3(0.0f,1.0f/3.0f,0.0f),
  372.            Float3(0.0f,1.0f,0.0f)};
  373.  
  374. struct  Ray{
  375.     Float3 ray_d;
  376.     Float3 ray_o;
  377.     float tMin, tMax;
  378. };
  379.  
  380. struct Co_ordinateFrame
  381. {
  382.     Float3 x_axis;
  383.     Float3 y_axis;
  384.     Float3 z_axis;
  385.     Float3 origin;
  386. };
  387. Co_ordinateFrame CF;
  388.  
  389. Float3 Scale(Float3 vec1,float s)
  390. {
  391.     Float3 res;
  392.     res.X = vec1.X*s;
  393.     res.Y = vec1.Y*s;
  394.     res.Z = vec1.Z*s;
  395.  
  396.     return res;
  397. }
  398. float Dot(Float3 vec1,Float3 vec2)
  399. {
  400.     float dot = vec1.X*vec2.X+vec1.Y*vec2.Y +vec1.Z*vec2.Z;
  401.     return dot;
  402. }
  403.  
  404. Float3 Cross(Float3 vec1,Float3 vec2)
  405. {
  406.      Float3 cross;
  407.  
  408.      cross.X = (vec1.Y*vec2.Z) - (vec1.Z*vec2.Y);
  409.      cross.Y = (vec1.Z*vec2.X) - (vec1.X*vec2.Z);
  410.      cross.Z = (vec1.X*vec2.Y) - (vec1.Y*vec2.X);
  411.  
  412.      return cross;
  413. }
  414.  
  415.  Float3 normalize(Float3 vec)
  416.  {
  417.  
  418.      float mag = sqrt(Dot(vec,vec));
  419.      Float3 result;
  420.      result.X = vec.X /mag;
  421.      result.Y = vec.Y/mag;
  422.      result.Z = vec.Z/mag;
  423.  
  424.      return result;
  425.  }
  426.  void  ComputeCameraframe()
  427.  {
  428.     CF.origin = Cam.From;
  429.     CF.z_axis = normalize(Cam.From - Cam.At);
  430.     CF.x_axis = normalize(Cross(Cam.Up,CF.z_axis));
  431.         CF.y_axis = normalize(Cross(CF.z_axis,CF.x_axis));
  432.  }
  433. float distancesq(const Float3& a, const Float3& b)
  434. {
  435.    
  436.     float dx=a.X - b.X;
  437.     float dy=a.Y - b.Y;
  438.     float dz=a.Z - b.Z;
  439.     return dx*dx + dy*dy + dz*dz;
  440. }
  441.  
  442. float Distance(const Float3& a, const Float3& b)
  443. {
  444.    
  445.     float dx=a.X - b.X;
  446.     float dy=a.Y - b.Y;
  447.     float dz=a.Z - b.Z;
  448.     return sqrt(dx*dx + dy*dy + dz*dz);
  449. }
  450.  
  451. struct BVHNode {
  452.     Float3 bottom;
  453.     Float3 top;
  454.     virtual bool IsLeaf() = 0;
  455. };
  456.  
  457.  
  458. struct BVHInner : BVHNode {
  459.     BVHNode *left;
  460.     BVHNode *right;
  461.     virtual bool IsLeaf() { return false; }
  462. };
  463.  
  464. struct BVHLeaf : BVHNode {
  465.     Float3 leafbottom;
  466.     Float3 leaftop;
  467.         std::list<const Triangle*> _triangles;
  468.         virtual bool IsLeaf() { return true; }
  469. };
  470.  
  471. struct CacheFriendlyBVHNode
  472. {
  473.     Float3 _bottom;
  474.     Float3 _top;
  475.     union
  476.     {
  477.          struct {
  478.           unsigned _idxLeft;
  479.           unsigned _idxRight;
  480.         } inner;
  481.     struct {
  482.          unsigned _count; // Top-most bit set
  483.          unsigned _startIndexInTriIndexList;
  484.            } leaf;
  485.         } u;
  486. };
  487. // Bounding Volume Hierarchy
  488. // Cache-friendly version of the Bounding Volume Hierarchy data
  489. // (32 bytes per CacheFriendlyBVHNode, i.e. one CPU cache line)
  490.  
  491. struct Scene {
  492.     static const float MaxCoordAfterRescale;
  493.  
  494.     std::vector<Vertex>    _vertices;
  495.     std::vector<Triangle>  _triangles;
  496.    
  497.     // Bounding Volume Hierarchy
  498.     BVHNode *_pSceneBVH;
  499.  
  500.     // Cache-friendly version of the Bounding Volume Hierarchy data
  501.     // (32 bytes per CacheFriendlyBVHNode, i.e. one CPU cache line)
  502.     unsigned _triIndexListNo;
  503.     int *_triIndexList;
  504.     unsigned _pCFBVH_No;
  505.     CacheFriendlyBVHNode *_pCFBVH;
  506.  
  507.     Scene()
  508.     :
  509.     _pSceneBVH(NULL),
  510.     _triIndexListNo(-1),
  511.     _triIndexList(NULL),
  512.     _pCFBVH_No(-1),
  513.     _pCFBVH(NULL)
  514.     {}
  515.  
  516.     // Load object
  517.     void load(const char *filename,Bound *b, Camera *cam);
  518.  
  519.     // Update triangle normals
  520.     void fixns(void);
  521.  
  522.     // Cache-friendly version of the Bounding Volume Hierarchy data
  523.     // (creation functions)
  524.     void PopulateCacheFriendlyBVH(
  525.     Triangle *pFirstTriangle,
  526.     BVHNode *root,
  527.     unsigned& idxBoxes,
  528.     unsigned& idxTriList);
  529.     void CreateCFBVH();
  530.  
  531.     // Creates BVH and Cache-friendly version of BVH
  532.     void UpdateBoundingVolumeHierarchy(const char *filename, bool forceRecalc=false);
  533.  
  534.     // Since it may be aborted for taking too long, this returns "boolCompletedOK"
  535.     bool renderRaytracer(Camera& eye, Screen& canvas, bool antiAlias = false);
  536. };
  537.  
  538. //BVHNode *CreateBVH(const Scene *pScene);
  539. //void CreateCFBVH(Scene *);
  540. // Work item for creation of BVH:
  541.  
  542. struct BBoxTmp {
  543.     // Bottom point (ie minx,miny,minz)
  544.     Float3 boxbottom;
  545.     // Top point (ie maxx,maxy,maxz)
  546.     Float3 boxtop;
  547.     // Center point, ie 0.5*(top-bottom)
  548.     Float3 boxcenter;
  549.     // Triangle
  550.     const Triangle *pTri;
  551.     BBoxTmp()
  552.     :
  553.     boxbottom(FLT_MAX,FLT_MAX,FLT_MAX),
  554.     boxtop(-FLT_MAX,-FLT_MAX,-FLT_MAX),
  555.     pTri(NULL)
  556.     {}
  557.     };
  558.  
  559. typedef vector<BBoxTmp> BBoxEntries;
  560.  
  561. // This builds the BVH, finding optimal split planes for each depth
  562. BVHNode *Recurse(BBoxEntries& work, REPORTPRM(float pct=0.0f) int depth=0)
  563. {
  564.     REPORT( float pctSpan  = 11.0f/pow(3.0f,depth); )
  565.     if (work.size() < 4)
  566.     {
  567.         BVHLeaf *leaf = new BVHLeaf;
  568.         for(BBoxEntries::iterator it=work.begin(); it!=work.end(); it++)
  569.             leaf->_triangles.push_back(it->pTri);
  570.         return leaf;
  571.         }
  572.     // Start by finding the working list's bounding box
  573.     Float3 bottom(FLT_MAX,FLT_MAX,FLT_MAX), top(-FLT_MAX,-FLT_MAX,-FLT_MAX);
  574.    
  575.     for(unsigned i=0; i<work.size(); i++)
  576.     {
  577.       BBoxTmp& v = work[i];
  578.       bottom.assignSmaller(v.boxbottom);
  579.       top.assignBigger(v.boxtop);
  580.         }
  581.  
  582.     float side1 = top.X-bottom.X;
  583.     float side2 = top.Y-bottom.Y;
  584.     float side3 = top.Z-bottom.Z;
  585.     // The current box has a cost of (No of triangles)*surfaceArea
  586.     float minCost = work.size() * (side1*side2 + side2*side3 + side3*side1);
  587.     float bestSplit = FLT_MAX; // will indicate no split with better cost found (below)
  588.     int bestAxis = -1;
  589.  
  590.     // Try all different axis
  591.     for (int j=0; j<3; j++)
  592.     {
  593.       int axis = j;
  594.  
  595.     // try dividing the triangles based on the current axis,
  596.     // and  split values from "start" to "stop", one "step" at a time.
  597.       float start, stop, step;
  598.  
  599.       if (axis==0)
  600.        {
  601.         start = bottom.X;
  602.         stop  = top.X;
  603.        }
  604.       else if (axis==1)
  605.        {
  606.         start = bottom.Y;
  607.         stop  = top.Y;
  608.        }
  609.     else
  610.       {
  611.         start = bottom.Z;
  612.         stop  = top.Z;
  613.       }
  614.     // In that axis, do the bounding boxes in the work queue "span" across?
  615.     // Or are they all already "packed" on the axis's plane?
  616.    
  617.         if (fabsf(stop-start)<1e-4)  continue;// if so move to a different axis!
  618.  
  619.     // Try splitting at a uniform sampling that gets smaller the deeper u go:
  620.     // size of "sampling grid": 1024 (depth 0), 512 (depth 1), etc
  621.    
  622.         step = (stop-start)/(1024.0f/(depth+1.0f));
  623.     // track the Progress: the Progress report variables...
  624.    
  625.         #ifdef PROGRESS_REPORT
  626.         float pctStart = pct + j*pctSpan;
  627.         float pctStep  = pctSpan/((stop - start - 2*step)/step);
  628.         #endif
  629.  
  630.     float testSplit;
  631.     for(testSplit = start+step; testSplit<stop-step; testSplit+=step)
  632.       {
  633.         pctStart += pctStep;
  634.         #ifdef PROGRESS_REPORT
  635.         if ((1023&g_reportCounter++) == 0)
  636.           {
  637.                     printf( "\b\b\b%02d%%", int(pctStart));
  638.             fflush(stdout);
  639.           }
  640.         pctStart += pctStep;
  641.         #endif
  642.         // The left and right bounding box
  643.        Float3 lbottom(FLT_MAX,FLT_MAX,FLT_MAX),
  644.               ltop(-FLT_MAX,-FLT_MAX,-FLT_MAX),
  645.               rbottom(FLT_MAX,FLT_MAX,FLT_MAX),
  646.               rtop(-FLT_MAX,-FLT_MAX,-FLT_MAX);
  647.        
  648. // The number of triangles in the left and right bboxes
  649.  
  650.    int countLeft=0, countRight=0;
  651. // For each test split, allocate triangles based on their bounding boxes centers
  652.        
  653.      for(unsigned i=0; i<work.size(); i++)
  654.     {
  655.       BBoxTmp& v = work[i];
  656.           float value;
  657.       if (axis==0) value=v.boxcenter.X;
  658.       else if (axis==1) value=v.boxcenter.Y;
  659.       else value=v.boxcenter.Z;
  660.  
  661.         if (value < testSplit)
  662.         {
  663.             lbottom.assignSmaller(v.boxbottom);
  664.             ltop.assignBigger(v.boxtop);
  665.                     countLeft++;
  666.         }
  667.         else
  668.         {
  669.             rbottom.assignSmaller(v.boxbottom);
  670.             rtop.assignBigger(v.boxtop);
  671.             countRight++;
  672.         }
  673.         }
  674.         // Now use the Surface Area Heuristic to see if this split has a better "cost"
  675.         // First, check for flase partitionings
  676.         if (countLeft<=1 || countRight<=1) continue;
  677.         // It's a real partitioning, calculate the surface areas
  678.         float lside1 = ltop.X-lbottom.X;
  679.         float lside2 = ltop.Y-lbottom.Y;
  680.         float lside3 = ltop.Z-lbottom.Z;
  681.         float rside1 = rtop.X-rbottom.X;
  682.         float rside2 = rtop.Y-rbottom.Y;
  683.         float rside3 = rtop.Z-rbottom.Z;
  684.         float surfaceLeft  = lside1*lside2 + lside2*lside3 + lside3*lside1;
  685.         float surfaceRight = rside1*rside2 + rside2*rside3 + rside3*rside1;
  686.         float totalCost = surfaceLeft*countLeft + surfaceRight*countRight;
  687.        
  688.         if (totalCost < minCost)
  689.         {
  690.             minCost = totalCost;
  691.             bestSplit = testSplit;
  692.             bestAxis = axis;
  693.              }
  694.     }
  695.     }
  696.     // We found no split to improve the cost :( create a BVH leaf
  697.     if (bestAxis == -1)
  698.     {
  699.         BVHLeaf *leaf = new BVHLeaf;
  700.         for(BBoxEntries::iterator it=work.begin(); it!=work.end(); it++)
  701.         {
  702.           leaf->_triangles.push_back(it->pTri);
  703.           return leaf;
  704.         }
  705.     }
  706. // Create a BVH inner node, split with the optimal value we found above
  707. BBoxEntries left, right;
  708. Float3 lbottom(FLT_MAX,FLT_MAX,FLT_MAX),
  709.        ltop(-FLT_MAX,-FLT_MAX,-FLT_MAX),
  710.        rbottom(FLT_MAX,FLT_MAX,FLT_MAX),
  711.        rtop(-FLT_MAX,-FLT_MAX,-FLT_MAX);
  712.    
  713.     for(int i=0; i<(int)work.size(); i++)
  714.     {
  715.        BBoxTmp& v = work[i];
  716.  
  717.        float value;
  718.        if (bestAxis==0) value=v.boxcenter.X;
  719.        else if (bestAxis==1) value=v.boxcenter.Y;
  720.        else value=v.boxcenter.Z;
  721.  
  722.       if (value < bestSplit)
  723.        {
  724.         #ifdef DEBUG_LOG_BVH
  725.         printf("LADD: B(%f %f %f) T(%f %f %f) C(%f %f %f)\n",
  726.             v.boxbottom.X,
  727.             v.boxbottom.Y,
  728.             v.boxbottom.Z,
  729.  
  730.             v.boxtop.X,
  731.             v.boxtop.Y,
  732.             v.boxtop.Z,
  733.  
  734.             v.boxcenter.X,
  735.             v.boxcenter.Y,
  736.             v.boxcenter.Z);
  737.         #endif
  738.             left.push_back(v);
  739.             lbottom.assignSmaller(v.boxbottom);
  740.             ltop.assignBigger(v.boxtop);
  741.       }
  742.        else
  743.       {
  744.         #ifdef DEBUG_LOG_BVH
  745.         printf("RADD: B(%f %f %f) T(%f %f %f) C(%f %f %f)\n",
  746.             v.boxbottom.X,
  747.             v.boxbottom.Y,
  748.             v.boxbottom.Z,
  749.  
  750.             v.boxtop.X,
  751.             v.boxtop.Y,
  752.             v.boxtop.Z,
  753.  
  754.             v.boxcenter.X,
  755.             v.boxcenter.Y,
  756.             v.boxcenter.Z);
  757.         #endif
  758.             right.push_back(v);
  759.             rbottom.assignSmaller(v.boxbottom);
  760.             rtop.assignBigger(v.boxtop);
  761.         }
  762.     }
  763.  
  764.     BVHInner *inner = new BVHInner;
  765.     #ifdef PROGRESS_REPORT
  766.      if ((1023&g_reportCounter++) == 0)
  767.     {
  768.        printf("\b\b\b%2d%%", int(pct+3.f*pctSpan)); // Update progress indicator
  769.        fflush(stdout);
  770.         }
  771.     #endif
  772.     inner->left = Recurse(left, REPORTPRM(pct+3.f*pctSpan) depth+1);
  773.     inner->left->bottom = lbottom;
  774.     inner->left->top = ltop;
  775.     #ifdef PROGRESS_REPORT
  776.     if ((1023&g_reportCounter++) == 0)
  777.     {
  778.         printf("\b\b\b%2d%%", int(pct+6.f*pctSpan)); // Update progress indicator
  779.         fflush(stdout);
  780.     }
  781.     #endif
  782.     inner->right = Recurse(right, REPORTPRM(pct+6.f*pctSpan) depth+1);
  783.     inner->right->bottom = rbottom;
  784.     inner->right->top = rtop;
  785.  
  786.     // Used for debugging only - dump the BVH in stdout
  787.     #ifdef DEBUG_LOG_BVH
  788.     float origRange[2], newRangeL[2], newRangeR[2];
  789.     if (bestAxis==0)
  790.     {
  791.         origRange[0] = bottom.X;
  792.         origRange[1] = top.X;
  793.         newRangeL[0] = lbottom.X;
  794.         newRangeL[1] = ltop.X;
  795.         newRangeR[0] = rbottom.X;
  796.         newRangeR[1] = rtop.X;
  797.         }
  798.    else if (bestAxis==1)
  799.     {
  800.         origRange[0] = bottom.Y;
  801.         origRange[1] = top.Y;
  802.         newRangeL[0] = lbottom.Y;
  803.         newRangeL[1] = ltop.Y;
  804.         newRangeR[0] = rbottom.Y;
  805.         newRangeR[1] = rtop.Y;
  806.         }
  807.    else
  808.     {
  809.         origRange[0] = bottom.Z;
  810.         origRange[1] = top.Z;
  811.         newRangeL[0] = lbottom.Z;
  812.         newRangeL[1] = ltop.Z;
  813.         newRangeR[0] = rbottom.Z;
  814.         newRangeR[1] = rtop.Z;
  815.          }
  816.     printf("(%9f,%9f) => (%9f,%9f) and (%9f,%9f)\n", origRange[0], origRange[1],
  817.        newRangeL[0], newRangeL[1], newRangeR[0], newRangeR[1]);
  818.     #endif
  819.  
  820.     return inner;
  821. }
  822.  
  823. BVHNode *CreateBVH(const Scene *pScene)//Triangle *Tri
  824. {
  825.     vector<BBoxTmp> work;
  826.     Float3 bottom(FLT_MAX,FLT_MAX,FLT_MAX), top(-FLT_MAX,-FLT_MAX,-FLT_MAX);
  827.    
  828.     puts("Gathering bounding box info from all triangles...");
  829.  
  830.     for(unsigned j=0; j<pScene->_triangles.size(); j++)
  831.     {
  832.       const Triangle& tri = pScene->_triangles[j];
  833.          
  834.       BBoxTmp box;
  835.       box.pTri = &tri;
  836.       box.boxbottom.assignSmaller(*tri._vertexA);
  837.       box.boxbottom.assignSmaller(*tri._vertexB);
  838.       box.boxbottom.assignSmaller(*tri._vertexC);
  839.       box.boxtop.assignBigger(*tri._vertexA);
  840.       box.boxtop.assignBigger(*tri._vertexB);
  841.       box.boxtop.assignBigger(*tri._vertexC);
  842.        
  843.       bottom.assignSmaller(box.boxbottom);
  844.       top.assignBigger(box.boxtop);
  845.  
  846.       box.boxcenter = box.boxtop;
  847.       box.boxcenter += box.boxbottom;
  848.        
  849.       box.boxcenter *= 0.5f;
  850.    
  851.           work.push_back(box);
  852.         #ifdef DEBUG_LOG_BVH
  853.         printf("ADD: B(%f %f %f) T(%f %f %f) C(%f %f %f)\n",
  854.             box.boxbottom.X,
  855.             box.boxbottom.Y,
  856.             box.boxbottom.Z,
  857.             box.boxtop.X,
  858.             box.boxtop.Y,
  859.             box.boxtop.Z,
  860.             box.boxcenter.X,
  861.             box.boxcenter.Y,
  862.             box.boxcenter.Z);
  863.         #endif
  864.     }
  865.  
  866.     // ...and pass it to the recursive function that creates the SAH AABB BVH
  867.     // (Surface Area Heuristic, Axis-Aligned Bounding Boxes, Bounding Volume Hierarchy)
  868.     printf("Creating Bounding Volume Hierarchy data...    ");
  869.     fflush(stdout);
  870.     BVHNode *root = Recurse(work);
  871.     cout<< "\b\b\b100%%\n";
  872.     root->bottom = bottom;
  873.     root->top = top;
  874.  
  875.     return root;
  876. }
  877.  
  878. int CountBoxes(BVHNode *root)
  879. {
  880.     if (!root->IsLeaf())
  881.     {
  882.       BVHInner *p = dynamic_cast<BVHInner*>(root);
  883.       return 1 + CountBoxes(p->left) + CountBoxes(p->right);
  884.         } else  return 1;
  885. }
  886.  
  887. unsigned CountTriangles(BVHNode *root)
  888. {
  889.     if (!root->IsLeaf())
  890.     {
  891.        BVHInner *p = dynamic_cast<BVHInner*>(root);
  892.        return CountTriangles(p->left) + CountTriangles(p->right);
  893.         }
  894.     else
  895.     {
  896.        BVHLeaf *p = dynamic_cast<BVHLeaf*>(root);
  897.        return (unsigned) p->_triangles.size();
  898.         }
  899. }
  900.  
  901. void CountDepth(BVHNode *root, int depth, int& maxDepth)
  902. {
  903.     if (maxDepth<depth)
  904.     maxDepth=depth;
  905.     if (!root->IsLeaf())
  906.     {
  907.       BVHInner *p = dynamic_cast<BVHInner*>(root);
  908.       CountDepth(p->left, depth+1, maxDepth);
  909.       CountDepth(p->right, depth+1, maxDepth);
  910.         }
  911. }
  912.  
  913. void Scene::PopulateCacheFriendlyBVH(Triangle *pFirstTriangle,
  914.     BVHNode *root, unsigned& idxBoxes,unsigned& idxTriList)
  915. {
  916.     unsigned currIdxBoxes = idxBoxes;
  917.     _pCFBVH[currIdxBoxes]._bottom = root->bottom;
  918.     _pCFBVH[currIdxBoxes]._top    = root->top;
  919.  
  920.     if (!root->IsLeaf())
  921.     {
  922.       BVHInner *p = dynamic_cast<BVHInner*>(root);
  923.       int idxLeft = ++idxBoxes;
  924.       PopulateCacheFriendlyBVH(pFirstTriangle, p->left, idxBoxes, idxTriList);
  925.       int idxRight = ++idxBoxes;
  926.       PopulateCacheFriendlyBVH(pFirstTriangle, p->right, idxBoxes, idxTriList);
  927.       _pCFBVH[currIdxBoxes].u.inner._idxLeft  = idxLeft;
  928.       _pCFBVH[currIdxBoxes].u.inner._idxRight = idxRight;
  929.         }
  930.     else
  931.     {
  932.       BVHLeaf *p = dynamic_cast<BVHLeaf*>(root);
  933.       unsigned count = (unsigned) p->_triangles.size();
  934.       _pCFBVH[currIdxBoxes].u.leaf._count = 0x80000000 | count;
  935.       _pCFBVH[currIdxBoxes].u.leaf._startIndexInTriIndexList = idxTriList;
  936.       for(std::list<const Triangle*>::iterator it= p->_triangles.begin();
  937.             it != p->_triangles.end();it++)
  938.         {_triIndexList[idxTriList++] = *it - pFirstTriangle;}
  939.         }
  940. }
  941.  
  942. void Scene::CreateCFBVH()
  943. {
  944.     if (!_pSceneBVH)
  945.     {
  946.       puts("Internal bug in CreateCFBVH, please report it..."); fflush(stdout);
  947.       exit(1);
  948.         }
  949.  
  950.     unsigned idxTriList=0;
  951.     unsigned idxBoxes=0;
  952.  
  953.     _triIndexListNo = CountTriangles(_pSceneBVH);
  954.     _triIndexList = new int[_triIndexListNo];
  955.  
  956.     _pCFBVH_No = CountBoxes(_pSceneBVH);
  957.     _pCFBVH = new CacheFriendlyBVHNode[_pCFBVH_No];
  958.  
  959.     PopulateCacheFriendlyBVH(&_triangles[0], _pSceneBVH,idxBoxes,idxTriList);
  960.  
  961.     if ((idxBoxes != _pCFBVH_No-1) || (idxTriList != _triIndexListNo))
  962.     {
  963.       puts("Internal bug in CreateCFBVH, please report it..."); fflush(stdout);
  964.       exit(1);
  965.         }
  966.  
  967.     int maxDepth = 0;
  968.     CountDepth(_pSceneBVH, 0, maxDepth);
  969.     if (maxDepth>=BVH_STACK_SIZE)
  970.     {
  971.       printf("Max depth of BVH was %d\n", maxDepth);
  972.       puts("Recompile with BVH_STACK_SIZE set to more than that..."); fflush(stdout);
  973.       exit(1);
  974.         }
  975. }
  976.  
  977. void Scene::UpdateBoundingVolumeHierarchy(const char *filename, bool forceRecalc)
  978. {
  979.     if (!_pCFBVH)
  980.     {
  981.       std::string BVHcacheFilename(filename);
  982.       BVHcacheFilename += ".bvh";
  983.       FILE *fp = fopen(BVHcacheFilename.c_str(), "rb");
  984.       if (forceRecalc || !fp)
  985.        {
  986.          // No cached BVH data - we need to calculate them
  987.        
  988.         _pSceneBVH = CreateBVH(this);
  989.         printf("Building the BVH%s took %.2f seconds\n");
  990.  
  991.             // Now that the BVH has been created, copy its data into a more cache-friendly format
  992.        // (CacheFriendlyBVHNode occupies exactly 32 bytes, i.e. a cache-line)
  993.        
  994.            CreateCFBVH();
  995.  
  996.       // Now store the results, if possible...
  997.       fp = fopen(BVHcacheFilename.c_str(), "wb");
  998.       if (!fp) return;
  999.       if (1 != fwrite(&_pCFBVH_No, sizeof(unsigned), 1, fp)) return;
  1000.       if (1 != fwrite(&_triIndexListNo, sizeof(unsigned), 1, fp)) return;
  1001.       if (_pCFBVH_No != fwrite(_pCFBVH, sizeof(CacheFriendlyBVHNode), _pCFBVH_No, fp)) return;
  1002.       if (_triIndexListNo != fwrite(_triIndexList, sizeof(int), _triIndexListNo, fp)) return;
  1003.       fclose(fp);
  1004.     }
  1005.     else
  1006.     {
  1007.       puts("Cache exists, reading the pre-calculated BVH data...");
  1008.       if (1 != fread(&_pCFBVH_No, sizeof(unsigned), 1, fp))
  1009.         {
  1010.            UpdateBoundingVolumeHierarchy(filename, true);
  1011.            return;
  1012.         }
  1013.       if (1 != fread(&_triIndexListNo, sizeof(unsigned), 1, fp))
  1014.         {
  1015.            UpdateBoundingVolumeHierarchy(filename, true);
  1016.            return;
  1017.         }
  1018.     _pCFBVH = new CacheFriendlyBVHNode[_pCFBVH_No];
  1019.     _triIndexList = new int[_triIndexListNo];
  1020.     if (_pCFBVH_No != fread(_pCFBVH, sizeof(CacheFriendlyBVHNode), _pCFBVH_No, fp))
  1021.         {
  1022.           delete [] _pCFBVH;
  1023.           delete [] _triIndexList;
  1024.           _pCFBVH = NULL;
  1025.           _triIndexList = NULL;
  1026.           UpdateBoundingVolumeHierarchy(filename, true);
  1027.           return;
  1028.         }
  1029.     if (_triIndexListNo != fread(_triIndexList, sizeof(int), _triIndexListNo, fp))
  1030.         {
  1031.             delete [] _pCFBVH;
  1032.             delete [] _triIndexList;
  1033.             _pCFBVH = NULL;
  1034.             _triIndexList = NULL;
  1035.             UpdateBoundingVolumeHierarchy(filename, true);
  1036.             return;
  1037.         }
  1038.     fclose(fp);
  1039.     }
  1040.     }
  1041. }
  1042.  
  1043. void Scene:: fixns()
  1044. {
  1045.     for(unsigned  j=0; j<_triangles.size(); j++)
  1046.     {
  1047.        Float3 worldPointA = *_triangles[j]._vertexA;
  1048.        Float3 worldPointB = *_triangles[j]._vertexB;
  1049.        Float3 worldPointC = *_triangles[j]._vertexC;
  1050.        Float3 AB = worldPointB;
  1051.        AB -= worldPointA;
  1052.        Float3 AC = worldPointC;
  1053.        AC -= worldPointA;
  1054.        Float3 cr = normalize(Cross(AB, AC));
  1055.        _triangles[j].n = cr;
  1056.    
  1057.        const_cast<Vertex*>(_triangles[j]._vertexA)->n += cr;
  1058.        const_cast<Vertex*>(_triangles[j]._vertexB)->n += cr;
  1059.        const_cast<Vertex*>(_triangles[j]._vertexC)->n += cr;
  1060.        
  1061.     }
  1062.       for(unsigned j=0; j<_triangles.size(); j++)
  1063.       {
  1064.          const_cast<Vertex*>(_triangles[j]._vertexA)->n.Normalize();
  1065.          const_cast<Vertex*>(_triangles[j]._vertexB)->n.Normalize();
  1066.          const_cast<Vertex*>(_triangles[j]._vertexC)->n.Normalize();    
  1067.       }
  1068. }
  1069.  
  1070. namespace enums
  1071. {
  1072.     enum ColorComponent {Red = 0, Green = 1, Blue = 2 };
  1073. }
  1074. using namespace enums;
  1075. struct MaterialColors
  1076. {
  1077.  
  1078.     MaterialColors(
  1079.     const Lib3dsRgba& ambient, const Lib3dsRgba& diffuse, const Lib3dsRgba& specular, bool twoSided)
  1080.     :
  1081.     _ambient(ambient), _diffuse(diffuse), _specular(specular), _twoSided(twoSided)
  1082.     {}
  1083.  
  1084.     template <ColorComponent c>
  1085.     unsigned getByteAmbient() const { return unsigned(255.0*_ambient[c]); }
  1086.  
  1087.     template <ColorComponent c>
  1088.     unsigned getByteDiffuse() const { return unsigned(255.0*_diffuse[c]); }
  1089.  
  1090.     template <ColorComponent c>
  1091.     unsigned getByteSpecularRed() const { return unsigned(255.0*_specular[c]); }
  1092.  
  1093.     const Lib3dsRgba& _ambient;
  1094.     const Lib3dsRgba& _diffuse;
  1095.     const Lib3dsRgba& _specular;
  1096.     bool _twoSided;
  1097. };
  1098.  
  1099. const float Scene::MaxCoordAfterRescale = 1.2f;
  1100. void Scene::load(const char *filename, Bound *b, Camera *cam)
  1101. {
  1102.     FILE *fp = fopen(filename, "rb");
  1103.     if (filename[0] == '@' && filename[1] == 'p')
  1104.     {   // Platform
  1105.        _vertices.reserve(4);
  1106.        _vertices.push_back(Vertex( 0.5, -0.5, 0.0,  0.0, 0.0, 1.0));
  1107.        _vertices.push_back(Vertex( 0.5,  0.5, 0.0,  0.0, 0.0, 1.0));
  1108.        _vertices.push_back(Vertex(-0.5,  0.5, 0.0,  0.0, 0.0, 1.0));
  1109.        _vertices.push_back(Vertex(-0.5, -0.5, 0.0,  0.0, 0.0, 1.0));
  1110.        _triangles.reserve(2);
  1111.        _triangles.push_back(Triangle(&_vertices[0], &_vertices[1], &_vertices[2],255,0,0));
  1112.        _triangles.push_back(Triangle(&_vertices[0], &_vertices[2], &_vertices[3],255,0,0));
  1113.        return;
  1114.     }
  1115.  
  1116.     const char *dt = strrchr(filename, '.');
  1117.     if (dt)
  1118.     {
  1119.       dt++;
  1120.         if (!strcmp(dt, "tri"))
  1121.         {
  1122.  
  1123.             // Simple binary format:
  1124.             //
  1125.             // Basically:
  1126.             //    <magic (uint32)>  TRI_MAGIC, TRI_MAGICNORMAL or missing
  1127.             //    one or more of these blocks:
  1128.             //        no_of_vertices (uint32)
  1129.             //        x1,y1,z1 (float coordinates of vertex)
  1130.             //        ...
  1131.             //        xn,yn,zn (float coordinates of vertex)
  1132.             //        (magic == TRI_MAGICNORMAL)? nx1, ny1, nz1 (float coordinates of normal)
  1133.             //        no_of_triangles (uint32)
  1134.             //        idx,idx,idx (uint32 indices into the vertex array)
  1135.             //        (magic == TRI_MAGIC | TRI_MAGICNORMAL)? r,g,b (floats)
  1136.             //        ...
  1137.             //        idx,idx,idx (uint32 indices into the vertex array)
  1138.             //        (magic == TRI_MAGIC | TRI_MAGICNORMAL)? r,g,b (floats)
  1139.             FILE *fp = fopen(filename, "rb");
  1140.             if (!fp)
  1141.             cout<<(string("File '") + string(filename) + string("' not found!")).c_str();
  1142.             //THROW((string("File '") + string(filename) + string("' not found!")).c_str());
  1143.             Uint32 totalPoints = 0, totalTris = 0;
  1144.             Uint32 magic;
  1145.  
  1146.             fread(&magic, 1, sizeof(Uint32), fp);
  1147.             if (magic != TRI_MAGIC && magic != TRI_MAGICNORMAL)
  1148.             {
  1149.                 //// No magic, just vertices and points (no normals, no colors)
  1150.                 fseek(fp, 0, SEEK_SET);
  1151.                 cout<<"file not found";
  1152.             }
  1153.  
  1154.             // Calculate total number of vertices in order to reserve the vectors memory
  1155.             unsigned currentOffset = ftell(fp);
  1156.             unsigned currentTotalPoints = 0;
  1157.             unsigned currentTotalTris = 0;
  1158.             while(1)
  1159.             {
  1160.                 unsigned temp;
  1161.                 fread(&temp, 1, sizeof(Uint32), fp);
  1162.                 if (feof(fp))
  1163.                     break;
  1164.                 currentTotalPoints += temp;
  1165.                 fseek(fp, temp*(magic==TRI_MAGICNORMAL?24:12), SEEK_CUR);
  1166.                 fread(&temp, 1, sizeof(Uint32), fp);
  1167.                 if (feof(fp))
  1168.                     break;
  1169.                 currentTotalTris += temp;
  1170.                 fseek(fp, temp*24, SEEK_CUR);
  1171.             }
  1172.  
  1173.             // Reserve the space, now that you know
  1174.             if (magic == TRI_MAGICNORMAL || magic == TRI_MAGIC)
  1175.                 _vertices.reserve(currentTotalPoints);
  1176.             else
  1177.             // when we have no normals, we'll need extra space for fixns()...
  1178.             _vertices.reserve(currentTotalTris*3);
  1179.             _triangles.reserve(currentTotalTris);
  1180.  
  1181.             // Now load them inside the std::vectors...
  1182.             fseek(fp, currentOffset, SEEK_SET);
  1183.             do
  1184.             {
  1185.                 Uint32 noOfPoints;
  1186.                 fread(&noOfPoints, 1, sizeof(Uint32), fp);
  1187.                 if (feof(fp))
  1188.                     break;
  1189.                 for(Uint32 i=0; i<noOfPoints; i++)
  1190.                 {
  1191.                     float x,y,z;
  1192.                     fread(&x,1,4,fp); if (feof(fp)) { cout<<"Malformed 3D file"; }
  1193.                     fread(&y,1,4,fp); if (feof(fp)) { cout<<"Malformed 3D file"; }
  1194.                     fread(&z,1,4,fp); if (feof(fp)) { cout<<"Malformed 3D file"; }
  1195.  
  1196.                     float nx=0.,ny=0.,nz=0.;
  1197.                     if (magic == TRI_MAGICNORMAL) {
  1198.                     fread(&nx,1,4,fp); if (feof(fp)) { cout<<"Malformed 3D file"; }
  1199.                     fread(&ny,1,4,fp); if (feof(fp)) { cout<<"Malformed 3D file"; }
  1200.                     fread(&nz,1,4,fp); if (feof(fp)) { cout<<"Malformed 3D file"; }
  1201.                     }
  1202.                     else
  1203.                     {
  1204.                     nx = ny = nz = 0; // Will be calculated in fixns()
  1205.                     }
  1206.                     assert(_vertices.size() < _vertices.capacity());
  1207.                     _vertices.push_back(Vertex(x,y,z, nx,ny,nz));
  1208.                 }
  1209.  
  1210.                 Uint32 noOfTris;
  1211.                 fread(&noOfTris, 1, sizeof(Uint32), fp);
  1212.                 if (feof(fp)) { cout<<"Malformed 3D file"; }
  1213.  
  1214.                 for(Uint32 i=0; i<noOfTris; i++)
  1215.                 {
  1216.                     Uint32 idx1,idx2,idx3;
  1217.                     fread(&idx1,1,4,fp); if (feof(fp)) { cout<<"Malformed 3D file"; }
  1218.                     fread(&idx2,1,4,fp); if (feof(fp)) { cout<<"Malformed 3D file"; }
  1219.                     fread(&idx3,1,4,fp); if (feof(fp)) { cout<<"Malformed 3D file"; }
  1220.                     if (idx1>=(totalPoints+noOfPoints)) { cout<<"Malformed 3D file (idx1)"; }
  1221.                     if (idx2>=(totalPoints+noOfPoints)) { cout<<"Malformed 3D file (idx2)"; }
  1222.                     if (idx3>=(totalPoints+noOfPoints)) { cout<<"Malformed 3D file (idx3)"; }
  1223.  
  1224.                    
  1225.                     float r, g, b;
  1226.                     if (magic == TRI_MAGIC || magic == TRI_MAGICNORMAL)
  1227.                         {
  1228.                         fread(&r,1,4,fp); if (feof(fp)) { cout<<"Malformed 3D file"; }
  1229.                         fread(&g,1,4,fp); if (feof(fp)) { cout<<"Malformed 3D file"; }
  1230.                         fread(&b,1,4,fp); if (feof(fp)) { cout<<"Malformed 3D file"; }
  1231.                         r*=255.; g*=255.; b*=255.;
  1232.                         }
  1233.                     else {r = g = b = 255.0;} // No colors? White, then...
  1234.                
  1235.                     _triangles.push_back(Triangle(
  1236.                         &_vertices[idx1], &_vertices[idx2], &_vertices[idx3],
  1237.                         unsigned(r),unsigned(g),unsigned(b)));
  1238.                 }
  1239.  
  1240.                 totalPoints += noOfPoints;
  1241.                 totalTris   += noOfTris;
  1242.             } while(!feof(fp));
  1243.  
  1244.             fclose(fp);
  1245.             if (magic != TRI_MAGICNORMAL)
  1246.             fixns();
  1247.         }
  1248.         else if (!strcmp(dt, "ra2"))
  1249.         {
  1250.             // http://ompf.org/forum/viewtopic.php?t=64
  1251.             FILE *fp = fopen(filename, "rb");
  1252.             if (!fp)
  1253.             cout<< (string("File '") + string(filename) + string("' not found!")).c_str();
  1254.  
  1255.             Uint32 totalPoints = 0, totalTriangles = 0;
  1256.  
  1257.             fseek(fp, 0, SEEK_END);
  1258.             totalTriangles = ftell(fp)/36;
  1259.             totalPoints = 3*totalTriangles;
  1260.             fseek(fp, 0, SEEK_SET);
  1261.  
  1262.             _vertices.reserve(totalPoints);
  1263.             _triangles.reserve(totalTriangles);
  1264.  
  1265.             // Now load them inside the std::vectors...
  1266.             for(Uint32 i=0; i<totalPoints; i++)
  1267.             {
  1268.                 float x,y,z;
  1269.                 fread(&y,1,4,fp); if (feof(fp)) { cout<<"Malformed 3D file"; }
  1270.                 fread(&z,1,4,fp); if (feof(fp)) { cout<<"Malformed 3D file"; }
  1271.                 fread(&x,1,4,fp); if (feof(fp)) { cout<<"Malformed 3D file"; }
  1272.  
  1273.                 float nx=0.,ny=0.,nz=0.;
  1274.                 assert(_vertices.size() < _vertices.capacity());
  1275.                 _vertices.push_back(Vertex(x,y,z, nx,ny,nz));
  1276.             }
  1277.  
  1278.             for(Uint32 i=0; i<totalTriangles; i++)
  1279.             {
  1280.             Uint32 idx1,idx2,idx3;
  1281.             idx1 = 3*i + 0;
  1282.             if (getenv("RA2")!=NULL)
  1283.             {
  1284.                 idx2 = 3*i + 2;
  1285.                 idx3 = 3*i + 1;
  1286.             }
  1287.             else
  1288.             {
  1289.                 idx2 = 3*i + 1;
  1290.                 idx3 = 3*i + 2;
  1291.             }
  1292.             if (idx1>=(totalPoints)) { cout<<"Malformed 3D file (idx1)"; }
  1293.             if (idx2>=(totalPoints)) { cout<<"Malformed 3D file (idx2)"; }
  1294.             if (idx3>=(totalPoints)) { cout<<"Malformed 3D file (idx3)"; }
  1295.  
  1296.             //uchar4 color;
  1297.             float r,g,b;
  1298.             r = g = b = 255.0; // No colors? White, then..
  1299.  
  1300.             _triangles.push_back(
  1301.                 Triangle(&_vertices[idx1], &_vertices[idx2], &_vertices[idx3],
  1302.                 unsigned(r),unsigned(g),unsigned(b)));
  1303.             }
  1304.             fclose(fp);
  1305.             fixns();
  1306.         }
  1307.         else if (!strcmp(dt, "3ds") || !strcmp(dt, "3DS"))
  1308.         {
  1309.             int i = 0;
  1310.             Lib3dsFile* p3DS = lib3ds_file_load(filename);
  1311.             if (!p3DS)
  1312.             cout<<"Lib3DS couldn't load this .3ds file";
  1313.             lib3ds_file_eval(p3DS, 0);
  1314.  
  1315.             Lib3dsDword currentTotalTris = 0;
  1316.             Lib3dsMesh *pMesh = p3DS->meshes;
  1317.             if (!pMesh)
  1318.             cout<<"This .3ds file has no meshes";
  1319.             std::map<Lib3dsMesh*, Lib3dsVector*> normals;
  1320.             while(pMesh)
  1321.             {
  1322.                 currentTotalTris   += pMesh->faces;
  1323.                 Lib3dsVector *pMeshNormals = new Lib3dsVector[3*pMesh->faces];
  1324.                 lib3ds_mesh_calculate_normals(pMesh, pMeshNormals);
  1325.                 normals[pMesh] = pMeshNormals;
  1326.                 pMesh = pMesh->next;
  1327.             }
  1328.             _vertices.reserve(3*currentTotalTris);
  1329.             _triangles.reserve(currentTotalTris);
  1330.             std::map<string, MaterialColors> colors;
  1331.             Lib3dsMaterial *pMaterial = p3DS->materials;
  1332.             while(pMaterial)
  1333.             {
  1334.                 colors.insert(
  1335.                     std::map<string, MaterialColors>::value_type(
  1336.                     string(pMaterial->name),
  1337.                     MaterialColors(pMaterial->ambient, pMaterial->diffuse,  pMaterial->specular, pMaterial->two_sided!=0)));
  1338.                 pMaterial = pMaterial->next;
  1339.             }
  1340.             pMesh = p3DS->meshes;
  1341.             int currentTotalPoints = 0;
  1342.             while(pMesh)
  1343.             {
  1344.             if (!pMesh->pointL) { pMesh=pMesh->next; continue; }
  1345.             if (!pMesh->faceL)  { pMesh=pMesh->next; continue; }
  1346.             for(i=0; i<(int)pMesh->faces; i++)
  1347.             {
  1348.                 std::map<string, MaterialColors>::iterator pMat = colors.find(string(pMesh->faceL[i].material));
  1349.                 unsigned r,g,b;
  1350.                 if (pMat != colors.end())
  1351.                 {
  1352.                     r = pMat->second.getByteDiffuse<Red>();
  1353.                     g = pMat->second.getByteDiffuse<Green>();
  1354.                     b = pMat->second.getByteDiffuse<Blue>();
  1355.                 } else {r = g = b = 255; }
  1356.                 for (int k=0; k<3; k++)
  1357.                 {
  1358.                 int pointIdx = pMesh->faceL[i].points[k];
  1359.                 Float3 nr(
  1360.                     normals[pMesh][3*i+k][0],
  1361.                     normals[pMesh][3*i+k][1],
  1362.                     normals[pMesh][3*i+k][2]);
  1363.                  assert(_vertices.size() < _vertices.capacity());
  1364.                 _vertices.push_back(
  1365.                     Vertex(
  1366.                            pMesh->pointL[pointIdx].pos[0],
  1367.                            pMesh->pointL[pointIdx].pos[1],
  1368.                            pMesh->pointL[pointIdx].pos[2],
  1369.                     nr.X,
  1370.                     nr.Y,
  1371.                     nr.Z));
  1372.                 }
  1373.                 assert(_triangles.size() < _triangles.capacity());
  1374.                 _triangles.push_back(
  1375.                 Triangle(
  1376.                     &_vertices[currentTotalPoints + 3*i],
  1377.                     &_vertices[currentTotalPoints + 3*i + 1],
  1378.                     &_vertices[currentTotalPoints + 3*i + 2],
  1379.                     255,0,0,
  1380.                     pMat->second._twoSided,
  1381.                     true,
  1382.                     Float3(pMesh->faceL[i].normal[0],
  1383.                         pMesh->faceL[i].normal[1],
  1384.                         pMesh->faceL[i].normal[2]) ));
  1385.             }//for loop
  1386.             currentTotalPoints += 3*pMesh->faces;
  1387.             pMesh = pMesh->next;
  1388.             }// while ends here
  1389.         }
  1390.         else if (!strcmp(dt, "PLY") || !strcmp(dt, "ply"))
  1391.         {
  1392.             // Only shadevis generated objects, not full blown parser!
  1393.             std::ifstream file(filename, std::ios::in);
  1394.             if (!file) {cout<<(string("Missing ")+string(filename)).c_str();}
  1395.             string line;
  1396.             unsigned totalVertices, totalTriangles, lineNo=0;
  1397.             bool inside = false;
  1398.             while(getline(file, line))
  1399.             {
  1400.             lineNo++;
  1401.             if (!inside)
  1402.             {
  1403.                 if (line.substr(0, 14) == "element vertex")
  1404.                 {
  1405.                     std::istringstream str(line);
  1406.                     string word1;
  1407.                     str >> word1;
  1408.                     str >> word1;
  1409.                     str >> totalVertices;
  1410.                     _vertices.reserve(totalVertices);
  1411.                 }
  1412.                 else if (line.substr(0, 12) == "element face")
  1413.                 {
  1414.                     std::istringstream str(line);
  1415.                     string word1;
  1416.                     str >> word1;
  1417.                     str >> word1;
  1418.                     str >> totalTriangles;
  1419.                 }
  1420.                 else if (line.substr(0, 10) == "end_header")
  1421.                 inside = true;
  1422.             }
  1423.             else {
  1424.                 if (totalVertices)
  1425.                 {
  1426.                     totalVertices--;
  1427.                     float x,y,z;
  1428.                     x = 0.0f; y = 0.0f; z = 0.0f;
  1429.                     unsigned ambientOcclusionCoeff;
  1430.                     std::istringstream str(line);
  1431.                     str >> x >> y >> z >> ambientOcclusionCoeff;
  1432.                     _vertices.push_back(Vertex(x,y,z,0.0f,0.0f,0.0f,ambientOcclusionCoeff));
  1433.                 }
  1434.                 else if (totalTriangles)
  1435.                 {
  1436.                     totalTriangles--;
  1437.                     //uchar4 Color_totalTriangles;
  1438.                     unsigned dummy,r,g,b;
  1439.                     unsigned idx1, idx2, idx3;
  1440.                     std::istringstream str(line);
  1441.                     if (str >> dummy >> idx1 >> idx2 >> idx3)
  1442.                     {
  1443.                         if (str >> r >> g >> b)
  1444.                         ;
  1445.                         else {r =  g =  b = 255;}
  1446.                         _triangles.push_back(
  1447.                         Triangle( &_vertices[idx1], &_vertices[idx2], &_vertices[idx3],
  1448.                             r,g,b));
  1449.                     }
  1450.                 }
  1451.             }
  1452.             }
  1453.             fixns();
  1454.         }
  1455.         else
  1456.             cout<<"Unknown extension (only .tri .3ds or .ply accepted)";
  1457.     }
  1458.     else
  1459.     cout<<"No extension in filename (only tri .3ds or .ply accepted)";
  1460.  
  1461.     std::cout << "Vertexes: " << _vertices.size();
  1462.     std::cout << " Triangles: " << _triangles.size() << std::endl;
  1463.  
  1464.     // Center scene at world's center
  1465.  
  1466.     Float3 minp(FLT_MAX,FLT_MAX,FLT_MAX), maxp(-FLT_MAX,-FLT_MAX,-FLT_MAX);
  1467.    
  1468.     for(unsigned i=0; i<_triangles.size(); i++)
  1469.     {
  1470.         minp.assignSmaller(*_triangles[i]._vertexA);
  1471.         minp.assignSmaller(*_triangles[i]._vertexB);
  1472.         minp.assignSmaller(*_triangles[i]._vertexC);
  1473.         maxp.assignBigger(*_triangles[i]._vertexA);
  1474.         maxp.assignBigger(*_triangles[i]._vertexB);
  1475.         maxp.assignBigger(*_triangles[i]._vertexC);
  1476.     }
  1477.    
  1478.     Float3 origCenter = Float3( (maxp.X+ minp.X)/2,
  1479.                                 (maxp.Y+minp.Y)/2,
  1480.                                 (maxp.Z+minp.Z)/2);
  1481.  
  1482.     b->minBound = minp;
  1483.     b->maxBound = maxp;
  1484.  
  1485.     minp -= origCenter;
  1486.     maxp -= origCenter;
  1487.  
  1488.     b->center = origCenter;
  1489.  
  1490.     float dX = (b->maxBound.X-b->minBound.X);
  1491.     float dY = (b->maxBound.Y-b->minBound.Y);
  1492.     float dZ = (b->maxBound.Z-b->minBound.Z);
  1493.     b->dia = sqrt(dX*dX+dY*dY+dZ*dZ);
  1494.    
  1495.     cam->At = b->center;
  1496.     if ((dX > dY) && (dX > dZ))
  1497.     {
  1498.         cam->Up.X = 1.0f; cam->Up.Y = cam->Up.Z = 0.0f;
  1499.         if (dY > dZ)
  1500.         {
  1501.             cam->From.Z = b->center.Z+b->dia;
  1502.             cam->From.X = b->center.X;cam->From.Y = b->center.Y;
  1503.         }
  1504.         else
  1505.         {
  1506.             cam->From.Y = b->center.Y+b->dia;
  1507.             cam->From.X = b->center.X;cam->From.Z = b->center.Z;
  1508.         }
  1509.     }
  1510.     else if((dY > dX) && (dY > dZ))
  1511.     {
  1512.             cam->Up.Y = 1.0f; cam->Up.X = cam->Up.Z = 0.0f;
  1513.         if (dX > dZ)
  1514.         {
  1515.             cam->From.Z = b->center.Z+b->dia;
  1516.             cam->From.Y = b->center.Y;cam->From.X = b->center.X;
  1517.         }
  1518.         else
  1519.         {
  1520.             cam->From.X = b->center.X+b->dia;
  1521.             cam->From.Y = b->center.Y;cam->From.Z = b->center.Z;
  1522.         }
  1523.     }
  1524.     else
  1525.     {
  1526.         cam->Up.Z = 1.0f; cam->Up.X = cam->Up.Y = 0.0f;
  1527.         if (dX > dY)
  1528.         {
  1529.             cam->From.Y = b->center.Y+b->dia;
  1530.             cam->From.X = b->center.X;cam->From.Z = b->center.Z;
  1531.         }
  1532.         else
  1533.         {
  1534.             cam->From.X = b->center.X-b->dia;
  1535.             cam->From.Y = b->center.Y;cam->From.Z = b->center.Z;
  1536.         }
  1537.     }
  1538.     // Scale scene so max(abs x,y,z coordinates) = MaxCoordAfterRescale
  1539.     //typedef float coord;
  1540.  
  1541.     float maxi = 0.0f;
  1542.     maxi = max(maxi, (float) fabs(minp.X));
  1543.     maxi = max(maxi, (float) fabs(minp.Y));
  1544.     maxi = max(maxi, (float) fabs(minp.Z));
  1545.     maxi = max(maxi, (float) fabs(maxp.X));
  1546.     maxi = max(maxi, (float) fabs(maxp.Y));
  1547.     maxi = max(maxi, (float) fabs(maxp.Z));
  1548.  
  1549.     for(unsigned i=0; i<_vertices.size(); i++)
  1550.     {
  1551.         _vertices[i] -= origCenter;
  1552.         _vertices[i] *= MaxCoordAfterRescale/maxi;
  1553.     }
  1554.     for(unsigned i=0; i<_triangles.size(); i++)
  1555.     {
  1556.         _triangles[i].centroid -= origCenter;
  1557.         _triangles[i].centroid *= MaxCoordAfterRescale/maxi;
  1558.     }
  1559.     // Update triangle bounding boxes (used by BVH)
  1560.     for(unsigned i=0; i<_triangles.size(); i++)
  1561.     {
  1562.         _triangles[i]._bottom.assignSmaller(*_triangles[i]._vertexA);
  1563.         _triangles[i]._bottom.assignSmaller(*_triangles[i]._vertexB);
  1564.         _triangles[i]._bottom.assignSmaller(*_triangles[i]._vertexC);
  1565.         _triangles[i]._top.assignBigger(*_triangles[i]._vertexA);
  1566.         _triangles[i]._top.assignBigger(*_triangles[i]._vertexB);
  1567.         _triangles[i]._top.assignBigger(*_triangles[i]._vertexC);
  1568.     }
  1569.     // Pre-compute triangle intersection data (used by raytracer)
  1570.    
  1571.     for(unsigned i=0; i<_triangles.size(); i++)
  1572.     {
  1573.         Triangle& triangle = _triangles[i];
  1574.  
  1575.         // Algorithm for triangle intersection is taken from Roman Kuchkuda's paper.
  1576.         // edge vectors
  1577.         Float3 vc1=*triangle._vertexB; vc1-=*triangle._vertexA;
  1578.         Float3 vc2=*triangle._vertexC; vc2-=*triangle._vertexB;
  1579.         Float3 vc3=*triangle._vertexA; vc3-=*triangle._vertexC;
  1580.  
  1581.         // plane of triangle
  1582.         triangle.n = Cross(vc1, vc2);
  1583.         Float3 alt1 = Cross(vc2, vc3);
  1584.         if (alt1.length() > triangle.n.length()) triangle.n = alt1;
  1585.         Float3 alt2 = Cross(vc3, vc1);
  1586.         if (alt2.length() > triangle.n.length()) triangle.n = alt2;
  1587.         triangle.n.Normalize();
  1588.         triangle._d = Dot(triangle.n, *triangle._vertexA);
  1589.  
  1590.         // edge planes
  1591.         triangle._e1 = Cross(triangle.n, vc1);
  1592.         triangle._e1.Normalize();
  1593.         triangle._d1 = Dot(triangle._e1, *triangle._vertexA);
  1594.         triangle._e2 = Cross(triangle.n, vc2);
  1595.         triangle._e2.Normalize();
  1596.         triangle._d2 = Dot(triangle._e2, *triangle._vertexB);
  1597.         triangle._e3 = Cross(triangle.n, vc3);
  1598.         triangle._e3.Normalize();
  1599.         triangle._d3 = Dot(triangle._e3, *triangle._vertexC);
  1600.     }
  1601. }
  1602.  
  1603. bool RayIntersectsBox(const Float3& originInWorldSpace, const Float3& rayInWorldSpace, CacheFriendlyBVHNode *pBox)
  1604. {
  1605.     // set Tnear = - infinity, Tfar = infinity
  1606.     //
  1607.     // For each pair of planes P associated with X, Y, and Z do:
  1608.     //     (example using X planes)
  1609.     //     if direction Xd = 0 then the ray is parallel to the X planes, so
  1610.     //         if origin Xo is not between the slabs ( Xo < Xl or Xo > Xh) then
  1611.     //             return false
  1612.     //     else, if the ray is not parallel to the plane then
  1613.     //     begin
  1614.     //         compute the intersection distance of the planes
  1615.     //         T1 = (Xl - Xo) / Xd
  1616.     //         T2 = (Xh - Xo) / Xd
  1617.     //         If T1 > T2 swap (T1, T2) /* since T1 intersection with near plane */
  1618.     //         If T1 > Tnear set Tnear =T1 /* want largest Tnear */
  1619.     //         If T2 < Tfar set Tfar="T2" /* want smallest Tfar */
  1620.     //         If Tnear > Tfar box is missed so
  1621.     //             return false
  1622.     //         If Tfar < 0 box is behind ray
  1623.     //             return false
  1624.     //     end
  1625.     // end of for loop
  1626.     //
  1627.     // If Box survived all above tests, return true with intersection point Tnear and exit point Tfar.
  1628.    
  1629.     CacheFriendlyBVHNode& box = *pBox;
  1630.     float Tnear, Tfar;
  1631.     Tnear = -FLT_MAX;
  1632.     Tfar = FLT_MAX;
  1633.  
  1634.     #define CHECK_NEAR_AND_FAR_INTERSECTION(c)                                          \
  1635.     if (rayInWorldSpace.## c == 0.){                                    \
  1636.         if (originInWorldSpace.##c < box._bottom.##c) return false;                 \
  1637.         if (originInWorldSpace.##c > box._top.##c) return false;                    \
  1638.     } else{                                            \
  1639.         float T1 = (box._bottom.##c - originInWorldSpace.##c)/rayInWorldSpace.##c;          \
  1640.         float T2 = (box._top.##c    - originInWorldSpace.##c)/rayInWorldSpace.##c;          \
  1641.         if (T1>T2) {float tmp=T1; T1=T2; T2=tmp; }                          \
  1642.         if (T1 > Tnear) Tnear = T1;                                 \
  1643.         if (T2 < Tfar)  Tfar = T2;                                  \
  1644.         if (Tnear > Tfar)                                       \
  1645.             return false;                                       \
  1646.         if (Tfar < 0.)                                          \
  1647.             return false;                                       \
  1648.         }
  1649.  
  1650.     CHECK_NEAR_AND_FAR_INTERSECTION(X)
  1651.     CHECK_NEAR_AND_FAR_INTERSECTION(Y)
  1652.     CHECK_NEAR_AND_FAR_INTERSECTION(Z)
  1653.  
  1654.     return true;
  1655. }
  1656.  
  1657. ////////////////Raytracer////////////
  1658. class RaytraceScanline
  1659. {
  1660.     // Since this class contains only references and has no virtual methods, it (hopefully)
  1661.     // doesn't exist in runtime; it is optimized away when RaytraceHorizontalSegment is called.
  1662.    // const Triangle& scene;
  1663.     const Scene& scene;
  1664.     const Camera& eye;
  1665.     Screen& canvas;
  1666.     int& y;
  1667.     bool& antialias;
  1668. public: RaytraceScanline(const Scene& scene,
  1669.                     //const Triangle& scene,
  1670.                     const Camera& e, Screen& c,
  1671.                     int& scanline,bool withAntialiasing)
  1672.                     :
  1673.                     scene(scene), eye(e),
  1674.                     canvas(c), y(scanline),
  1675.                     antialias(withAntialiasing)
  1676.                     {}
  1677.  
  1678. template <bool stopAtfirstRayHit, bool doCulling>
  1679. bool BVH_IntersectTriangles(
  1680.      //Inputs
  1681.     const Float3& origin, const Float3& ray,  
  1682.     const Triangle *avoidSelf,
  1683.      //outputs
  1684.     const Triangle*& pBestTri,
  1685.  
  1686.    
  1687.     // both inputs and outputs!
  1688.    
  1689.      //for normal rays:
  1690.       //pointHitInWorldSpace (output)
  1691.       //    kXX (outputs) perpendicular distances of intersection point from the 3 triangle edges
  1692.       //   (used for PhongNormal calculations)
  1693.    
  1694.      //for shadow rays:
  1695.       //pointHitInWorldSpace (input) provides the light position
  1696.     Float3& pointHitInWorldSpace,
  1697.     float& kAB, float& kBC, float& kCA
  1698. )const{
  1699.      //in the loop below, maintain the closest triangle and the point where we hit it:
  1700.         pBestTri = NULL;
  1701.         float bestTriDist;
  1702.  
  1703.         // light position passed-in pointHitInWorldSpace (only in shadow mode - i.e. stopAtfirstRayHit=true)
  1704.         Float3& lightPos = pointHitInWorldSpace;
  1705.         bool stopAtfirstRayHit = true;
  1706.          //Compile-time work (stopAtfirstRayHit is template param)
  1707.         if (stopAtfirstRayHit)
  1708.             // In shadow ray mode, start from light distance
  1709.             bestTriDist = distancesq(origin, lightPos);
  1710.         else
  1711.             // In normal mode, start from infinity
  1712.             bestTriDist = FLT_MAX;
  1713.  
  1714.         CacheFriendlyBVHNode* stack[BVH_STACK_SIZE];
  1715.         //BVHNode* stack[BVH_STACK_SIZE];
  1716.         //bvh box index
  1717.         int stackIdx = 0;
  1718.         stack[stackIdx++] = scene._pCFBVH;
  1719.         while(stackIdx)
  1720.         {
  1721.             CacheFriendlyBVHNode *pCurrent = stack[stackIdx-1];
  1722.             stackIdx--;
  1723.             //if (!pCurrent->IsLeaf()) {
  1724.             if (!(pCurrent->u.leaf._count & 0x80000000))
  1725.             {
  1726.                 if (RayIntersectsBox(origin,ray, pCurrent))
  1727.                 {
  1728.                     stack[stackIdx++] = &scene._pCFBVH[pCurrent->u.inner._idxRight];
  1729.                     stack[stackIdx++] = &scene._pCFBVH[pCurrent->u.inner._idxLeft];
  1730.                     assert(stackIdx<=BVH_STACK_SIZE);
  1731.                 }
  1732.             }
  1733.             else
  1734.             {
  1735.                 //BVHLeaf *p = dynamic_cast<BVHLeaf*>(pCurrent);
  1736.                 //for(std::list<const Triangle*>::iterator it=p->_triangles.begin();
  1737.                 //    it != p->_triangles.end();
  1738.                 //    it++)
  1739.                 for(unsigned i=pCurrent->u.leaf._startIndexInTriIndexList;
  1740.                     i<pCurrent->u.leaf._startIndexInTriIndexList +
  1741.                     (pCurrent->u.leaf._count & 0x7fffffff); i++)
  1742.                    {
  1743.                         //const triangle& triangle = *(*it);
  1744.                         const Triangle& Tri = scene._triangles[scene._triIndexList[i]];
  1745.                        
  1746.                         if (avoidSelf == &Tri)continue; // avoid self-reflections/refractions
  1747.  
  1748.                          //doCulling is a compile-time param, this code will be "codegenerated"
  1749.                         // at compile time only for reflection-related calls to Raytrace (see below)
  1750.                        
  1751.                         if (doCulling && !Tri._twoSided)
  1752.                         {
  1753.                              //Check visibility of triangle via dot product
  1754.                             Float3 fromTriToOrigin = origin;
  1755.                             fromTriToOrigin -= Tri.centroid;
  1756.                             // Normally we would normalize, but since we just need the sign
  1757.                             //of the dot product (to determine if it facing us or not)...
  1758.                             fromTriToOrigin = normalize(fromTriToOrigin);
  1759.                             if (Dot(fromTriToOrigin, Tri.n)<0)continue;
  1760.                         }
  1761.                        
  1762.                         // Use the pre-computed triangle intersection data: normal
  1763.                         float k = Dot(Tri.n, ray);
  1764.                         if (k == 0.0f)
  1765.                         continue; // this triangle is parallel to the ray, ignore it.
  1766.                        
  1767.                         float s = (Tri._vertexA->X - Dot(Tri.n, origin))/k;
  1768.                        
  1769.                         if(s <= 0.0f && s <=0.0f && s <=0.0f) // this triangle is "behind" the origin.
  1770.                          continue;
  1771.                         if (s <= NUDGE_FACTOR && s <= NUDGE_FACTOR && s <= NUDGE_FACTOR )
  1772.                         continue;
  1773.                         if (s <= 0.0) // this triangle is "behind" the origin.
  1774.                         continue;
  1775.                         if (s <= NUDGE_FACTOR)
  1776.                         continue;
  1777.  
  1778.                         Float3 hit = Scale(ray,s);
  1779.                         hit -= origin;
  1780.  
  1781.                         //Is the intersection of the ray with the triangle's plane INSIDE the triangle?
  1782.                         float kt1 = Dot(Tri._e1, hit) - Tri._d1; if (kt1<0.0) continue;
  1783.                         float kt2 = Dot(Tri._e2, hit) - Tri._d2; if (kt2<0.0) continue;
  1784.                         float kt3 = Dot(Tri._e3, hit) - Tri._d3; if (kt3<0.0) continue;
  1785.  
  1786.                          //It is, "hit" is the world space floatinate of the intersection.
  1787.  
  1788.                          //check whether it Was this a normal ray or a shadow ray? (template param)
  1789.                         if (stopAtfirstRayHit)
  1790.                         {
  1791.                             // Shadow ray, check whether the triangle obstructs the light
  1792.                             float dist = distancesq(lightPos, hit);
  1793.                             if (dist < bestTriDist) // distance to light (squared) passed in kAB
  1794.                                 return true; // we found a triangle obstructing the light, return true
  1795.                         }
  1796.                         else
  1797.                         { // Normal ray - it this intersection closer than all the others?
  1798.                             float hitZ = distancesq(origin, hit);
  1799.                             if (hitZ < bestTriDist)
  1800.                             {
  1801.                                 // maintain the closest hit
  1802.                                 bestTriDist = hitZ;
  1803.                                 pBestTri = &Tri;
  1804.                                 pointHitInWorldSpace = hit;
  1805.                                 kAB = kt1;
  1806.                                 kBC = kt2;
  1807.                                 kCA = kt3;
  1808.                             }
  1809.                         }
  1810.                     }
  1811.                 }
  1812.         }
  1813.          //Normal ray or shadow ray? (compile-time template param)
  1814.         if (!stopAtfirstRayHit)
  1815.            //  for normal ray, return true if we pierced a triangle
  1816.               return pBestTri != NULL;
  1817.         else
  1818.             // for shadow ray, return true if we found a triangle obstructing the light.
  1819.             return false;
  1820. }
  1821. template <bool doCulling>
  1822. Pixel Raytrace(Float3 originInWorldSpace,
  1823.                Float3 rayInWorldSpace,
  1824.                const Triangle *avoidSelf, int depth)const
  1825. {
  1826.     if (depth >= MAX_RAY_DEPTH)
  1827.         return Pixel(0.,0.,0.);
  1828.  
  1829.     const Triangle *pBestTri = NULL;
  1830.     Float3 pointHitInWorldSpace;
  1831.     float kAB= 0.f, kBC= 0.f, kCA= 0.f; // distances from the 3 edges of the triangle (from where we hit it)
  1832.  
  1833.     // Use the surface-area heuristic based, bounding volume hierarchy of axis-aligned bounding boxes
  1834.     // (keywords: SAH, BVH, AABB)
  1835.     if (!BVH_IntersectTriangles<false,doCulling>(
  1836.         originInWorldSpace, rayInWorldSpace, avoidSelf,
  1837.         pBestTri, pointHitInWorldSpace, kAB, kBC, kCA))
  1838.         // We pierced no triangle, return with no contribution (ambient is black)
  1839.         return Pixel(0.,0.,0.);
  1840.  
  1841.     // Set this to pass to recursive calls below, so that we don't get self-shadow or self-reflection
  1842.     // from this triangle...
  1843.     avoidSelf = pBestTri;
  1844.  
  1845.     // We'll also calculate the color contributed from this intersection
  1846.     // Start from the triangle's color
  1847.     Pixel color = pBestTri->_colorf;
  1848.  
  1849.     return color;
  1850. }
  1851. void RaytraceHorizontalSegment(int xStarting, int iOnePastEndingX) const
  1852. {
  1853.     for(int x=xStarting; x<iOnePastEndingX; x++)
  1854.     {
  1855.         Pixel finalColor(0,0,0);
  1856.  
  1857.         int pixelsTraced = 1;
  1858.         if (antialias)
  1859.         pixelsTraced = 4;
  1860.  
  1861.         while(pixelsTraced--)
  1862.         {
  1863.             // We will shoot a ray in camera space (from Eye to the screen point, so in camera
  1864.             // space, from (0,0,0) to this:
  1865.             float xx = (float)x;
  1866.             float yy = (float)y;
  1867.  
  1868.             if (antialias)
  1869.             {
  1870.                 // nudge in a cross pattern around the uchar4 center
  1871.                 xx += 0.25f - .5f*(pixelsTraced&1);
  1872.                 yy += 0.25f - .5f*((pixelsTraced&2)>>1);
  1873.             }
  1874.             float lx = float((HEIGHT/2)-yy)/SCREEN_DIST;
  1875.             float ly = float(xx-(WIDTH/2))/SCREEN_DIST;
  1876.             float lz = 1.0;
  1877.             Float3 rayInCameraSpace(lx,ly,lz);
  1878.             rayInCameraSpace.Normalize();
  1879.  
  1880.             // We will need the origin in world space
  1881.             Float3 originInWorldSpace = eye.From;
  1882.  
  1883.             // We have a rayInCameraSpace, and we want to use the BVH, which was constructed
  1884.             // in World space, so we convert the ray in World space
  1885.             Float3 rayInWorldSpace = Scale(eye.From, rayInCameraSpace.X);
  1886.             rayInWorldSpace += Scale(eye.At, rayInCameraSpace.Y);
  1887.             rayInWorldSpace += Scale(eye.Up, rayInCameraSpace.Z);
  1888.             // in theory, this should not be required
  1889.             rayInWorldSpace.Normalize();
  1890.  
  1891.             // Primary ray, we want backface culling: <true>
  1892.             finalColor += Raytrace<true>(originInWorldSpace, rayInWorldSpace, NULL, 0);
  1893.         }
  1894.        // if (antialias)
  1895.         finalColor /= 4.;
  1896.         if (finalColor._r>255.0f) finalColor._r=255.0f;
  1897.         if (finalColor._g>255.0f) finalColor._g=255.0f;
  1898.         if (finalColor._b>255.0f) finalColor._b=255.0f;
  1899.         canvas.DrawPixel(y,x, SDL_MapRGB(
  1900.         canvas._surface->format, (Uint8)finalColor._r, (Uint8)finalColor._g, (Uint8)finalColor._b));
  1901.     }
  1902.     }
  1903. };
  1904.  
  1905. bool Scene :: renderRaytracer(Camera& eye, Screen& canvas, bool antialias)
  1906. {
  1907.     bool needToUpdateTitleBar = !_pSceneBVH; // see below
  1908.     // Update the BVH and its cache-friendly version
  1909.      extern const char *g_filename;
  1910.     UpdateBoundingVolumeHierarchy(g_filename);
  1911.  
  1912.     // Main loop: for each uchar4...
  1913.     for(int y=0; y<HEIGHT; y++)
  1914.     {
  1915.  
  1916.     // For both OpenMP and single-threaded, call the RaytraceHorizontalSegment member
  1917.     // of the RaytraceScanline, requesting drawing of ALL the scanline.
  1918.     // For OpenMP, the appropriate pragma inside RaytraceHorizontalSegment will make it execute via SMP...
  1919.         RaytraceScanline(*this, eye, canvas, y, antialias).
  1920.         RaytraceHorizontalSegment(0, WIDTH);
  1921.  
  1922.     }
  1923.     canvas.ShowScreen(true);
  1924.     return true;
  1925. }
  1926.  
  1927. bool g_benchmark = false;
  1928. const char *g_filename = NULL;
  1929.  
  1930.  int main(int argc,char *argv[])
  1931. {  
  1932.     char *fname = argv[1];
  1933.     g_filename = fname;
  1934.     bool doBenchmark = false;
  1935.     g_benchmark =doBenchmark;
  1936.    
  1937.     ComputeCameraframe();
  1938.     try
  1939.     {
  1940.         Scene scene;
  1941.         scene.load(fname, &b, &Cam);
  1942.             if (g_benchmark )
  1943.             {
  1944.                 // When benchmarking, we dont want the first frame to "suffer" the BVH creation
  1945.                 puts("Creating BVH... please wait...");
  1946.                 scene.UpdateBoundingVolumeHierarchy(fname);
  1947.             }
  1948.    
  1949.         Screen canvas(scene);
  1950.         canvas.ShowScreen();
  1951.         scene.renderRaytracer(Cam,canvas,false);
  1952.     }
  1953.     catch(const string& s) {cerr << s.c_str();}
  1954.     return 0;
  1955.  }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement