diff --git a/source/codeblocks/AssaultCube.cbp b/source/codeblocks/AssaultCube.cbp index cd907543..56c47b66 100644 --- a/source/codeblocks/AssaultCube.cbp +++ b/source/codeblocks/AssaultCube.cbp @@ -166,6 +166,7 @@ + diff --git a/source/src/Makefile b/source/src/Makefile index 5a741f7e..7615a326 100644 --- a/source/src/Makefile +++ b/source/src/Makefile @@ -29,6 +29,7 @@ CLIENT_OBJS= \ server.o \ serverbrowser.o \ serverms.o \ + shadow.o \ sound.o \ texture.o \ tools.o \ diff --git a/source/src/cube.h b/source/src/cube.h index fd288256..b0f21110 100644 --- a/source/src/cube.h +++ b/source/src/cube.h @@ -38,6 +38,8 @@ extern int curtime; // current frame time extern int gamemode, nextmode; extern int gamespeed; extern int xtraverts; +extern float fovy, aspect; +extern int farplane; extern bool minimap, reflecting, refracting; extern int stenciling, stencilshadow; extern bool intermission; diff --git a/source/src/protos.h b/source/src/protos.h index 916910f2..a7e6e74a 100644 --- a/source/src/protos.h +++ b/source/src/protos.h @@ -221,7 +221,10 @@ extern void renderaboveheadicon(playerent *p); extern void drawcrosshair(playerent *p, bool showteamwarning); extern void drawscope(); extern float dynfov(); -extern bool addshadowbox(const vec &bbmin, const vec &bbmax, const glmatrixf &mat); + +// shadow +extern bool addshadowbox(const vec &bbmin, const vec &bbmax, const vec &extrude, const glmatrixf &mat); +extern void drawstencilshadows(); // texture struct Texture diff --git a/source/src/rendergl.cpp b/source/src/rendergl.cpp index d3ae1fa6..5bff2424 100644 --- a/source/src/rendergl.cpp +++ b/source/src/rendergl.cpp @@ -830,267 +830,6 @@ void readdepth(int w, int h, vec &pos) pos.z = (float)worldz; } -VARP(stencilshadow, 0, 40, 100); - -int stenciling = 0; - -VAR(shadowcasters, 1, 0, 0); - -#define SHADOWTILES 32 -#define SHADOWTILEMASK (0xFFFFFFFFU>>(32-SHADOWTILES)) -uint shadowtiles[SHADOWTILES+1]; -float shadowx1 = 1, shadowy1 = 1, shadowx2 = -1, shadowy2 = -1; - -bool addshadowtiles(float x1, float y1, float x2, float y2) -{ - if(x1 >= 1 || y1 >= 1 || x2 <= -1 || y2 <= -1) return false; - - shadowcasters++; - - shadowx1 = min(shadowx1, max(x1, -1.0f)); - shadowy1 = min(shadowy1, max(y1, -1.0f)); - shadowx2 = max(shadowx2, min(x2, 1.0f)); - shadowy2 = max(shadowy2, min(y2, 1.0f)); - - int tx1 = clamp(int((x1 + 1)/2 * SHADOWTILES), 0, SHADOWTILES - 1), - ty1 = clamp(int((y1 + 1)/2 * SHADOWTILES), 0, SHADOWTILES - 1), - tx2 = clamp(int((x2 + 1)/2 * SHADOWTILES), 0, SHADOWTILES - 1), - ty2 = clamp(int((y2 + 1)/2 * SHADOWTILES), 0, SHADOWTILES - 1); - - uint mask = (SHADOWTILEMASK>>(SHADOWTILES - (tx2+1))) & (SHADOWTILEMASK<= 0) - { - float x = pv.x / pv.w, y = pv.y / pv.w; - sx1 = min(sx1, x); - sy1 = min(sy1, y); - sx2 = max(sx2, x); - sy2 = max(sy2, y); - } - } - if(sx1 >= sx2 || sy1 >= sy2) return false; - loopi(8) - { - const vec4 &p = v[i]; - if(p.z >= 0) continue; - loopj(3) - { - const vec4 &o = v[i^(1<= shadowx2 || shadowy1 >= shadowy2) return; - - float clipx1 = (shadowx1 + 1) / 2, - clipy1 = (shadowy1 + 1) / 2, - clipx2 = (shadowx2 + 1) / 2, - clipy2 = (shadowy2 + 1) / 2; - if(!shadowclip) - { - clipx1 = clipy1 = 0; - clipx2 = clipy2 = 1; - } - - if(!shadowtile) - { - glBegin(GL_QUADS); - glVertex2f(clipx1, clipy2); - glVertex2f(clipx2, clipy2); - glVertex2f(clipx2, clipy1); - glVertex2f(clipx1, clipy1); - glEnd(); - return; - } - - glBegin(GL_QUADS); - float tsz = 1.0f/SHADOWTILES; - loop(y, SHADOWTILES+1) - { - uint mask = shadowtiles[y]; - int x = 0; - while(mask) - { - while(!(mask&0xFF)) { mask >>= 8; x += 8; } - while(!(mask&1)) { mask >>= 1; x++; } - int xstart = x; - do { mask >>= 1; x++; } while(mask&1); - uint strip = (SHADOWTILEMASK>>(SHADOWTILES - x)) & (SHADOWTILEMASK<>(32-SHADOWTILES)) +uint shadowtiles[SHADOWTILES+1]; +float shadowx1 = 1, shadowy1 = 1, shadowx2 = -1, shadowy2 = -1; + +static void extrudeshadowtiles(int x1, int y1, int x2, int y2, int x3, int y3) +{ + if(y1 > y2) { swap(x1, x2); swap(y1, y2); } + if(y2 > y3) { swap(x2, x3); swap(y2, y3); } + if(y1 > y2) { swap(x1, x2); swap(y1, y2); } + + if(y3 < 0 || y1 >= SHADOWTILES) return; + + int lx = x1, rx = x1, + fracl = 0, fracr = 0, + dlx, dly, drx, dry; + if(x2 <= x3) { dlx = x2; dly = y2; drx = x3; dry = y3; } + else { dlx = x3; dly = y3; drx = x2; dry = y2; } + dlx -= x1; dly -= y1; + drx -= x1; dry -= y1; + int ldir = 1, rdir = 1; + if(dlx < 0) + { + ldir = -1; + dlx = -dlx; + } + if(drx < 0) + { + rdir = -1; + drx = -drx; + } + + int cy = y1; + y2 = min(y2, SHADOWTILES); + if(cy < 0 && y2 > cy) + { + int dy = min(y2, 0) - cy; + cy += dy; + fracl += dy*dlx; + lx += ldir*(fracl/dly); + fracl %= dly; + fracr += dy*drx; + rx += rdir*(fracr/dry); + fracr %= dry; + } + + for(; cy < y2; cy++) + { + if(lx < SHADOWTILES && rx >= 0) shadowtiles[cy] |= (SHADOWTILEMASK>>(SHADOWTILES - (min(rx, SHADOWTILES-1)+1))) & (SHADOWTILEMASK<= dly) { lx += ldir; fracl -= dly; } + fracr += drx; + while(fracr >= dry) { rx += rdir; fracr -= dry; } + } + + if(cy >= SHADOWTILES) return; + + if(x2 < x3 || y1 == cy) + { + if(x2 < lx) lx = x2; + dlx = x3 - lx; dly = y3 - cy; + ldir = 1; + if(dlx < 0) + { + ldir = -1; + dlx = -dlx; + } + fracl = 0; + } + if(x2 > x3 || y1 == cy) + { + if(x2 > rx) rx = x2; + drx = x3 - rx; dry = y3 - cy; + rdir = 1; + if(drx < 0) + { + rdir = -1; + drx = -drx; + } + fracr = 0; + } + + y3 = min(y3, SHADOWTILES); + if(cy < 0 && y3 > cy) + { + int dy = min(y3, 0) - cy; + cy += dy; + fracl += dy*dlx; + lx += ldir*(fracl/dly); + fracl %= dly; + fracr += dy*drx; + rx += rdir*(fracr/dry); + fracr %= dry; + } + + for(; cy < y3; cy++) + { + if(lx < SHADOWTILES && rx >= 0) shadowtiles[cy] |= (SHADOWTILEMASK>>(SHADOWTILES - (min(rx, SHADOWTILES-1)+1))) & (SHADOWTILEMASK<= dly) { lx += ldir; fracl -= dly; } + fracr += drx; + while(fracr >= dry) { rx += rdir; fracr -= dry; } + } + + if(cy < SHADOWTILES && lx < SHADOWTILES && rx >= 0) shadowtiles[cy] |= (SHADOWTILEMASK>>(SHADOWTILES - (min(rx, SHADOWTILES-1)+1))) & (SHADOWTILEMASK<>(SHADOWTILES - (tx2+1))) & (SHADOWTILEMASK<= 0) + { + float x = p.x / p.w, y = p.y / p.w; + sx1 = min(sx1, x); + sy1 = min(sy1, y); + sx2 = max(sx2, x); + sy2 = max(sy2, y); + front++; + } + } + vec4 ev; + mat.transform(extrude, ev); + if(ev.z < 0 && !front) return false; + if(front < 8 || ev.z < 0) loopi(8) + { + const vec4 &p = v[i]; + if(p.z >= 0) + { + if(ev.z >= 0) continue; + float t = ev.z/(ev.z - p.z), + w = ev.w + t*(p.w - ev.w), + x = (ev.x + t*(p.x - ev.x))/w, + y = (ev.y + t*(p.y - ev.y))/w; + sx1 = min(sx1, x); + sy1 = min(sy1, y); + sx2 = max(sx2, x); + sy2 = max(sy2, y); + continue; + } + loopj(3) + { + const vec4 &o = v[i^(1<= 0) + { + float x = ev.x / ev.w, y = ev.y / ev.w, + tx1, ty1, tx2, ty2; + if((sx1 >= 1 && x >= 1) || (sy1 >= 1 && y >= 1) || (sx2 <= -1 && x <= -1) || (sy2 <= -1 && y <= -1)) return false; + if(x < sx1) + { + if(y < sy1) { tx1 = sx1; ty1 = sy2; tx2 = sx2; ty2 = sy1; } + else if(y > sy2) { tx1 = sx1; ty1 = sy1; tx2 = sx2; ty2 = sy2; } + else { tx1 = sx1; ty1 = sy1; tx2 = sx1; ty2 = sy2; } + } + else if(x <= sx2) + { + if(y < sy1) { tx1 = sx1; ty1 = sy1; tx2 = sx2; ty2 = sy1; } + else if(y > sy2) { tx1 = sx1; ty1 = sy2; tx2 = sx2; ty2 = sy2; } + else goto noextrusion; + } + else + { + if(y < sy1) { tx1 = sx1; ty1 = sy1; tx2 = sx2; ty2 = sy2; } + else if(y > sy2) { tx1 = sx2; ty1 = sy1; tx2 = sx1; ty2 = sy2; } + else { tx1 = sx2; ty1 = sy1; tx2 = sx2; ty2 = sy2; } + } + extrudeshadowtiles(int(floor(SHADOWTILES * (x + 1) / 2)), int(floor(SHADOWTILES * (y + 1) / 2)), + int(floor(SHADOWTILES * (tx1 + 1) / 2)), int(floor(SHADOWTILES * (ty1 + 1) / 2)), + int(floor(SHADOWTILES * (tx2 + 1) / 2)), int(floor(SHADOWTILES * (ty2 + 1) / 2))); + shadowx1 = min(x, shadowx1); + shadowy1 = min(y, shadowy1); + shadowx2 = max(x, shadowx2); + shadowy2 = max(y, shadowy2); + noextrusion:; + } + else if(sx1 >= 1 || sy1 >= 1 || sx2 <= -1 || sy2 <= -1) return false; + shadowcasters++; + addshadowtiles(sx1, sy1, sx2, sy2); + return true; +} + +void rendershadowtiles() +{ + shadowx1 = clamp(shadowx1, -1.0f, 1.0f); + shadowy1 = clamp(shadowy1, -1.0f, 1.0f); + shadowx2 = clamp(shadowx2, -1.0f, 1.0f); + shadowy2 = clamp(shadowy2, -1.0f, 1.0f); + + if(shadowx1 >= shadowx2 || shadowy1 >= shadowy2) return; + + float clipx1 = (shadowx1 + 1) / 2, + clipy1 = (shadowy1 + 1) / 2, + clipx2 = (shadowx2 + 1) / 2, + clipy2 = (shadowy2 + 1) / 2; + if(!shadowclip) + { + clipx1 = clipy1 = 0; + clipx2 = clipy2 = 1; + } + + if(!shadowtile) + { + glBegin(GL_QUADS); + glVertex2f(clipx1, clipy2); + glVertex2f(clipx2, clipy2); + glVertex2f(clipx2, clipy1); + glVertex2f(clipx1, clipy1); + xtraverts += 4; + glEnd(); + return; + } + + glBegin(GL_QUADS); + float tsz = 1.0f/SHADOWTILES; + loop(y, SHADOWTILES+1) + { + uint mask = shadowtiles[y]; + int x = 0; + while(mask) + { + while(!(mask&0xFF)) { mask >>= 8; x += 8; } + while(!(mask&1)) { mask >>= 1; x++; } + int xstart = x; + do { mask >>= 1; x++; } while(mask&1); + uint strip = (SHADOWTILEMASK>>(SHADOWTILES - x)) & (SHADOWTILEMASK<