bool cornertest(int mip, int x, int y, int dx, int dy, int &bx, int &by, int &bs) // recursively collide with a mipmapped corner cube { sqr *w = wmip[mip]; int sz = ssize>>mip; bool stest = SOLID(SWS(w, x+dx, y, sz)) && SOLID(SWS(w, x, y+dy, sz)); mip++; x /= 2; y /= 2; if(SWS(wmip[mip], x, y, ssize>>mip)->type==CORNER) { bx = x<<mip; by = y<<mip; bs = 1<<mip; return cornertest(mip, x, y, dx, dy, bx, by, bs); }; return stest; };
bool issemi(int mip, int x, int y, int x1, int y1, int x2, int y2) { if(!(mip--)) return true; sqr *w = wmip[mip]; int mfactor = sfactor - mip; x *= 2; y *= 2; switch(SWS(w, x+x1, y+y1, mfactor)->type) { case SEMISOLID: if(issemi(mip, x+x1, y+y1, x1, y1, x2, y2)) return true; case CORNER: case SOLID: break; default: return true; } switch(SWS(w, x+x2, y+y2, mfactor)->type) { case SEMISOLID: if(issemi(mip, x+x2, y+y2, x1, y1, x2, y2)) return true; case CORNER: case SOLID: break; default: return true; } return false; }
void cursorupdate() // called every frame from hud { flrceil = ((int)(player1->pitch>=0))*2; volatile float x = worldpos.x; // volatile needed to prevent msvc7 optimizer bug? volatile float y = worldpos.y; volatile float z = worldpos.z; cx = (int)x; cy = (int)y; if(OUTBORD(cx, cy)) return; sqr *s = S(cx,cy); if(fabs(sheight(s,s,z)-z)>1) // selected wall { x += x>player1->o.x ? 0.5f : -0.5f; // find right wall cube y += y>player1->o.y ? 0.5f : -0.5f; cx = (int)x; cy = (int)y; if(OUTBORD(cx, cy)) return; }; if(dragging) makesel(); const int GRIDSIZE = 5; const float GRIDW = 0.5f; const float GRID8 = 2.0f; const float GRIDS = 2.0f; const int GRIDM = 0x7; // render editing grid /* for(int ix = cx-GRIDSIZE; ix<=cx+GRIDSIZE; ix++) for(int iy = cy-GRIDSIZE; iy<=cy+GRIDSIZE; iy++) { if(OUTBORD(ix, iy)) continue; sqr *s = S(ix,iy); if(SOLID(s)) continue; float h1 = sheight(s, s, z); float h2 = sheight(s, SWS(s,1,0,ssize), z); float h3 = sheight(s, SWS(s,1,1,ssize), z); float h4 = sheight(s, SWS(s,0,1,ssize), z); if(s->tag) linestyle(GRIDW, 0xFF, 0x40, 0x40); else if(s->type==FHF || s->type==CHF) linestyle(GRIDW, 0x80, 0xFF, 0x80); else linestyle(GRIDW, 0x80, 0x80, 0x80); block b = { ix, iy, 1, 1 }; box(b, h1, h2, h3, h4); linestyle(GRID8, 0x40, 0x40, 0xFF); if(!(ix&GRIDM)) line(ix, iy, h1, ix, iy+1, h4); if(!(ix+1&GRIDM)) line(ix+1, iy, h2, ix+1, iy+1, h3); if(!(iy&GRIDM)) line(ix, iy, h1, ix+1, iy, h2); if(!(iy+1&GRIDM)) line(ix, iy+1, h4, ix+1, iy+1, h3); }; */ if(!SOLID(s)) { float ih = sheight(s, s, z); linestyle(GRIDS, 0xFF, 0xFF, 0xFF); block b = { cx, cy, 1, 1 }; box(b, ih, sheight(s, SWS(s,1,0,ssize), z), sheight(s, SWS(s,1,1,ssize), z), sheight(s, SWS(s,0,1,ssize), z)); linestyle(GRIDS, 0xFF, 0x00, 0x00); dot(cx, cy, ih); ch = (int)ih; }; if(selset) { linestyle(GRIDS, 0xFF, 0x40, 0x40); box(sel, (float)selh, (float)selh, (float)selh, (float)selh); std::vector< std::pair<block, int> >::iterator sel_it = secondary_sel.begin(); std::vector< std::pair<block, int> >::iterator sel_end = secondary_sel.end(); for (; sel_it != sel_end; ++sel_it) box(sel_it->first, (float)sel_it->second, (float)sel_it->second, (float)sel_it->second, (float)sel_it->second); }; };
void render_seg_new(float vx, float vy, float vh, int mip, int x, int y, int xs, int ys) { sqr *w = wmip[mip]; int mfactor = sfactor - mip; int sz = 1<<mfactor; int vxx = ((int)vx+(1<<mip)/2)>>mip; int vyy = ((int)vy+(1<<mip)/2)>>mip; int lx = vxx-lodleft; // these mark the rect inside the current rest that we want to render using a lower mip level int ly = vyy-lodtop; int rx = vxx+lodright; int ry = vyy+lodbot; float fsize = (float)(1<<mip); for(int oy = y; oy<ys; oy++) // first collect occlusion information for this block { sqr *s = SWS(w,x,oy,mfactor); for(int ox = x; ox<xs; ox++, s++) s->occluded = isoccluded(camera1->o.x, camera1->o.y, (float)(ox<<mip), (float)(oy<<mip), fsize); } int pvx = (int)vx>>mip; int pvy = (int)vy>>mip; if(pvx>=0 && pvy>=0 && pvx<sz && pvy<sz) { //SWS(w,vxx,vyy,mfactor)->occluded = 0; SWS(w, pvx, pvy, mfactor)->occluded = 0; // player cell never occluded } #define df(x) s->floor-(x->vdelta/4.0f) #define dc(x) s->ceil+(x->vdelta/4.0f) // loop through the rect 3 times (for floor/ceil/walls seperately, to facilitate dynamic stripify) // for each we skip occluded cubes (occlusion at higher mip levels is a big time saver!). // during the first loop (ceil) we collect cubes that lie within the lower mip rect and are // also deferred, and render them recursively. Anything left (perfect mips and higher lods) we // render here. #define LOOPH {for(int yy = y; yy<ys; yy++) { sqr *s = SWS(w,x,yy,mfactor); \ for(int xx = x; xx<xs; xx++, s++) { if(s->occluded) continue; #define LOOPD sqr *t = SWS(s,1,0,mfactor); \ sqr *v = SWS(s,0,1,mfactor); \ sqr *u = SWS(v,1,0,mfactor); int rendered = 0; LOOPH // floors if(s->defer && mip && xx>=lx && xx<rx && yy>=ly && yy<ry) { s->occluded = 1; // shortcut for the other LOOPHs int start = xx; while(xx<xs-1 && s[1].defer && !s[1].occluded) {xx++; s++; if(xx<rx) s->occluded = 1;} // collect 2xN rect of lower mip render_seg_new(vx, vy, vh, mip-1, start*2, yy*2, xx*2+2, yy*2+2); continue; } rendered++; switch(s->type) { case SPACE: case CHF: if(s->floor<=vh && render_floor) { sqr *v = SWS(s,0,1,mfactor); render_flat(s->ftex, xx<<mip, yy<<mip, 1<<mip, s->floor, s, s + 1, v + 1, v, false); if(s->floor<hdr.waterlevel && !reflecting) addwaterquad(xx<<mip, yy<<mip, 1<<mip); } break; case FHF: { LOOPD render_flatdelta(s->ftex, xx<<mip, yy<<mip, 1<<mip, df(s), df(t), df(u), df(v), s, t, u, v, false); if(s->floor-s->vdelta/4.0f<hdr.waterlevel && !reflecting) addwaterquad(xx<<mip, yy<<mip, 1<<mip); break; } } }}}