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

  1. // worldrender.cpp: goes through all cubes in top down quad tree fashion, determines what has to
  2. // be rendered and how (depending on neighbouring cubes), then calls functions in rendercubes.cpp
  3.  
  4. #include "cube.h"
  5.  
  6. void render_wall(sqr *o, sqr *s, int x1, int y1, int x2, int y2, int mip, sqr *d1, sqr *d2, bool topleft)
  7. {
  8.     if(minimap) return;
  9.     if(SOLID(o) || o->type==SEMISOLID)
  10.     {
  11.         float c1 = s->floor;
  12.         float c2 = s->floor;
  13.         if(s->type==FHF) { c1 -= d1->vdelta/4.0f; c2 -= d2->vdelta/4.0f; }
  14.         float f1 = s->ceil;
  15.         float f2 = s->ceil;
  16.         if(s->type==CHF) { f1 += d1->vdelta/4.0f; f2 += d2->vdelta/4.0f; }
  17.         //if(f1-c1<=0 && f2-c2<=0) return;
  18.         render_square(o->wtex, c1, c2, f1, f2, x1<<mip, y1<<mip, x2<<mip, y2<<mip, 1<<mip, d1, d2, topleft);
  19.         return;
  20.     }
  21.     {
  22.         float f1 = s->floor;
  23.         float f2 = s->floor;
  24.         float c1 = o->floor;
  25.         float c2 = o->floor;
  26.         if(o->type==FHF && s->type!=FHF)
  27.         {
  28.             c1 -= d1->vdelta/4.0f;
  29.             c2 -= d2->vdelta/4.0f;
  30.         }
  31.         if(s->type==FHF && o->type!=FHF)
  32.         {
  33.             f1 -= d1->vdelta/4.0f;
  34.             f2 -= d2->vdelta/4.0f;
  35.         }
  36.         if(f1>=c1 && f2>=c2) goto skip;
  37.         render_square(o->wtex, f1, f2, c1, c2, x1<<mip, y1<<mip, x2<<mip, y2<<mip, 1<<mip, d1, d2, topleft);
  38.     }
  39.     skip:
  40.     {
  41.         float f1 = o->ceil;
  42.         float f2 = o->ceil;
  43.         float c1 = s->ceil;
  44.         float c2 = s->ceil;
  45.         if(o->type==CHF && s->type!=CHF)
  46.         {
  47.             f1 += d1->vdelta/4.0f;
  48.             f2 += d2->vdelta/4.0f;
  49.         }
  50.         else if(s->type==CHF && o->type!=CHF)
  51.         {
  52.             c1 += d1->vdelta/4.0f;
  53.             c2 += d2->vdelta/4.0f;
  54.         }
  55.         if(c1<=f1 && c2<=f2) return;
  56.         render_square(o->utex, f1, f2, c1, c2, x1<<mip, y1<<mip, x2<<mip, y2<<mip, 1<<mip, d1, d2, topleft);
  57.     }
  58. }
  59.  
  60. const int MAX_MIP = 5;   // 32x32 unit blocks
  61. const int MIN_LOD = 2;
  62. const int LOW_LOD = 25;
  63. const int MAX_LOD = 250;
  64.  
  65. int lod = 40, lodtop, lodbot, lodleft, lodright;
  66. int min_lod;
  67.  
  68. int lod_factor() { return lod; }
  69.  
  70. VARP(minlod, LOW_LOD, 60, MAX_LOD);
  71.  
  72. int stats[LARGEST_FACTOR];
  73.  
  74. // detect those cases where a higher mip solid has a visible wall next to lower mip cubes
  75. // (used for wall rendering below)
  76.  
  77. bool issemi(int mip, int x, int y, int x1, int y1, int x2, int y2)      
  78. {
  79.     if(!(mip--)) return true;
  80.     sqr *w = wmip[mip];
  81.     int msize = ssize>>mip;
  82.     x *= 2;
  83.     y *= 2;
  84.     switch(SWS(w, x+x1, y+y1, msize)->type)
  85.     {
  86.         case SEMISOLID: if(issemi(mip, x+x1, y+y1, x1, y1, x2, y2)) return true;
  87.         case CORNER:
  88.         case SOLID: break;
  89.         default: return true;
  90.     }
  91.     switch(SWS(w, x+x2, y+y2, msize)->type)
  92.     {
  93.         case SEMISOLID: if(issemi(mip, x+x2, y+y2, x1, y1, x2, y2)) return true;
  94.         case CORNER:
  95.         case SOLID: break;
  96.         default: return true;
  97.     }
  98.     return false;
  99. }
  100.  
  101. bool render_floor, render_ceil;
  102.  
  103. // the core recursive function, renders a rect of cubes at a certain mip level from a viewer perspective
  104. // call itself for lower mip levels, on most modern machines however this function will use the higher
  105. // mip levels only for perfect mips.
  106.  
  107. void render_seg_new(float vx, float vy, float vh, int mip, int x, int y, int xs, int ys)
  108. {
  109.     sqr *w = wmip[mip];
  110.     int sz = ssize>>mip;
  111.     int vxx = ((int)vx+(1<<mip)/2)>>mip;
  112.     int vyy = ((int)vy+(1<<mip)/2)>>mip;
  113.     int lx = vxx-lodleft;   // these mark the rect inside the current rest that we want to render using a lower mip level
  114.     int ly = vyy-lodtop;
  115.     int rx = vxx+lodright;
  116.     int ry = vyy+lodbot;
  117.  
  118.     float fsize = (float)(1<<mip);
  119.     for(int ox = x; ox<xs; ox++) for(int oy = y; oy<ys; oy++)       // first collect occlusion information for this block
  120.     {
  121.         SWS(w,ox,oy,sz)->occluded = isoccluded(camera1->o.x, camera1->o.y, (float)(ox<<mip), (float)(oy<<mip), fsize);
  122.     }
  123.     
  124.     int pvx = (int)vx>>mip;
  125.     int pvy = (int)vy>>mip;
  126.     if(pvx>=0 && pvy>=0 && pvx<sz && pvy<sz)
  127.     {
  128.         //SWS(w,vxx,vyy,sz)->occluded = 0; 
  129.         SWS(w, pvx, pvy, sz)->occluded = 0;  // player cell never occluded
  130.     }
  131.  
  132.     #define df(x) s->floor-(x->vdelta/4.0f)
  133.     #define dc(x) s->ceil+(x->vdelta/4.0f)
  134.     
  135.     // loop through the rect 3 times (for floor/ceil/walls seperately, to facilitate dynamic stripify)
  136.     // for each we skip occluded cubes (occlusion at higher mip levels is a big time saver!).
  137.     // during the first loop (ceil) we collect cubes that lie within the lower mip rect and are
  138.     // also deferred, and render them recursively. Anything left (perfect mips and higher lods) we
  139.     // render here.
  140.  
  141.     #define LOOPH {for(int xx = x; xx<xs; xx++) for(int yy = y; yy<ys; yy++) { \
  142.                   sqr *s = SWS(w,xx,yy,sz); if(s->occluded==1) continue; \
  143.                   if(s->defer && !s->occluded && mip && xx>=lx && xx<rx && yy>=ly && yy<ry)
  144.     #define LOOPD sqr *t = SWS(s,1,0,sz); \
  145.                   sqr *u = SWS(s,1,1,sz); \
  146.                   sqr *v = SWS(s,0,1,sz);
  147.  
  148.     LOOPH // floors
  149.         {
  150.             int start = yy;
  151.             sqr *next;
  152.             while(yy<ys-1 && (next = SWS(w,xx,yy+1,sz))->defer && !next->occluded) yy++;    // collect 2xN rect of lower mip
  153.             render_seg_new(vx, vy, vh, mip-1, xx*2, start*2, xx*2+2, yy*2+2);
  154.             continue;
  155.         }
  156.         stats[mip]++;
  157.         LOOPD
  158.         if((s->type==SPACE || s->type==CHF) && s->floor<=vh && render_floor)
  159.         {
  160.             render_flat(s->ftex, xx<<mip, yy<<mip, 1<<mip, s->floor, s, t, u, v, false);
  161.             if(s->floor<hdr.waterlevel && !SOLID(s) && !reflecting) addwaterquad(xx<<mip, yy<<mip, 1<<mip);
  162.         }
  163.         if(s->type==FHF)
  164.         {
  165.             render_flatdelta(s->ftex, xx<<mip, yy<<mip, 1<<mip, df(s), df(t), df(u), df(v), s, t, u, v, false);
  166.             if(s->floor-s->vdelta/4.0f<hdr.waterlevel && !SOLID(s) && !reflecting) addwaterquad(xx<<mip, yy<<mip, 1<<mip);
  167.         }
  168.     }}
  169.  
  170.     if(!minimap) LOOPH continue; // ceils
  171.         LOOPD
  172.         if((s->type==SPACE || s->type==FHF) && s->ceil>=vh && render_ceil)
  173.             render_flat(s->ctex, xx<<mip, yy<<mip, 1<<mip, s->ceil, s, t, u, v, true);
  174.         if(s->type==CHF) //if(s->ceil>=vh)
  175.             render_flatdelta(s->ctex, xx<<mip, yy<<mip, 1<<mip, dc(s), dc(t), dc(u), dc(v), s, t, u, v, true);
  176.     }}
  177.  
  178.     LOOPH continue; // walls
  179.         LOOPD
  180.         //  w
  181.         // zSt
  182.         //  vu
  183.  
  184.         sqr *w = SWS(s,0,-1,sz);
  185.         sqr *z = SWS(s,-1,0,sz);
  186.         bool normalwall = true;
  187.  
  188.         if(s->type==CORNER)
  189.         {
  190.             // cull also
  191.             bool topleft = true;
  192.             sqr *h1 = NULL;
  193.             sqr *h2 = NULL;
  194.             if(SOLID(z))
  195.             {
  196.                 if(SOLID(w))      { render_wall(w, h2 = s, xx+1, yy, xx, yy+1, mip, t, v, false); topleft = false; }
  197.                 else if(SOLID(v)) { render_wall(v, h2 = s, xx, yy, xx+1, yy+1, mip, s, u, false); }
  198.             }
  199.             else if(SOLID(t))
  200.             {
  201.                 if(SOLID(w))      { render_wall(w, h1 = s, xx+1, yy+1, xx, yy, mip, u, s, false); }
  202.                 else if(SOLID(v)) { render_wall(v, h1 = s, xx, yy+1, xx+1, yy, mip, v, t, false); topleft = false; }
  203.             }
  204.             else
  205.             {
  206.                 normalwall = false;
  207.                 bool wv = w->ceil-w->floor < v->ceil-v->floor;
  208.                 if(z->ceil-z->floor < t->ceil-t->floor)
  209.                 {
  210.                     if(wv) { render_wall(h1 = s, h2 = v, xx+1, yy, xx, yy+1, mip, t, v, false); topleft = false; }
  211.                     else   { render_wall(h1 = s, h2 = w, xx, yy, xx+1, yy+1, mip, s, u, false); }
  212.                 }
  213.                 else
  214.                 {
  215.                     if(wv) { render_wall(h2 = s, h1 = v, xx+1, yy+1, xx, yy, mip, u, s, false); }
  216.                     else   { render_wall(h2 = s, h1 = w, xx, yy+1, xx+1, yy, mip, v, t, false); topleft = false; }
  217.                 }
  218.             }
  219.             render_tris(xx<<mip, yy<<mip, 1<<mip, topleft, h1, h2, s, t, u, v);
  220.         }
  221.  
  222.         if(normalwall)
  223.         {
  224.             bool inner = xx!=sz-1 && yy!=sz-1;
  225.  
  226.             if(xx>=vxx && xx!=0 && yy!=sz-1 && !SOLID(z) && (!SOLID(s) || z->type!=CORNER)
  227.                 && (z->type!=SEMISOLID || issemi(mip, xx-1, yy, 1, 0, 1, 1)))
  228.                 render_wall(s, z, xx,   yy,   xx,   yy+1, mip, s, v, true);
  229.             if(xx<=vxx && inner && !SOLID(t) && (!SOLID(s) || t->type!=CORNER)
  230.                 && (t->type!=SEMISOLID || issemi(mip, xx+1, yy, 0, 0, 0, 1)))
  231.                 render_wall(s, t, xx+1, yy,   xx+1, yy+1, mip, t, u, false);
  232.             if(yy>=vyy && yy!=0 && xx!=sz-1 && !SOLID(w) && (!SOLID(s) || w->type!=CORNER)
  233.                 && (w->type!=SEMISOLID || issemi(mip, xx, yy-1, 0, 1, 1, 1)))
  234.                 render_wall(s, w, xx,   yy,   xx+1, yy,   mip, s, t, false);
  235.             if(yy<=vyy && inner && !SOLID(v) && (!SOLID(s) || v->type!=CORNER)
  236.                 && (v->type!=SEMISOLID || issemi(mip, xx, yy+1, 0, 0, 1, 0)))
  237.                 render_wall(s, v, xx,   yy+1, xx+1, yy+1, mip, v, u, true);
  238.         }
  239.     }}
  240.  
  241. }
  242.  
  243. void distlod(int &low, int &high, int angle, float widef)
  244. {
  245.     float f = 90.0f/lod/widef;
  246.     low = (int)((90-angle)/f);
  247.     high = (int)(angle/f);
  248.     if(low<min_lod) low = min_lod;
  249.     if(high<min_lod) high = min_lod;
  250. }
  251.  
  252. // does some out of date view frustrum optimisation that doesn't contribute much anymore
  253.  
  254. void render_world(float vx, float vy, float vh, float changelod, int yaw, int pitch, float fov, int w, int h)
  255. {
  256.     loopi(LARGEST_FACTOR) stats[i] = 0;
  257.     min_lod = minimap ? MAX_LOD : MIN_LOD+abs(pitch)/12;
  258.     yaw = 360-yaw;
  259.     float widef = fov/75.0f;
  260.     int cdist = abs(yaw%90-45);
  261.     if(cdist<7)    // hack to avoid popup at high fovs at 45 yaw
  262.     {
  263.         min_lod = max(min_lod, (int)(MIN_LOD+(10-cdist)/1.0f*widef)); // less if lod worked better
  264.         widef = 1.0f;
  265.     }
  266.     lod = (int)(lod*changelod);
  267.     if(lod<minlod) lod = minlod;
  268.     if(lod>MAX_LOD) lod = MAX_LOD;
  269.     lodtop = lodbot = lodleft = lodright = min_lod;
  270.     if(yaw>45 && yaw<=135)
  271.     {
  272.         lodleft = lod;
  273.         distlod(lodtop, lodbot, yaw-45, widef);
  274.     }
  275.     else if(yaw>135 && yaw<=225)
  276.     {
  277.         lodbot = lod;
  278.         distlod(lodleft, lodright, yaw-135, widef);
  279.     }
  280.     else if(yaw>225 && yaw<=315)
  281.     {
  282.         lodright = lod;
  283.         distlod(lodbot, lodtop, yaw-225, widef);
  284.     }
  285.     else
  286.     {
  287.         lodtop = lod;
  288.         distlod(lodright, lodleft, yaw<=45 ? yaw+45 : yaw-315, widef);
  289.     }
  290.     float hyfov = fov*h/w/2;
  291.     render_floor = pitch<hyfov;
  292.     render_ceil  = -pitch<hyfov;
  293.  
  294.     render_seg_new(vx, vy, vh, MAX_MIP, 0, 0, ssize>>MAX_MIP, ssize>>MAX_MIP);
  295.     mipstats(stats[0], stats[1], stats[2]);
  296. }
  297.  
  298.