new experimental shadow volumes, try r_shadows 2 to see the shadow volumes cast by...
[divverent/darkplaces.git] / r_shadow.c
1
2 #include "quakedef.h"
3
4 mempool_t *r_shadow_mempool;
5
6 int maxshadowelements;
7 int *shadowelements;
8 int maxtrianglefacinglight;
9 qbyte *trianglefacinglight;
10
11 void r_shadow_start(void)
12 {
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;
19 }
20
21 void r_shadow_shutdown(void)
22 {
23         maxshadowelements = 0;
24         shadowelements = NULL;
25         maxtrianglefacinglight = 0;
26         trianglefacinglight = NULL;
27         Mem_FreePool(&r_shadow_mempool);
28 }
29
30 void r_shadow_newmap(void)
31 {
32 }
33
34 void R_Shadow_Init(void)
35 {
36         R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
37 }
38
39 void R_ShadowVolume(int numverts, int numtris, int *elements, int *neighbors, vec3_t relativelightorigin, float projectdistance)
40 {
41         int i, *e, *n, *out, tris;
42         float *v0, *v1, *v2, dir0[3], dir1[3], temp[3], f;
43 // terminology:
44 //
45 // frontface:
46 // a triangle facing the light source
47 //
48 // backface:
49 // a triangle not facing the light source
50 //
51 // shadow volume:
52 // an extrusion of the backfaces, beginning at the original geometry and
53 // ending further from the light source than the original geometry
54 // (presumably at least as far as the light's radius, if the light has a
55 // radius at all), capped at both front and back to avoid any problems
56 //
57 // description:
58 // draws the shadow volumes of the model.
59 // requirements:
60 // vertex loations must already be in varray_vertex before use.
61 // varray_vertex must have capacity for numverts * 2.
62
63         // make sure trianglefacinglight is big enough for this volume
64         if (maxtrianglefacinglight < numtris)
65         {
66                 maxtrianglefacinglight = numtris;
67                 if (trianglefacinglight)
68                         Mem_Free(trianglefacinglight);
69                 trianglefacinglight = Mem_Alloc(r_shadow_mempool, maxtrianglefacinglight);
70         }
71
72         // make sure shadowelements is big enough for this volume
73         if (maxshadowelements < numtris * 24)
74         {
75                 maxshadowelements = numtris * 24;
76                 if (shadowelements)
77                         Mem_Free(shadowelements);
78                 shadowelements = Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int));
79         }
80
81         // make projected vertices
82         // by clever use of elements we'll construct the whole shadow from
83         // the unprojected vertices and these projected vertices
84         for (i = 0, v0 = varray_vertex, v1 = varray_vertex + numverts * 4;i < numverts;i++, v0 += 4, v1 += 4)
85         {
86                 VectorSubtract(v0, relativelightorigin, temp);
87                 f = projectdistance / sqrt(DotProduct(temp,temp));
88                 VectorMA(v0, f, temp, v1);
89         }
90
91         // check which triangles are facing the light
92         for (i = 0, e = elements;i < numtris;i++, e += 3)
93         {
94                 // calculate surface plane
95                 v0 = varray_vertex + e[0] * 4;
96                 v1 = varray_vertex + e[1] * 4;
97                 v2 = varray_vertex + e[2] * 4;
98                 VectorSubtract(v0, v1, dir0);
99                 VectorSubtract(v2, v1, dir1);
100                 CrossProduct(dir0, dir1, temp);
101                 // we do not need to normalize the surface normal because both sides
102                 // of the comparison use it, therefore they are both multiplied the
103                 // same amount...
104                 trianglefacinglight[i] = DotProduct(relativelightorigin, temp) >= DotProduct(v0, temp);
105         }
106
107         // output triangle elements
108         out = shadowelements;
109         tris = 0;
110
111         // check each backface for bordering frontfaces,
112         // and cast shadow polygons from those edges,
113         // also create front and back caps for shadow volume
114         for (i = 0, e = elements, n = neighbors;i < numtris;i++, e += 3, n += 3)
115         {
116                 if (!trianglefacinglight[i])
117                 {
118                         // triangle is backface and therefore casts shadow,
119                         // output front and back caps for shadow volume
120                         // front cap (with flipped winding order)
121                         out[0] = e[0];
122                         out[1] = e[2];
123                         out[2] = e[1];
124                         // rear cap
125                         out[3] = e[0] + numverts;
126                         out[4] = e[1] + numverts;
127                         out[5] = e[2] + numverts;
128                         out += 6;
129                         tris += 2;
130                         // check the edges
131                         if (trianglefacinglight[n[0]])
132                         {
133                                 out[0] = e[0];
134                                 out[1] = e[1];
135                                 out[2] = e[1] + numverts;
136                                 out[3] = e[0];
137                                 out[4] = e[1] + numverts;
138                                 out[5] = e[0] + numverts;
139                                 out += 6;
140                                 tris += 2;
141                         }
142                         if (trianglefacinglight[n[1]])
143                         {
144                                 out[0] = e[1];
145                                 out[1] = e[2];
146                                 out[2] = e[2] + numverts;
147                                 out[3] = e[1];
148                                 out[4] = e[2] + numverts;
149                                 out[5] = e[1] + numverts;
150                                 out += 6;
151                                 tris += 2;
152                         }
153                         if (trianglefacinglight[n[2]])
154                         {
155                                 out[0] = e[2];
156                                 out[1] = e[0];
157                                 out[2] = e[0] + numverts;
158                                 out[3] = e[2];
159                                 out[4] = e[0] + numverts;
160                                 out[5] = e[2] + numverts;
161                                 out += 6;
162                                 tris += 2;
163                         }
164                 }
165         }
166         // draw the volume
167         R_Mesh_Draw(numverts * 2, tris, shadowelements);
168 }