1
// shadow.cpp: stencil shadow rendering
6
VARP(stencilshadow, 0, 40, 100);
10
VAR(shadowclip, 0, 1, 1);
11
VAR(shadowtile, 0, 1, 1);
12
VAR(dbgtiles, 0, 0, 1);
13
VAR(shadowcasters, 1, 0, 0);
16
#define SHADOWCOLUMNS 32
17
#define SHADOWCOLUMNMASK (0xFFFFFFFFU>>(32-SHADOWCOLUMNS))
18
uint shadowtiles[SHADOWROWS+1];
19
float shadowx1 = 1, shadowy1 = 1, shadowx2 = -1, shadowy2 = -1;
21
static void extrudeshadowtiles(int x1, int y1, int x2, int y2, int x3, int y3)
23
if(y1 > y2) { swap(x1, x2); swap(y1, y2); }
24
if(y2 > y3) { swap(x2, x3); swap(y2, y3); }
25
if(y1 > y2) { swap(x1, x2); swap(y1, y2); }
27
if(y3 < 0 || y1 >= SHADOWROWS) return;
32
if(x2 <= x3) { dlx = x2; dly = y2; drx = x3; dry = y3; }
33
else { dlx = x3; dly = y3; drx = x2; dry = y2; }
36
int ldir = 1, rdir = 1;
49
y2 = min(y2, SHADOWROWS);
52
int dy = min(y2, 0) - cy;
55
lx += ldir*(fracl/dly);
58
rx += rdir*(fracr/dry);
64
int cx1 = lx, cx2 = rx;
66
while(fracl >= dly) { lx += ldir; if(ldir < 0) cx1 = lx; fracl -= dly; }
68
while(fracr >= dry) { rx += rdir; if(rdir > 0) cx2 = rx; fracr -= dry; }
69
if(cx1 < SHADOWCOLUMNS && cx2 >= 0) shadowtiles[cy] |= (SHADOWCOLUMNMASK>>(SHADOWCOLUMNS - (min(cx2, SHADOWCOLUMNS-1)+1))) & (SHADOWCOLUMNMASK<<max(cx1, 0));
72
if(cy >= SHADOWROWS) return;
74
if(x2 < x3 || y1 == cy)
77
dlx = x3 - lx; dly = y3 - cy;
86
if(x2 > x3 || y1 == cy)
89
drx = x3 - rx; dry = y3 - cy;
99
y3 = min(y3, SHADOWROWS);
100
if(cy < 0 && y3 > cy)
102
int dy = min(y3, 0) - cy;
105
lx += ldir*(fracl/dly);
108
rx += rdir*(fracr/dry);
114
int cx1 = lx, cx2 = rx;
116
while(fracl >= dly) { lx += ldir; if(ldir < 0) cx1 = lx; fracl -= dly; }
118
while(fracr >= dry) { rx += rdir; if(rdir > 0) cx2 = rx; fracr -= dry; }
119
if(cx1 < SHADOWCOLUMNS && cx2 >= 0) shadowtiles[cy] |= (SHADOWCOLUMNMASK>>(SHADOWCOLUMNS - (min(cx2, SHADOWCOLUMNS-1)+1))) & (SHADOWCOLUMNMASK<<max(cx1, 0));
124
int cx1 = lx, cx2 = rx;
128
while(fracl >= dly) { lx += ldir; if(ldir < 0) cx1 = lx; fracl -= dly; }
133
while(fracr >= dry) { rx += rdir; if(rdir > 0) cx2 = rx; fracr -= dry; }
135
if(cx1 < SHADOWCOLUMNS && cx2 >= 0) shadowtiles[cy] |= (SHADOWCOLUMNMASK>>(SHADOWCOLUMNS - (min(cx2, SHADOWCOLUMNS-1)+1))) & (SHADOWCOLUMNMASK<<max(cx1, 0));
139
static void addshadowtiles(float x1, float y1, float x2, float y2)
141
shadowx1 = min(shadowx1, x1);
142
shadowy1 = min(shadowy1, y1);
143
shadowx2 = max(shadowx2, x2);
144
shadowy2 = max(shadowy2, y2);
146
int tx1 = clamp(int(floor((y1 + 1)/2 * SHADOWCOLUMNS)), 0, SHADOWCOLUMNS - 1),
147
ty1 = clamp(int(floor((x1 + 1)/2 * SHADOWROWS)), 0, SHADOWROWS - 1),
148
tx2 = clamp(int(floor((y2 + 1)/2 * SHADOWCOLUMNS)), 0, SHADOWCOLUMNS - 1),
149
ty2 = clamp(int(floor((x2 + 1)/2 * SHADOWROWS)), 0, SHADOWROWS - 1);
151
uint mask = (SHADOWCOLUMNMASK>>(SHADOWCOLUMNS - (tx2+1))) & (SHADOWCOLUMNMASK<<tx1);
152
for(int y = ty1; y <= ty2; y++) shadowtiles[y] |= mask;
155
bool addshadowbox(const vec &bbmin, const vec &bbmax, const vec &extrude, const glmatrixf &mat)
158
float sx1 = 1e16f, sy1 = 1e16f, sx2 = -1e16f, sy2 = -1e16f;
163
mat.transform(vec(i&1 ? bbmax.x : bbmin.x, i&2 ? bbmax.y : bbmin.y, i&4 ? bbmax.z : bbmin.z), p);
166
float x = p.x / p.w, y = p.y / p.w;
175
mat.transform(extrude, ev);
176
if(ev.z < 0 && !front) return false;
177
if(front < 8 || ev.z < 0) loopi(8)
179
const vec4 &p = v[i];
182
if(ev.z >= 0) continue;
183
float t = ev.z/(ev.z - p.z),
184
w = ev.w + t*(p.w - ev.w),
185
x = (ev.x + t*(p.x - ev.x))/w,
186
y = (ev.y + t*(p.y - ev.y))/w;
195
const vec4 &o = v[i^(1<<j)];
196
if(o.z < 0) continue;
197
float t = p.z/(p.z - o.z),
198
w = p.w + t*(o.w - p.w),
199
x = (p.x + t*(o.x - p.x))/w,
200
y = (p.y + t*(o.y - p.y))/w;
206
if(ev.z < 0) continue;
207
float t = p.z/(p.z - ev.z),
208
w = p.w + t*(ev.w - p.w),
209
x = (p.x + t*(ev.x - p.x))/w,
210
y = (p.y + t*(ev.y - p.y))/w;
218
float x = ev.x/ev.w, y = ev.y/ev.w;
219
if((sx1 >= 1 && x >= 1) || (sy1 >= 1 && y >= 1) || (sx2 <= -1 && x <= -1) || (sy2 <= -1 && y <= -1)) return false;
220
int tx = int(floor(SHADOWCOLUMNS * (y + 1) / 2)), ty = int(floor(SHADOWROWS * (x + 1) / 2)),
221
tx1 = int(floor(SHADOWCOLUMNS * (sy1 + 1) / 2)), ty1 = int(floor(SHADOWROWS * (sx1 + 1) / 2)),
222
tx2 = int(floor(SHADOWCOLUMNS * (sy2 + 1) / 2)), ty2 = int(floor(SHADOWROWS * (sx2 + 1) / 2));
225
if(ty < ty1) { swap(ty1, ty2); tx1--; ty1--; }
226
else if(ty > ty2) { tx1--; ty1++; }
227
else { tx2 = tx1; tx1--; tx2--; }
231
if(ty < ty1) { ty1--; tx2++; }
232
else if(ty > ty2) { swap(ty1, ty2); ty1++; tx2++; }
233
else { tx1 = tx2; tx1++; tx2++; }
237
if(ty < ty1) { ty2 = ty1; ty1--; ty2--; }
238
else if(ty > ty2) { ty1 = ty2; ty1++; ty2++; }
239
else goto noextrusion;
241
extrudeshadowtiles(tx, ty, tx1, ty1, tx2, ty2);
242
shadowx1 = min(x, shadowx1);
243
shadowy1 = min(y, shadowy1);
244
shadowx2 = max(x, shadowx2);
245
shadowy2 = max(y, shadowy2);
248
else if(sx1 >= 1 || sy1 >= 1 || sx2 <= -1 || sy2 <= -1) return false;
250
addshadowtiles(sx1, sy1, sx2, sy2);
254
static void rendershadowtiles()
256
shadowx1 = clamp(shadowx1, -1.0f, 1.0f);
257
shadowy1 = clamp(shadowy1, -1.0f, 1.0f);
258
shadowx2 = clamp(shadowx2, -1.0f, 1.0f);
259
shadowy2 = clamp(shadowy2, -1.0f, 1.0f);
261
if(shadowx1 >= shadowx2 || shadowy1 >= shadowy2) return;
263
float clipx1 = (shadowy1 + 1) / 2,
264
clipy1 = (shadowx1 + 1) / 2,
265
clipx2 = (shadowy2 + 1) / 2,
266
clipy2 = (shadowx2 + 1) / 2;
276
glVertex2f(clipy1, clipx1);
277
glVertex2f(clipy1, clipx2);
278
glVertex2f(clipy2, clipx2);
279
glVertex2f(clipy2, clipx1);
286
float tw = 1.0f/SHADOWCOLUMNS, th = 1.0f/SHADOWROWS;
287
loop(y, SHADOWROWS+1)
289
uint mask = shadowtiles[y];
293
while(!(mask&0xFF)) { mask >>= 8; x += 8; }
294
while(!(mask&1)) { mask >>= 1; x++; }
296
do { mask >>= 1; x++; } while(mask&1);
297
uint strip = (SHADOWCOLUMNMASK>>(SHADOWCOLUMNS - x)) & (SHADOWCOLUMNMASK<<xstart);
299
do { shadowtiles[yend] &= ~strip; yend++; } while((shadowtiles[yend] & strip) == strip);
300
float vx = xstart*tw,
304
vx1 = max(vx, clipx1),
305
vy1 = max(vy, clipy1),
306
vx2 = min(vx+vw, clipx2),
307
vy2 = min(vy+vh, clipy2);
308
glVertex2f(vy1, vx1);
309
glVertex2f(vy1, vx2);
310
glVertex2f(vy2, vx2);
311
glVertex2f(vy2, vx1);
318
void drawstencilshadows()
321
glEnable(GL_STENCIL_TEST);
322
glDisable(GL_TEXTURE_2D);
324
glDepthMask(GL_FALSE);
325
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
330
shadowx2 = shadowy2 = -1;
331
shadowx1 = shadowy1 = 1;
332
memset(shadowtiles, 0, sizeof(shadowtiles));
336
glDisable(GL_CULL_FACE);
340
glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
342
glActiveStencilFace_(GL_BACK);
343
glStencilFunc(GL_ALWAYS, 0, ~0U);
344
glStencilOp(GL_KEEP, GL_KEEP, hasSTW ? GL_INCR_WRAP_EXT : GL_INCR);
346
glActiveStencilFace_(GL_FRONT);
347
glStencilFunc(GL_ALWAYS, 0, ~0U);
348
glStencilOp(GL_KEEP, GL_KEEP, hasSTW ? GL_DECR_WRAP_EXT : GL_DECR);
352
glStencilFuncSeparate_(GL_ALWAYS, GL_ALWAYS, 0, ~0U);
353
glStencilOpSeparate_(GL_BACK, GL_KEEP, GL_KEEP, hasSTW ? GL_INCR_WRAP_EXT : GL_INCR);
354
glStencilOpSeparate_(GL_FRONT, GL_KEEP, GL_KEEP, hasSTW ? GL_DECR_WRAP_EXT : GL_DECR);
364
if(hasST2) glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
365
glEnable(GL_CULL_FACE);
369
glStencilFunc(GL_ALWAYS, 0, ~0U);
370
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
377
endmodelbatches(false);
383
glStencilFunc(GL_ALWAYS, 0, ~0U);
384
glStencilOp(GL_KEEP, GL_KEEP, GL_DECR);
387
endmodelbatches(true);
389
glCullFace(GL_FRONT);
391
else clearmodelbatches();
396
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
397
glDepthMask(GL_TRUE);
401
glDisable(GL_DEPTH_TEST);
403
glStencilFunc(GL_NOTEQUAL, (hasST2 || hasSTS) && !hasSTW ? 128 : 0, ~0U);
404
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
407
glBlendFunc(GL_ZERO, GL_SRC_COLOR);
409
float intensity = 1.0f - stencilshadow/100.0f;
410
glColor3f(intensity, intensity, intensity);
412
glMatrixMode(GL_PROJECTION);
414
glOrtho(0, 1, 0, 1, -1, 1);
416
glMatrixMode(GL_MODELVIEW);
420
static uint debugtiles[SHADOWROWS+1];
421
if(dbgtiles) memcpy(debugtiles, shadowtiles, sizeof(debugtiles));
427
glDisable(GL_STENCIL_TEST);
428
glColor3f(0.5f, 1, 0.5f);
429
memcpy(shadowtiles, debugtiles, sizeof(debugtiles));
433
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
434
memcpy(shadowtiles, debugtiles, sizeof(debugtiles));
436
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
438
else glDisable(GL_BLEND);
440
glMatrixMode(GL_PROJECTION);
442
setperspective(fovy, aspect, 0.15f, farplane);
444
glMatrixMode(GL_MODELVIEW);
447
glEnable(GL_DEPTH_TEST);
450
// necessary to avoid ATI bug!
451
// punts to software mode if separate stencil op is set, even while stencil disabled, when drawing lines!
452
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
454
glDisable(GL_STENCIL_TEST);
455
glEnable(GL_TEXTURE_2D);