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