5 #define SHADOWSTAGE_NONE 0
6 #define SHADOWSTAGE_STENCIL 1
7 #define SHADOWSTAGE_LIGHT 2
8 #define SHADOWSTAGE_ERASESTENCIL 3
10 int r_shadowstage = SHADOWSTAGE_NONE;
12 mempool_t *r_shadow_mempool;
14 int maxshadowelements;
16 int maxtrianglefacinglight;
17 qbyte *trianglefacinglight;
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;
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"};
36 void r_shadow_start(void)
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;
51 void r_shadow_shutdown(void)
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);
65 void r_shadow_newmap(void)
69 void R_Shadow_Init(void)
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);
84 void R_Shadow_Volume(int numverts, int numtris, float *vertex, int *elements, int *neighbors, vec3_t relativelightorigin, float lightradius, float projectdistance)
86 int i, *e, *n, *out, tris;
87 float *v0, *v1, *v2, temp[3], f;
88 if (projectdistance < 0.1)
90 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
93 projectdistance = lightradius;
97 // a triangle facing the light source
100 // a triangle not facing the light source
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
109 // draws the shadow volumes of the model.
111 // vertex loations must already be in vertex before use.
112 // vertex must have capacity for numverts * 2.
114 // make sure trianglefacinglight is big enough for this volume
115 if (maxtrianglefacinglight < numtris)
117 maxtrianglefacinglight = numtris;
118 if (trianglefacinglight)
119 Mem_Free(trianglefacinglight);
120 trianglefacinglight = Mem_Alloc(r_shadow_mempool, maxtrianglefacinglight);
123 // make sure shadowelements is big enough for this volume
124 if (maxshadowelements < numtris * 24)
126 maxshadowelements = numtris * 24;
128 Mem_Free(shadowelements);
129 shadowelements = Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int));
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)
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]);
142 VectorSubtract(v0, relativelightorigin, temp);
143 f = lightradius / sqrt(DotProduct(temp,temp));
146 VectorMA(relativelightorigin, f, temp, v1);
148 VectorSubtract(v0, relativelightorigin, temp);
149 f = projectdistance / sqrt(DotProduct(temp,temp));
150 VectorMA(v0, f, temp, v1);
154 // check which triangles are facing the light
155 for (i = 0, e = elements;i < numtris;i++, e += 3)
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
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;
179 float dir0[3], dir1[3];
181 // calculate two mostly perpendicular edge directions
182 VectorSubtract(v0, v1, dir0);
183 VectorSubtract(v2, v1, dir1);
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
188 CrossProduct(dir0, dir1, temp);
190 // this is entirely unnecessary, but kept for clarity
191 //VectorNormalize(temp);
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));
205 // output triangle elements
206 out = shadowelements;
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)
215 if (trianglefacinglight[i])
217 // triangle is backface and therefore casts shadow,
218 // output front and back caps for shadow volume
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;
232 out[0] = e[0] + numverts;
233 out[1] = e[2] + numverts;
234 out[2] = e[1] + numverts;
239 if (n[0] < 0 || !trianglefacinglight[n[0]])
243 out[2] = e[0] + numverts;
245 out[4] = e[0] + numverts;
246 out[5] = e[1] + numverts;
250 if (n[1] < 0 || !trianglefacinglight[n[1]])
254 out[2] = e[1] + numverts;
256 out[4] = e[1] + numverts;
257 out[5] = e[2] + numverts;
261 if (n[2] < 0 || !trianglefacinglight[n[2]])
265 out[2] = e[2] + numverts;
267 out[4] = e[2] + numverts;
268 out[5] = e[0] + numverts;
274 if (!trianglefacinglight[i])
276 // triangle is backface and therefore casts shadow,
277 // output front and back caps for shadow volume
279 // front cap (with flipped winding order)
284 out[3] = e[0] + numverts;
285 out[4] = e[1] + numverts;
286 out[5] = e[2] + numverts;
291 out[0] = e[0] + numverts;
292 out[1] = e[1] + numverts;
293 out[2] = e[2] + numverts;
298 if (n[0] < 0 || trianglefacinglight[n[0]])
302 out[2] = e[1] + numverts;
304 out[4] = e[1] + numverts;
305 out[5] = e[0] + numverts;
309 if (n[1] < 0 || trianglefacinglight[n[1]])
313 out[2] = e[2] + numverts;
315 out[4] = e[2] + numverts;
316 out[5] = e[1] + numverts;
320 if (n[2] < 0 || trianglefacinglight[n[2]])
324 out[2] = e[0] + numverts;
326 out[4] = e[0] + numverts;
327 out[5] = e[2] + numverts;
334 R_Shadow_RenderVolume(numverts * 2, tris, shadowelements);
337 void R_Shadow_RenderVolume(int numverts, int numtris, int *elements)
339 if (!numverts || !numtris)
342 if (r_shadowstage == SHADOWSTAGE_STENCIL)
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);
354 R_Mesh_Draw(numverts, numtris, elements);
357 float r_shadow_atten1, r_shadow_atten2, r_shadow_atten5;
358 #define ATTEN3DSIZE 64
359 static void R_Shadow_Make3DTextures(void)
362 float v[3], intensity, ilen, bordercolor[4];
364 if (r_light_quality.integer != 1 || !gl_texture3d)
366 data = Mem_Alloc(tempmempool, ATTEN3DSIZE * ATTEN3DSIZE * ATTEN3DSIZE * 4);
367 for (z = 0;z < ATTEN3DSIZE;z++)
369 for (y = 0;y < ATTEN3DSIZE;y++)
371 for (x = 0;x < ATTEN3DSIZE;x++)
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));
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;
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);
396 static void R_Shadow_MakeTextures(void)
399 float v[3], s, t, intensity;
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++)
409 for (x = 0;x < 128;x++)
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;
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++)
420 for (y = 0;y < 128;y++)
422 for (x = 0;x < 128;x++)
424 s = (x + 0.5f) * (2.0f / 128.0f) - 1.0f;
425 t = (y + 0.5f) * (2.0f / 128.0f) - 1.0f;
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;
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++)
470 for (x = 0;x < 128;x++)
472 v[0] = (x + 0.5f) * (2.0f / 128.0f) - 1.0f;
473 v[1] = (y + 0.5f) * (2.0f / 128.0f) - 1.0f;
475 intensity = 1.0f - sqrt(DotProduct(v, v));
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;
486 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", 128, 128, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA | TEXF_MIPMAP, NULL);
488 R_Shadow_Make3DTextures();
491 void R_Shadow_Stage_Begin(void)
495 if (r_light_quality.integer == 1 && !gl_texture3d)
497 Con_Printf("3D texture support not detected, falling back on slower 2D + 1D + normalization lighting\n");
498 Cvar_SetValueQuick(&r_light_quality, 0);
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();
508 memset(&m, 0, sizeof(m));
509 m.blendfunc1 = GL_ONE;
510 m.blendfunc2 = GL_ZERO;
512 GL_Color(0, 0, 0, 1);
513 r_shadowstage = SHADOWSTAGE_NONE;
516 void R_Shadow_Stage_ShadowVolumes(void)
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);
525 qglDepthFunc(GL_LESS);
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;
536 void R_Shadow_Stage_Light(void)
539 memset(&m, 0, sizeof(m));
540 R_Mesh_TextureState(&m);
541 qglActiveTexture(GL_TEXTURE0_ARB);
544 qglBlendFunc(GL_ONE, GL_ONE);
545 GL_Color(1, 1, 1, 1);
546 qglColorMask(1, 1, 1, 1);
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;
559 void R_Shadow_Stage_EraseShadowVolumes(void)
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);
568 qglDepthFunc(GL_LESS);
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;
579 void R_Shadow_Stage_End(void)
581 // attempt to restore state to what Mesh_State thinks it is
582 qglDisable(GL_BLEND);
583 qglBlendFunc(GL_ONE, GL_ZERO);
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;
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)
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)
604 VectorSubtract(vertex, relativelightorigin, lightvec);
605 out2d[0] = 0.5f + DotProduct(svectors, lightvec) * iradius;
606 out2d[1] = 0.5f + DotProduct(tvectors, lightvec) * iradius;
608 out1d[0] = 0.5f + DotProduct(normals, lightvec) * iradius;
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)
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)
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;
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)
632 for (i = 0;i < numverts;i++, vertex += 4, svectors += 4, tvectors += 4, normals += 4, out += 4)
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);
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)
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)
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;
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)
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)
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);
681 void R_Shadow_GenTexCoords_LightCubeMap(float *out, int numverts, const float *vertex, const vec3_t relativelightorigin)
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);
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)
693 float scale, colorscale;
695 memset(&m, 0, sizeof(m));
697 bumptexture = r_shadow_blankbumptexture;
698 // colorscale accounts for how much we multiply the brightness during combine
699 if (r_light_quality.integer == 1)
701 if (r_textureunits.integer >= 4)
702 colorscale = r_colorscale * 0.125f / r_shadow3.value;
704 colorscale = r_colorscale * 0.5f / r_shadow3.value;
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]);
711 for (;mult > 0;mult--)
713 if (r_light_quality.integer == 1)
715 if (r_textureunits.integer >= 4)
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]));
734 R_Shadow_GenTexCoords_LightCubeMap(varray_texcoord[3], numverts, varray_vertex, relativelightorigin);
737 qglActiveTexture(GL_TEXTURE3_ARB);
738 qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PRIMARY_COLOR_ARB);
740 R_Shadow_GenTexCoords_Diffuse_Attenuation3D(varray_texcoord[1], numverts, varray_vertex, svectors, tvectors, normals, relativelightorigin, lightradius);
741 R_Mesh_Draw(numverts, numtriangles, elements);
744 qglActiveTexture(GL_TEXTURE3_ARB);
745 qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
747 if (r_light_gloss.integer && glosstexture)
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);
754 qglActiveTexture(GL_TEXTURE3_ARB);
755 qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PRIMARY_COLOR_ARB);
757 R_Mesh_Draw(numverts, numtriangles, elements);
760 qglActiveTexture(GL_TEXTURE3_ARB);
761 qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
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);
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);
780 m.tex[0] = R_GetTexture(basetexture);
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);
790 GL_Color(lightcolor[0] * colorscale, lightcolor[1] * colorscale, lightcolor[2] * colorscale, 1);
792 R_Shadow_GenTexCoords_LightCubeMap(varray_texcoord[1], numverts, varray_vertex, relativelightorigin);
793 R_Mesh_Draw(numverts, numtriangles, elements);
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);
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);
808 m.tex[0] = R_GetTexture(bumptexture);
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);
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);
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);
830 R_Shadow_GenTexCoords_LightCubeMap(varray_texcoord[1], numverts, varray_vertex, relativelightorigin);
831 R_Mesh_Draw(numverts, numtriangles, elements);