Initial Comit: First commit.
[SauerEngine.git] / src / engine / shadowmap.cpp
blob0b3b7c27424c54fbcced4c20b2114f0ddd1ee759
1 #include "pch.h"
2 #include "engine.h"
3 #include "rendertarget.h"
5 VARP(shadowmap, 0, 0, 1);
7 extern void cleanshadowmap();
8 VARFP(shadowmapsize, 7, 9, 11, cleanshadowmap());
9 VARP(shadowmapradius, 64, 96, 256);
10 VAR(shadowmapheight, 0, 32, 128);
11 VARP(shadowmapdist, 128, 256, 512);
12 VARFP(fpshadowmap, 0, 0, 1, cleanshadowmap());
13 VARFP(shadowmapprecision, 0, 0, 1, cleanshadowmap());
14 VARR(shadowmapambient, 0, 0, 0xFFFFFF);
16 VARP(blurshadowmap, 0, 1, 3);
17 VARP(blursmsigma, 1, 100, 200);
19 #define SHADOWSKEW 0.7071068f
21 vec shadowoffset(0, 0, 0), shadowfocus(0, 0, 0), shadowdir(0, SHADOWSKEW, 1);
22 VAR(shadowmapcasters, 1, 0, 0);
24 void setshadowdir(int angle)
26 shadowdir = vec(0, SHADOWSKEW, 1);
27 shadowdir.rotate_around_z(angle*RAD);
30 VARFR(shadowmapangle, 0, 0, 360, setshadowdir(shadowmapangle));
32 void guessshadowdir()
34 if(shadowmapangle) return;
35 vec lightpos(0, 0, 0), casterpos(0, 0, 0);
36 int numlights = 0, numcasters = 0;
37 const vector<extentity *> &ents = et->getents();
38 loopv(ents)
40 extentity &e = *ents[i];
41 switch(e.type)
43 case ET_LIGHT:
44 if(!e.attr1) { lightpos.add(e.o); numlights++; }
45 break;
47 case ET_MAPMODEL:
48 casterpos.add(e.o);
49 numcasters++;
50 break;
52 default:
53 if(e.type<ET_GAMESPECIFIC) break;
54 casterpos.add(e.o);
55 numcasters++;
56 break;
59 if(!numlights || !numcasters) return;
60 lightpos.div(numlights);
61 casterpos.div(numcasters);
62 vec dir(lightpos);
63 dir.sub(casterpos);
64 dir.z = 0;
65 if(dir.iszero()) return;
66 dir.normalize();
67 dir.mul(SHADOWSKEW);
68 dir.z = 1;
69 shadowdir = dir;
72 bool shadowmapping = false;
74 static GLdouble shadowmapprojection[16], shadowmapmodelview[16];
76 VARP(shadowmapbias, 0, 5, 1024);
77 VARP(shadowmappeelbias, 0, 20, 1024);
78 VAR(smdepthpeel, 0, 1, 1);
79 VAR(smoothshadowmappeel, 1, 0, 0);
81 static struct shadowmaptexture : rendertarget
83 const GLenum *colorformats() const
85 static const GLenum colorfmts[] = { GL_RGBA16F_ARB, GL_RGBA16, GL_RGBA, GL_RGBA8, GL_FALSE };
86 int offset = fpshadowmap && hasTF && hasFBO ? 0 : (shadowmapprecision && hasFBO ? 1 : 2);
87 return &colorfmts[offset];
90 bool swaptexs() const { return true; }
92 bool scissorblur(int &x, int &y, int &w, int &h)
94 x = max(int(floor((scissorx1+1)/2*vieww)) - 2*blursize, 2);
95 y = max(int(floor((scissory1+1)/2*viewh)) - 2*blursize, 2);
96 w = min(int(ceil((scissorx2+1)/2*vieww)) + 2*blursize, vieww-2) - x;
97 h = min(int(ceil((scissory2+1)/2*viewh)) + 2*blursize, viewh-2) - y;
98 return true;
101 bool scissorrender(int &x, int &y, int &w, int &h)
103 x = y = 2;
104 w = vieww - 2*2;
105 h = viewh - 2*2;
106 return true;
109 void doclear()
111 glClearColor(0, 0, 0, 0);
112 glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
115 bool dorender()
117 // nvidia bug, must push modelview here, then switch to projection, then back to modelview before can safely modify it
118 glPushMatrix();
120 glMatrixMode(GL_PROJECTION);
121 glPushMatrix();
122 glLoadIdentity();
123 glOrtho(-shadowmapradius, shadowmapradius, -shadowmapradius, shadowmapradius, -shadowmapdist, shadowmapdist);
125 glMatrixMode(GL_MODELVIEW);
127 vec skewdir(shadowdir);
128 skewdir.neg();
129 skewdir.rotate_around_z(-camera1->yaw*RAD);
131 vec dir;
132 vecfromyawpitch(camera1->yaw, camera1->pitch, 1, 0, dir);
133 dir.z = 0;
134 dir.mul(shadowmapradius);
136 vec dirx, diry;
137 vecfromyawpitch(camera1->yaw, 0, 0, 1, dirx);
138 vecfromyawpitch(camera1->yaw, 0, 1, 0, diry);
139 shadowoffset.x = -fmod(dirx.dot(camera1->o) - skewdir.x*camera1->o.z, 2.0f*shadowmapradius/vieww);
140 shadowoffset.y = -fmod(diry.dot(camera1->o) - skewdir.y*camera1->o.z, 2.0f*shadowmapradius/viewh);
142 GLfloat skew[] =
144 1, 0, 0, 0,
145 0, 1, 0, 0,
146 skewdir.x, skewdir.y, 1, 0,
147 0, 0, 0, 1
149 glLoadMatrixf(skew);
150 glTranslatef(skewdir.x*shadowmapheight + shadowoffset.x, skewdir.y*shadowmapheight + shadowoffset.y + dir.magnitude(), -shadowmapheight);
151 glRotatef(camera1->yaw, 0, 0, -1);
152 glTranslatef(-camera1->o.x, -camera1->o.y, -camera1->o.z);
153 shadowfocus = camera1->o;
154 shadowfocus.add(dir);
155 shadowfocus.add(vec(-shadowdir.x, -shadowdir.y, 1).mul(shadowmapheight));
156 shadowfocus.add(dirx.mul(shadowoffset.x));
157 shadowfocus.add(diry.mul(shadowoffset.y));
159 glGetDoublev(GL_PROJECTION_MATRIX, shadowmapprojection);
160 glGetDoublev(GL_MODELVIEW_MATRIX, shadowmapmodelview);
162 setenvparamf("shadowmapbias", SHPARAM_VERTEX, 0, -shadowmapbias/float(shadowmapdist), 1 - (shadowmapbias + (smoothshadowmappeel ? 0 : shadowmappeelbias))/float(shadowmapdist));
164 shadowmapcasters = 0;
165 shadowmapping = true;
166 rendergame();
167 shadowmapping = false;
169 if(shadowmapcasters && smdepthpeel)
171 int sx, sy, sw, sh;
172 bool scissoring = rtscissor && scissorblur(sx, sy, sw, sh) && sw > 0 && sh > 0;
173 if(scissoring)
175 if(!hasFBO)
177 sx += screen->w-vieww;
178 sy += screen->h-viewh;
180 glScissor(sx, sy, sw, sh);
182 if(!rtscissor || scissoring) rendershadowmapreceivers();
185 glMatrixMode(GL_PROJECTION);
186 glPopMatrix();
188 glMatrixMode(GL_MODELVIEW);
189 glPopMatrix();
191 return shadowmapcasters>0;
194 bool flipdebug() const { return false; }
196 void dodebug(int w, int h)
198 if(shadowmapcasters)
200 glColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_FALSE);
201 debugscissor(w, h);
202 glColorMask(GL_FALSE, GL_FALSE, GL_TRUE, GL_FALSE);
203 debugblurtiles(w, h);
204 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
207 } shadowmaptex;
209 void cleanshadowmap()
211 shadowmaptex.cleanup(true);
214 void calcshadowmapbb(const vec &o, float xyrad, float zrad, float &x1, float &y1, float &x2, float &y2)
216 vec skewdir(shadowdir);
217 skewdir.neg();
218 skewdir.rotate_around_z(-camera1->yaw*RAD);
220 vec ro(o);
221 ro.sub(camera1->o);
222 ro.rotate_around_z(-camera1->yaw*RAD);
223 ro.x += ro.z * skewdir.x + shadowoffset.x;
224 ro.y += ro.z * skewdir.y + shadowmapradius * cosf(camera1->pitch*RAD) + shadowoffset.y;
226 vec high(ro), low(ro);
227 high.x += zrad * skewdir.x;
228 high.y += zrad * skewdir.y;
229 low.x -= zrad * skewdir.x;
230 low.y -= zrad * skewdir.y;
232 x1 = (min(high.x, low.x) - xyrad) / shadowmapradius;
233 y1 = (min(high.y, low.y) - xyrad) / shadowmapradius;
234 x2 = (max(high.x, low.x) + xyrad) / shadowmapradius;
235 y2 = (max(high.y, low.y) + xyrad) / shadowmapradius;
238 bool addshadowmapcaster(const vec &o, float xyrad, float zrad)
240 if(o.z + zrad <= shadowfocus.z - shadowmapdist || o.z - zrad >= shadowfocus.z) return false;
242 float x1, y1, x2, y2;
243 calcshadowmapbb(o, xyrad, zrad, x1, y1, x2, y2);
245 if(!shadowmaptex.addblurtiles(x1, y1, x2, y2, 2)) return false;
247 shadowmapcasters++;
248 return true;
251 bool isshadowmapreceiver(vtxarray *va)
253 if(!shadowmap || renderpath==R_FIXEDFUNCTION || !shadowmapcasters) return false;
255 if(va->shadowmapmax.z <= shadowfocus.z - shadowmapdist || va->shadowmapmin.z >= shadowfocus.z) return false;
257 float xyrad = SQRT2*0.5f*max(va->shadowmapmax.x-va->shadowmapmin.x, va->shadowmapmax.y-va->shadowmapmin.y),
258 zrad = 0.5f*(va->shadowmapmax.z-va->shadowmapmin.z),
259 x1, y1, x2, y2;
260 if(xyrad<0 || zrad<0) return false;
262 vec center(va->shadowmapmin.tovec());
263 center.add(va->shadowmapmax.tovec()).mul(0.5f);
264 calcshadowmapbb(center, xyrad, zrad, x1, y1, x2, y2);
266 return shadowmaptex.checkblurtiles(x1, y1, x2, y2, 2);
268 #if 0
269 // cheaper inexact test
270 float dz = va->o.z + va->size/2 - shadowfocus.z;
271 float cx = shadowfocus.x - dz*shadowdir.x, cy = shadowfocus.y - dz*shadowdir.y;
272 float skew = va->size/2*SHADOWSKEW;
273 if(!shadowmap || !shadowmaptex ||
274 va->o.z + va->size <= shadowfocus.z - shadowmapdist || va->o.z >= shadowfocus.z ||
275 va->o.x + va->size <= cx - shadowmapradius-skew || va->o.x >= cx + shadowmapradius+skew ||
276 va->o.y + va->size <= cy - shadowmapradius-skew || va->o.y >= cy + shadowmapradius+skew)
277 return false;
278 return true;
279 #endif
282 bool isshadowmapcaster(const vec &o, float rad)
284 // cheaper inexact test
285 float dz = o.z - shadowfocus.z;
286 float cx = shadowfocus.x - dz*shadowdir.x, cy = shadowfocus.y - dz*shadowdir.y;
287 float skew = rad*SHADOWSKEW;
288 if(!shadowmapping ||
289 o.z + rad <= shadowfocus.z - shadowmapdist || o.z - rad >= shadowfocus.z ||
290 o.x + rad <= cx - shadowmapradius-skew || o.x - rad >= cx + shadowmapradius+skew ||
291 o.y + rad <= cy - shadowmapradius-skew || o.y - rad >= cy + shadowmapradius+skew)
292 return false;
293 return true;
296 void pushshadowmap()
298 if(!shadowmap || !shadowmaptex.rendertex) return;
300 glActiveTexture_(GL_TEXTURE7_ARB);
301 glEnable(GL_TEXTURE_2D);
302 glBindTexture(GL_TEXTURE_2D, shadowmaptex.rendertex);
304 glActiveTexture_(GL_TEXTURE2_ARB);
305 glEnable(GL_TEXTURE_2D);
306 glMatrixMode(GL_TEXTURE);
307 glLoadIdentity();
308 glTranslatef(0.5f, 0.5f, 1-shadowmapbias/float(shadowmapdist));
309 glScalef(0.5f, 0.5f, -1);
310 glMultMatrixd(shadowmapprojection);
311 glMultMatrixd(shadowmapmodelview);
312 glPushMatrix();
313 glMatrixMode(GL_MODELVIEW);
314 glActiveTexture_(GL_TEXTURE0_ARB);
315 glClientActiveTexture_(GL_TEXTURE0_ARB);
317 float r, g, b;
318 if(!shadowmapambient)
320 if(hdr.skylight[0] || hdr.skylight[1] || hdr.skylight[2])
322 r = max(25.0f, 0.4f*hdr.ambient + 0.6f*max(hdr.ambient, hdr.skylight[0]));
323 g = max(25.0f, 0.4f*hdr.ambient + 0.6f*max(hdr.ambient, hdr.skylight[1]));
324 b = max(25.0f, 0.4f*hdr.ambient + 0.6f*max(hdr.ambient, hdr.skylight[2]));
326 else r = g = b = max(25.0f, 2.0f*hdr.ambient);
328 else if(shadowmapambient<=255) r = g = b = shadowmapambient;
329 else { r = (shadowmapambient>>16)&0xFF; g = (shadowmapambient>>8)&0xFF; b = shadowmapambient&0xFF; }
330 setenvparamf("shadowmapambient", SHPARAM_PIXEL, 7, r/255.0f, g/255.0f, b/255.0f);
333 void adjustshadowmatrix(const ivec &o, float scale)
335 if(!shadowmap || !shadowmaptex.rendertex) return;
337 glActiveTexture_(GL_TEXTURE2_ARB);
338 glMatrixMode(GL_TEXTURE);
339 glPopMatrix();
340 glPushMatrix();
341 glTranslatef(o.x, o.y, o.z);
342 glScalef(scale, scale, scale);
343 glMatrixMode(GL_MODELVIEW);
344 glActiveTexture_(GL_TEXTURE0_ARB);
347 void popshadowmap()
349 if(!shadowmap || !shadowmaptex.rendertex) return;
351 glActiveTexture_(GL_TEXTURE7_ARB);
352 glDisable(GL_TEXTURE_2D);
354 glActiveTexture_(GL_TEXTURE2_ARB);
355 glMatrixMode(GL_TEXTURE);
356 glPopMatrix();
357 glMatrixMode(GL_MODELVIEW);
359 glActiveTexture_(GL_TEXTURE0_ARB);
362 void rendershadowmap()
364 if(!shadowmap || renderpath==R_FIXEDFUNCTION) return;
366 // Apple/ATI bug - fixed-function fog state can force software fallback even when fragment program is enabled
367 glDisable(GL_FOG);
368 shadowmaptex.render(1<<shadowmapsize, 1<<shadowmapsize, blurshadowmap, blursmsigma/100.0f);
369 glEnable(GL_FOG);
372 VAR(debugsm, 0, 0, 1);
374 void viewshadowmap()
376 if(!shadowmap) return;
377 shadowmaptex.debug();