home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2007 September / maximum-cd-2007-09.iso / Assets / data / AssaultCube_v0.93.exe / source / src / worldocull.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2007-04-09  |  4.7 KB  |  135 lines

  1. // worldocull.cpp: occlusion map and occlusion test
  2.  
  3. #include "cube.h"
  4.  
  5. #define NUMRAYS 512
  6.  
  7. float rdist[NUMRAYS];
  8. bool ocull = true;
  9. float odist = 256;
  10.  
  11. void toggleocull() { ocull = !ocull; }
  12.  
  13. COMMAND(toggleocull, ARG_NONE);
  14.  
  15. // constructs occlusion map: cast rays in all directions on the 2d plane and record distance.
  16. // done exactly once per frame.
  17.  
  18. void computeraytable(float vx, float vy)
  19. {
  20.     if(!ocull) return;
  21.  
  22.     odist = getvar("fog")*1.5f;
  23.  
  24.     float apitch = (float)fabs(camera1->pitch);
  25.     float af = getvar("fov")/2+apitch/1.5f+3;
  26.     float byaw = (camera1->yaw-90+af)/360*PI2;
  27.     float syaw = (camera1->yaw-90-af)/360*PI2;
  28.  
  29.     loopi(NUMRAYS)
  30.     {
  31.         float angle = i*PI2/NUMRAYS;
  32.         if((apitch>45 // must be bigger if fov>120
  33.         || (angle<byaw && angle>syaw)
  34.         || (angle<byaw-PI2 && angle>syaw-PI2)
  35.         || (angle<byaw+PI2 && angle>syaw+PI2))
  36.         && !OUTBORD(vx, vy)
  37.         && !SOLID(S(int(vx), int(vy))))       // try to avoid tracing ray if outside of frustrum
  38.         {
  39.             float ray = i*8/(float)NUMRAYS;
  40.             float dx, dy;
  41.             if(ray>1 && ray<3) { dx = -(ray-2); dy = 1; }
  42.             else if(ray>=3 && ray<5) { dx = -1; dy = -(ray-4); }
  43.             else if(ray>=5 && ray<7) { dx = ray-6; dy = -1; }
  44.             else { dx = 1; dy = ray>4 ? ray-8 : ray; }
  45.             float sx = vx;
  46.             float sy = vy;
  47.             for(;;)
  48.             {
  49.                 sx += dx;
  50.                 sy += dy;
  51.                 if(SOLID(S(int(sx), int(sy))))    // 90% of time spend in this function is on this line
  52.                 {
  53.                     rdist[i] = (float)(fabs(sx-vx)+fabs(sy-vy));
  54.                     break;
  55.                 }
  56.             }
  57.         }
  58.         else
  59.         {
  60.             rdist[i] = 2;
  61.         }
  62.     }
  63. }
  64.  
  65. // test occlusion for a cube... one of the most computationally expensive functions in the engine
  66. // as its done for every cube and entity, but its effect is more than worth it!
  67.  
  68. inline float ca(float x, float y) { return x>y ? y/x : 2-x/y; } 
  69. inline float ma(float x, float y) { return x==0 ? (y>0 ? 2 : -2) : y/x; }
  70.  
  71. int isoccluded(float vx, float vy, float cx, float cy, float csize)     // v = viewer, c = cube to test 
  72. {
  73.     if(!ocull || minimap) return 0;
  74.  
  75.     float xdist = 0, ydist = 0; // distance from point on the border of the cube that is closest to v
  76.     if(vx<cx) xdist = cx-vx;
  77.     else if(vx>cx+csize) xdist = vx-(cx+csize);
  78.     if(vy<cy) ydist = cy-vy;
  79.     else if(vy>cy+csize) ydist = vy-(cy+csize);
  80.     if(xdist>odist || ydist>odist) return 2;
  81.     float dist = xdist+ydist-1; // 1 needed?
  82.  
  83.     // ABC
  84.     // D E
  85.     // FGH
  86.  
  87.     // - check middle cube? BG
  88.  
  89.     // find highest and lowest angle in the occlusion map that this cube spans, based on its most left and right
  90.     // points on the border from the viewer pov... I see no easier way to do this than this silly code below
  91.  
  92.     float h, l;
  93.     if(cx<=vx)              // ABDFG
  94.     {
  95.         if(cx+csize<vx)     // ADF
  96.         {
  97.             if(cy<=vy)      // AD
  98.             {
  99.                 if(cy+csize<vy) { h = ca(-(cx-vx), -(cy+csize-vy))+4; l = ca(-(cx+csize-vx), -(cy-vy))+4; }        // A
  100.                 else            { h = ma(-(cx+csize-vx), -(cy+csize-vy))+4; l =  ma(-(cx+csize-vx), -(cy-vy))+4; } // D
  101.             }
  102.             else                { h = ca(cy+csize-vy, -(cx+csize-vx))+2; l = ca(cy-vy, -(cx-vx))+2; }              // F
  103.         }
  104.         else                // BG
  105.         {
  106.             if(cy<=vy)
  107.             {
  108.                 if(cy+csize<vy) { h = ma(-(cy+csize-vy), cx-vx)+6; l = ma(-(cy+csize-vy), cx+csize-vx)+6; }        // B
  109.                 else return 0;
  110.             }
  111.             else     { h = ma(cy-vy, -(cx+csize-vx))+2; l = ma(cy-vy, -(cx-vx))+2; }                               // G
  112.         }
  113.     }
  114.     else                    // CEH
  115.     {
  116.         if(cy<=vy)          // CE
  117.         {
  118.             if(cy+csize<vy) { h = ca(-(cy-vy), cx-vx)+6; l = ca(-(cy+csize-vy), cx+csize-vx)+6; }                  // C
  119.             else            { h = ma(cx-vx, cy-vy); l = ma(cx-vx, cy+csize-vy); }                                  // E
  120.         }
  121.         else                { h = ca(cx+csize-vx, cy-vy); l = ca(cx-vx, cy+csize-vy); }                            // H
  122.     }
  123.     int si = int(h*(NUMRAYS/8))+NUMRAYS;     // get indexes into occlusion map from angles
  124.     int ei = int(l*(NUMRAYS/8))+NUMRAYS+1; 
  125.     if(ei<=si) ei += NUMRAYS;
  126.  
  127.     for(int i = si; i<=ei; i++)
  128.     {
  129.         if(dist<rdist[i&(NUMRAYS-1)]) return 0;     // if any value in this segment of the occlusion map is further away then cube is not occluded
  130.     }
  131.  
  132.     return 1;                                       // cube is entirely occluded
  133. }
  134.  
  135.