]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - r_shadow.c
c13a9779d631727405390ba6e0565fa8069fbb79
[xonotic/darkplaces.git] / r_shadow.c
1
2 #include "quakedef.h"
3 #include "r_shadow.h"
4
5 mempool_t *r_shadow_mempool;
6
7 int maxshadowelements;
8 int *shadowelements;
9 int maxtrianglefacinglight;
10 qbyte *trianglefacinglight;
11
12 void r_shadow_start(void)
13 {
14         // allocate vertex processing arrays
15         r_shadow_mempool = Mem_AllocPool("R_Shadow");
16         maxshadowelements = 0;
17         shadowelements = NULL;
18         maxtrianglefacinglight = 0;
19         trianglefacinglight = NULL;
20 }
21
22 void r_shadow_shutdown(void)
23 {
24         maxshadowelements = 0;
25         shadowelements = NULL;
26         maxtrianglefacinglight = 0;
27         trianglefacinglight = NULL;
28         Mem_FreePool(&r_shadow_mempool);
29 }
30
31 void r_shadow_newmap(void)
32 {
33 }
34
35 void R_Shadow_Init(void)
36 {
37         R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
38 }
39
40 void R_Shadow_Volume(int numverts, int numtris, float *vertex, int *elements, int *neighbors, vec3_t relativelightorigin, float lightradius, float projectdistance, int visiblevolume)
41 {
42         int i, *e, *n, *out, tris;
43         float *v0, *v1, *v2, temp[3], f;
44         if (projectdistance < 0.1)
45         {
46                 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
47                 return;
48         }
49 // terminology:
50 //
51 // frontface:
52 // a triangle facing the light source
53 //
54 // backface:
55 // a triangle not facing the light source
56 //
57 // shadow volume:
58 // an extrusion of the backfaces, beginning at the original geometry and
59 // ending further from the light source than the original geometry
60 // (presumably at least as far as the light's radius, if the light has a
61 // radius at all), capped at both front and back to avoid any problems
62 //
63 // description:
64 // draws the shadow volumes of the model.
65 // requirements:
66 // vertex loations must already be in vertex before use.
67 // vertex must have capacity for numverts * 2.
68
69         // make sure trianglefacinglight is big enough for this volume
70         if (maxtrianglefacinglight < numtris)
71         {
72                 maxtrianglefacinglight = numtris;
73                 if (trianglefacinglight)
74                         Mem_Free(trianglefacinglight);
75                 trianglefacinglight = Mem_Alloc(r_shadow_mempool, maxtrianglefacinglight);
76         }
77
78         // make sure shadowelements is big enough for this volume
79         if (maxshadowelements < numtris * 24)
80         {
81                 maxshadowelements = numtris * 24;
82                 if (shadowelements)
83                         Mem_Free(shadowelements);
84                 shadowelements = Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int));
85         }
86
87         // make projected vertices
88         // by clever use of elements we'll construct the whole shadow from
89         // the unprojected vertices and these projected vertices
90         for (i = 0, v0 = vertex, v1 = vertex + numverts * 4;i < numverts;i++, v0 += 4, v1 += 4)
91         {
92                 VectorSubtract(v0, relativelightorigin, temp);
93 #if 0
94                 f = lightradius / sqrt(DotProduct(temp,temp));
95                 if (f < 1)
96                         f = 1;
97                 VectorMA(relativelightorigin, f, temp, v1);
98 #else
99                 f = projectdistance / sqrt(DotProduct(temp,temp));
100                 VectorMA(v0, f, temp, v1);
101 #endif
102         }
103
104         // check which triangles are facing the light
105         for (i = 0, e = elements;i < numtris;i++, e += 3)
106         {
107                 // calculate triangle facing flag
108                 v0 = vertex + e[0] * 4;
109                 v1 = vertex + e[1] * 4;
110                 v2 = vertex + e[2] * 4;
111                 // we do not need to normalize the surface normal because both sides
112                 // of the comparison use it, therefore they are both multiplied the
113                 // same amount...  furthermore the subtract can be done on the
114                 // vectors, saving a little bit of math in the dotproducts
115 #if 1
116                 // fast version
117                 // subtracts v1 from v0 and v2, combined into a crossproduct,
118                 // combined with a dotproduct of the light location relative to the
119                 // first point of the triangle (any point works, since the triangle
120                 // is obviously flat), and finally a comparison to determine if the
121                 // light is infront of the triangle (the goal of this statement)
122                 trianglefacinglight[i] =
123                    (relativelightorigin[0] - v0[0]) * ((v0[1] - v1[1]) * (v2[2] - v1[2]) - (v0[2] - v1[2]) * (v2[1] - v1[1]))
124                  + (relativelightorigin[1] - v0[1]) * ((v0[2] - v1[2]) * (v2[0] - v1[0]) - (v0[0] - v1[0]) * (v2[2] - v1[2]))
125                  + (relativelightorigin[2] - v0[2]) * ((v0[0] - v1[0]) * (v2[1] - v1[1]) - (v0[1] - v1[1]) * (v2[0] - v1[0])) > 0;
126 #else
127                 // readable version
128                 {
129                 float dir0[3], dir1[3];
130
131                 // calculate two mostly perpendicular edge directions
132                 VectorSubtract(v0, v1, dir0);
133                 VectorSubtract(v2, v1, dir1);
134
135                 // we have two edge directions, we can calculate a third vector from
136                 // them, which is the direction of the surface normal (it's magnitude
137                 // is not 1 however)
138                 CrossProduct(dir0, dir1, temp);
139
140                 // this is entirely unnecessary, but kept for clarity
141                 //VectorNormalize(temp);
142
143                 // compare distance of light along normal, with distance of any point
144                 // of the triangle along the same normal (the triangle is planar,
145                 // I.E. flat, so all points give the same answer)
146                 // the normal is not normalized because it is used on both sides of
147                 // the comparison, so it's magnitude does not matter
148                 trianglefacinglight[i] = DotProduct(relativelightorigin, temp) >= DotProduct(v0, temp);
149 #endif
150         }
151
152         // output triangle elements
153         out = shadowelements;
154         tris = 0;
155
156         // check each backface for bordering frontfaces,
157         // and cast shadow polygons from those edges,
158         // also create front and back caps for shadow volume
159         for (i = 0, e = elements, n = neighbors;i < numtris;i++, e += 3, n += 3)
160         {
161                 if (!trianglefacinglight[i])
162                 {
163                         // triangle is backface and therefore casts shadow,
164                         // output front and back caps for shadow volume
165 #if 1
166                         // front cap (with flipped winding order)
167                         out[0] = e[0];
168                         out[1] = e[2];
169                         out[2] = e[1];
170                         // rear cap
171                         out[3] = e[0] + numverts;
172                         out[4] = e[1] + numverts;
173                         out[5] = e[2] + numverts;
174                         out += 6;
175                         tris += 2;
176 #else
177                         // rear cap
178                         out[0] = e[0] + numverts;
179                         out[1] = e[1] + numverts;
180                         out[2] = e[2] + numverts;
181                         out += 3;
182                         tris += 1;
183 #endif
184                         // check the edges
185                         if (n[0] < 0 || trianglefacinglight[n[0]])
186                         {
187                                 out[0] = e[0];
188                                 out[1] = e[1];
189                                 out[2] = e[1] + numverts;
190                                 out[3] = e[0];
191                                 out[4] = e[1] + numverts;
192                                 out[5] = e[0] + numverts;
193                                 out += 6;
194                                 tris += 2;
195                         }
196                         if (n[1] < 0 || trianglefacinglight[n[1]])
197                         {
198                                 out[0] = e[1];
199                                 out[1] = e[2];
200                                 out[2] = e[2] + numverts;
201                                 out[3] = e[1];
202                                 out[4] = e[2] + numverts;
203                                 out[5] = e[1] + numverts;
204                                 out += 6;
205                                 tris += 2;
206                         }
207                         if (n[2] < 0 || trianglefacinglight[n[2]])
208                         {
209                                 out[0] = e[2];
210                                 out[1] = e[0];
211                                 out[2] = e[0] + numverts;
212                                 out[3] = e[2];
213                                 out[4] = e[0] + numverts;
214                                 out[5] = e[2] + numverts;
215                                 out += 6;
216                                 tris += 2;
217                         }
218                 }
219         }
220         R_Shadow_RenderVolume(numverts * 2, tris, shadowelements, visiblevolume);
221 }
222
223 void R_Shadow_RenderVolume(int numverts, int numtris, int *elements, int visiblevolume)
224 {
225         // draw the volume
226         if (visiblevolume)
227         {
228                 qglDisable(GL_CULL_FACE);
229                 R_Mesh_Draw(numverts, numtris, elements);
230                 qglEnable(GL_CULL_FACE);
231         }
232         else
233         {
234                 // increment stencil if backface is behind depthbuffer
235                 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
236                 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
237                 R_Mesh_Draw(numverts, numtris, elements);
238                 // decrement stencil if frontface is behind depthbuffer
239                 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
240                 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
241                 R_Mesh_Draw(numverts, numtris, elements);
242         }
243 }
244
245 void R_Shadow_Stage_Depth(void)
246 {
247         rmeshstate_t m;
248         memset(&m, 0, sizeof(m));
249         m.blendfunc1 = GL_ONE;
250         m.blendfunc2 = GL_ZERO;
251         R_Mesh_State(&m);
252         GL_Color(0, 0, 0, 1);
253 }
254
255 void R_Shadow_Stage_ShadowVolumes(void)
256 {
257         GL_Color(1, 1, 1, 1);
258         qglColorMask(0, 0, 0, 0);
259         qglDisable(GL_BLEND);
260         qglDepthMask(0);
261         qglDepthFunc(GL_LEQUAL);
262         qglClearStencil(0);
263         qglClear(GL_STENCIL_BUFFER_BIT);
264         qglEnable(GL_STENCIL_TEST);
265         qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
266         qglStencilFunc(GL_ALWAYS, 0, 0xFF);
267 }
268
269 void R_Shadow_Stage_Light(void)
270 {
271         qglEnable(GL_BLEND);
272         qglBlendFunc(GL_ONE, GL_ONE);
273         GL_Color(1, 1, 1, 1);
274         qglColorMask(1, 1, 1, 1);
275         qglDepthMask(0);
276         qglDepthFunc(GL_EQUAL);
277         qglEnable(GL_STENCIL_TEST);
278         qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
279         // only draw light where this geometry was already rendered AND the
280         // stencil is 0 (non-zero means shadow)
281         qglStencilFunc(GL_EQUAL, 0, 0xFF);
282 }
283
284 void R_Shadow_Stage_Textures(void)
285 {
286         rmeshstate_t m;
287         // attempt to restore state to what Mesh_State thinks it is
288         qglDisable(GL_BLEND);
289         qglBlendFunc(GL_ONE, GL_ZERO);
290         qglDepthMask(1);
291
292         // now change to a more useful state
293         memset(&m, 0, sizeof(m));
294         m.blendfunc1 = GL_DST_COLOR;
295         m.blendfunc2 = GL_SRC_COLOR;
296         R_Mesh_State(&m);
297
298         // now hack some more
299         GL_Color(1, 1, 1, 1);
300         qglColorMask(1, 1, 1, 1);
301         qglDepthFunc(GL_EQUAL);
302         qglEnable(GL_STENCIL_TEST);
303         qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
304         // only draw in lit areas
305         qglStencilFunc(GL_EQUAL, 0, 0xFF);
306 }
307
308 void R_Shadow_Stage_End(void)
309 {
310         rmeshstate_t m;
311         GL_Color(1, 1, 1, 1);
312         qglColorMask(1, 1, 1, 1);
313         qglDepthFunc(GL_LEQUAL);
314         qglDisable(GL_STENCIL_TEST);
315         qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
316         qglStencilFunc(GL_ALWAYS, 0, 0xFF);
317
318         // now change to a more useful state
319         memset(&m, 0, sizeof(m));
320         m.blendfunc1 = GL_ONE;
321         m.blendfunc2 = GL_ZERO;
322         R_Mesh_State(&m);
323 }
324
325 void R_Shadow_VertexLight(int numverts, float *vertex, float *normals, vec3_t relativelightorigin, float lightradius2, float lightdistbias, float lightsubtract, float *lightcolor)
326 {
327         int i;
328         float *n, *v, *c, f, dist, temp[3], light[3];
329         // calculate vertex colors
330         VectorCopy(lightcolor, light);
331         for (i = 0, v = vertex, c = varray_color, n = normals;i < numverts;i++, v += 4, c += 4, n += 3)
332         {
333                 VectorSubtract(relativelightorigin, v, temp);
334                 c[0] = 0;
335                 c[1] = 0;
336                 c[2] = 0;
337                 c[3] = 1;
338                 f = DotProduct(n, temp);
339                 if (f > 0)
340                 {
341                         dist = DotProduct(temp, temp);
342                         if (dist < lightradius2)
343                         {
344                                 f = ((1.0f / (dist + lightdistbias)) - lightsubtract) * (f / sqrt(dist));
345                                 c[0] = f * light[0];
346                                 c[1] = f * light[1];
347                                 c[2] = f * light[2];
348                         }
349                 }
350         }
351 }