5 mempool_t *r_shadow_mempool;
9 int maxtrianglefacinglight;
10 qbyte *trianglefacinglight;
12 rtexturepool_t *r_shadow_texturepool;
13 rtexture_t *r_shadow_attenuationtexture;
15 cvar_t r_shadow1 = {0, "r_shadow1", "16"};
16 cvar_t r_shadow2 = {0, "r_shadow2", "2"};
17 cvar_t r_shadow3 = {0, "r_shadow3", "65536"};
18 cvar_t r_shadow4 = {0, "r_shadow4", "1"};
19 cvar_t r_shadow5 = {0, "r_shadow5", "0.05"};
20 cvar_t r_shadow6 = {0, "r_shadow6", "1"};
22 void r_shadow_start(void)
24 // allocate vertex processing arrays
25 r_shadow_mempool = Mem_AllocPool("R_Shadow");
26 maxshadowelements = 0;
27 shadowelements = NULL;
28 maxtrianglefacinglight = 0;
29 trianglefacinglight = NULL;
30 r_shadow_attenuationtexture = NULL;
31 r_shadow_texturepool = NULL;
34 void r_shadow_shutdown(void)
36 r_shadow_attenuationtexture = NULL;
37 R_FreeTexturePool(&r_shadow_texturepool);
38 maxshadowelements = 0;
39 shadowelements = NULL;
40 maxtrianglefacinglight = 0;
41 trianglefacinglight = NULL;
42 Mem_FreePool(&r_shadow_mempool);
45 void r_shadow_newmap(void)
49 void R_Shadow_Init(void)
51 Cvar_RegisterVariable(&r_shadow1);
52 Cvar_RegisterVariable(&r_shadow2);
53 Cvar_RegisterVariable(&r_shadow3);
54 Cvar_RegisterVariable(&r_shadow4);
55 Cvar_RegisterVariable(&r_shadow5);
56 Cvar_RegisterVariable(&r_shadow6);
57 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
60 void R_Shadow_Volume(int numverts, int numtris, float *vertex, int *elements, int *neighbors, vec3_t relativelightorigin, float lightradius, float projectdistance, int visiblevolume)
62 int i, *e, *n, *out, tris;
63 float *v0, *v1, *v2, temp[3], f;
64 if (projectdistance < 0.1)
66 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
72 // a triangle facing the light source
75 // a triangle not facing the light source
78 // an extrusion of the backfaces, beginning at the original geometry and
79 // ending further from the light source than the original geometry
80 // (presumably at least as far as the light's radius, if the light has a
81 // radius at all), capped at both front and back to avoid any problems
84 // draws the shadow volumes of the model.
86 // vertex loations must already be in vertex before use.
87 // vertex must have capacity for numverts * 2.
89 // make sure trianglefacinglight is big enough for this volume
90 if (maxtrianglefacinglight < numtris)
92 maxtrianglefacinglight = numtris;
93 if (trianglefacinglight)
94 Mem_Free(trianglefacinglight);
95 trianglefacinglight = Mem_Alloc(r_shadow_mempool, maxtrianglefacinglight);
98 // make sure shadowelements is big enough for this volume
99 if (maxshadowelements < numtris * 24)
101 maxshadowelements = numtris * 24;
103 Mem_Free(shadowelements);
104 shadowelements = Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int));
107 // make projected vertices
108 // by clever use of elements we'll construct the whole shadow from
109 // the unprojected vertices and these projected vertices
110 for (i = 0, v0 = vertex, v1 = vertex + numverts * 4;i < numverts;i++, v0 += 4, v1 += 4)
112 VectorSubtract(v0, relativelightorigin, temp);
114 f = lightradius / sqrt(DotProduct(temp,temp));
117 VectorMA(relativelightorigin, f, temp, v1);
119 f = projectdistance / sqrt(DotProduct(temp,temp));
120 VectorMA(v0, f, temp, v1);
124 // check which triangles are facing the light
125 for (i = 0, e = elements;i < numtris;i++, e += 3)
127 // calculate triangle facing flag
128 v0 = vertex + e[0] * 4;
129 v1 = vertex + e[1] * 4;
130 v2 = vertex + e[2] * 4;
131 // we do not need to normalize the surface normal because both sides
132 // of the comparison use it, therefore they are both multiplied the
133 // same amount... furthermore the subtract can be done on the
134 // vectors, saving a little bit of math in the dotproducts
137 // subtracts v1 from v0 and v2, combined into a crossproduct,
138 // combined with a dotproduct of the light location relative to the
139 // first point of the triangle (any point works, since the triangle
140 // is obviously flat), and finally a comparison to determine if the
141 // light is infront of the triangle (the goal of this statement)
142 trianglefacinglight[i] =
143 (relativelightorigin[0] - v0[0]) * ((v0[1] - v1[1]) * (v2[2] - v1[2]) - (v0[2] - v1[2]) * (v2[1] - v1[1]))
144 + (relativelightorigin[1] - v0[1]) * ((v0[2] - v1[2]) * (v2[0] - v1[0]) - (v0[0] - v1[0]) * (v2[2] - v1[2]))
145 + (relativelightorigin[2] - v0[2]) * ((v0[0] - v1[0]) * (v2[1] - v1[1]) - (v0[1] - v1[1]) * (v2[0] - v1[0])) > 0;
149 float dir0[3], dir1[3];
151 // calculate two mostly perpendicular edge directions
152 VectorSubtract(v0, v1, dir0);
153 VectorSubtract(v2, v1, dir1);
155 // we have two edge directions, we can calculate a third vector from
156 // them, which is the direction of the surface normal (it's magnitude
158 CrossProduct(dir0, dir1, temp);
160 // this is entirely unnecessary, but kept for clarity
161 //VectorNormalize(temp);
163 // compare distance of light along normal, with distance of any point
164 // of the triangle along the same normal (the triangle is planar,
165 // I.E. flat, so all points give the same answer)
166 // the normal is not normalized because it is used on both sides of
167 // the comparison, so it's magnitude does not matter
168 trianglefacinglight[i] = DotProduct(relativelightorigin, temp) >= DotProduct(v0, temp);
172 // output triangle elements
173 out = shadowelements;
176 // check each backface for bordering frontfaces,
177 // and cast shadow polygons from those edges,
178 // also create front and back caps for shadow volume
179 for (i = 0, e = elements, n = neighbors;i < numtris;i++, e += 3, n += 3)
181 if (!trianglefacinglight[i])
183 // triangle is backface and therefore casts shadow,
184 // output front and back caps for shadow volume
186 // front cap (with flipped winding order)
191 out[3] = e[0] + numverts;
192 out[4] = e[1] + numverts;
193 out[5] = e[2] + numverts;
198 out[0] = e[0] + numverts;
199 out[1] = e[1] + numverts;
200 out[2] = e[2] + numverts;
205 if (n[0] < 0 || trianglefacinglight[n[0]])
209 out[2] = e[1] + numverts;
211 out[4] = e[1] + numverts;
212 out[5] = e[0] + numverts;
216 if (n[1] < 0 || trianglefacinglight[n[1]])
220 out[2] = e[2] + numverts;
222 out[4] = e[2] + numverts;
223 out[5] = e[1] + numverts;
227 if (n[2] < 0 || trianglefacinglight[n[2]])
231 out[2] = e[0] + numverts;
233 out[4] = e[0] + numverts;
234 out[5] = e[2] + numverts;
240 R_Shadow_RenderVolume(numverts * 2, tris, shadowelements, visiblevolume);
243 void R_Shadow_RenderVolume(int numverts, int numtris, int *elements, int visiblevolume)
248 qglDisable(GL_CULL_FACE);
249 R_Mesh_Draw(numverts, numtris, elements);
250 qglEnable(GL_CULL_FACE);
254 // increment stencil if backface is behind depthbuffer
255 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
256 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
257 R_Mesh_Draw(numverts, numtris, elements);
258 // decrement stencil if frontface is behind depthbuffer
259 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
260 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
261 R_Mesh_Draw(numverts, numtris, elements);
265 float r_shadow_atten1, r_shadow_atten2, r_shadow_atten5;
266 static void R_Shadow_MakeTextures(void)
270 qbyte data[32][32][32][4];
271 R_FreeTexturePool(&r_shadow_texturepool);
272 r_shadow_texturepool = R_AllocTexturePool();
273 r_shadow_atten1 = r_shadow1.value;
274 r_shadow_atten2 = r_shadow2.value;
275 r_shadow_atten5 = r_shadow5.value;
276 for (z = 0;z < 32;z++)
278 for (y = 0;y < 32;y++)
280 for (x = 0;x < 32;x++)
282 v[0] = (x / 32.0f) - 0.5f;
283 v[1] = (y / 32.0f) - 0.5f;
284 v[2] = (z / 32.0f) - 0.5f;
285 d = (int) (((r_shadow_atten1 / (DotProduct(v, v)+r_shadow_atten5)) - (r_shadow_atten1 * r_shadow_atten2)));
286 d = bound(0, d, 255);
287 data[z][y][x][0] = data[z][y][x][1] = data[z][y][x][2] = data[z][y][x][3] = d;
291 r_shadow_attenuationtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation", 32, 32, 32, &data[0][0][0][0], TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_ALPHA);
292 qglTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP);
293 qglTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP);
294 qglTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP);
297 void R_Shadow_Stage_Depth(void)
301 //cl.worldmodel->numlights = min(cl.worldmodel->numlights, 1);
302 if (!r_shadow_attenuationtexture || r_shadow1.value != r_shadow_atten1 || r_shadow2.value != r_shadow_atten2 || r_shadow5.value != r_shadow_atten5)
303 R_Shadow_MakeTextures();
305 memset(&m, 0, sizeof(m));
306 m.blendfunc1 = GL_ONE;
307 m.blendfunc2 = GL_ZERO;
309 GL_Color(0, 0, 0, 1);
312 void R_Shadow_Stage_ShadowVolumes(void)
315 memset(&m, 0, sizeof(m));
316 R_Mesh_TextureState(&m);
317 GL_Color(1, 1, 1, 1);
318 qglColorMask(0, 0, 0, 0);
319 qglDisable(GL_BLEND);
321 qglDepthFunc(GL_LEQUAL);
323 qglClear(GL_STENCIL_BUFFER_BIT);
324 qglEnable(GL_STENCIL_TEST);
325 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
326 qglStencilFunc(GL_ALWAYS, 0, 0xFF);
329 void R_Shadow_Stage_Light(void)
332 memset(&m, 0, sizeof(m));
333 if (r_shadow6.integer)
334 m.tex3d[0] = R_GetTexture(r_shadow_attenuationtexture);
335 R_Mesh_TextureState(&m);
337 qglBlendFunc(GL_ONE, GL_ONE);
338 GL_Color(1, 1, 1, 1);
339 qglColorMask(1, 1, 1, 1);
341 qglDepthFunc(GL_EQUAL);
342 qglEnable(GL_STENCIL_TEST);
343 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
344 // only draw light where this geometry was already rendered AND the
345 // stencil is 0 (non-zero means shadow)
346 qglStencilFunc(GL_EQUAL, 0, 0xFF);
349 void R_Shadow_Stage_Textures(void)
352 // attempt to restore state to what Mesh_State thinks it is
353 qglDisable(GL_BLEND);
354 qglBlendFunc(GL_ONE, GL_ZERO);
357 // now change to a more useful state
358 memset(&m, 0, sizeof(m));
359 m.blendfunc1 = GL_DST_COLOR;
360 m.blendfunc2 = GL_SRC_COLOR;
363 // now hack some more
364 GL_Color(1, 1, 1, 1);
365 qglColorMask(1, 1, 1, 1);
366 qglDepthFunc(GL_EQUAL);
367 qglEnable(GL_STENCIL_TEST);
368 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
369 // only draw in lit areas
370 qglStencilFunc(GL_EQUAL, 0, 0xFF);
373 void R_Shadow_Stage_End(void)
376 GL_Color(1, 1, 1, 1);
377 qglColorMask(1, 1, 1, 1);
378 qglDepthFunc(GL_LEQUAL);
379 qglDisable(GL_STENCIL_TEST);
380 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
381 qglStencilFunc(GL_ALWAYS, 0, 0xFF);
383 // now change to a more useful state
384 memset(&m, 0, sizeof(m));
385 m.blendfunc1 = GL_ONE;
386 m.blendfunc2 = GL_ZERO;
390 void R_Shadow_Light(int numverts, float *normals, vec3_t relativelightorigin, float lightradius, float lightdistbias, float lightsubtract, float *lightcolor)
392 if (!r_shadow6.integer)
395 float *n, *v, *c, f, dist, temp[3], light[3], lightradius2;
396 VectorCopy(lightcolor, light);
397 lightradius2 = lightradius * lightradius;
398 for (i = 0, v = varray_vertex, c = varray_color, n = normals;i < numverts;i++, v += 4, c += 4, n += 3)
400 VectorSubtract(relativelightorigin, v, temp);
405 f = DotProduct(n, temp);
408 dist = DotProduct(temp, temp);
409 if (dist < lightradius2)
411 f = ((1.0f / (dist + lightdistbias)) - lightsubtract) * (f / sqrt(dist));
422 float *n, *v, *c, *t, f, temp[3], light[3], iradius, attentexbase[3];
423 VectorScale(lightcolor, (1.0f / r_shadow3.value), light);
424 iradius = 0.5f / lightradius;
425 attentexbase[0] = 0.5f;
426 attentexbase[1] = 0.5f;
427 attentexbase[2] = 0.5f;
428 for (i = 0, v = varray_vertex, c = varray_color, n = normals, t = varray_texcoord[0];i < numverts;i++, v += 4, c += 4, n += 3, t += 4)
430 VectorSubtract(v, relativelightorigin, temp);
431 VectorMA(attentexbase, iradius, temp, t);
436 f = DotProduct(n, temp);
439 f /= -sqrt(DotProduct(temp, temp));