]> icculus.org git repositories - divverent/darkplaces.git/blob - r_shadow.c
make profile now works
[divverent/darkplaces.git] / r_shadow.c
1
2 #include "quakedef.h"
3 #include "r_shadow.h"
4
5 #define SHADOWSTAGE_NONE 0
6 #define SHADOWSTAGE_STENCIL 1
7 #define SHADOWSTAGE_LIGHT 2
8 #define SHADOWSTAGE_ERASESTENCIL 3
9
10 int r_shadowstage = SHADOWSTAGE_NONE;
11
12 mempool_t *r_shadow_mempool;
13
14 int maxshadowelements;
15 int *shadowelements;
16 int maxtrianglefacinglight;
17 qbyte *trianglefacinglight;
18
19 rtexturepool_t *r_shadow_texturepool;
20 rtexture_t *r_shadow_normalsattenuationtexture;
21 rtexture_t *r_shadow_normalscubetexture;
22 rtexture_t *r_shadow_attenuation2dtexture;
23 rtexture_t *r_shadow_blankbumptexture;
24
25 cvar_t r_shadow1 = {0, "r_shadow1", "2"};
26 cvar_t r_shadow2 = {0, "r_shadow2", "0"};
27 cvar_t r_shadow3 = {0, "r_shadow3", "32768"};
28 cvar_t r_shadow4 = {0, "r_shadow4", "0"};
29 cvar_t r_shadow5 = {0, "r_shadow5", "0"};
30 cvar_t r_shadow6 = {0, "r_shadow6", "0"};
31 cvar_t r_light_realtime = {0, "r_light_realtime", "0"};
32 cvar_t r_light_quality = {0, "r_light_quality", "1"};
33 cvar_t r_light_gloss = {0, "r_light_gloss", "0"};
34 cvar_t r_light_debuglight = {0, "r_light_debuglight", "-1"};
35
36 void r_shadow_start(void)
37 {
38         // allocate vertex processing arrays
39         r_shadow_mempool = Mem_AllocPool("R_Shadow");
40         maxshadowelements = 0;
41         shadowelements = NULL;
42         maxtrianglefacinglight = 0;
43         trianglefacinglight = NULL;
44         r_shadow_normalsattenuationtexture = NULL;
45         r_shadow_normalscubetexture = NULL;
46         r_shadow_attenuation2dtexture = NULL;
47         r_shadow_blankbumptexture = NULL;
48         r_shadow_texturepool = NULL;
49 }
50
51 void r_shadow_shutdown(void)
52 {
53         r_shadow_normalsattenuationtexture = NULL;
54         r_shadow_normalscubetexture = NULL;
55         r_shadow_attenuation2dtexture = NULL;
56         r_shadow_blankbumptexture = NULL;
57         R_FreeTexturePool(&r_shadow_texturepool);
58         maxshadowelements = 0;
59         shadowelements = NULL;
60         maxtrianglefacinglight = 0;
61         trianglefacinglight = NULL;
62         Mem_FreePool(&r_shadow_mempool);
63 }
64
65 void r_shadow_newmap(void)
66 {
67 }
68
69 void R_Shadow_Init(void)
70 {
71         Cvar_RegisterVariable(&r_shadow1);
72         Cvar_RegisterVariable(&r_shadow2);
73         Cvar_RegisterVariable(&r_shadow3);
74         Cvar_RegisterVariable(&r_shadow4);
75         Cvar_RegisterVariable(&r_shadow5);
76         Cvar_RegisterVariable(&r_shadow6);
77         Cvar_RegisterVariable(&r_light_realtime);
78         Cvar_RegisterVariable(&r_light_quality);
79         Cvar_RegisterVariable(&r_light_gloss);
80         Cvar_RegisterVariable(&r_light_debuglight);
81         R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
82 }
83
84 void R_Shadow_Volume(int numverts, int numtris, float *vertex, int *elements, int *neighbors, vec3_t relativelightorigin, float lightradius, float projectdistance)
85 {
86         int i, *e, *n, *out, tris;
87         float *v0, *v1, *v2, temp[3], f;
88         if (projectdistance < 0.1)
89         {
90                 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
91                 return;
92         }
93         projectdistance = lightradius;
94 // terminology:
95 //
96 // frontface:
97 // a triangle facing the light source
98 //
99 // backface:
100 // a triangle not facing the light source
101 //
102 // shadow volume:
103 // an extrusion of the backfaces, beginning at the original geometry and
104 // ending further from the light source than the original geometry
105 // (presumably at least as far as the light's radius, if the light has a
106 // radius at all), capped at both front and back to avoid any problems
107 //
108 // description:
109 // draws the shadow volumes of the model.
110 // requirements:
111 // vertex loations must already be in vertex before use.
112 // vertex must have capacity for numverts * 2.
113
114         // make sure trianglefacinglight is big enough for this volume
115         if (maxtrianglefacinglight < numtris)
116         {
117                 maxtrianglefacinglight = numtris;
118                 if (trianglefacinglight)
119                         Mem_Free(trianglefacinglight);
120                 trianglefacinglight = Mem_Alloc(r_shadow_mempool, maxtrianglefacinglight);
121         }
122
123         // make sure shadowelements is big enough for this volume
124         if (maxshadowelements < numtris * 24)
125         {
126                 maxshadowelements = numtris * 24;
127                 if (shadowelements)
128                         Mem_Free(shadowelements);
129                 shadowelements = Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int));
130         }
131
132         // make projected vertices
133         // by clever use of elements we'll construct the whole shadow from
134         // the unprojected vertices and these projected vertices
135         for (i = 0, v0 = vertex, v1 = vertex + numverts * 4;i < numverts;i++, v0 += 4, v1 += 4)
136         {
137 #if 0
138                 v1[0] = v0[0] + 250.0f * (v0[0] - relativelightorigin[0]);
139                 v1[1] = v0[1] + 250.0f * (v0[1] - relativelightorigin[1]);
140                 v1[2] = v0[2] + 250.0f * (v0[2] - relativelightorigin[2]);
141 #elif 0
142                 VectorSubtract(v0, relativelightorigin, temp);
143                 f = lightradius / sqrt(DotProduct(temp,temp));
144                 if (f < 1)
145                         f = 1;
146                 VectorMA(relativelightorigin, f, temp, v1);
147 #else
148                 VectorSubtract(v0, relativelightorigin, temp);
149                 f = projectdistance / sqrt(DotProduct(temp,temp));
150                 VectorMA(v0, f, temp, v1);
151 #endif
152         }
153
154         // check which triangles are facing the light
155         for (i = 0, e = elements;i < numtris;i++, e += 3)
156         {
157                 // calculate triangle facing flag
158                 v0 = vertex + e[0] * 4;
159                 v1 = vertex + e[1] * 4;
160                 v2 = vertex + e[2] * 4;
161                 // we do not need to normalize the surface normal because both sides
162                 // of the comparison use it, therefore they are both multiplied the
163                 // same amount...  furthermore the subtract can be done on the
164                 // vectors, saving a little bit of math in the dotproducts
165 #if 0
166                 // fast version
167                 // subtracts v1 from v0 and v2, combined into a crossproduct,
168                 // combined with a dotproduct of the light location relative to the
169                 // first point of the triangle (any point works, since the triangle
170                 // is obviously flat), and finally a comparison to determine if the
171                 // light is infront of the triangle (the goal of this statement)
172                 trianglefacinglight[i] =
173                    (relativelightorigin[0] - v0[0]) * ((v0[1] - v1[1]) * (v2[2] - v1[2]) - (v0[2] - v1[2]) * (v2[1] - v1[1]))
174                  + (relativelightorigin[1] - v0[1]) * ((v0[2] - v1[2]) * (v2[0] - v1[0]) - (v0[0] - v1[0]) * (v2[2] - v1[2]))
175                  + (relativelightorigin[2] - v0[2]) * ((v0[0] - v1[0]) * (v2[1] - v1[1]) - (v0[1] - v1[1]) * (v2[0] - v1[0])) > 0;
176 #else
177                 // readable version
178                 {
179                 float dir0[3], dir1[3];
180
181                 // calculate two mostly perpendicular edge directions
182                 VectorSubtract(v0, v1, dir0);
183                 VectorSubtract(v2, v1, dir1);
184
185                 // we have two edge directions, we can calculate a third vector from
186                 // them, which is the direction of the surface normal (it's magnitude
187                 // is not 1 however)
188                 CrossProduct(dir0, dir1, temp);
189
190                 // this is entirely unnecessary, but kept for clarity
191                 //VectorNormalize(temp);
192
193                 // compare distance of light along normal, with distance of any point
194                 // of the triangle along the same normal (the triangle is planar,
195                 // I.E. flat, so all points give the same answer)
196                 // the normal is not normalized because it is used on both sides of
197                 // the comparison, so it's magnitude does not matter
198                 //trianglefacinglight[i] = DotProduct(relativelightorigin, temp) >= DotProduct(v0, temp);
199                 f = DotProduct(relativelightorigin, temp) - DotProduct(v0, temp);
200                 trianglefacinglight[i] = f > 0 && f < lightradius * sqrt(DotProduct(temp, temp));
201                 }
202 #endif
203         }
204
205         // output triangle elements
206         out = shadowelements;
207         tris = 0;
208
209         // check each backface for bordering frontfaces,
210         // and cast shadow polygons from those edges,
211         // also create front and back caps for shadow volume
212         for (i = 0, e = elements, n = neighbors;i < numtris;i++, e += 3, n += 3)
213         {
214 #if 1
215                 if (trianglefacinglight[i])
216                 {
217                         // triangle is backface and therefore casts shadow,
218                         // output front and back caps for shadow volume
219 #if 1
220                         // front cap
221                         out[0] = e[0];
222                         out[1] = e[1];
223                         out[2] = e[2];
224                         // rear cap (with flipped winding order)
225                         out[3] = e[0] + numverts;
226                         out[4] = e[2] + numverts;
227                         out[5] = e[1] + numverts;
228                         out += 6;
229                         tris += 2;
230 #elif 1
231                         // rear cap
232                         out[0] = e[0] + numverts;
233                         out[1] = e[2] + numverts;
234                         out[2] = e[1] + numverts;
235                         out += 3;
236                         tris += 1;
237 #endif
238                         // check the edges
239                         if (n[0] < 0 || !trianglefacinglight[n[0]])
240                         {
241                                 out[0] = e[1];
242                                 out[1] = e[0];
243                                 out[2] = e[0] + numverts;
244                                 out[3] = e[1];
245                                 out[4] = e[0] + numverts;
246                                 out[5] = e[1] + numverts;
247                                 out += 6;
248                                 tris += 2;
249                         }
250                         if (n[1] < 0 || !trianglefacinglight[n[1]])
251                         {
252                                 out[0] = e[2];
253                                 out[1] = e[1];
254                                 out[2] = e[1] + numverts;
255                                 out[3] = e[2];
256                                 out[4] = e[1] + numverts;
257                                 out[5] = e[2] + numverts;
258                                 out += 6;
259                                 tris += 2;
260                         }
261                         if (n[2] < 0 || !trianglefacinglight[n[2]])
262                         {
263                                 out[0] = e[0];
264                                 out[1] = e[2];
265                                 out[2] = e[2] + numverts;
266                                 out[3] = e[0];
267                                 out[4] = e[2] + numverts;
268                                 out[5] = e[0] + numverts;
269                                 out += 6;
270                                 tris += 2;
271                         }
272                 }
273 #else
274                 if (!trianglefacinglight[i])
275                 {
276                         // triangle is backface and therefore casts shadow,
277                         // output front and back caps for shadow volume
278 #if 1
279                         // front cap (with flipped winding order)
280                         out[0] = e[0];
281                         out[1] = e[2];
282                         out[2] = e[1];
283                         // rear cap
284                         out[3] = e[0] + numverts;
285                         out[4] = e[1] + numverts;
286                         out[5] = e[2] + numverts;
287                         out += 6;
288                         tris += 2;
289 #elif 1
290                         // rear cap
291                         out[0] = e[0] + numverts;
292                         out[1] = e[1] + numverts;
293                         out[2] = e[2] + numverts;
294                         out += 3;
295                         tris += 1;
296 #endif
297                         // check the edges
298                         if (n[0] < 0 || trianglefacinglight[n[0]])
299                         {
300                                 out[0] = e[0];
301                                 out[1] = e[1];
302                                 out[2] = e[1] + numverts;
303                                 out[3] = e[0];
304                                 out[4] = e[1] + numverts;
305                                 out[5] = e[0] + numverts;
306                                 out += 6;
307                                 tris += 2;
308                         }
309                         if (n[1] < 0 || trianglefacinglight[n[1]])
310                         {
311                                 out[0] = e[1];
312                                 out[1] = e[2];
313                                 out[2] = e[2] + numverts;
314                                 out[3] = e[1];
315                                 out[4] = e[2] + numverts;
316                                 out[5] = e[1] + numverts;
317                                 out += 6;
318                                 tris += 2;
319                         }
320                         if (n[2] < 0 || trianglefacinglight[n[2]])
321                         {
322                                 out[0] = e[2];
323                                 out[1] = e[0];
324                                 out[2] = e[0] + numverts;
325                                 out[3] = e[2];
326                                 out[4] = e[0] + numverts;
327                                 out[5] = e[2] + numverts;
328                                 out += 6;
329                                 tris += 2;
330                         }
331                 }
332 #endif
333         }
334         R_Shadow_RenderVolume(numverts * 2, tris, shadowelements);
335 }
336
337 void R_Shadow_RenderVolume(int numverts, int numtris, int *elements)
338 {
339         if (!numverts || !numtris)
340                 return;
341         // draw the volume
342         if (r_shadowstage == SHADOWSTAGE_STENCIL)
343         {
344                 // increment stencil if backface is behind depthbuffer
345                 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
346                 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
347                 R_Mesh_Draw(numverts, numtris, elements);
348                 // decrement stencil if frontface is behind depthbuffer
349                 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
350                 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
351                 R_Mesh_Draw(numverts, numtris, elements);
352         }
353         else
354                 R_Mesh_Draw(numverts, numtris, elements);
355 }
356
357 float r_shadow_atten1, r_shadow_atten2, r_shadow_atten5;
358 #define ATTEN3DSIZE 64
359 static void R_Shadow_Make3DTextures(void)
360 {
361         int x, y, z;
362         float v[3], intensity, ilen, bordercolor[4];
363         qbyte *data;
364         if (r_light_quality.integer != 1 || !gl_texture3d)
365                 return;
366         data = Mem_Alloc(tempmempool, ATTEN3DSIZE * ATTEN3DSIZE * ATTEN3DSIZE * 4);
367         for (z = 0;z < ATTEN3DSIZE;z++)
368         {
369                 for (y = 0;y < ATTEN3DSIZE;y++)
370                 {
371                         for (x = 0;x < ATTEN3DSIZE;x++)
372                         {
373                                 v[0] = (x + 0.5f) * (2.0f / (float) ATTEN3DSIZE) - 1.0f;
374                                 v[1] = (y + 0.5f) * (2.0f / (float) ATTEN3DSIZE) - 1.0f;
375                                 v[2] = (z + 0.5f) * (2.0f / (float) ATTEN3DSIZE) - 1.0f;
376                                 intensity = 1.0f - sqrt(DotProduct(v, v));
377                                 if (intensity > 0)
378                                         intensity *= intensity;
379                                 ilen = 127.0f * bound(0, intensity * r_shadow_atten1, 1) / sqrt(DotProduct(v, v));
380                                 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = 128.0f + ilen * v[0];
381                                 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = 128.0f + ilen * v[1];
382                                 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = 128.0f + ilen * v[2];
383                                 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = 255;
384                         }
385                 }
386         }
387         r_shadow_normalsattenuationtexture = R_LoadTexture3D(r_shadow_texturepool, "normalsattenuation", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
388         bordercolor[0] = 0.5f;
389         bordercolor[1] = 0.5f;
390         bordercolor[2] = 0.5f;
391         bordercolor[3] = 1.0f;
392         qglTexParameterfv(GL_TEXTURE_3D, GL_TEXTURE_BORDER_COLOR, bordercolor);
393         Mem_Free(data);
394 }
395
396 static void R_Shadow_MakeTextures(void)
397 {
398         int x, y, d, side;
399         float v[3], s, t, intensity;
400         qbyte *data;
401         data = Mem_Alloc(tempmempool, 6*128*128*4);
402         R_FreeTexturePool(&r_shadow_texturepool);
403         r_shadow_texturepool = R_AllocTexturePool();
404         r_shadow_atten1 = r_shadow1.value;
405         r_shadow_atten2 = r_shadow2.value;
406         r_shadow_atten5 = r_shadow5.value;
407         for (y = 0;y < 128;y++)
408         {
409                 for (x = 0;x < 128;x++)
410                 {
411                         data[((0*128+y)*128+x)*4+0] = 128;
412                         data[((0*128+y)*128+x)*4+1] = 128;
413                         data[((0*128+y)*128+x)*4+2] = 255;
414                         data[((0*128+y)*128+x)*4+3] = 255;
415                 }
416         }
417         r_shadow_blankbumptexture = R_LoadTexture2D(r_shadow_texturepool, "blankbump", 128, 128, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
418         for (side = 0;side < 6;side++)
419         {
420                 for (y = 0;y < 128;y++)
421                 {
422                         for (x = 0;x < 128;x++)
423                         {
424                                 s = (x + 0.5f) * (2.0f / 128.0f) - 1.0f;
425                                 t = (y + 0.5f) * (2.0f / 128.0f) - 1.0f;
426                                 switch(side)
427                                 {
428                                 case 0:
429                                         v[0] = 1;
430                                         v[1] = -t;
431                                         v[2] = -s;
432                                         break;
433                                 case 1:
434                                         v[0] = -1;
435                                         v[1] = -t;
436                                         v[2] = s;
437                                         break;
438                                 case 2:
439                                         v[0] = s;
440                                         v[1] = 1;
441                                         v[2] = t;
442                                         break;
443                                 case 3:
444                                         v[0] = s;
445                                         v[1] = -1;
446                                         v[2] = -t;
447                                         break;
448                                 case 4:
449                                         v[0] = s;
450                                         v[1] = -t;
451                                         v[2] = 1;
452                                         break;
453                                 case 5:
454                                         v[0] = -s;
455                                         v[1] = -t;
456                                         v[2] = -1;
457                                         break;
458                                 }
459                                 intensity = 127.0f / sqrt(DotProduct(v, v));
460                                 data[((side*128+y)*128+x)*4+0] = 128.0f + intensity * v[0];
461                                 data[((side*128+y)*128+x)*4+1] = 128.0f + intensity * v[1];
462                                 data[((side*128+y)*128+x)*4+2] = 128.0f + intensity * v[2];
463                                 data[((side*128+y)*128+x)*4+3] = 255;
464                         }
465                 }
466         }
467         r_shadow_normalscubetexture = R_LoadTextureCubeMap(r_shadow_texturepool, "normalscube", 128, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
468         for (y = 0;y < 128;y++)
469         {
470                 for (x = 0;x < 128;x++)
471                 {
472                         v[0] = (x + 0.5f) * (2.0f / 128.0f) - 1.0f;
473                         v[1] = (y + 0.5f) * (2.0f / 128.0f) - 1.0f;
474                         v[2] = 0;
475                         intensity = 1.0f - sqrt(DotProduct(v, v));
476                         if (intensity > 0)
477                                 intensity *= intensity;
478                         intensity = bound(0, intensity * r_shadow_atten1 * 256.0f, 255.0f);
479                         d = bound(0, intensity, 255);
480                         data[((0*128+y)*128+x)*4+0] = d;
481                         data[((0*128+y)*128+x)*4+1] = d;
482                         data[((0*128+y)*128+x)*4+2] = d;
483                         data[((0*128+y)*128+x)*4+3] = d;
484                 }
485         }
486         r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", 128, 128, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA | TEXF_MIPMAP, NULL);
487         Mem_Free(data);
488         R_Shadow_Make3DTextures();
489 }
490
491 void R_Shadow_Stage_Begin(void)
492 {
493         rmeshstate_t m;
494
495         if (r_light_quality.integer == 1 && !gl_texture3d)
496         {
497                 Con_Printf("3D texture support not detected, falling back on slower 2D + 1D + normalization lighting\n");
498                 Cvar_SetValueQuick(&r_light_quality, 0);
499         }
500         //cl.worldmodel->numlights = min(cl.worldmodel->numlights, 1);
501         if (!r_shadow_attenuation2dtexture
502          || (r_light_quality.integer == 1 && !r_shadow_normalsattenuationtexture)
503          || r_shadow1.value != r_shadow_atten1
504          || r_shadow2.value != r_shadow_atten2
505          || r_shadow5.value != r_shadow_atten5)
506                 R_Shadow_MakeTextures();
507
508         memset(&m, 0, sizeof(m));
509         m.blendfunc1 = GL_ONE;
510         m.blendfunc2 = GL_ZERO;
511         R_Mesh_State(&m);
512         GL_Color(0, 0, 0, 1);
513         r_shadowstage = SHADOWSTAGE_NONE;
514 }
515
516 void R_Shadow_Stage_ShadowVolumes(void)
517 {
518         rmeshstate_t m;
519         memset(&m, 0, sizeof(m));
520         R_Mesh_TextureState(&m);
521         GL_Color(1, 1, 1, 1);
522         qglColorMask(0, 0, 0, 0);
523         qglDisable(GL_BLEND);
524         qglDepthMask(0);
525         qglDepthFunc(GL_LESS);
526         qglClearStencil(0);
527         qglClear(GL_STENCIL_BUFFER_BIT);
528         qglEnable(GL_STENCIL_TEST);
529         qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
530         qglStencilFunc(GL_ALWAYS, 0, 0xFF);
531         qglEnable(GL_CULL_FACE);
532         qglEnable(GL_DEPTH_TEST);
533         r_shadowstage = SHADOWSTAGE_STENCIL;
534 }
535
536 void R_Shadow_Stage_Light(void)
537 {
538         rmeshstate_t m;
539         memset(&m, 0, sizeof(m));
540         R_Mesh_TextureState(&m);
541         qglActiveTexture(GL_TEXTURE0_ARB);
542
543         qglEnable(GL_BLEND);
544         qglBlendFunc(GL_ONE, GL_ONE);
545         GL_Color(1, 1, 1, 1);
546         qglColorMask(1, 1, 1, 1);
547         qglDepthMask(0);
548         qglDepthFunc(GL_EQUAL);
549         qglEnable(GL_STENCIL_TEST);
550         qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
551         // only draw light where this geometry was already rendered AND the
552         // stencil is 0 (non-zero means shadow)
553         qglStencilFunc(GL_EQUAL, 0, 0xFF);
554         qglEnable(GL_CULL_FACE);
555         qglEnable(GL_DEPTH_TEST);
556         r_shadowstage = SHADOWSTAGE_LIGHT;
557 }
558
559 void R_Shadow_Stage_EraseShadowVolumes(void)
560 {
561         rmeshstate_t m;
562         memset(&m, 0, sizeof(m));
563         R_Mesh_TextureState(&m);
564         GL_Color(1, 1, 1, 1);
565         qglColorMask(0, 0, 0, 0);
566         qglDisable(GL_BLEND);
567         qglDepthMask(0);
568         qglDepthFunc(GL_LESS);
569         qglClearStencil(0);
570         qglClear(GL_STENCIL_BUFFER_BIT);
571         qglEnable(GL_STENCIL_TEST);
572         qglStencilOp(GL_ZERO, GL_KEEP, GL_KEEP);
573         qglStencilFunc(GL_NOTEQUAL, 0, 0xFF);
574         qglDisable(GL_CULL_FACE);
575         qglDisable(GL_DEPTH_TEST);
576         r_shadowstage = SHADOWSTAGE_ERASESTENCIL;
577 }
578
579 void R_Shadow_Stage_End(void)
580 {
581         // attempt to restore state to what Mesh_State thinks it is
582         qglDisable(GL_BLEND);
583         qglBlendFunc(GL_ONE, GL_ZERO);
584         qglDepthMask(1);
585         // now restore the rest of the state to normal
586         GL_Color(1, 1, 1, 1);
587         qglColorMask(1, 1, 1, 1);
588         qglDepthFunc(GL_LEQUAL);
589         qglDisable(GL_STENCIL_TEST);
590         qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
591         qglStencilFunc(GL_ALWAYS, 0, 0xFF);
592         qglEnable(GL_CULL_FACE);
593         qglEnable(GL_DEPTH_TEST);
594         r_shadowstage = SHADOWSTAGE_NONE;
595 }
596
597 void R_Shadow_GenTexCoords_Attenuation2D1D(float *out2d, float *out1d, int numverts, const float *vertex, const float *svectors, const float *tvectors, const float *normals, const vec3_t relativelightorigin, float lightradius)
598 {
599         int i;
600         float lightvec[3], iradius;
601         iradius = 0.5f / lightradius;
602         for (i = 0;i < numverts;i++, vertex += 4, svectors += 4, tvectors += 4, normals += 4, out2d += 4, out1d += 4)
603         {
604                 VectorSubtract(vertex, relativelightorigin, lightvec);
605                 out2d[0] = 0.5f + DotProduct(svectors, lightvec) * iradius;
606                 out2d[1] = 0.5f + DotProduct(tvectors, lightvec) * iradius;
607                 out2d[2] = 0;
608                 out1d[0] = 0.5f + DotProduct(normals, lightvec) * iradius;
609                 out1d[1] = 0.5f;
610                 out1d[2] = 0;
611         }
612 }
613
614 void R_Shadow_GenTexCoords_Diffuse_Attenuation3D(float *out, int numverts, const float *vertex, const float *svectors, const float *tvectors, const float *normals, const vec3_t relativelightorigin, float lightradius)
615 {
616         int i;
617         float lightvec[3], iradius;
618         iradius = 0.5f / lightradius;
619         for (i = 0;i < numverts;i++, vertex += 4, svectors += 4, tvectors += 4, normals += 4, out += 4)
620         {
621                 VectorSubtract(vertex, relativelightorigin, lightvec);
622                 out[0] = 0.5f + DotProduct(svectors, lightvec) * iradius;
623                 out[1] = 0.5f + DotProduct(tvectors, lightvec) * iradius;
624                 out[2] = 0.5f + DotProduct(normals, lightvec) * iradius;
625         }
626 }
627
628 void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(float *out, int numverts, const float *vertex, const float *svectors, const float *tvectors, const float *normals, const vec3_t relativelightorigin)
629 {
630         int i;
631         float lightdir[3];
632         for (i = 0;i < numverts;i++, vertex += 4, svectors += 4, tvectors += 4, normals += 4, out += 4)
633         {
634                 VectorSubtract(vertex, relativelightorigin, lightdir);
635                 // the cubemap normalizes this for us
636                 out[0] = DotProduct(svectors, lightdir);
637                 out[1] = DotProduct(tvectors, lightdir);
638                 out[2] = DotProduct(normals, lightdir);
639         }
640 }
641
642 void R_Shadow_GenTexCoords_Specular_Attenuation3D(float *out, int numverts, const float *vertex, const float *svectors, const float *tvectors, const float *normals, const vec3_t relativelightorigin, const vec3_t relativeeyeorigin, float lightradius)
643 {
644         int i;
645         float lightdir[3], eyedir[3], halfdir[3], lightdirlen, iradius;
646         iradius = 0.5f / lightradius;
647         for (i = 0;i < numverts;i++, vertex += 4, svectors += 4, tvectors += 4, normals += 4, out += 4)
648         {
649                 VectorSubtract(vertex, relativelightorigin, lightdir);
650                 // this is used later to make the attenuation correct
651                 lightdirlen = sqrt(DotProduct(lightdir, lightdir)) * iradius;
652                 VectorNormalizeFast(lightdir);
653                 VectorSubtract(vertex, relativeeyeorigin, eyedir);
654                 VectorNormalizeFast(eyedir);
655                 VectorAdd(lightdir, eyedir, halfdir);
656                 VectorNormalizeFast(halfdir);
657                 out[0] = 0.5f + DotProduct(svectors, halfdir) * lightdirlen;
658                 out[1] = 0.5f + DotProduct(tvectors, halfdir) * lightdirlen;
659                 out[2] = 0.5f + DotProduct(normals, halfdir) * lightdirlen;
660         }
661 }
662
663 void R_Shadow_GenTexCoords_Specular_NormalCubeMap(float *out, int numverts, const float *vertex, const float *svectors, const float *tvectors, const float *normals, const vec3_t relativelightorigin, const vec3_t relativeeyeorigin)
664 {
665         int i;
666         float lightdir[3], eyedir[3], halfdir[3];
667         for (i = 0;i < numverts;i++, vertex += 4, svectors += 4, tvectors += 4, normals += 4, out += 4)
668         {
669                 VectorSubtract(vertex, relativelightorigin, lightdir);
670                 VectorNormalizeFast(lightdir);
671                 VectorSubtract(vertex, relativeeyeorigin, eyedir);
672                 VectorNormalizeFast(eyedir);
673                 VectorAdd(lightdir, eyedir, halfdir);
674                 // the cubemap normalizes this for us
675                 out[0] = DotProduct(svectors, halfdir);
676                 out[1] = DotProduct(tvectors, halfdir);
677                 out[2] = DotProduct(normals, halfdir);
678         }
679 }
680
681 void R_Shadow_GenTexCoords_LightCubeMap(float *out, int numverts, const float *vertex, const vec3_t relativelightorigin)
682 {
683         int i;
684         // FIXME: this needs to be written
685         // this code assumes the vertices are in worldspace (a false assumption)
686         for (i = 0;i < numverts;i++, vertex += 4, out += 4)
687                 VectorSubtract(vertex, relativelightorigin, out);
688 }
689
690 void R_Shadow_RenderLighting(int numverts, int numtriangles, const int *elements, const float *svectors, const float *tvectors, const float *normals, const float *texcoords, const float *relativelightorigin, const float *relativeeyeorigin, float lightradius, const float *lightcolor, rtexture_t *basetexture, rtexture_t *glosstexture, rtexture_t *bumptexture, rtexture_t *lightcubemap)
691 {
692         int mult;
693         float scale, colorscale;
694         rmeshstate_t m;
695         memset(&m, 0, sizeof(m));
696         if (!bumptexture)
697                 bumptexture = r_shadow_blankbumptexture;
698         // colorscale accounts for how much we multiply the brightness during combine
699         if (r_light_quality.integer == 1)
700         {
701                 if (r_textureunits.integer >= 4)
702                         colorscale = r_colorscale * 0.125f / r_shadow3.value;
703                 else
704                         colorscale = r_colorscale * 0.5f / r_shadow3.value;
705         }
706         else
707                 colorscale = r_colorscale * 0.5f / r_shadow3.value;
708         // limit mult to 64 for sanity sake
709         for (mult = 1, scale = ixtable[mult];mult < 64 && (lightcolor[0] * scale * colorscale > 1 || lightcolor[1] * scale * colorscale > 1 || lightcolor[2] * scale * colorscale > 1);mult++, scale = ixtable[mult]);
710         colorscale *= scale;
711         for (;mult > 0;mult--)
712         {
713                 if (r_light_quality.integer == 1)
714                 {
715                         if (r_textureunits.integer >= 4)
716                         {
717                                 // 4 texture 3D path, two pass
718                                 m.tex[0] = R_GetTexture(bumptexture);
719                                 m.tex3d[1] = R_GetTexture(r_shadow_normalsattenuationtexture);
720                                 m.tex[2] = R_GetTexture(basetexture);
721                                 m.texcubemap[3] = R_GetTexture(lightcubemap);
722                                 m.tex[3] = R_GetTexture(r_notexture);
723                                 m.texcombinergb[0] = GL_REPLACE;
724                                 m.texcombinergb[1] = GL_DOT3_RGB_ARB;
725                                 m.texcombinergb[2] = GL_MODULATE;
726                                 m.texcombinergb[3] = GL_MODULATE;
727                                 m.texrgbscale[1] = 2;
728                                 m.texrgbscale[3] = 4;
729                                 R_Mesh_TextureState(&m);
730                                 GL_Color(lightcolor[0] * colorscale, lightcolor[1] * colorscale, lightcolor[2] * colorscale, 1);
731                                 memcpy(varray_texcoord[0], texcoords, numverts * sizeof(float[4]));
732                                 memcpy(varray_texcoord[2], texcoords, numverts * sizeof(float[4]));
733                                 if (lightcubemap)
734                                         R_Shadow_GenTexCoords_LightCubeMap(varray_texcoord[3], numverts, varray_vertex, relativelightorigin);
735                                 else
736                                 {
737                                         qglActiveTexture(GL_TEXTURE3_ARB);
738                                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PRIMARY_COLOR_ARB);
739                                 }
740                                 R_Shadow_GenTexCoords_Diffuse_Attenuation3D(varray_texcoord[1], numverts, varray_vertex, svectors, tvectors, normals, relativelightorigin, lightradius);
741                                 R_Mesh_Draw(numverts, numtriangles, elements);
742                                 if (!lightcubemap)
743                                 {
744                                         qglActiveTexture(GL_TEXTURE3_ARB);
745                                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
746                                 }
747                                 if (r_light_gloss.integer && glosstexture)
748                                 {
749                                         m.tex[2] = R_GetTexture(glosstexture);
750                                         R_Mesh_TextureState(&m);
751                                         R_Shadow_GenTexCoords_Specular_Attenuation3D(varray_texcoord[1], numverts, varray_vertex, svectors, tvectors, normals, relativelightorigin, relativeeyeorigin, lightradius);
752                                         if (!lightcubemap)
753                                         {
754                                                 qglActiveTexture(GL_TEXTURE3_ARB);
755                                                 qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PRIMARY_COLOR_ARB);
756                                         }
757                                         R_Mesh_Draw(numverts, numtriangles, elements);
758                                         if (!lightcubemap)
759                                         {
760                                                 qglActiveTexture(GL_TEXTURE3_ARB);
761                                                 qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
762                                         }
763                                 }
764                         }
765                         else
766                         {
767                                 // 2 texture 3D path, four pass
768                                 m.tex[0] = R_GetTexture(bumptexture);
769                                 m.tex3d[1] = R_GetTexture(r_shadow_normalsattenuationtexture);
770                                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
771                                 m.texalphascale[1] = 2;
772                                 R_Mesh_TextureState(&m);
773                                 qglColorMask(0,0,0,1);
774                                 qglDisable(GL_BLEND);
775                                 GL_Color(1,1,1,1);
776                                 memcpy(varray_texcoord[0], texcoords, numverts * sizeof(float[4]));
777                                 R_Shadow_GenTexCoords_Diffuse_Attenuation3D(varray_texcoord[1], numverts, varray_vertex, svectors, tvectors, normals, relativelightorigin, lightradius);
778                                 R_Mesh_Draw(numverts, numtriangles, elements);
779
780                                 m.tex[0] = R_GetTexture(basetexture);
781                                 m.tex3d[1] = 0;
782                                 m.texcubemap[1] = R_GetTexture(lightcubemap);
783                                 m.texcombinergb[1] = GL_MODULATE;
784                                 m.texrgbscale[1] = 1;
785                                 m.texalphascale[1] = 1;
786                                 R_Mesh_TextureState(&m);
787                                 qglColorMask(1,1,1,1);
788                                 qglBlendFunc(GL_DST_ALPHA, GL_ONE);
789                                 qglEnable(GL_BLEND);
790                                 GL_Color(lightcolor[0] * colorscale, lightcolor[1] * colorscale, lightcolor[2] * colorscale, 1);
791                                 if (lightcubemap)
792                                         R_Shadow_GenTexCoords_LightCubeMap(varray_texcoord[1], numverts, varray_vertex, relativelightorigin);
793                                 R_Mesh_Draw(numverts, numtriangles, elements);
794                         }
795                 }
796                 else
797                 {
798                         // 2 texture no3D path, six pass
799                         m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
800                         m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
801                         R_Mesh_TextureState(&m);
802                         qglColorMask(0,0,0,1);
803                         qglDisable(GL_BLEND);
804                         GL_Color(1,1,1,1);
805                         R_Shadow_GenTexCoords_Attenuation2D1D(varray_texcoord[0], varray_texcoord[1], numverts, varray_vertex, svectors, tvectors, normals, relativelightorigin, lightradius);
806                         R_Mesh_Draw(numverts, numtriangles, elements);
807
808                         m.tex[0] = R_GetTexture(bumptexture);
809                         m.tex[1] = 0;
810                         m.texcubemap[1] = R_GetTexture(r_shadow_normalscubetexture);
811                         m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
812                         m.texalphascale[1] = 2;
813                         R_Mesh_TextureState(&m);
814                         qglBlendFunc(GL_DST_ALPHA, GL_ZERO);
815                         qglEnable(GL_BLEND);
816                         memcpy(varray_texcoord[0], texcoords, numverts * sizeof(float[4]));
817                         R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord[1], numverts, varray_vertex, svectors, tvectors, normals, relativelightorigin);
818                         R_Mesh_Draw(numverts, numtriangles, elements);
819
820                         m.tex[0] = R_GetTexture(basetexture);
821                         m.texcubemap[1] = R_GetTexture(lightcubemap);
822                         m.texcombinergb[1] = GL_MODULATE;
823                         m.texrgbscale[1] = 1;
824                         m.texalphascale[1] = 1;
825                         R_Mesh_TextureState(&m);
826                         qglColorMask(1,1,1,1);
827                         qglBlendFunc(GL_DST_ALPHA, GL_ONE);
828                         GL_Color(lightcolor[0] * colorscale, lightcolor[1] * colorscale, lightcolor[2] * colorscale, 1);
829                         if (lightcubemap)
830                                 R_Shadow_GenTexCoords_LightCubeMap(varray_texcoord[1], numverts, varray_vertex, relativelightorigin);
831                         R_Mesh_Draw(numverts, numtriangles, elements);
832                 }
833         }
834 }
835