4 mempool_t *r_shadow_mempool;
8 int maxtrianglefacinglight;
9 qbyte *trianglefacinglight;
11 void r_shadow_start(void)
13 // allocate vertex processing arrays
14 r_shadow_mempool = Mem_AllocPool("R_Shadow");
15 maxshadowelements = 0;
16 shadowelements = NULL;
17 maxtrianglefacinglight = 0;
18 trianglefacinglight = NULL;
21 void r_shadow_shutdown(void)
23 maxshadowelements = 0;
24 shadowelements = NULL;
25 maxtrianglefacinglight = 0;
26 trianglefacinglight = NULL;
27 Mem_FreePool(&r_shadow_mempool);
30 void r_shadow_newmap(void)
34 void R_Shadow_Init(void)
36 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
39 void R_Shadow_Volume(int numverts, int numtris, float *vertex, int *elements, int *neighbors, vec3_t relativelightorigin, float lightradius, float projectdistance, int visiblevolume)
41 int i, *e, *n, *out, tris;
42 float *v0, *v1, *v2, temp[3], f;
43 if (projectdistance < 0.1)
45 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
51 // a triangle facing the light source
54 // a triangle not facing the light source
57 // an extrusion of the backfaces, beginning at the original geometry and
58 // ending further from the light source than the original geometry
59 // (presumably at least as far as the light's radius, if the light has a
60 // radius at all), capped at both front and back to avoid any problems
63 // draws the shadow volumes of the model.
65 // vertex loations must already be in vertex before use.
66 // vertex must have capacity for numverts * 2.
68 // make sure trianglefacinglight is big enough for this volume
69 if (maxtrianglefacinglight < numtris)
71 maxtrianglefacinglight = numtris;
72 if (trianglefacinglight)
73 Mem_Free(trianglefacinglight);
74 trianglefacinglight = Mem_Alloc(r_shadow_mempool, maxtrianglefacinglight);
77 // make sure shadowelements is big enough for this volume
78 if (maxshadowelements < numtris * 24)
80 maxshadowelements = numtris * 24;
82 Mem_Free(shadowelements);
83 shadowelements = Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int));
86 // make projected vertices
87 // by clever use of elements we'll construct the whole shadow from
88 // the unprojected vertices and these projected vertices
89 for (i = 0, v0 = vertex, v1 = vertex + numverts * 4;i < numverts;i++, v0 += 4, v1 += 4)
91 VectorSubtract(v0, relativelightorigin, temp);
93 f = lightradius / sqrt(DotProduct(temp,temp));
96 VectorMA(relativelightorigin, f, temp, v1);
98 f = projectdistance / sqrt(DotProduct(temp,temp));
99 VectorMA(v0, f, temp, v1);
103 // check which triangles are facing the light
104 for (i = 0, e = elements;i < numtris;i++, e += 3)
106 // calculate triangle facing flag
107 v0 = vertex + e[0] * 4;
108 v1 = vertex + e[1] * 4;
109 v2 = vertex + e[2] * 4;
110 // we do not need to normalize the surface normal because both sides
111 // of the comparison use it, therefore they are both multiplied the
112 // same amount... furthermore the subtract can be done on the
113 // vectors, saving a little bit of math in the dotproducts
116 // subtracts v1 from v0 and v2, combined into a crossproduct,
117 // combined with a dotproduct of the light location relative to the
118 // first point of the triangle (any point works, since the triangle
119 // is obviously flat), and finally a comparison to determine if the
120 // light is infront of the triangle (the goal of this statement)
121 trianglefacinglight[i] =
122 (relativelightorigin[0] - v0[0]) * ((v0[1] - v1[1]) * (v2[2] - v1[2]) - (v0[2] - v1[2]) * (v2[1] - v1[1]))
123 + (relativelightorigin[1] - v0[1]) * ((v0[2] - v1[2]) * (v2[0] - v1[0]) - (v0[0] - v1[0]) * (v2[2] - v1[2]))
124 + (relativelightorigin[2] - v0[2]) * ((v0[0] - v1[0]) * (v2[1] - v1[1]) - (v0[1] - v1[1]) * (v2[0] - v1[0])) > 0;
128 float dir0[3], dir1[3];
130 // calculate two mostly perpendicular edge directions
131 VectorSubtract(v0, v1, dir0);
132 VectorSubtract(v2, v1, dir1);
134 // we have two edge directions, we can calculate a third vector from
135 // them, which is the direction of the surface normal (it's magnitude
137 CrossProduct(dir0, dir1, temp);
139 // this is entirely unnecessary, but kept for clarity
140 //VectorNormalize(temp);
142 // compare distance of light along normal, with distance of any point
143 // of the triangle along the same normal (the triangle is planar,
144 // I.E. flat, so all points give the same answer)
145 // the normal is not normalized because it is used on both sides of
146 // the comparison, so it's magnitude does not matter
147 trianglefacinglight[i] = DotProduct(relativelightorigin, temp) >= DotProduct(v0, temp);
151 // output triangle elements
152 out = shadowelements;
155 // check each backface for bordering frontfaces,
156 // and cast shadow polygons from those edges,
157 // also create front and back caps for shadow volume
158 for (i = 0, e = elements, n = neighbors;i < numtris;i++, e += 3, n += 3)
160 if (!trianglefacinglight[i])
162 // triangle is backface and therefore casts shadow,
163 // output front and back caps for shadow volume
165 // front cap (with flipped winding order)
170 out[3] = e[0] + numverts;
171 out[4] = e[1] + numverts;
172 out[5] = e[2] + numverts;
177 out[0] = e[0] + numverts;
178 out[1] = e[1] + numverts;
179 out[2] = e[2] + numverts;
184 if (n[0] < 0 || trianglefacinglight[n[0]])
188 out[2] = e[1] + numverts;
190 out[4] = e[1] + numverts;
191 out[5] = e[0] + numverts;
195 if (n[1] < 0 || trianglefacinglight[n[1]])
199 out[2] = e[2] + numverts;
201 out[4] = e[2] + numverts;
202 out[5] = e[1] + numverts;
206 if (n[2] < 0 || trianglefacinglight[n[2]])
210 out[2] = e[0] + numverts;
212 out[4] = e[0] + numverts;
213 out[5] = e[2] + numverts;
222 //qglDisable(GL_CULL_FACE);
223 R_Mesh_Draw(numverts * 2, tris, shadowelements);
224 //qglEnable(GL_CULL_FACE);
228 qglColorMask(0,0,0,0);
230 qglEnable(GL_STENCIL_TEST);
232 // increment stencil if backface is behind depthbuffer
233 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
234 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
235 R_Mesh_Draw(numverts * 2, tris, shadowelements);
236 // decrement stencil if frontface is infront of depthbuffer
237 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
238 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
239 R_Mesh_Draw(numverts * 2, tris, shadowelements);
241 // restore to normal quake rendering
242 qglDisable(GL_STENCIL_TEST);
243 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
245 qglColorMask(1,1,1,1);
249 void R_Shadow_VertexLight(int numverts, float *vertex, float *normals, vec3_t relativelightorigin, float lightradius2, float lightdistbias, float lightsubtract, float *lightcolor)
252 float *n, *v, *c, f, dist, temp[3];
253 // calculate vertex colors
254 for (i = 0, v = vertex, c = varray_color, n = normals;i < numverts;i++, v += 4, c += 4, n += 3)
256 VectorSubtract(relativelightorigin, v, temp);
261 f = DotProduct(n, temp);
264 dist = DotProduct(temp, temp);
265 if (dist < lightradius2)
267 f = ((1.0f / (dist + lightdistbias)) - lightsubtract) * (f / sqrt(dist));
268 c[0] = f * lightcolor[0];
269 c[1] = f * lightcolor[1];
270 c[2] = f * lightcolor[2];
276 void R_Shadow_RenderLightThroughStencil(int numverts, int numtris, int *elements, vec3_t relativelightorigin, float *normals)
278 // only draw light where this geometry was already rendered AND the
279 // stencil is 0 (non-zero means shadow)
280 qglDepthFunc(GL_EQUAL);
281 qglEnable(GL_STENCIL_TEST);
282 qglStencilFunc(GL_EQUAL, 0, 0xFF);
283 R_Mesh_Draw(numverts, numtris, elements);
284 qglDisable(GL_STENCIL_TEST);
285 qglDepthFunc(GL_LEQUAL);
288 void R_Shadow_ClearStencil(void)
291 qglClear(GL_STENCIL_BUFFER_BIT);