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
));
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();
40 extentity
&e
= *ents
[i
];
44 if(!e
.attr1
) { lightpos
.add(e
.o
); numlights
++; }
53 if(e
.type
<ET_GAMESPECIFIC
) break;
59 if(!numlights
|| !numcasters
) return;
60 lightpos
.div(numlights
);
61 casterpos
.div(numcasters
);
65 if(dir
.iszero()) return;
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
;
101 bool scissorrender(int &x
, int &y
, int &w
, int &h
)
111 glClearColor(0, 0, 0, 0);
112 glClear(GL_DEPTH_BUFFER_BIT
| GL_COLOR_BUFFER_BIT
);
117 // nvidia bug, must push modelview here, then switch to projection, then back to modelview before can safely modify it
120 glMatrixMode(GL_PROJECTION
);
123 glOrtho(-shadowmapradius
, shadowmapradius
, -shadowmapradius
, shadowmapradius
, -shadowmapdist
, shadowmapdist
);
125 glMatrixMode(GL_MODELVIEW
);
127 vec
skewdir(shadowdir
);
129 skewdir
.rotate_around_z(-camera1
->yaw
*RAD
);
132 vecfromyawpitch(camera1
->yaw
, camera1
->pitch
, 1, 0, dir
);
134 dir
.mul(shadowmapradius
);
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
);
146 skewdir
.x
, skewdir
.y
, 1, 0,
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;
167 shadowmapping
= false;
169 if(shadowmapcasters
&& smdepthpeel
)
172 bool scissoring
= rtscissor
&& scissorblur(sx
, sy
, sw
, sh
) && sw
> 0 && sh
> 0;
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
);
188 glMatrixMode(GL_MODELVIEW
);
191 return shadowmapcasters
>0;
194 bool flipdebug() const { return false; }
196 void dodebug(int w
, int h
)
200 glColorMask(GL_TRUE
, GL_FALSE
, GL_FALSE
, GL_FALSE
);
202 glColorMask(GL_FALSE
, GL_FALSE
, GL_TRUE
, GL_FALSE
);
203 debugblurtiles(w
, h
);
204 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
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
);
218 skewdir
.rotate_around_z(-camera1
->yaw
*RAD
);
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;
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
),
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);
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
)
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
;
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
)
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
);
308 glTranslatef(0.5f
, 0.5f
, 1-shadowmapbias
/float(shadowmapdist
));
309 glScalef(0.5f
, 0.5f
, -1);
310 glMultMatrixd(shadowmapprojection
);
311 glMultMatrixd(shadowmapmodelview
);
313 glMatrixMode(GL_MODELVIEW
);
314 glActiveTexture_(GL_TEXTURE0_ARB
);
315 glClientActiveTexture_(GL_TEXTURE0_ARB
);
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
);
341 glTranslatef(o
.x
, o
.y
, o
.z
);
342 glScalef(scale
, scale
, scale
);
343 glMatrixMode(GL_MODELVIEW
);
344 glActiveTexture_(GL_TEXTURE0_ARB
);
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
);
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
368 shadowmaptex
.render(1<<shadowmapsize
, 1<<shadowmapsize
, blurshadowmap
, blursmsigma
/100.0f
);
372 VAR(debugsm
, 0, 0, 1);
376 if(!shadowmap
) return;
377 shadowmaptex
.debug();