4 #include "cl_collision.h"
6 extern void R_Shadow_EditLights_Init(void);
8 #define SHADOWSTAGE_NONE 0
9 #define SHADOWSTAGE_STENCIL 1
10 #define SHADOWSTAGE_LIGHT 2
11 #define SHADOWSTAGE_ERASESTENCIL 3
13 int r_shadowstage = SHADOWSTAGE_NONE;
14 int r_shadow_reloadlights = false;
16 int r_shadow_lightingmode = 0;
18 mempool_t *r_shadow_mempool;
20 int maxshadowelements;
22 int maxtrianglefacinglight;
23 qbyte *trianglefacinglight;
25 rtexturepool_t *r_shadow_texturepool;
26 rtexture_t *r_shadow_normalsattenuationtexture;
27 rtexture_t *r_shadow_normalscubetexture;
28 rtexture_t *r_shadow_attenuation2dtexture;
29 rtexture_t *r_shadow_blankbumptexture;
30 rtexture_t *r_shadow_blankglosstexture;
31 rtexture_t *r_shadow_blankwhitetexture;
33 cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "2"};
34 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1"};
35 cvar_t r_shadow_realtime = {0, "r_shadow_realtime", "0"};
36 cvar_t r_shadow_erasebydrawing = {0, "r_shadow_erasebydrawing", "0"};
37 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "0"};
38 cvar_t r_shadow_gloss = {0, "r_shadow_gloss", "1"};
39 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1"};
40 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1"};
42 void R_Shadow_ClearWorldLights(void);
43 void r_shadow_start(void)
45 // allocate vertex processing arrays
46 r_shadow_mempool = Mem_AllocPool("R_Shadow");
47 maxshadowelements = 0;
48 shadowelements = NULL;
49 maxtrianglefacinglight = 0;
50 trianglefacinglight = NULL;
51 r_shadow_normalsattenuationtexture = NULL;
52 r_shadow_normalscubetexture = NULL;
53 r_shadow_attenuation2dtexture = NULL;
54 r_shadow_blankbumptexture = NULL;
55 r_shadow_blankglosstexture = NULL;
56 r_shadow_blankwhitetexture = NULL;
57 r_shadow_texturepool = NULL;
58 R_Shadow_ClearWorldLights();
59 r_shadow_reloadlights = true;
62 void r_shadow_shutdown(void)
64 R_Shadow_ClearWorldLights();
65 r_shadow_reloadlights = true;
66 r_shadow_normalsattenuationtexture = NULL;
67 r_shadow_normalscubetexture = NULL;
68 r_shadow_attenuation2dtexture = NULL;
69 r_shadow_blankbumptexture = NULL;
70 r_shadow_blankglosstexture = NULL;
71 r_shadow_blankwhitetexture = NULL;
72 R_FreeTexturePool(&r_shadow_texturepool);
73 maxshadowelements = 0;
74 shadowelements = NULL;
75 maxtrianglefacinglight = 0;
76 trianglefacinglight = NULL;
77 Mem_FreePool(&r_shadow_mempool);
80 void R_Shadow_LoadWorldLights(const char *mapname);
81 void r_shadow_newmap(void)
83 R_Shadow_ClearWorldLights();
84 r_shadow_reloadlights = true;
87 void R_Shadow_Init(void)
89 Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
90 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
91 Cvar_RegisterVariable(&r_shadow_realtime);
92 Cvar_RegisterVariable(&r_shadow_texture3d);
93 Cvar_RegisterVariable(&r_shadow_gloss);
94 Cvar_RegisterVariable(&r_shadow_debuglight);
95 Cvar_RegisterVariable(&r_shadow_erasebydrawing);
96 Cvar_RegisterVariable(&r_shadow_scissor);
97 R_Shadow_EditLights_Init();
98 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
101 void R_Shadow_ProjectVertices(const float *in, float *out, int numverts, const float *relativelightorigin, float projectdistance)
104 for (i = 0;i < numverts;i++, in += 4, out += 4)
107 out[0] = in[0] + 1000000.0f * (in[0] - relativelightorigin[0]);
108 out[1] = in[1] + 1000000.0f * (in[1] - relativelightorigin[1]);
109 out[2] = in[2] + 1000000.0f * (in[2] - relativelightorigin[2]);
111 VectorSubtract(in, relativelightorigin, temp);
112 f = lightradius / sqrt(DotProduct(temp,temp));
115 VectorMA(relativelightorigin, f, temp, out);
117 VectorSubtract(in, relativelightorigin, temp);
118 f = projectdistance / sqrt(DotProduct(temp,temp));
119 VectorMA(in, f, temp, out);
124 void R_Shadow_MakeTriangleShadowFlags(const int *elements, const float *vertex, int numtris, qbyte *trianglefacinglight, const float *relativelightorigin, float lightradius)
127 const float *v0, *v1, *v2;
128 for (i = 0;i < numtris;i++, elements += 3)
130 // calculate triangle facing flag
131 v0 = vertex + elements[0] * 4;
132 v1 = vertex + elements[1] * 4;
133 v2 = vertex + elements[2] * 4;
134 // we do not need to normalize the surface normal because both sides
135 // of the comparison use it, therefore they are both multiplied the
136 // same amount... furthermore the subtract can be done on the
137 // vectors, saving a little bit of math in the dotproducts
140 // subtracts v1 from v0 and v2, combined into a crossproduct,
141 // combined with a dotproduct of the light location relative to the
142 // first point of the triangle (any point works, since the triangle
143 // is obviously flat), and finally a comparison to determine if the
144 // light is infront of the triangle (the goal of this statement)
145 trianglefacinglight[i] =
146 (relativelightorigin[0] - v0[0]) * ((v0[1] - v1[1]) * (v2[2] - v1[2]) - (v0[2] - v1[2]) * (v2[1] - v1[1]))
147 + (relativelightorigin[1] - v0[1]) * ((v0[2] - v1[2]) * (v2[0] - v1[0]) - (v0[0] - v1[0]) * (v2[2] - v1[2]))
148 + (relativelightorigin[2] - v0[2]) * ((v0[0] - v1[0]) * (v2[1] - v1[1]) - (v0[1] - v1[1]) * (v2[0] - v1[0])) > 0;
152 float dir0[3], dir1[3], temp[3], f;
154 // calculate two mostly perpendicular edge directions
155 VectorSubtract(v0, v1, dir0);
156 VectorSubtract(v2, v1, dir1);
158 // we have two edge directions, we can calculate a third vector from
159 // them, which is the direction of the surface normal (it's magnitude
161 CrossProduct(dir0, dir1, temp);
163 // this is entirely unnecessary, but kept for clarity
164 //VectorNormalize(temp);
166 // compare distance of light along normal, with distance of any point
167 // of the triangle along the same normal (the triangle is planar,
168 // I.E. flat, so all points give the same answer)
169 // the normal is not normalized because it is used on both sides of
170 // the comparison, so it's magnitude does not matter
171 //trianglefacinglight[i] = DotProduct(relativelightorigin, temp) >= DotProduct(v0, temp);
172 f = DotProduct(relativelightorigin, temp) - DotProduct(v0, temp);
173 trianglefacinglight[i] = f > 0 && f < lightradius * sqrt(DotProduct(temp, temp));
179 int R_Shadow_BuildShadowVolumeTriangles(const int *elements, const int *neighbors, int numtris, int numverts, const qbyte *trianglefacinglight, int *out)
182 // check each frontface for bordering backfaces,
183 // and cast shadow polygons from those edges,
184 // also create front and back caps for shadow volume
186 for (i = 0;i < numtris;i++, elements += 3, neighbors += 3)
188 if (trianglefacinglight[i])
190 // triangle is frontface and therefore casts shadow,
191 // output front and back caps for shadow volume
193 out[0] = elements[0];
194 out[1] = elements[1];
195 out[2] = elements[2];
196 // rear cap (with flipped winding order)
197 out[3] = elements[0] + numverts;
198 out[4] = elements[2] + numverts;
199 out[5] = elements[1] + numverts;
203 if (neighbors[0] < 0 || !trianglefacinglight[neighbors[0]])
205 out[0] = elements[1];
206 out[1] = elements[0];
207 out[2] = elements[0] + numverts;
208 out[3] = elements[1];
209 out[4] = elements[0] + numverts;
210 out[5] = elements[1] + numverts;
214 if (neighbors[1] < 0 || !trianglefacinglight[neighbors[1]])
216 out[0] = elements[2];
217 out[1] = elements[1];
218 out[2] = elements[1] + numverts;
219 out[3] = elements[2];
220 out[4] = elements[1] + numverts;
221 out[5] = elements[2] + numverts;
225 if (neighbors[2] < 0 || !trianglefacinglight[neighbors[2]])
227 out[0] = elements[0];
228 out[1] = elements[2];
229 out[2] = elements[2] + numverts;
230 out[3] = elements[0];
231 out[4] = elements[2] + numverts;
232 out[5] = elements[0] + numverts;
241 void R_Shadow_ResizeTriangleFacingLight(int numtris)
243 // make sure trianglefacinglight is big enough for this volume
244 if (maxtrianglefacinglight < numtris)
246 maxtrianglefacinglight = numtris;
247 if (trianglefacinglight)
248 Mem_Free(trianglefacinglight);
249 trianglefacinglight = Mem_Alloc(r_shadow_mempool, maxtrianglefacinglight);
253 void R_Shadow_ResizeShadowElements(int numtris)
255 // make sure shadowelements is big enough for this volume
256 if (maxshadowelements < numtris * 24)
258 maxshadowelements = numtris * 24;
260 Mem_Free(shadowelements);
261 shadowelements = Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int));
265 void R_Shadow_Volume(int numverts, int numtris, int *elements, int *neighbors, vec3_t relativelightorigin, float lightradius, float projectdistance)
268 if (projectdistance < 0.1)
270 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
276 // a triangle facing the light source
279 // a triangle not facing the light source
282 // an extrusion of the frontfaces, beginning at the original geometry and
283 // ending further from the light source than the original geometry
284 // (presumably at least as far as the light's radius, if the light has a
285 // radius at all), capped at both front and back to avoid any problems
288 // draws the shadow volumes of the model.
290 // vertex locations must already be in varray_vertex before use.
291 // varray_vertex must have capacity for numverts * 2.
293 // make sure trianglefacinglight is big enough for this volume
294 if (maxtrianglefacinglight < numtris)
295 R_Shadow_ResizeTriangleFacingLight(numtris);
297 // make sure shadowelements is big enough for this volume
298 if (maxshadowelements < numtris * 24)
299 R_Shadow_ResizeShadowElements(numtris);
301 // generate projected vertices
302 // by clever use of elements we'll construct the whole shadow from
303 // the unprojected vertices and these projected vertices
304 R_Shadow_ProjectVertices(varray_vertex, varray_vertex + numverts * 4, numverts, relativelightorigin, projectdistance);
306 // check which triangles are facing the light
307 R_Shadow_MakeTriangleShadowFlags(elements, varray_vertex, numtris, trianglefacinglight, relativelightorigin, lightradius);
309 // output triangle elements
310 tris = R_Shadow_BuildShadowVolumeTriangles(elements, neighbors, numtris, numverts, trianglefacinglight, shadowelements);
311 R_Shadow_RenderVolume(numverts * 2, tris, shadowelements);
314 void R_Shadow_RenderVolume(int numverts, int numtris, int *elements)
316 if (!numverts || !numtris)
318 if (r_shadowstage == SHADOWSTAGE_STENCIL)
320 // increment stencil if backface is behind depthbuffer
321 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
322 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
323 R_Mesh_Draw(numverts, numtris, elements);
324 // decrement stencil if frontface is behind depthbuffer
325 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
326 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
328 R_Mesh_Draw(numverts, numtris, elements);
331 void R_Shadow_RenderShadowMeshVolume(shadowmesh_t *firstmesh)
334 if (r_shadowstage == SHADOWSTAGE_STENCIL)
336 // increment stencil if backface is behind depthbuffer
337 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
338 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
339 for (mesh = firstmesh;mesh;mesh = mesh->next)
341 R_Mesh_ResizeCheck(mesh->numverts);
342 memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
343 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->elements);
345 // decrement stencil if frontface is behind depthbuffer
346 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
347 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
349 for (mesh = firstmesh;mesh;mesh = mesh->next)
351 R_Mesh_ResizeCheck(mesh->numverts);
352 memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
353 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->elements);
357 float r_shadow_atten1;
358 #define ATTEN3DSIZE 64
359 static void R_Shadow_Make3DTextures(void)
362 float v[3], intensity, ilen, bordercolor[4];
364 if (r_shadow_texture3d.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_shadow_lightattenuationscale.value;
409 r_shadow_blankbumptexture = R_LoadTexture2D(r_shadow_texturepool, "blankbump", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
414 r_shadow_blankglosstexture = R_LoadTexture2D(r_shadow_texturepool, "blankgloss", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
419 r_shadow_blankwhitetexture = R_LoadTexture2D(r_shadow_texturepool, "blankwhite", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
420 for (side = 0;side < 6;side++)
422 for (y = 0;y < 128;y++)
424 for (x = 0;x < 128;x++)
426 s = (x + 0.5f) * (2.0f / 128.0f) - 1.0f;
427 t = (y + 0.5f) * (2.0f / 128.0f) - 1.0f;
461 intensity = 127.0f / sqrt(DotProduct(v, v));
462 data[((side*128+y)*128+x)*4+0] = 128.0f + intensity * v[0];
463 data[((side*128+y)*128+x)*4+1] = 128.0f + intensity * v[1];
464 data[((side*128+y)*128+x)*4+2] = 128.0f + intensity * v[2];
465 data[((side*128+y)*128+x)*4+3] = 255;
469 r_shadow_normalscubetexture = R_LoadTextureCubeMap(r_shadow_texturepool, "normalscube", 128, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
470 for (y = 0;y < 128;y++)
472 for (x = 0;x < 128;x++)
474 v[0] = (x + 0.5f) * (2.0f / 128.0f) - 1.0f;
475 v[1] = (y + 0.5f) * (2.0f / 128.0f) - 1.0f;
477 intensity = 1.0f - sqrt(DotProduct(v, v));
479 intensity *= intensity;
480 intensity = bound(0, intensity * r_shadow_atten1 * 256.0f, 255.0f);
481 d = bound(0, intensity, 255);
482 data[((0*128+y)*128+x)*4+0] = d;
483 data[((0*128+y)*128+x)*4+1] = d;
484 data[((0*128+y)*128+x)*4+2] = d;
485 data[((0*128+y)*128+x)*4+3] = d;
488 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", 128, 128, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA | TEXF_MIPMAP, NULL);
490 R_Shadow_Make3DTextures();
493 void R_Shadow_Stage_Begin(void)
497 if (r_shadow_texture3d.integer == 1 && !gl_texture3d)
499 Con_Printf("3D texture support not detected, falling back on slower 2D + 1D + normalization lighting\n");
500 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
502 //cl.worldmodel->numlights = min(cl.worldmodel->numlights, 1);
503 if (!r_shadow_attenuation2dtexture
504 || (r_shadow_texture3d.integer == 1 && !r_shadow_normalsattenuationtexture)
505 || r_shadow_lightattenuationscale.value != r_shadow_atten1)
506 R_Shadow_MakeTextures();
507 if (r_shadow_reloadlights && cl.worldmodel)
509 r_shadow_reloadlights = false;
510 R_Shadow_LoadWorldLights(cl.worldmodel->name);
513 memset(&m, 0, sizeof(m));
514 m.blendfunc1 = GL_ONE;
515 m.blendfunc2 = GL_ZERO;
517 GL_Color(0, 0, 0, 1);
518 r_shadowstage = SHADOWSTAGE_NONE;
521 void R_Shadow_Stage_ShadowVolumes(void)
524 memset(&m, 0, sizeof(m));
525 R_Mesh_TextureState(&m);
526 GL_Color(1, 1, 1, 1);
527 qglColorMask(0, 0, 0, 0);
528 qglDisable(GL_BLEND);
530 qglDepthFunc(GL_LESS);
531 qglEnable(GL_STENCIL_TEST);
532 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
533 qglStencilFunc(GL_ALWAYS, 0, 0xFF);
534 qglEnable(GL_CULL_FACE);
535 qglEnable(GL_DEPTH_TEST);
536 r_shadowstage = SHADOWSTAGE_STENCIL;
537 if (!r_shadow_erasebydrawing.integer)
538 qglClear(GL_STENCIL_BUFFER_BIT);
541 void R_Shadow_Stage_Light(void)
544 memset(&m, 0, sizeof(m));
545 R_Mesh_TextureState(&m);
546 qglActiveTexture(GL_TEXTURE0_ARB);
549 qglBlendFunc(GL_ONE, GL_ONE);
550 GL_Color(1, 1, 1, 1);
551 qglColorMask(1, 1, 1, 1);
553 qglDepthFunc(GL_EQUAL);
554 qglEnable(GL_STENCIL_TEST);
555 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
556 // only draw light where this geometry was already rendered AND the
557 // stencil is 0 (non-zero means shadow)
558 qglStencilFunc(GL_EQUAL, 0, 0xFF);
559 qglEnable(GL_CULL_FACE);
560 qglEnable(GL_DEPTH_TEST);
561 r_shadowstage = SHADOWSTAGE_LIGHT;
564 int R_Shadow_Stage_EraseShadowVolumes(void)
566 if (r_shadow_erasebydrawing.integer)
569 memset(&m, 0, sizeof(m));
570 R_Mesh_TextureState(&m);
571 GL_Color(1, 1, 1, 1);
572 qglColorMask(0, 0, 0, 0);
573 qglDisable(GL_BLEND);
575 qglDepthFunc(GL_LESS);
576 qglEnable(GL_STENCIL_TEST);
577 qglStencilOp(GL_ZERO, GL_ZERO, GL_ZERO);
578 qglStencilFunc(GL_ALWAYS, 0, 0xFF);
579 qglDisable(GL_CULL_FACE);
580 qglDisable(GL_DEPTH_TEST);
581 r_shadowstage = SHADOWSTAGE_ERASESTENCIL;
588 void R_Shadow_Stage_End(void)
591 // attempt to restore state to what Mesh_State thinks it is
592 qglDisable(GL_BLEND);
593 qglBlendFunc(GL_ONE, GL_ZERO);
595 // now restore the rest of the state to normal
596 GL_Color(1, 1, 1, 1);
597 qglColorMask(1, 1, 1, 1);
598 qglDisable(GL_SCISSOR_TEST);
599 qglDepthFunc(GL_LEQUAL);
600 qglDisable(GL_STENCIL_TEST);
601 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
602 qglStencilFunc(GL_ALWAYS, 0, 0xFF);
603 qglEnable(GL_CULL_FACE);
604 qglEnable(GL_DEPTH_TEST);
605 // force mesh state to reset by using various combinations of features
606 memset(&m, 0, sizeof(m));
607 m.blendfunc1 = GL_SRC_ALPHA;
608 m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
610 m.blendfunc1 = GL_ONE;
611 m.blendfunc2 = GL_ZERO;
613 r_shadowstage = SHADOWSTAGE_NONE;
616 int R_Shadow_ScissorForBBoxAndSphere(const float *mins, const float *maxs, const float *origin, float radius)
618 int i, ix1, iy1, ix2, iy2;
619 float x1, y1, x2, y2, x, y;
622 if (!r_shadow_scissor.integer)
624 // if view is inside the box, just say yes it's visible
625 if (r_origin[0] >= mins[0] && r_origin[0] <= maxs[0]
626 && r_origin[1] >= mins[1] && r_origin[1] <= maxs[1]
627 && r_origin[2] >= mins[2] && r_origin[2] <= maxs[2])
629 qglDisable(GL_SCISSOR_TEST);
632 VectorSubtract(r_origin, origin, v);
633 if (DotProduct(v, v) < radius * radius)
635 qglDisable(GL_SCISSOR_TEST);
638 // create viewspace bbox
639 for (i = 0;i < 8;i++)
641 v[0] = ((i & 1) ? mins[0] : maxs[0]) - r_origin[0];
642 v[1] = ((i & 2) ? mins[1] : maxs[1]) - r_origin[1];
643 v[2] = ((i & 4) ? mins[2] : maxs[2]) - r_origin[2];
644 v2[0] = DotProduct(v, vright);
645 v2[1] = DotProduct(v, vup);
646 v2[2] = DotProduct(v, vpn);
649 if (smins[0] > v2[0]) smins[0] = v2[0];
650 if (smaxs[0] < v2[0]) smaxs[0] = v2[0];
651 if (smins[1] > v2[1]) smins[1] = v2[1];
652 if (smaxs[1] < v2[1]) smaxs[1] = v2[1];
653 if (smins[2] > v2[2]) smins[2] = v2[2];
654 if (smaxs[2] < v2[2]) smaxs[2] = v2[2];
658 smins[0] = smaxs[0] = v2[0];
659 smins[1] = smaxs[1] = v2[1];
660 smins[2] = smaxs[2] = v2[2];
663 // now we have a bbox in viewspace
664 // clip it to the viewspace version of the sphere
665 v[0] = origin[0] - r_origin[0];
666 v[1] = origin[1] - r_origin[1];
667 v[2] = origin[2] - r_origin[2];
668 v2[0] = DotProduct(v, vright);
669 v2[1] = DotProduct(v, vup);
670 v2[2] = DotProduct(v, vpn);
671 if (smins[0] < v2[0] - radius) smins[0] = v2[0] - radius;
672 if (smaxs[0] < v2[0] - radius) smaxs[0] = v2[0] + radius;
673 if (smins[1] < v2[1] - radius) smins[1] = v2[1] - radius;
674 if (smaxs[1] < v2[1] - radius) smaxs[1] = v2[1] + radius;
675 if (smins[2] < v2[2] - radius) smins[2] = v2[2] - radius;
676 if (smaxs[2] < v2[2] - radius) smaxs[2] = v2[2] + radius;
677 // clip it to the view plane
680 // return true if that culled the box
681 if (smins[2] >= smaxs[2])
683 // ok some of it is infront of the view, transform each corner back to
684 // worldspace and then to screenspace and make screen rect
685 for (i = 0;i < 8;i++)
687 v2[0] = (i & 1) ? smins[0] : smaxs[0];
688 v2[1] = (i & 2) ? smins[1] : smaxs[1];
689 v2[2] = (i & 4) ? smins[2] : smaxs[2];
690 v[0] = v2[0] * vright[0] + v2[1] * vup[0] + v2[2] * vpn[0] + r_origin[0];
691 v[1] = v2[0] * vright[1] + v2[1] * vup[1] + v2[2] * vpn[1] + r_origin[1];
692 v[2] = v2[0] * vright[2] + v2[1] * vup[2] + v2[2] * vpn[2] + r_origin[2];
694 GL_TransformToScreen(v, v2);
695 //Con_Printf("%.3f %.3f %.3f %.3f transformed to %.3f %.3f %.3f %.3f\n", v[0], v[1], v[2], v[3], v2[0], v2[1], v2[2], v2[3]);
712 // this code doesn't handle boxes with any points behind view properly
713 x1 = 1000;x2 = -1000;
714 y1 = 1000;y2 = -1000;
715 for (i = 0;i < 8;i++)
717 v[0] = (i & 1) ? mins[0] : maxs[0];
718 v[1] = (i & 2) ? mins[1] : maxs[1];
719 v[2] = (i & 4) ? mins[2] : maxs[2];
721 GL_TransformToScreen(v, v2);
722 //Con_Printf("%.3f %.3f %.3f %.3f transformed to %.3f %.3f %.3f %.3f\n", v[0], v[1], v[2], v[3], v2[0], v2[1], v2[2], v2[3]);
739 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
740 if (ix1 < r_refdef.x) ix1 = r_refdef.x;
741 if (iy1 < r_refdef.y) iy1 = r_refdef.y;
742 if (ix2 > r_refdef.x + r_refdef.width) ix2 = r_refdef.x + r_refdef.width;
743 if (iy2 > r_refdef.y + r_refdef.height) iy2 = r_refdef.y + r_refdef.height;
744 if (ix2 <= ix1 || iy2 <= iy1)
746 // set up the scissor rectangle
747 qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
748 qglEnable(GL_SCISSOR_TEST);
752 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)
755 float lightvec[3], iradius;
756 iradius = 0.5f / lightradius;
757 for (i = 0;i < numverts;i++, vertex += 4, svectors += 4, tvectors += 4, normals += 4, out2d += 4, out1d += 4)
759 VectorSubtract(vertex, relativelightorigin, lightvec);
760 out2d[0] = 0.5f + DotProduct(svectors, lightvec) * iradius;
761 out2d[1] = 0.5f + DotProduct(tvectors, lightvec) * iradius;
763 out1d[0] = 0.5f + DotProduct(normals, lightvec) * iradius;
769 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)
772 float lightvec[3], iradius;
773 iradius = 0.5f / lightradius;
774 for (i = 0;i < numverts;i++, vertex += 4, svectors += 4, tvectors += 4, normals += 4, out += 4)
776 VectorSubtract(vertex, relativelightorigin, lightvec);
777 out[0] = 0.5f + DotProduct(svectors, lightvec) * iradius;
778 out[1] = 0.5f + DotProduct(tvectors, lightvec) * iradius;
779 out[2] = 0.5f + DotProduct(normals, lightvec) * iradius;
783 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)
787 for (i = 0;i < numverts;i++, vertex += 4, svectors += 4, tvectors += 4, normals += 4, out += 4)
789 VectorSubtract(vertex, relativelightorigin, lightdir);
790 // the cubemap normalizes this for us
791 out[0] = DotProduct(svectors, lightdir);
792 out[1] = DotProduct(tvectors, lightdir);
793 out[2] = DotProduct(normals, lightdir);
797 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)
800 float lightdir[3], eyedir[3], halfdir[3], lightdirlen, iradius;
801 iradius = 0.5f / lightradius;
802 for (i = 0;i < numverts;i++, vertex += 4, svectors += 4, tvectors += 4, normals += 4, out += 4)
804 VectorSubtract(vertex, relativelightorigin, lightdir);
805 // this is used later to make the attenuation correct
806 lightdirlen = sqrt(DotProduct(lightdir, lightdir)) * iradius;
807 VectorNormalizeFast(lightdir);
808 VectorSubtract(vertex, relativeeyeorigin, eyedir);
809 VectorNormalizeFast(eyedir);
810 VectorAdd(lightdir, eyedir, halfdir);
811 VectorNormalizeFast(halfdir);
812 out[0] = 0.5f + DotProduct(svectors, halfdir) * lightdirlen;
813 out[1] = 0.5f + DotProduct(tvectors, halfdir) * lightdirlen;
814 out[2] = 0.5f + DotProduct(normals, halfdir) * lightdirlen;
818 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)
821 float lightdir[3], eyedir[3], halfdir[3];
822 for (i = 0;i < numverts;i++, vertex += 4, svectors += 4, tvectors += 4, normals += 4, out += 4)
824 VectorSubtract(vertex, relativelightorigin, lightdir);
825 VectorNormalizeFast(lightdir);
826 VectorSubtract(vertex, relativeeyeorigin, eyedir);
827 VectorNormalizeFast(eyedir);
828 VectorAdd(lightdir, eyedir, halfdir);
829 // the cubemap normalizes this for us
830 out[0] = DotProduct(svectors, halfdir);
831 out[1] = DotProduct(tvectors, halfdir);
832 out[2] = DotProduct(normals, halfdir);
836 void R_Shadow_GenTexCoords_LightCubeMap(float *out, int numverts, const float *vertex, const vec3_t relativelightorigin)
839 // FIXME: this needs to be written
840 // this code assumes the vertices are in worldspace (a false assumption)
841 for (i = 0;i < numverts;i++, vertex += 4, out += 4)
842 VectorSubtract(vertex, relativelightorigin, out);
845 void R_Shadow_DiffuseLighting(int numverts, int numtriangles, const int *elements, const float *svectors, const float *tvectors, const float *normals, const float *texcoords, const float *relativelightorigin, float lightradius, const float *lightcolor, rtexture_t *basetexture, rtexture_t *bumptexture, rtexture_t *lightcubemap)
848 float scale, colorscale;
850 memset(&m, 0, sizeof(m));
852 bumptexture = r_shadow_blankbumptexture;
853 // colorscale accounts for how much we multiply the brightness during combine
854 // mult is how many times the final pass of the lighting will be
855 // performed to get more brightness than otherwise possible
856 // limit mult to 64 for sanity sake
857 if (r_shadow_texture3d.integer)
859 if (r_textureunits.integer >= 4 && !lightcubemap)
861 // 4 texture 3D combine path, one pass, no light cubemap support
862 m.tex[0] = R_GetTexture(bumptexture);
863 m.tex3d[1] = R_GetTexture(r_shadow_normalsattenuationtexture);
864 m.tex[2] = R_GetTexture(basetexture);
865 m.tex[3] = R_GetTexture(r_shadow_blankwhitetexture);
866 m.texcombinergb[0] = GL_REPLACE;
867 m.texcombinergb[1] = GL_DOT3_RGB_ARB;
868 m.texcombinergb[2] = GL_MODULATE;
869 m.texcombinergb[3] = GL_MODULATE;
870 m.texrgbscale[1] = 1;
871 m.texrgbscale[3] = 4;
872 R_Mesh_TextureState(&m);
873 memcpy(varray_texcoord[0], texcoords, numverts * sizeof(float[4]));
874 memcpy(varray_texcoord[2], texcoords, numverts * sizeof(float[4]));
875 R_Shadow_GenTexCoords_Diffuse_Attenuation3D(varray_texcoord[1], numverts, varray_vertex, svectors, tvectors, normals, relativelightorigin, lightradius);
876 qglActiveTexture(GL_TEXTURE3_ARB);
877 qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PRIMARY_COLOR_ARB);
878 colorscale = r_colorscale * 0.25f * r_shadow_lightintensityscale.value;
879 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]);
881 GL_Color(lightcolor[0] * colorscale, lightcolor[1] * colorscale, lightcolor[2] * colorscale, 1);
882 for (renders = 0;renders < mult;renders++)
883 R_Mesh_Draw(numverts, numtriangles, elements);
884 qglActiveTexture(GL_TEXTURE3_ARB);
885 qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
889 // 2 texture no3D combine path, two pass
890 m.tex[0] = R_GetTexture(bumptexture);
891 m.tex3d[1] = R_GetTexture(r_shadow_normalsattenuationtexture);
892 m.texcombinergb[0] = GL_REPLACE;
893 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
894 m.texalphascale[1] = 1;
895 R_Mesh_TextureState(&m);
896 qglColorMask(0,0,0,1);
897 qglDisable(GL_BLEND);
899 memcpy(varray_texcoord[0], texcoords, numverts * sizeof(float[4]));
900 R_Shadow_GenTexCoords_Diffuse_Attenuation3D(varray_texcoord[1], numverts, varray_vertex, svectors, tvectors, normals, relativelightorigin, lightradius);
901 R_Mesh_Draw(numverts, numtriangles, elements);
903 m.tex[0] = R_GetTexture(basetexture);
905 m.texcubemap[1] = R_GetTexture(lightcubemap);
906 m.texcombinergb[0] = GL_MODULATE;
907 m.texcombinergb[1] = GL_MODULATE;
908 m.texrgbscale[1] = 1;
909 m.texalphascale[1] = 1;
910 R_Mesh_TextureState(&m);
911 qglColorMask(1,1,1,1);
912 qglBlendFunc(GL_DST_ALPHA, GL_ONE);
915 R_Shadow_GenTexCoords_LightCubeMap(varray_texcoord[1], numverts, varray_vertex, relativelightorigin);
917 colorscale = r_colorscale * 1.0f * r_shadow_lightintensityscale.value;
918 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]);
920 GL_Color(lightcolor[0] * colorscale, lightcolor[1] * colorscale, lightcolor[2] * colorscale, 1);
921 for (renders = 0;renders < mult;renders++)
922 R_Mesh_Draw(numverts, numtriangles, elements);
925 else if (r_textureunits.integer >= 4)
927 // 4 texture no3D combine path, two pass
928 m.tex[0] = R_GetTexture(bumptexture);
929 m.texcubemap[1] = R_GetTexture(r_shadow_normalscubetexture);
930 m.texcombinergb[0] = GL_REPLACE;
931 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
932 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
933 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
934 R_Mesh_TextureState(&m);
935 qglColorMask(0,0,0,1);
936 qglDisable(GL_BLEND);
938 memcpy(varray_texcoord[0], texcoords, numverts * sizeof(float[4]));
939 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord[1], numverts, varray_vertex, svectors, tvectors, normals, relativelightorigin);
940 R_Shadow_GenTexCoords_Attenuation2D1D(varray_texcoord[2], varray_texcoord[3], numverts, varray_vertex, svectors, tvectors, normals, relativelightorigin, lightradius);
941 R_Mesh_Draw(numverts, numtriangles, elements);
943 m.tex[0] = R_GetTexture(basetexture);
944 m.texcubemap[1] = R_GetTexture(lightcubemap);
945 m.texcombinergb[0] = GL_MODULATE;
946 m.texcombinergb[1] = GL_MODULATE;
949 R_Mesh_TextureState(&m);
950 qglColorMask(1,1,1,1);
951 qglBlendFunc(GL_DST_ALPHA, GL_ONE);
954 R_Shadow_GenTexCoords_LightCubeMap(varray_texcoord[1], numverts, varray_vertex, relativelightorigin);
956 colorscale = r_colorscale * 1.0f * r_shadow_lightintensityscale.value;
957 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]);
959 GL_Color(lightcolor[0] * colorscale, lightcolor[1] * colorscale, lightcolor[2] * colorscale, 1);
960 for (renders = 0;renders < mult;renders++)
961 R_Mesh_Draw(numverts, numtriangles, elements);
965 // 2 texture no3D combine path, three pass
966 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
967 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
968 R_Mesh_TextureState(&m);
969 qglColorMask(0,0,0,1);
970 qglDisable(GL_BLEND);
972 R_Shadow_GenTexCoords_Attenuation2D1D(varray_texcoord[0], varray_texcoord[1], numverts, varray_vertex, svectors, tvectors, normals, relativelightorigin, lightradius);
973 R_Mesh_Draw(numverts, numtriangles, elements);
975 m.tex[0] = R_GetTexture(bumptexture);
977 m.texcubemap[1] = R_GetTexture(r_shadow_normalscubetexture);
978 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
979 R_Mesh_TextureState(&m);
980 qglBlendFunc(GL_DST_ALPHA, GL_ZERO);
982 memcpy(varray_texcoord[0], texcoords, numverts * sizeof(float[4]));
983 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord[1], numverts, varray_vertex, svectors, tvectors, normals, relativelightorigin);
984 R_Mesh_Draw(numverts, numtriangles, elements);
986 m.tex[0] = R_GetTexture(basetexture);
987 m.texcubemap[1] = R_GetTexture(lightcubemap);
988 m.texcombinergb[1] = GL_MODULATE;
989 R_Mesh_TextureState(&m);
990 qglColorMask(1,1,1,1);
991 qglBlendFunc(GL_DST_ALPHA, GL_ONE);
993 R_Shadow_GenTexCoords_LightCubeMap(varray_texcoord[1], numverts, varray_vertex, relativelightorigin);
995 colorscale = r_colorscale * 1.0f * r_shadow_lightintensityscale.value;
996 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]);
998 GL_Color(lightcolor[0] * colorscale, lightcolor[1] * colorscale, lightcolor[2] * colorscale, 1);
999 for (renders = 0;renders < mult;renders++)
1000 R_Mesh_Draw(numverts, numtriangles, elements);
1004 void R_Shadow_SpecularLighting(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 *glosstexture, rtexture_t *bumptexture, rtexture_t *lightcubemap)
1007 float scale, colorscale;
1009 memset(&m, 0, sizeof(m));
1011 bumptexture = r_shadow_blankbumptexture;
1013 glosstexture = r_shadow_blankglosstexture;
1014 if (r_shadow_gloss.integer >= 2 || (r_shadow_gloss.integer >= 1 && glosstexture != r_shadow_blankglosstexture))
1016 // 2 texture no3D combine path, five pass
1017 memset(&m, 0, sizeof(m));
1019 m.tex[0] = R_GetTexture(bumptexture);
1020 m.texcubemap[1] = R_GetTexture(r_shadow_normalscubetexture);
1021 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1022 R_Mesh_TextureState(&m);
1023 qglColorMask(0,0,0,1);
1024 qglDisable(GL_BLEND);
1026 memcpy(varray_texcoord[0], texcoords, numverts * sizeof(float[4]));
1027 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord[1], numverts, varray_vertex, svectors, tvectors, normals, relativelightorigin, relativeeyeorigin);
1028 R_Mesh_Draw(numverts, numtriangles, elements);
1031 m.texcubemap[1] = 0;
1032 m.texcombinergb[1] = GL_MODULATE;
1033 R_Mesh_TextureState(&m);
1034 // square alpha in framebuffer a few times to make it shiny
1035 qglBlendFunc(GL_ZERO, GL_DST_ALPHA);
1036 qglEnable(GL_BLEND);
1037 // these comments are a test run through this math for intensity 0.5
1039 R_Mesh_Draw(numverts, numtriangles, elements);
1040 // 0.25 * 0.25 = 0.0625
1041 R_Mesh_Draw(numverts, numtriangles, elements);
1042 // 0.0625 * 0.0625 = 0.00390625
1043 R_Mesh_Draw(numverts, numtriangles, elements);
1045 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1046 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1047 R_Mesh_TextureState(&m);
1048 qglBlendFunc(GL_DST_ALPHA, GL_ZERO);
1049 R_Shadow_GenTexCoords_Attenuation2D1D(varray_texcoord[0], varray_texcoord[1], numverts, varray_vertex, svectors, tvectors, normals, relativelightorigin, lightradius);
1050 R_Mesh_Draw(numverts, numtriangles, elements);
1052 m.tex[0] = R_GetTexture(glosstexture);
1053 m.texcubemap[1] = R_GetTexture(lightcubemap);
1054 R_Mesh_TextureState(&m);
1055 qglColorMask(1,1,1,1);
1056 qglBlendFunc(GL_DST_ALPHA, GL_ONE);
1057 memcpy(varray_texcoord[0], texcoords, numverts * sizeof(float[4]));
1059 R_Shadow_GenTexCoords_LightCubeMap(varray_texcoord[1], numverts, varray_vertex, relativelightorigin);
1061 // the 0.25f makes specular lighting much dimmer than diffuse (intentionally)
1062 colorscale = r_colorscale * 0.25f * r_shadow_lightintensityscale.value;
1063 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]);
1064 colorscale *= scale;
1065 GL_Color(lightcolor[0] * colorscale, lightcolor[1] * colorscale, lightcolor[2] * colorscale, 1);
1066 for (renders = 0;renders < mult;renders++)
1067 R_Mesh_Draw(numverts, numtriangles, elements);
1071 #define PRECOMPUTEDSHADOWVOLUMES 1
1072 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, worldlight_t *light)
1074 #if PRECOMPUTEDSHADOWVOLUMES
1075 R_Mesh_Matrix(matrix);
1076 R_Shadow_RenderShadowMeshVolume(light->shadowvolume);
1079 R_Mesh_Matrix(matrix);
1080 for (mesh = light->shadowvolume;mesh;mesh = mesh->next)
1082 R_Mesh_ResizeCheck(mesh->numverts * 2);
1083 memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
1084 R_Shadow_Volume(mesh->numverts, mesh->numtriangles, varray_vertex, mesh->elements, mesh->neighbors, light->origin, light->lightradius, light->lightradius);
1089 cvar_t r_editlights = {0, "r_editlights", "0"};
1090 cvar_t r_editlights_cursordistance = {0, "r_editlights_distance", "1024"};
1091 cvar_t r_editlights_cursorpushback = {0, "r_editlights_pushback", "0"};
1092 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_pushoff", "4"};
1093 cvar_t r_editlights_cursorgrid = {0, "r_editlights_grid", "4"};
1094 worldlight_t *r_shadow_worldlightchain;
1095 worldlight_t *r_shadow_selectedlight;
1096 vec3_t r_editlights_cursorlocation;
1098 static int castshadowcount = 1;
1099 void R_Shadow_NewWorldLight(vec3_t origin, float radius, vec3_t color, int style, const char *cubemapname)
1101 int i, j, k, l, maxverts, *mark;
1102 float *verts, *v, *v0, *v1, f, projectdistance, temp[3], temp2[3], temp3[3], radius2;
1109 e = Mem_Alloc(r_shadow_mempool, sizeof(worldlight_t));
1110 VectorCopy(origin, e->origin);
1111 VectorCopy(color, e->light);
1112 e->lightradius = radius;
1113 VectorCopy(origin, e->mins);
1114 VectorCopy(origin, e->maxs);
1117 e->next = r_shadow_worldlightchain;
1118 r_shadow_worldlightchain = e;
1121 e->cubemapname = Mem_Alloc(r_shadow_mempool, strlen(cubemapname) + 1);
1122 strcpy(e->cubemapname, cubemapname);
1123 // FIXME: add cubemap loading (and don't load a cubemap twice)
1128 leaf = Mod_PointInLeaf(origin, cl.worldmodel);
1129 pvs = Mod_LeafPVS(leaf, cl.worldmodel);
1130 for (i = 0, leaf = cl.worldmodel->leafs + 1;i < cl.worldmodel->numleafs;i++, leaf++)
1132 if (pvs[i >> 3] & (1 << (i & 7)))
1134 VectorCopy(origin, temp);
1135 if (temp[0] < leaf->mins[0]) temp[0] = leaf->mins[0];
1136 if (temp[0] > leaf->maxs[0]) temp[0] = leaf->maxs[0];
1137 if (temp[1] < leaf->mins[1]) temp[1] = leaf->mins[1];
1138 if (temp[1] > leaf->maxs[1]) temp[1] = leaf->maxs[1];
1139 if (temp[2] < leaf->mins[2]) temp[2] = leaf->mins[2];
1140 if (temp[2] > leaf->maxs[2]) temp[2] = leaf->maxs[2];
1141 VectorSubtract(temp, origin, temp);
1142 if (DotProduct(temp, temp) < e->lightradius * e->lightradius)
1144 leaf->worldnodeframe = castshadowcount;
1145 for (j = 0, mark = leaf->firstmarksurface;j < leaf->nummarksurfaces;j++, mark++)
1147 surf = cl.worldmodel->surfaces + *mark;
1148 if (surf->castshadow != castshadowcount)
1150 f = DotProduct(e->origin, surf->plane->normal) - surf->plane->dist;
1151 if (surf->flags & SURF_PLANEBACK)
1153 if (f > 0 && f < e->lightradius)
1155 VectorSubtract(e->origin, surf->poly_center, temp);
1156 if (DotProduct(temp, temp) - surf->poly_radius2 < e->lightradius * e->lightradius)
1157 surf->castshadow = castshadowcount;
1166 for (i = 0, leaf = cl.worldmodel->leafs + 1;i < cl.worldmodel->numleafs;i++, leaf++)
1167 if (leaf->worldnodeframe == castshadowcount)
1170 for (i = 0, surf = cl.worldmodel->surfaces + cl.worldmodel->firstmodelsurface;i < cl.worldmodel->nummodelsurfaces;i++, surf++)
1171 if (surf->castshadow == castshadowcount)
1175 e->leafs = Mem_Alloc(r_shadow_mempool, e->numleafs * sizeof(mleaf_t *));
1177 e->surfaces = Mem_Alloc(r_shadow_mempool, e->numsurfaces * sizeof(msurface_t *));
1179 for (i = 0, leaf = cl.worldmodel->leafs + 1;i < cl.worldmodel->numleafs;i++, leaf++)
1180 if (leaf->worldnodeframe == castshadowcount)
1181 e->leafs[e->numleafs++] = leaf;
1183 for (i = 0, surf = cl.worldmodel->surfaces + cl.worldmodel->firstmodelsurface;i < cl.worldmodel->nummodelsurfaces;i++, surf++)
1184 if (surf->castshadow == castshadowcount)
1185 e->surfaces[e->numsurfaces++] = surf;
1186 // find bounding box and sphere of lit surfaces
1187 // (these will be used for creating a shape to clip the light)
1189 VectorCopy(e->origin, e->mins);
1190 VectorCopy(e->origin, e->maxs);
1191 for (j = 0;j < e->numsurfaces;j++)
1193 surf = e->surfaces[j];
1194 for (k = 0, v = surf->poly_verts;k < surf->poly_numverts;k++, v += 3)
1196 if (e->mins[0] > v[0]) e->mins[0] = v[0];if (e->maxs[0] < v[0]) e->maxs[0] = v[0];
1197 if (e->mins[1] > v[1]) e->mins[1] = v[1];if (e->maxs[1] < v[1]) e->maxs[1] = v[1];
1198 if (e->mins[2] > v[2]) e->mins[2] = v[2];if (e->maxs[2] < v[2]) e->maxs[2] = v[2];
1199 VectorSubtract(v, e->origin, temp);
1200 f = DotProduct(temp, temp);
1205 e->cullradius = sqrt(radius2);
1206 if (e->cullradius > e->lightradius)
1207 e->cullradius = e->lightradius;
1208 if (e->mins[0] < e->origin[0] - e->lightradius) e->mins[0] = e->origin[0] - e->lightradius;
1209 if (e->maxs[0] > e->origin[0] + e->lightradius) e->maxs[0] = e->origin[0] + e->lightradius;
1210 if (e->mins[1] < e->origin[1] - e->lightradius) e->mins[1] = e->origin[1] - e->lightradius;
1211 if (e->maxs[1] > e->origin[1] + e->lightradius) e->maxs[1] = e->origin[1] + e->lightradius;
1212 if (e->mins[2] < e->origin[2] - e->lightradius) e->mins[2] = e->origin[2] - e->lightradius;
1213 if (e->maxs[2] > e->origin[2] + e->lightradius) e->maxs[2] = e->origin[2] + e->lightradius;
1214 Con_Printf("%f %f %f, %f %f %f, %f, %f, %d, %d\n", e->mins[0], e->mins[1], e->mins[2], e->maxs[0], e->maxs[1], e->maxs[2], e->cullradius, e->lightradius, e->numleafs, e->numsurfaces);
1215 // clip shadow volumes against eachother to remove unnecessary
1216 // polygons (and sections of polygons)
1220 for (j = 0;j < e->numsurfaces;j++)
1222 surf = e->surfaces[j];
1223 if (surf->flags & SURF_SHADOWCAST)
1225 surf->castshadow = castshadowcount;
1226 if (maxverts < surf->poly_numverts)
1227 maxverts = surf->poly_numverts;
1230 e->shadowvolume = Mod_ShadowMesh_Begin(loadmodel->mempool, 32768);
1231 #if !PRECOMPUTEDSHADOWVOLUMES
1232 // make a mesh to cast a shadow volume from
1233 for (j = 0;j < e->numsurfaces;j++)
1234 if (e->surfaces[j]->castshadow == castshadowcount)
1235 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, e->surfaces[j]->poly_numverts, e->surfaces[j]->poly_verts);
1240 shadowmesh_t *castmesh, *mesh;
1241 surfmesh_t *surfmesh;
1242 // make a mesh to cast a shadow volume from
1243 castmesh = Mod_ShadowMesh_Begin(loadmodel->mempool, 32768);
1244 for (j = 0;j < e->numsurfaces;j++)
1245 if (e->surfaces[j]->castshadow == castshadowcount)
1246 for (surfmesh = e->surfaces[j]->mesh;surfmesh;surfmesh = surfmesh->chain)
1247 Mod_ShadowMesh_AddMesh(loadmodel->mempool, castmesh, surfmesh->numverts, surfmesh->verts, surfmesh->numtriangles, surfmesh->index);
1248 castmesh = Mod_ShadowMesh_Finish(loadmodel->mempool, castmesh);
1250 // cast shadow volume from castmesh
1251 for (mesh = castmesh;mesh;mesh = mesh->next)
1253 R_Shadow_ResizeTriangleFacingLight(castmesh->numtriangles);
1254 R_Shadow_ResizeShadowElements(castmesh->numtriangles);
1256 if (maxverts < castmesh->numverts * 2)
1258 maxverts = castmesh->numverts * 2;
1263 if (verts == NULL && maxverts > 0)
1264 verts = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[4]));
1266 // now that we have the buffers big enough, construct shadow volume mesh
1267 memcpy(verts, castmesh->verts, castmesh->numverts * sizeof(float[4]));
1268 R_Shadow_ProjectVertices(verts, verts + castmesh->numverts * 4, castmesh->numverts, e->origin, e->lightradius);
1269 R_Shadow_MakeTriangleShadowFlags(castmesh->elements, verts, castmesh->numtriangles, trianglefacinglight, e->origin, e->lightradius);
1270 tris = R_Shadow_BuildShadowVolumeTriangles(castmesh->elements, castmesh->neighbors, castmesh->numtriangles, castmesh->numverts, trianglefacinglight, shadowelements);
1271 // add the constructed shadow volume mesh
1272 Mod_ShadowMesh_AddMesh(loadmodel->mempool, e->shadowvolume, castmesh->numverts, verts, tris, shadowelements);
1274 // we're done with castmesh now
1275 Mod_ShadowMesh_Free(castmesh);
1278 // make a shadow volume mesh
1279 if (verts == NULL && maxverts > 0)
1280 verts = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[4]));
1281 for (j = 0;j < e->numsurfaces;j++)
1283 surf = e->surfaces[j];
1284 if (surf->castshadow != castshadowcount)
1286 projectdistance = 1000000.0f;//e->lightradius;
1287 // copy the original polygon, for the front cap of the volume
1288 for (k = 0, v0 = surf->poly_verts, v1 = verts;k < surf->poly_numverts;k++, v0 += 3, v1 += 3)
1290 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, surf->poly_numverts, verts);
1291 // project the original polygon, reversed, for the back cap of the volume
1292 for (k = 0, v0 = surf->poly_verts + (surf->poly_numverts - 1) * 3, v1 = verts;k < surf->poly_numverts;k++, v0 -= 3, v1 += 3)
1294 VectorSubtract(v0, e->origin, temp);
1295 //VectorNormalize(temp);
1296 VectorMA(v0, projectdistance, temp, v1);
1298 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, surf->poly_numverts, verts);
1299 // project the shadow volume sides
1300 for (l = surf->poly_numverts - 1, k = 0, v0 = surf->poly_verts + (surf->poly_numverts - 1) * 3, v1 = surf->poly_verts;k < surf->poly_numverts;l = k, k++, v0 = v1, v1 += 3)
1302 if (surf->neighborsurfaces == NULL || surf->neighborsurfaces[l] == NULL || surf->neighborsurfaces[l]->castshadow != castshadowcount)
1304 VectorCopy(v1, &verts[0]);
1305 VectorCopy(v0, &verts[3]);
1306 VectorCopy(v0, &verts[6]);
1307 VectorCopy(v1, &verts[9]);
1308 VectorSubtract(&verts[6], e->origin, temp);
1309 //VectorNormalize(temp);
1310 VectorMA(&verts[6], projectdistance, temp, &verts[6]);
1311 VectorSubtract(&verts[9], e->origin, temp);
1312 //VectorNormalize(temp);
1313 VectorMA(&verts[9], projectdistance, temp, &verts[9]);
1316 VectorSubtract(&verts[0], &verts[3], temp);
1317 VectorSubtract(&verts[6], &verts[3], temp2);
1318 CrossProduct(temp, temp2, temp3);
1319 VectorNormalize(temp3);
1320 if (DotProduct(surf->poly_center, temp3) > DotProduct(&verts[0], temp3))
1322 VectorCopy(v0, &verts[0]);
1323 VectorCopy(v1, &verts[3]);
1324 VectorCopy(v1, &verts[6]);
1325 VectorCopy(v0, &verts[9]);
1326 VectorSubtract(&verts[6], e->origin, temp);
1327 //VectorNormalize(temp);
1328 VectorMA(&verts[6], projectdistance, temp, &verts[6]);
1329 VectorSubtract(&verts[9], e->origin, temp);
1330 //VectorNormalize(temp);
1331 VectorMA(&verts[9], projectdistance, temp, &verts[9]);
1332 Con_Printf("flipped shadow volume edge %8p %i\n", surf, l);
1336 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
1342 e->shadowvolume = Mod_ShadowMesh_Finish(loadmodel->mempool, e->shadowvolume);
1343 for (l = 0, mesh = e->shadowvolume;mesh;mesh = mesh->next)
1344 l += mesh->numtriangles;
1345 Con_Printf("static shadow volume built containing %i triangles\n", l);
1349 void R_Shadow_FreeWorldLight(worldlight_t *light)
1351 worldlight_t **lightpointer;
1352 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
1353 if (*lightpointer != light)
1354 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
1355 *lightpointer = light->next;
1356 if (light->cubemapname)
1357 Mem_Free(light->cubemapname);
1358 if (light->shadowvolume)
1359 Mod_ShadowMesh_Free(light->shadowvolume);
1360 if (light->surfaces)
1361 Mem_Free(light->surfaces);
1363 Mem_Free(light->leafs);
1367 void R_Shadow_ClearWorldLights(void)
1369 while (r_shadow_worldlightchain)
1370 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
1371 r_shadow_selectedlight = NULL;
1374 void R_Shadow_SelectLight(worldlight_t *light)
1376 if (r_shadow_selectedlight)
1377 r_shadow_selectedlight->selected = false;
1378 r_shadow_selectedlight = light;
1379 if (r_shadow_selectedlight)
1380 r_shadow_selectedlight->selected = true;
1383 void R_Shadow_FreeSelectedWorldLight(void)
1385 if (r_shadow_selectedlight)
1387 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
1388 r_shadow_selectedlight = NULL;
1392 void R_Shadow_SelectLightInView(void)
1394 float bestrating, rating, temp[3], dist;
1395 worldlight_t *best, *light;
1398 for (light = r_shadow_worldlightchain;light;light = light->next)
1400 VectorSubtract(light->origin, r_refdef.vieworg, temp);
1401 dist = sqrt(DotProduct(temp, temp));
1402 if (DotProduct(temp, vpn) >= 0.97 * dist && bestrating > dist && CL_TraceLine(light->origin, r_refdef.vieworg, NULL, NULL, 0, true, NULL) == 1.0f)
1408 R_Shadow_SelectLight(best);
1411 void R_Shadow_LoadWorldLights(const char *mapname)
1414 char name[MAX_QPATH], cubemapname[MAX_QPATH], *lightsstring, *s, *t;
1415 float origin[3], radius, color[3];
1416 COM_StripExtension(mapname, name);
1417 strcat(name, ".rtlights");
1418 lightsstring = COM_LoadFile(name, false);
1426 while (*s && *s != '\n')
1431 a = sscanf(t, "%f %f %f %f %f %f %f %d %s", &origin[0], &origin[1], &origin[2], &radius, &color[0], &color[1], &color[2], &style, &cubemapname);
1437 Con_Printf("found %d parameters on line %i, should be 8 or 9 parameters (origin[0] origin[1] origin[2] radius color[0] color[1] color[2] style cubemapname)\n", a, n + 1);
1440 R_Shadow_NewWorldLight(origin, radius, color, style, cubemapname);
1445 Con_Printf("invalid rtlights file \"%s\"\n", name);
1446 Mem_Free(lightsstring);
1450 void R_Shadow_SaveWorldLights(const char *mapname)
1452 worldlight_t *light;
1453 int bufchars, bufmaxchars;
1455 char name[MAX_QPATH];
1457 if (!r_shadow_worldlightchain)
1459 COM_StripExtension(mapname, name);
1460 strcat(name, ".rtlights");
1461 bufchars = bufmaxchars = 0;
1463 for (light = r_shadow_worldlightchain;light;light = light->next)
1465 sprintf(line, "%g %g %g %g %g %g %g %d %s\n", light->origin[0], light->origin[1], light->origin[2], light->lightradius, light->light[0], light->light[1], light->light[2], light->style, light->cubemapname ? light->cubemapname : "");
1466 if (bufchars + strlen(line) > bufmaxchars)
1468 bufmaxchars = bufchars + strlen(line) + 2048;
1470 buf = Mem_Alloc(r_shadow_mempool, bufmaxchars);
1474 memcpy(buf, oldbuf, bufchars);
1480 memcpy(buf + bufchars, line, strlen(line));
1481 bufchars += strlen(line);
1485 COM_WriteFile(name, buf, bufchars);
1490 void R_Shadow_SetCursorLocationForView(void)
1492 vec_t dist, push, frac;
1493 vec3_t dest, endpos, normal;
1494 VectorMA(r_refdef.vieworg, r_editlights_cursordistance.value, vpn, dest);
1495 frac = CL_TraceLine(r_refdef.vieworg, dest, endpos, normal, 0, true, NULL);
1498 dist = frac * r_editlights_cursordistance.value;
1499 push = r_editlights_cursorpushback.value;
1503 VectorMA(endpos, push, vpn, endpos);
1504 VectorMA(endpos, r_editlights_cursorpushoff.value, normal, endpos);
1506 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
1507 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
1508 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
1511 extern void R_DrawCrosshairSprite(rtexture_t *texture, vec3_t origin, vec_t scale, float cr, float cg, float cb, float ca);
1512 void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
1515 pic = Draw_CachePic("gfx/crosshair1.tga");
1517 R_DrawCrosshairSprite(pic->tex, r_editlights_cursorlocation, r_editlights_cursorgrid.value * 0.5f, 1, 1, 1, 1);
1520 void R_Shadow_DrawCursor(void)
1522 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
1525 void R_Shadow_UpdateLightingMode(void)
1527 r_shadow_lightingmode = 0;
1528 if (r_shadow_realtime.integer)
1530 if (r_shadow_worldlightchain)
1531 r_shadow_lightingmode = 2;
1533 r_shadow_lightingmode = 1;
1537 void R_Shadow_UpdateWorldLightSelection(void)
1539 if (r_editlights.integer)
1541 R_Shadow_SelectLightInView();
1542 R_Shadow_SetCursorLocationForView();
1543 R_Shadow_DrawCursor();
1546 R_Shadow_SelectLight(NULL);
1549 void R_Shadow_EditLights_Clear_f(void)
1551 R_Shadow_ClearWorldLights();
1554 void R_Shadow_EditLights_Reload_f(void)
1558 R_Shadow_ClearWorldLights();
1559 R_Shadow_LoadWorldLights(cl.worldmodel->name);
1563 void R_Shadow_EditLights_Save_f(void)
1566 R_Shadow_SaveWorldLights(cl.worldmodel->name);
1569 void R_Shadow_EditLights_Spawn_f(void)
1571 vec3_t origin, color;
1574 const char *cubemapname;
1575 if (!r_editlights.integer)
1577 Con_Printf("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
1580 if (Cmd_Argc() <= 7)
1583 color[0] = color[1] = color[2] = 1;
1586 if (Cmd_Argc() >= 2)
1588 radius = atof(Cmd_Argv(1));
1589 if (Cmd_Argc() >= 3)
1591 color[0] = atof(Cmd_Argv(2));
1592 color[1] = color[0];
1593 color[2] = color[0];
1594 if (Cmd_Argc() >= 5)
1596 color[1] = atof(Cmd_Argv(3));
1597 color[2] = atof(Cmd_Argv(4));
1598 if (Cmd_Argc() >= 6)
1600 style = atoi(Cmd_Argv(5));
1601 if (Cmd_Argc() >= 7)
1602 cubemapname = Cmd_Argv(6);
1607 if (cubemapname && !cubemapname[0])
1609 if (radius >= 16 && color[0] >= 0 && color[1] >= 0 && color[2] >= 0 && style >= 0 && style < 256 && (color[0] >= 0.1 || color[1] >= 0.1 || color[2] >= 0.1))
1611 VectorCopy(r_editlights_cursorlocation, origin);
1612 R_Shadow_NewWorldLight(origin, radius, color, style, cubemapname);
1616 Con_Printf("usage: r_editlights_spawn radius red green blue [style [cubemap]]\n");
1619 void R_Shadow_EditLights_Edit_f(void)
1621 vec3_t origin, color;
1624 const char *cubemapname;
1625 if (!r_editlights.integer)
1627 Con_Printf("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
1630 if (!r_shadow_selectedlight)
1632 Con_Printf("No selected light.\n");
1635 if (Cmd_Argc() <= 7)
1638 color[0] = color[1] = color[2] = 1;
1641 if (Cmd_Argc() >= 2)
1643 radius = atof(Cmd_Argv(1));
1644 if (Cmd_Argc() >= 3)
1646 color[0] = atof(Cmd_Argv(2));
1647 color[1] = color[0];
1648 color[2] = color[0];
1649 if (Cmd_Argc() >= 5)
1651 color[1] = atof(Cmd_Argv(3));
1652 color[2] = atof(Cmd_Argv(4));
1653 if (Cmd_Argc() >= 6)
1655 style = atoi(Cmd_Argv(5));
1656 if (Cmd_Argc() >= 7)
1657 cubemapname = Cmd_Argv(6);
1662 if (cubemapname && !cubemapname[0])
1664 if (radius >= 16 && color[0] >= 0 && color[1] >= 0 && color[2] >= 0 && style >= 0 && style < 256 && (color[0] >= 0.1 || color[1] >= 0.1 || color[2] >= 0.1))
1666 VectorCopy(r_shadow_selectedlight->origin, origin);
1667 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
1668 r_shadow_selectedlight = NULL;
1669 R_Shadow_NewWorldLight(origin, radius, color, style, cubemapname);
1673 Con_Printf("usage: r_editlights_edit radius red green blue [style [cubemap]]\n");
1676 void R_Shadow_EditLights_Remove_f(void)
1678 if (!r_editlights.integer)
1680 Con_Printf("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
1683 if (!r_shadow_selectedlight)
1685 Con_Printf("No selected light.\n");
1688 R_Shadow_FreeSelectedWorldLight();
1691 void R_Shadow_EditLights_Init(void)
1693 Cvar_RegisterVariable(&r_editlights);
1694 Cvar_RegisterVariable(&r_editlights_cursordistance);
1695 Cvar_RegisterVariable(&r_editlights_cursorpushback);
1696 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
1697 Cvar_RegisterVariable(&r_editlights_cursorgrid);
1698 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
1699 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
1700 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
1701 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
1702 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
1703 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);