3 Terminology: Stencil Shadow Volume (sometimes called Stencil Shadows)
4 An extrusion of the lit faces, beginning at the original geometry and ending
5 further from the light source than the original geometry (presumably at least
6 as far as the light's radius, if the light has a radius at all), capped at
7 both front and back to avoid any problems (extrusion from dark faces also
8 works but has a different set of problems)
10 This is rendered using Carmack's Reverse technique, in which backfaces behind
11 zbuffer (zfail) increment the stencil, and frontfaces behind zbuffer (zfail)
12 decrement the stencil, the result is a stencil value of zero where shadows
13 did not intersect the visible geometry, suitable as a stencil mask for
14 rendering lighting everywhere but shadow.
16 In our case we use a biased stencil clear of 128 to avoid requiring the
17 stencil wrap extension (but probably should support it), and to address
18 Creative's patent on this sort of technology we also draw the frontfaces
19 first, and backfaces second (decrement, increment).
22 This algorithm may be covered by Creative's patent (US Patent #6384822)
23 on Carmack's Reverse paper (which I have not read), however that patent
24 seems to be about drawing a stencil shadow from a model in an otherwise
25 unshadowed scene, where as realtime lighting technology draws light where
30 Terminology: Stencil Light Volume (sometimes called Light Volumes)
31 Similar to a Stencil Shadow Volume, but inverted; rather than containing the
32 areas in shadow it contanis the areas in light, this can only be built
33 quickly for certain limited cases (such as portal visibility from a point),
34 but is quite useful for some effects (sunlight coming from sky polygons is
35 one possible example, translucent occluders is another example).
39 Terminology: Optimized Stencil Shadow Volume
40 A Stencil Shadow Volume that has been processed sufficiently to ensure it has
41 no duplicate coverage of areas (no need to shadow an area twice), often this
42 greatly improves performance but is an operation too costly to use on moving
43 lights (however completely optimal Stencil Light Volumes can be constructed
48 Terminology: Per Pixel Lighting (sometimes abbreviated PPL)
49 Per pixel evaluation of lighting equations, at a bare minimum this involves
50 DOT3 shading of diffuse lighting (per pixel dotproduct of negated incidence
51 vector and surface normal, using a texture of the surface bumps, called a
52 NormalMap) if supported by hardware; in our case there is support for cards
53 which are incapable of DOT3, the quality is quite poor however. Additionally
54 it is desirable to have specular evaluation per pixel, per vertex
55 normalization of specular halfangle vectors causes noticable distortion but
56 is unavoidable on hardware without GL_ARB_fragment_program.
60 Terminology: Normalization CubeMap
61 A cubemap containing normalized dot3-encoded (vectors of length 1 or less
62 encoded as RGB colors) for any possible direction, this technique allows per
63 pixel calculation of incidence vector for per pixel lighting purposes, which
64 would not otherwise be possible per pixel without GL_ARB_fragment_program.
68 Terminology: 2D Attenuation Texturing
69 A very crude approximation of light attenuation with distance which results
70 in cylindrical light shapes which fade vertically as a streak (some games
71 such as Doom3 allow this to be rotated to be less noticable in specific
72 cases), the technique is simply modulating lighting by two 2D textures (which
73 can be the same) on different axes of projection (XY and Z, typically), this
74 is the best technique available without 3D Attenuation Texturing or
75 GL_ARB_fragment_program technology.
79 Terminology: 3D Attenuation Texturing
80 A slightly crude approximation of light attenuation with distance, its flaws
81 are limited radius and resolution (performance tradeoffs).
85 Terminology: 3D Attenuation-Normalization Texturing
86 A 3D Attenuation Texture merged with a Normalization CubeMap, by making the
87 vectors shorter the lighting becomes darker, a very effective optimization of
88 diffuse lighting if 3D Attenuation Textures are already used.
92 Terminology: Light Cubemap Filtering
93 A technique for modeling non-uniform light distribution according to
94 direction, for example projecting a stained glass window image onto a wall,
95 this is done by texturing the lighting with a cubemap.
99 Terminology: Light Projection Filtering
100 A technique for modeling shadowing of light passing through translucent
101 surfaces, allowing stained glass windows and other effects to be done more
102 elegantly than possible with Light Cubemap Filtering by applying an occluder
103 texture to the lighting combined with a stencil light volume to limit the lit
104 area (this allows evaluating multiple translucent occluders in a scene).
108 Terminology: Doom3 Lighting
109 A combination of Stencil Shadow Volume, Per Pixel Lighting, Normalization
110 CubeMap, 2D Attenuation Texturing, and Light Filtering, as demonstrated by
111 the (currently upcoming) game Doom3.
114 #include "quakedef.h"
115 #include "r_shadow.h"
116 #include "cl_collision.h"
120 extern void R_Shadow_EditLights_Init(void);
122 #define SHADOWSTAGE_NONE 0
123 #define SHADOWSTAGE_STENCIL 1
124 #define SHADOWSTAGE_LIGHT 2
125 #define SHADOWSTAGE_STENCILTWOSIDE 3
127 int r_shadowstage = SHADOWSTAGE_NONE;
128 int r_shadow_reloadlights = false;
130 mempool_t *r_shadow_mempool;
132 int maxshadowelements;
146 int r_shadow_buffer_numclusterpvsbytes;
147 qbyte *r_shadow_buffer_clusterpvs;
148 int *r_shadow_buffer_clusterlist;
150 int r_shadow_buffer_numsurfacepvsbytes;
151 qbyte *r_shadow_buffer_surfacepvs;
152 int *r_shadow_buffer_surfacelist;
154 rtexturepool_t *r_shadow_texturepool;
155 rtexture_t *r_shadow_normalcubetexture;
156 rtexture_t *r_shadow_attenuation2dtexture;
157 rtexture_t *r_shadow_attenuation3dtexture;
158 rtexture_t *r_shadow_blankbumptexture;
159 rtexture_t *r_shadow_blankglosstexture;
160 rtexture_t *r_shadow_blankwhitetexture;
162 // used only for light filters (cubemaps)
163 rtexturepool_t *r_shadow_filters_texturepool;
165 cvar_t r_shadow_realtime_world_lightmaps = {0, "r_shadow_realtime_world_lightmaps", "0"};
166 cvar_t r_shadow_lightattenuationpower = {0, "r_shadow_lightattenuationpower", "0.5"};
167 cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1"};
168 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1"};
169 cvar_t r_shadow_realtime_world = {0, "r_shadow_realtime_world", "0"};
170 cvar_t r_shadow_realtime_dlight = {0, "r_shadow_realtime_dlight", "0"};
171 cvar_t r_shadow_visiblevolumes = {0, "r_shadow_visiblevolumes", "0"};
172 cvar_t r_shadow_gloss = {0, "r_shadow_gloss", "1"};
173 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1"};
174 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.25"};
175 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1"};
176 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1"};
177 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4"};
178 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0"};
179 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0"};
180 cvar_t r_shadow_polygonoffset = {0, "r_shadow_polygonoffset", "1"};
181 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1"};
182 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "10000"};
183 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1"};
184 cvar_t r_shadow_singlepassvolumegeneration = {0, "r_shadow_singlepassvolumegeneration", "1"};
185 cvar_t r_shadow_worldshadows = {0, "r_shadow_worldshadows", "1"};
186 cvar_t r_shadow_dlightshadows = {CVAR_SAVE, "r_shadow_dlightshadows", "1"};
187 cvar_t r_shadow_staticworldlights = {0, "r_shadow_staticworldlights", "1"};
188 cvar_t r_shadow_cull = {0, "r_shadow_cull", "1"};
189 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1"};
191 int c_rt_lights, c_rt_clears, c_rt_scissored;
192 int c_rt_shadowmeshes, c_rt_shadowtris, c_rt_lightmeshes, c_rt_lighttris;
193 int c_rtcached_shadowmeshes, c_rtcached_shadowtris;
195 void R_Shadow_ClearWorldLights(void);
196 void R_Shadow_SaveWorldLights(void);
197 void R_Shadow_LoadWorldLights(void);
198 void R_Shadow_LoadLightsFile(void);
199 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
201 void r_shadow_start(void)
203 // allocate vertex processing arrays
204 r_shadow_mempool = Mem_AllocPool("R_Shadow");
205 maxshadowelements = 0;
206 shadowelements = NULL;
214 shadowmarklist = NULL;
216 r_shadow_buffer_numclusterpvsbytes = 0;
217 r_shadow_buffer_clusterpvs = NULL;
218 r_shadow_buffer_clusterlist = NULL;
219 r_shadow_buffer_numsurfacepvsbytes = 0;
220 r_shadow_buffer_surfacepvs = NULL;
221 r_shadow_buffer_surfacelist = NULL;
222 r_shadow_normalcubetexture = NULL;
223 r_shadow_attenuation2dtexture = NULL;
224 r_shadow_attenuation3dtexture = NULL;
225 r_shadow_blankbumptexture = NULL;
226 r_shadow_blankglosstexture = NULL;
227 r_shadow_blankwhitetexture = NULL;
228 r_shadow_texturepool = NULL;
229 r_shadow_filters_texturepool = NULL;
230 R_Shadow_ClearWorldLights();
231 r_shadow_reloadlights = true;
234 void r_shadow_shutdown(void)
236 R_Shadow_ClearWorldLights();
237 r_shadow_reloadlights = true;
238 r_shadow_normalcubetexture = NULL;
239 r_shadow_attenuation2dtexture = NULL;
240 r_shadow_attenuation3dtexture = NULL;
241 r_shadow_blankbumptexture = NULL;
242 r_shadow_blankglosstexture = NULL;
243 r_shadow_blankwhitetexture = NULL;
244 R_FreeTexturePool(&r_shadow_texturepool);
245 R_FreeTexturePool(&r_shadow_filters_texturepool);
246 maxshadowelements = 0;
247 shadowelements = NULL;
255 shadowmarklist = NULL;
257 r_shadow_buffer_numclusterpvsbytes = 0;
258 r_shadow_buffer_clusterpvs = NULL;
259 r_shadow_buffer_clusterlist = NULL;
260 r_shadow_buffer_numsurfacepvsbytes = 0;
261 r_shadow_buffer_surfacepvs = NULL;
262 r_shadow_buffer_surfacelist = NULL;
263 Mem_FreePool(&r_shadow_mempool);
266 void r_shadow_newmap(void)
268 R_Shadow_ClearWorldLights();
269 r_shadow_reloadlights = true;
272 void R_Shadow_Help_f(void)
275 "Documentation on r_shadow system:\n"
277 "r_shadow_lightattenuationpower : used to generate attenuation texture\n"
278 "r_shadow_lightattenuationscale : used to generate attenuation texture\n"
279 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
280 "r_shadow_realtime_world : use realtime world light rendering\n"
281 "r_shadow_realtime_dlight : use high quality dlight rendering\n"
282 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to rtlights\n"
283 "r_shadow_visiblevolumes : useful for performance testing; bright = slow!\n"
284 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
285 "r_shadow_glossintensity : brightness of textured gloss\n"
286 "r_shadow_gloss2intensity : brightness of forced gloss\n"
287 "r_shadow_debuglight : render only this light number (-1 = all)\n"
288 "r_shadow_scissor : use scissor optimization\n"
289 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
290 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
291 "r_shadow_polygonfactor : nudge shadow volumes closer/further\n"
292 "r_shadow_polygonoffset : nudge shadow volumes closer/further\n"
293 "r_shadow_portallight : use portal visibility for static light precomputation\n"
294 "r_shadow_projectdistance : shadow volume projection distance\n"
295 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
296 "r_shadow_singlepassvolumegeneration : selects shadow volume algorithm\n"
297 "r_shadow_worldshadows : enable world shadows\n"
298 "r_shadow_dlightshadows : enable dlight shadows\n"
300 "r_shadow_help : this help\n"
304 void R_Shadow_Init(void)
306 Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
307 Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
308 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
309 Cvar_RegisterVariable(&r_shadow_realtime_world);
310 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
311 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
312 Cvar_RegisterVariable(&r_shadow_visiblevolumes);
313 Cvar_RegisterVariable(&r_shadow_gloss);
314 Cvar_RegisterVariable(&r_shadow_glossintensity);
315 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
316 Cvar_RegisterVariable(&r_shadow_debuglight);
317 Cvar_RegisterVariable(&r_shadow_scissor);
318 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
319 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
320 Cvar_RegisterVariable(&r_shadow_polygonfactor);
321 Cvar_RegisterVariable(&r_shadow_polygonoffset);
322 Cvar_RegisterVariable(&r_shadow_portallight);
323 Cvar_RegisterVariable(&r_shadow_projectdistance);
324 Cvar_RegisterVariable(&r_shadow_texture3d);
325 Cvar_RegisterVariable(&r_shadow_singlepassvolumegeneration);
326 Cvar_RegisterVariable(&r_shadow_worldshadows);
327 Cvar_RegisterVariable(&r_shadow_dlightshadows);
328 Cvar_RegisterVariable(&r_shadow_staticworldlights);
329 Cvar_RegisterVariable(&r_shadow_cull);
330 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
331 if (gamemode == GAME_TENEBRAE)
333 Cvar_SetValue("r_shadow_gloss", 2);
334 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
336 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f);
337 R_Shadow_EditLights_Init();
338 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
341 matrix4x4_t matrix_attenuationxyz =
344 {0.5, 0.0, 0.0, 0.5},
345 {0.0, 0.5, 0.0, 0.5},
346 {0.0, 0.0, 0.5, 0.5},
351 matrix4x4_t matrix_attenuationz =
354 {0.0, 0.0, 0.5, 0.5},
355 {0.0, 0.0, 0.0, 0.5},
356 {0.0, 0.0, 0.0, 0.5},
361 int *R_Shadow_ResizeShadowElements(int numtris)
363 // make sure shadowelements is big enough for this volume
364 if (maxshadowelements < numtris * 24)
366 maxshadowelements = numtris * 24;
368 Mem_Free(shadowelements);
369 shadowelements = Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int));
371 return shadowelements;
374 void R_Shadow_EnlargeClusterBuffer(int numclusters)
376 int numclusterpvsbytes = (((numclusters + 7) >> 3) + 255) & ~255;
377 if (r_shadow_buffer_numclusterpvsbytes < numclusterpvsbytes)
379 if (r_shadow_buffer_clusterpvs)
380 Mem_Free(r_shadow_buffer_clusterpvs);
381 if (r_shadow_buffer_clusterlist)
382 Mem_Free(r_shadow_buffer_clusterlist);
383 r_shadow_buffer_numclusterpvsbytes = numclusterpvsbytes;
384 r_shadow_buffer_clusterpvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numclusterpvsbytes);
385 r_shadow_buffer_clusterlist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numclusterpvsbytes * 8 * sizeof(*r_shadow_buffer_clusterlist));
389 void R_Shadow_EnlargeSurfaceBuffer(int numsurfaces)
391 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
392 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
394 if (r_shadow_buffer_surfacepvs)
395 Mem_Free(r_shadow_buffer_surfacepvs);
396 if (r_shadow_buffer_surfacelist)
397 Mem_Free(r_shadow_buffer_surfacelist);
398 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
399 r_shadow_buffer_surfacepvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes);
400 r_shadow_buffer_surfacelist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
404 void R_Shadow_PrepareShadowMark(int numtris)
406 // make sure shadowmark is big enough for this volume
407 if (maxshadowmark < numtris)
409 maxshadowmark = numtris;
411 Mem_Free(shadowmark);
413 Mem_Free(shadowmarklist);
414 shadowmark = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmark));
415 shadowmarklist = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmarklist));
419 // if shadowmarkcount wrapped we clear the array and adjust accordingly
420 if (shadowmarkcount == 0)
423 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
428 int R_Shadow_ConstructShadowVolume(int innumvertices, int innumtris, const int *inelement3i, const int *inneighbor3i, const float *invertex3f, int *outnumvertices, int *outelement3i, float *outvertex3f, const float *projectorigin, float projectdistance, int numshadowmarktris, const int *shadowmarktris)
430 int i, j, tris = 0, vr[3], t, outvertices = 0;
434 if (maxvertexupdate < innumvertices)
436 maxvertexupdate = innumvertices;
438 Mem_Free(vertexupdate);
440 Mem_Free(vertexremap);
441 vertexupdate = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
442 vertexremap = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
446 if (vertexupdatenum == 0)
449 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
450 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
453 for (i = 0;i < numshadowmarktris;i++)
455 t = shadowmarktris[i];
456 shadowmark[t] = shadowmarkcount;
457 e = inelement3i + t * 3;
458 // make sure the vertices are created
459 for (j = 0;j < 3;j++)
461 if (vertexupdate[e[j]] != vertexupdatenum)
463 vertexupdate[e[j]] = vertexupdatenum;
464 vertexremap[e[j]] = outvertices;
465 VectorSubtract(invertex3f + e[j] * 3, projectorigin, temp);
466 f = projectdistance / VectorLength(temp);
467 VectorCopy(invertex3f + e[j] * 3, outvertex3f);
468 VectorMA(projectorigin, f, temp, (outvertex3f + 3));
473 // output the front and back triangles
474 outelement3i[0] = vertexremap[e[0]];
475 outelement3i[1] = vertexremap[e[1]];
476 outelement3i[2] = vertexremap[e[2]];
477 outelement3i[3] = vertexremap[e[2]] + 1;
478 outelement3i[4] = vertexremap[e[1]] + 1;
479 outelement3i[5] = vertexremap[e[0]] + 1;
484 for (i = 0;i < numshadowmarktris;i++)
486 t = shadowmarktris[i];
487 e = inelement3i + t * 3;
488 n = inneighbor3i + t * 3;
489 // output the sides (facing outward from this triangle)
490 if (shadowmark[n[0]] != shadowmarkcount)
492 vr[0] = vertexremap[e[0]];
493 vr[1] = vertexremap[e[1]];
494 outelement3i[0] = vr[1];
495 outelement3i[1] = vr[0];
496 outelement3i[2] = vr[0] + 1;
497 outelement3i[3] = vr[1];
498 outelement3i[4] = vr[0] + 1;
499 outelement3i[5] = vr[1] + 1;
503 if (shadowmark[n[1]] != shadowmarkcount)
505 vr[1] = vertexremap[e[1]];
506 vr[2] = vertexremap[e[2]];
507 outelement3i[0] = vr[2];
508 outelement3i[1] = vr[1];
509 outelement3i[2] = vr[1] + 1;
510 outelement3i[3] = vr[2];
511 outelement3i[4] = vr[1] + 1;
512 outelement3i[5] = vr[2] + 1;
516 if (shadowmark[n[2]] != shadowmarkcount)
518 vr[0] = vertexremap[e[0]];
519 vr[2] = vertexremap[e[2]];
520 outelement3i[0] = vr[0];
521 outelement3i[1] = vr[2];
522 outelement3i[2] = vr[2] + 1;
523 outelement3i[3] = vr[0];
524 outelement3i[4] = vr[2] + 1;
525 outelement3i[5] = vr[0] + 1;
531 *outnumvertices = outvertices;
535 float varray_vertex3f2[65536*3];
537 void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, float projectdistance, int nummarktris, const int *marktris)
540 if (projectdistance < 0.1)
542 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
545 if (!numverts || !nummarktris)
547 // make sure shadowelements is big enough for this volume
548 if (maxshadowelements < nummarktris * 24)
549 R_Shadow_ResizeShadowElements((nummarktris + 256) * 24);
550 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, varray_vertex3f2, projectorigin, projectdistance, nummarktris, marktris);
551 R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements);
554 void R_Shadow_VolumeFromBox(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, float projectdistance, const vec3_t mins, const vec3_t maxs)
559 // check which triangles are facing the , and then output
560 // triangle elements and vertices... by clever use of elements we
561 // can construct the whole shadow from the unprojected vertices and
562 // the projected vertices
564 // identify lit faces within the bounding box
565 R_Shadow_PrepareShadowMark(numtris);
566 for (i = 0;i < numtris;i++)
568 v[0] = invertex3f + elements[i*3+0] * 3;
569 v[1] = invertex3f + elements[i*3+1] * 3;
570 v[2] = invertex3f + elements[i*3+2] * 3;
571 if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]) && maxs[0] > min(v[0][0], min(v[1][0], v[2][0])) && mins[0] < max(v[0][0], max(v[1][0], v[2][0])) && maxs[1] > min(v[0][1], min(v[1][1], v[2][1])) && mins[1] < max(v[0][1], max(v[1][1], v[2][1])) && maxs[2] > min(v[0][2], min(v[1][2], v[2][2])) && mins[2] < max(v[0][2], max(v[1][2], v[2][2])))
572 shadowmarklist[numshadowmark++] = i;
574 R_Shadow_VolumeFromList(numverts, numtris, invertex3f, elements, neighbors, projectorigin, projectdistance, numshadowmark, shadowmarklist);
577 void R_Shadow_VolumeFromSphere(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, float projectdistance, float radius)
580 mins[0] = projectorigin[0] - radius;
581 mins[1] = projectorigin[1] - radius;
582 mins[2] = projectorigin[2] - radius;
583 maxs[0] = projectorigin[0] + radius;
584 maxs[1] = projectorigin[1] + radius;
585 maxs[2] = projectorigin[2] + radius;
586 R_Shadow_VolumeFromBox(numverts, numtris, invertex3f, elements, neighbors, projectorigin, projectdistance, mins, maxs);
589 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
592 if (r_shadow_compilingrtlight)
594 // if we're compiling an rtlight, capture the mesh
595 Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
598 memset(&m, 0, sizeof(m));
599 m.pointer_vertex = vertex3f;
601 GL_LockArrays(0, numvertices);
602 if (r_shadowstage == SHADOWSTAGE_STENCIL)
604 // increment stencil if backface is behind depthbuffer
605 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
606 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
607 R_Mesh_Draw(numvertices, numtriangles, element3i);
609 c_rt_shadowtris += numtriangles;
610 // decrement stencil if frontface is behind depthbuffer
611 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
612 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
614 R_Mesh_Draw(numvertices, numtriangles, element3i);
616 c_rt_shadowtris += numtriangles;
620 float r_shadow_attenpower, r_shadow_attenscale;
621 static void R_Shadow_MakeTextures(void)
623 int x, y, z, d, side;
624 float v[3], s, t, intensity;
626 R_FreeTexturePool(&r_shadow_texturepool);
627 r_shadow_texturepool = R_AllocTexturePool();
628 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
629 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
631 #define ATTEN2DSIZE 64
632 #define ATTEN3DSIZE 32
633 data = Mem_Alloc(tempmempool, max(6*NORMSIZE*NORMSIZE*4, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4)));
638 r_shadow_blankbumptexture = R_LoadTexture2D(r_shadow_texturepool, "blankbump", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
643 r_shadow_blankglosstexture = R_LoadTexture2D(r_shadow_texturepool, "blankgloss", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
648 r_shadow_blankwhitetexture = R_LoadTexture2D(r_shadow_texturepool, "blankwhite", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
649 if (gl_texturecubemap)
651 for (side = 0;side < 6;side++)
653 for (y = 0;y < NORMSIZE;y++)
655 for (x = 0;x < NORMSIZE;x++)
657 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
658 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
692 intensity = 127.0f / sqrt(DotProduct(v, v));
693 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+0] = 128.0f + intensity * v[0];
694 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+1] = 128.0f + intensity * v[1];
695 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+2] = 128.0f + intensity * v[2];
696 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+3] = 255;
700 r_shadow_normalcubetexture = R_LoadTextureCubeMap(r_shadow_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
703 r_shadow_normalcubetexture = NULL;
704 for (y = 0;y < ATTEN2DSIZE;y++)
706 for (x = 0;x < ATTEN2DSIZE;x++)
708 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
709 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
711 intensity = 1.0f - sqrt(DotProduct(v, v));
713 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
714 d = bound(0, intensity, 255);
715 data[(y*ATTEN2DSIZE+x)*4+0] = d;
716 data[(y*ATTEN2DSIZE+x)*4+1] = d;
717 data[(y*ATTEN2DSIZE+x)*4+2] = d;
718 data[(y*ATTEN2DSIZE+x)*4+3] = d;
721 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
722 if (r_shadow_texture3d.integer)
724 for (z = 0;z < ATTEN3DSIZE;z++)
726 for (y = 0;y < ATTEN3DSIZE;y++)
728 for (x = 0;x < ATTEN3DSIZE;x++)
730 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
731 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
732 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
733 intensity = 1.0f - sqrt(DotProduct(v, v));
735 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
736 d = bound(0, intensity, 255);
737 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
738 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
739 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
740 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
744 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
749 void R_Shadow_Stage_Begin(void)
753 if (r_shadow_texture3d.integer && !gl_texture3d)
754 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
755 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
756 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
758 if (!r_shadow_attenuation2dtexture
759 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
760 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
761 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
762 R_Shadow_MakeTextures();
764 memset(&m, 0, sizeof(m));
765 GL_BlendFunc(GL_ONE, GL_ZERO);
769 GL_Color(0, 0, 0, 1);
770 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
771 qglEnable(GL_CULL_FACE);
772 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
773 r_shadowstage = SHADOWSTAGE_NONE;
775 c_rt_lights = c_rt_clears = c_rt_scissored = 0;
776 c_rt_shadowmeshes = c_rt_shadowtris = c_rt_lightmeshes = c_rt_lighttris = 0;
777 c_rtcached_shadowmeshes = c_rtcached_shadowtris = 0;
780 void R_Shadow_LoadWorldLightsIfNeeded(void)
782 if (r_shadow_reloadlights && cl.worldmodel)
784 R_Shadow_ClearWorldLights();
785 r_shadow_reloadlights = false;
786 R_Shadow_LoadWorldLights();
787 if (r_shadow_worldlightchain == NULL)
789 R_Shadow_LoadLightsFile();
790 if (r_shadow_worldlightchain == NULL)
791 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
796 void R_Shadow_Stage_ShadowVolumes(void)
799 memset(&m, 0, sizeof(m));
801 GL_Color(1, 1, 1, 1);
802 GL_ColorMask(0, 0, 0, 0);
803 GL_BlendFunc(GL_ONE, GL_ZERO);
806 qglPolygonOffset(r_shadow_polygonfactor.value, r_shadow_polygonoffset.value);
807 //if (r_shadow_polygonoffset.value != 0)
809 // qglPolygonOffset(r_shadow_polygonfactor.value, r_shadow_polygonoffset.value);
810 // qglEnable(GL_POLYGON_OFFSET_FILL);
813 // qglDisable(GL_POLYGON_OFFSET_FILL);
814 qglDepthFunc(GL_LESS);
815 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
816 qglEnable(GL_STENCIL_TEST);
817 qglStencilFunc(GL_ALWAYS, 128, ~0);
818 if (gl_ext_stenciltwoside.integer)
820 r_shadowstage = SHADOWSTAGE_STENCILTWOSIDE;
821 qglDisable(GL_CULL_FACE);
822 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
823 qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
825 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
826 qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
828 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
832 r_shadowstage = SHADOWSTAGE_STENCIL;
833 qglEnable(GL_CULL_FACE);
835 // this is changed by every shadow render so its value here is unimportant
836 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
838 GL_Clear(GL_STENCIL_BUFFER_BIT);
840 // LordHavoc note: many shadow volumes reside entirely inside the world
841 // (that is to say they are entirely bounded by their lit surfaces),
842 // which can be optimized by handling things as an inverted light volume,
843 // with the shadow boundaries of the world being simulated by an altered
844 // (129) bias to stencil clearing on such lights
845 // FIXME: generate inverted light volumes for use as shadow volumes and
846 // optimize for them as noted above
849 void R_Shadow_Stage_LightWithoutShadows(void)
852 memset(&m, 0, sizeof(m));
854 GL_BlendFunc(GL_ONE, GL_ONE);
857 qglPolygonOffset(0, 0);
858 //qglDisable(GL_POLYGON_OFFSET_FILL);
859 GL_Color(1, 1, 1, 1);
860 GL_ColorMask(1, 1, 1, 1);
861 qglDepthFunc(GL_EQUAL);
862 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
863 qglEnable(GL_CULL_FACE);
864 qglDisable(GL_STENCIL_TEST);
865 if (gl_support_stenciltwoside)
866 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
868 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
869 qglStencilFunc(GL_EQUAL, 128, ~0);
870 r_shadowstage = SHADOWSTAGE_LIGHT;
874 void R_Shadow_Stage_LightWithShadows(void)
877 memset(&m, 0, sizeof(m));
879 GL_BlendFunc(GL_ONE, GL_ONE);
882 qglPolygonOffset(0, 0);
883 //qglDisable(GL_POLYGON_OFFSET_FILL);
884 GL_Color(1, 1, 1, 1);
885 GL_ColorMask(1, 1, 1, 1);
886 qglDepthFunc(GL_EQUAL);
887 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
888 qglEnable(GL_STENCIL_TEST);
889 if (gl_support_stenciltwoside)
890 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
892 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
893 // only draw light where this geometry was already rendered AND the
894 // stencil is 128 (values other than this mean shadow)
895 qglStencilFunc(GL_EQUAL, 128, ~0);
896 r_shadowstage = SHADOWSTAGE_LIGHT;
900 void R_Shadow_Stage_End(void)
903 memset(&m, 0, sizeof(m));
905 GL_BlendFunc(GL_ONE, GL_ZERO);
908 qglPolygonOffset(0, 0);
909 //qglDisable(GL_POLYGON_OFFSET_FILL);
910 GL_Color(1, 1, 1, 1);
911 GL_ColorMask(1, 1, 1, 1);
912 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
913 qglDepthFunc(GL_LEQUAL);
914 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
915 qglDisable(GL_STENCIL_TEST);
916 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
917 if (gl_support_stenciltwoside)
918 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
920 qglStencilFunc(GL_ALWAYS, 128, ~0);
921 r_shadowstage = SHADOWSTAGE_NONE;
924 int R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
926 int i, ix1, iy1, ix2, iy2;
927 float x1, y1, x2, y2, x, y, f;
930 if (!r_shadow_scissor.integer)
932 // if view is inside the box, just say yes it's visible
933 // LordHavoc: for some odd reason scissor seems broken without stencil
934 // (?!? seems like a driver bug) so abort if gl_stencil is false
935 if (!gl_stencil || BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
937 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
940 for (i = 0;i < 3;i++)
942 if (r_viewforward[i] >= 0)
953 f = DotProduct(r_viewforward, r_vieworigin) + 1;
954 if (DotProduct(r_viewforward, v2) <= f)
956 // entirely behind nearclip plane
959 if (DotProduct(r_viewforward, v) >= f)
961 // entirely infront of nearclip plane
962 x1 = y1 = x2 = y2 = 0;
963 for (i = 0;i < 8;i++)
965 v[0] = (i & 1) ? mins[0] : maxs[0];
966 v[1] = (i & 2) ? mins[1] : maxs[1];
967 v[2] = (i & 4) ? mins[2] : maxs[2];
969 GL_TransformToScreen(v, v2);
970 //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]);
989 // clipped by nearclip plane
990 // this is nasty and crude...
991 // create viewspace bbox
992 for (i = 0;i < 8;i++)
994 v[0] = ((i & 1) ? mins[0] : maxs[0]) - r_vieworigin[0];
995 v[1] = ((i & 2) ? mins[1] : maxs[1]) - r_vieworigin[1];
996 v[2] = ((i & 4) ? mins[2] : maxs[2]) - r_vieworigin[2];
997 v2[0] = -DotProduct(v, r_viewleft);
998 v2[1] = DotProduct(v, r_viewup);
999 v2[2] = DotProduct(v, r_viewforward);
1002 if (smins[0] > v2[0]) smins[0] = v2[0];
1003 if (smaxs[0] < v2[0]) smaxs[0] = v2[0];
1004 if (smins[1] > v2[1]) smins[1] = v2[1];
1005 if (smaxs[1] < v2[1]) smaxs[1] = v2[1];
1006 if (smins[2] > v2[2]) smins[2] = v2[2];
1007 if (smaxs[2] < v2[2]) smaxs[2] = v2[2];
1011 smins[0] = smaxs[0] = v2[0];
1012 smins[1] = smaxs[1] = v2[1];
1013 smins[2] = smaxs[2] = v2[2];
1016 // now we have a bbox in viewspace
1017 // clip it to the view plane
1020 // return true if that culled the box
1021 if (smins[2] >= smaxs[2])
1023 // ok some of it is infront of the view, transform each corner back to
1024 // worldspace and then to screenspace and make screen rect
1025 // initialize these variables just to avoid compiler warnings
1026 x1 = y1 = x2 = y2 = 0;
1027 for (i = 0;i < 8;i++)
1029 v2[0] = (i & 1) ? smins[0] : smaxs[0];
1030 v2[1] = (i & 2) ? smins[1] : smaxs[1];
1031 v2[2] = (i & 4) ? smins[2] : smaxs[2];
1032 v[0] = v2[0] * -r_viewleft[0] + v2[1] * r_viewup[0] + v2[2] * r_viewforward[0] + r_vieworigin[0];
1033 v[1] = v2[0] * -r_viewleft[1] + v2[1] * r_viewup[1] + v2[2] * r_viewforward[1] + r_vieworigin[1];
1034 v[2] = v2[0] * -r_viewleft[2] + v2[1] * r_viewup[2] + v2[2] * r_viewforward[2] + r_vieworigin[2];
1036 GL_TransformToScreen(v, v2);
1037 //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]);
1054 // this code doesn't handle boxes with any points behind view properly
1055 x1 = 1000;x2 = -1000;
1056 y1 = 1000;y2 = -1000;
1057 for (i = 0;i < 8;i++)
1059 v[0] = (i & 1) ? mins[0] : maxs[0];
1060 v[1] = (i & 2) ? mins[1] : maxs[1];
1061 v[2] = (i & 4) ? mins[2] : maxs[2];
1063 GL_TransformToScreen(v, v2);
1064 //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]);
1082 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1083 if (ix1 < r_view_x) ix1 = r_view_x;
1084 if (iy1 < r_view_y) iy1 = r_view_y;
1085 if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
1086 if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
1087 if (ix2 <= ix1 || iy2 <= iy1)
1089 // set up the scissor rectangle
1090 GL_Scissor(ix1, vid.realheight - iy2, ix2 - ix1, iy2 - iy1);
1091 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1092 //qglEnable(GL_SCISSOR_TEST);
1097 void R_Shadow_VertexLighting(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1099 float *color4f = varray_color4f;
1100 float dist, dot, intensity, v[3], n[3];
1101 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1103 Matrix4x4_Transform(m, vertex3f, v);
1104 if ((dist = DotProduct(v, v)) < 1)
1106 Matrix4x4_Transform3x3(m, normal3f, n);
1107 if ((dot = DotProduct(n, v)) > 0)
1110 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale * dot / sqrt(DotProduct(n,n));
1111 VectorScale(lightcolor, intensity, color4f);
1116 VectorClear(color4f);
1122 VectorClear(color4f);
1128 void R_Shadow_VertexLightingWithXYAttenuationTexture(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1130 float *color4f = varray_color4f;
1131 float dist, dot, intensity, v[3], n[3];
1132 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1134 Matrix4x4_Transform(m, vertex3f, v);
1135 if ((dist = fabs(v[2])) < 1)
1137 Matrix4x4_Transform3x3(m, normal3f, n);
1138 if ((dot = DotProduct(n, v)) > 0)
1140 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale * dot / sqrt(DotProduct(n,n));
1141 VectorScale(lightcolor, intensity, color4f);
1146 VectorClear(color4f);
1152 VectorClear(color4f);
1158 // FIXME: this should be done in a vertex program when possible
1159 // FIXME: if vertex program not available, this would really benefit from 3DNow! or SSE
1160 void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1164 tc3f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1165 tc3f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1166 tc3f[2] = vertex3f[0] * matrix->m[2][0] + vertex3f[1] * matrix->m[2][1] + vertex3f[2] * matrix->m[2][2] + matrix->m[2][3];
1173 void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1177 tc2f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1178 tc2f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1185 void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(float *out3f, int numverts, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const vec3_t relativelightorigin)
1189 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1191 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1192 // the cubemap normalizes this for us
1193 out3f[0] = DotProduct(svector3f, lightdir);
1194 out3f[1] = DotProduct(tvector3f, lightdir);
1195 out3f[2] = DotProduct(normal3f, lightdir);
1199 void R_Shadow_GenTexCoords_Specular_NormalCubeMap(float *out3f, int numverts, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const vec3_t relativelightorigin, const vec3_t relativeeyeorigin)
1202 float lightdir[3], eyedir[3], halfdir[3];
1203 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1205 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1206 VectorNormalizeFast(lightdir);
1207 VectorSubtract(vertex3f, relativeeyeorigin, eyedir);
1208 VectorNormalizeFast(eyedir);
1209 VectorAdd(lightdir, eyedir, halfdir);
1210 // the cubemap normalizes this for us
1211 out3f[0] = DotProduct(svector3f, halfdir);
1212 out3f[1] = DotProduct(tvector3f, halfdir);
1213 out3f[2] = DotProduct(normal3f, halfdir);
1217 #define USETEXMATRIX 1
1218 void R_Shadow_RenderLighting(int numverts, int numtriangles, const int *elements, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const float *texcoord2f, const float *relativelightorigin, const float *relativeeyeorigin, const float *lightcolor, const matrix4x4_t *matrix_modeltolight, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz, rtexture_t *basetexture, rtexture_t *bumptexture, rtexture_t *glosstexture, rtexture_t *lightcubemap, int lighting)
1221 float color[3], color2[3], colorscale;
1224 bumptexture = r_shadow_blankbumptexture;
1226 glosstexture = r_shadow_blankglosstexture;
1227 GL_DepthMask(false);
1229 if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
1231 if (lighting & LIGHTING_DIFFUSE)
1234 // colorscale accounts for how much we multiply the brightness during combine
1235 // mult is how many times the final pass of the lighting will be
1236 // performed to get more brightness than otherwise possible
1237 // limit mult to 64 for sanity sake
1238 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1240 // 3/2 3D combine path (Geforce3, Radeon 8500)
1241 memset(&m, 0, sizeof(m));
1242 m.pointer_vertex = vertex3f;
1243 m.tex[0] = R_GetTexture(bumptexture);
1244 m.texcombinergb[0] = GL_REPLACE;
1245 m.pointer_texcoord[0] = texcoord2f;
1246 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1247 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1248 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1249 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1250 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1252 m.pointer_texcoord3f[2] = vertex3f;
1253 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
1255 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1256 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1259 GL_ColorMask(0,0,0,1);
1260 GL_BlendFunc(GL_ONE, GL_ZERO);
1261 GL_LockArrays(0, numverts);
1262 R_Mesh_Draw(numverts, numtriangles, elements);
1263 GL_LockArrays(0, 0);
1265 c_rt_lighttris += numtriangles;
1267 memset(&m, 0, sizeof(m));
1268 m.pointer_vertex = vertex3f;
1269 m.tex[0] = R_GetTexture(basetexture);
1270 m.pointer_texcoord[0] = texcoord2f;
1273 m.texcubemap[1] = R_GetTexture(lightcubemap);
1275 m.pointer_texcoord3f[1] = vertex3f;
1276 m.texmatrix[1] = *matrix_modeltolight;
1278 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1279 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1283 GL_LockArrays(0, numverts);
1284 GL_ColorMask(1,1,1,0);
1285 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1286 VectorScale(lightcolor, r_shadow_lightintensityscale.value, color2);
1287 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1289 color[0] = bound(0, color2[0], 1);
1290 color[1] = bound(0, color2[1], 1);
1291 color[2] = bound(0, color2[2], 1);
1292 GL_Color(color[0], color[1], color[2], 1);
1293 R_Mesh_Draw(numverts, numtriangles, elements);
1295 c_rt_lighttris += numtriangles;
1297 GL_LockArrays(0, 0);
1299 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap)
1301 // 1/2/2 3D combine path (original Radeon)
1302 memset(&m, 0, sizeof(m));
1303 m.pointer_vertex = vertex3f;
1304 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1306 m.pointer_texcoord3f[0] = vertex3f;
1307 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1309 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1310 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1313 GL_ColorMask(0,0,0,1);
1314 GL_BlendFunc(GL_ONE, GL_ZERO);
1315 GL_LockArrays(0, numverts);
1316 R_Mesh_Draw(numverts, numtriangles, elements);
1317 GL_LockArrays(0, 0);
1319 c_rt_lighttris += numtriangles;
1321 memset(&m, 0, sizeof(m));
1322 m.pointer_vertex = vertex3f;
1323 m.tex[0] = R_GetTexture(bumptexture);
1324 m.texcombinergb[0] = GL_REPLACE;
1325 m.pointer_texcoord[0] = texcoord2f;
1326 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1327 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1328 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1329 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1331 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1332 GL_LockArrays(0, numverts);
1333 R_Mesh_Draw(numverts, numtriangles, elements);
1334 GL_LockArrays(0, 0);
1336 c_rt_lighttris += numtriangles;
1338 memset(&m, 0, sizeof(m));
1339 m.pointer_vertex = vertex3f;
1340 m.tex[0] = R_GetTexture(basetexture);
1341 m.pointer_texcoord[0] = texcoord2f;
1344 m.texcubemap[1] = R_GetTexture(lightcubemap);
1346 m.pointer_texcoord3f[1] = vertex3f;
1347 m.texmatrix[1] = *matrix_modeltolight;
1349 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1350 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1354 GL_LockArrays(0, numverts);
1355 GL_ColorMask(1,1,1,0);
1356 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1357 VectorScale(lightcolor, r_shadow_lightintensityscale.value, color2);
1358 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1360 color[0] = bound(0, color2[0], 1);
1361 color[1] = bound(0, color2[1], 1);
1362 color[2] = bound(0, color2[2], 1);
1363 GL_Color(color[0], color[1], color[2], 1);
1364 R_Mesh_Draw(numverts, numtriangles, elements);
1366 c_rt_lighttris += numtriangles;
1368 GL_LockArrays(0, 0);
1370 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap)
1372 // 2/2 3D combine path (original Radeon)
1373 memset(&m, 0, sizeof(m));
1374 m.pointer_vertex = vertex3f;
1375 m.tex[0] = R_GetTexture(bumptexture);
1376 m.texcombinergb[0] = GL_REPLACE;
1377 m.pointer_texcoord[0] = texcoord2f;
1378 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1379 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1380 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1381 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1383 GL_ColorMask(0,0,0,1);
1384 GL_BlendFunc(GL_ONE, GL_ZERO);
1385 GL_LockArrays(0, numverts);
1386 R_Mesh_Draw(numverts, numtriangles, elements);
1387 GL_LockArrays(0, 0);
1389 c_rt_lighttris += numtriangles;
1391 memset(&m, 0, sizeof(m));
1392 m.pointer_vertex = vertex3f;
1393 m.tex[0] = R_GetTexture(basetexture);
1394 m.pointer_texcoord[0] = texcoord2f;
1395 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1397 m.pointer_texcoord3f[1] = vertex3f;
1398 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1400 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1401 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1404 GL_LockArrays(0, numverts);
1405 GL_ColorMask(1,1,1,0);
1406 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1407 VectorScale(lightcolor, r_shadow_lightintensityscale.value, color2);
1408 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1410 color[0] = bound(0, color2[0], 1);
1411 color[1] = bound(0, color2[1], 1);
1412 color[2] = bound(0, color2[2], 1);
1413 GL_Color(color[0], color[1], color[2], 1);
1414 R_Mesh_Draw(numverts, numtriangles, elements);
1416 c_rt_lighttris += numtriangles;
1418 GL_LockArrays(0, 0);
1420 else if (r_textureunits.integer >= 4)
1422 // 4/2 2D combine path (Geforce3, Radeon 8500)
1423 memset(&m, 0, sizeof(m));
1424 m.pointer_vertex = vertex3f;
1425 m.tex[0] = R_GetTexture(bumptexture);
1426 m.texcombinergb[0] = GL_REPLACE;
1427 m.pointer_texcoord[0] = texcoord2f;
1428 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1429 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1430 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1431 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1432 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1434 m.pointer_texcoord3f[2] = vertex3f;
1435 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
1437 m.pointer_texcoord[2] = varray_texcoord2f[2];
1438 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1440 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1442 m.pointer_texcoord3f[3] = vertex3f;
1443 m.texmatrix[3] = *matrix_modeltoattenuationz;
1445 m.pointer_texcoord[3] = varray_texcoord2f[3];
1446 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[3], numverts, vertex3f, matrix_modeltoattenuationz);
1449 GL_ColorMask(0,0,0,1);
1450 GL_BlendFunc(GL_ONE, GL_ZERO);
1451 GL_LockArrays(0, numverts);
1452 R_Mesh_Draw(numverts, numtriangles, elements);
1453 GL_LockArrays(0, 0);
1455 c_rt_lighttris += numtriangles;
1457 memset(&m, 0, sizeof(m));
1458 m.pointer_vertex = vertex3f;
1459 m.tex[0] = R_GetTexture(basetexture);
1460 m.pointer_texcoord[0] = texcoord2f;
1463 m.texcubemap[1] = R_GetTexture(lightcubemap);
1465 m.pointer_texcoord3f[1] = vertex3f;
1466 m.texmatrix[1] = *matrix_modeltolight;
1468 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1469 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1473 GL_LockArrays(0, numverts);
1474 GL_ColorMask(1,1,1,0);
1475 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1476 VectorScale(lightcolor, r_shadow_lightintensityscale.value, color2);
1477 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1479 color[0] = bound(0, color2[0], 1);
1480 color[1] = bound(0, color2[1], 1);
1481 color[2] = bound(0, color2[2], 1);
1482 GL_Color(color[0], color[1], color[2], 1);
1483 R_Mesh_Draw(numverts, numtriangles, elements);
1485 c_rt_lighttris += numtriangles;
1487 GL_LockArrays(0, 0);
1491 // 2/2/2 2D combine path (any dot3 card)
1492 memset(&m, 0, sizeof(m));
1493 m.pointer_vertex = vertex3f;
1494 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1496 m.pointer_texcoord3f[0] = vertex3f;
1497 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1499 m.pointer_texcoord[0] = varray_texcoord2f[0];
1500 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1502 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1504 m.pointer_texcoord3f[1] = vertex3f;
1505 m.texmatrix[1] = *matrix_modeltoattenuationz;
1507 m.pointer_texcoord[1] = varray_texcoord2f[1];
1508 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1511 GL_ColorMask(0,0,0,1);
1512 GL_BlendFunc(GL_ONE, GL_ZERO);
1513 GL_LockArrays(0, numverts);
1514 R_Mesh_Draw(numverts, numtriangles, elements);
1515 GL_LockArrays(0, 0);
1517 c_rt_lighttris += numtriangles;
1519 memset(&m, 0, sizeof(m));
1520 m.pointer_vertex = vertex3f;
1521 m.tex[0] = R_GetTexture(bumptexture);
1522 m.texcombinergb[0] = GL_REPLACE;
1523 m.pointer_texcoord[0] = texcoord2f;
1524 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1525 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1526 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1527 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1529 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1530 GL_LockArrays(0, numverts);
1531 R_Mesh_Draw(numverts, numtriangles, elements);
1532 GL_LockArrays(0, 0);
1534 c_rt_lighttris += numtriangles;
1536 memset(&m, 0, sizeof(m));
1537 m.pointer_vertex = vertex3f;
1538 m.tex[0] = R_GetTexture(basetexture);
1539 m.pointer_texcoord[0] = texcoord2f;
1542 m.texcubemap[1] = R_GetTexture(lightcubemap);
1544 m.pointer_texcoord3f[1] = vertex3f;
1545 m.texmatrix[1] = *matrix_modeltolight;
1547 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1548 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1552 GL_LockArrays(0, numverts);
1553 GL_ColorMask(1,1,1,0);
1554 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1555 VectorScale(lightcolor, r_shadow_lightintensityscale.value, color2);
1556 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1558 color[0] = bound(0, color2[0], 1);
1559 color[1] = bound(0, color2[1], 1);
1560 color[2] = bound(0, color2[2], 1);
1561 GL_Color(color[0], color[1], color[2], 1);
1562 R_Mesh_Draw(numverts, numtriangles, elements);
1564 c_rt_lighttris += numtriangles;
1566 GL_LockArrays(0, 0);
1569 if ((lighting & LIGHTING_SPECULAR) && (r_shadow_gloss.integer >= 2 || (r_shadow_gloss.integer >= 1 && glosstexture != r_shadow_blankglosstexture)))
1571 colorscale = r_shadow_glossintensity.value;
1572 if (glosstexture == r_shadow_blankglosstexture)
1573 colorscale *= r_shadow_gloss2intensity.value;
1575 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1577 // 2/0/0/1/2 3D combine blendsquare path
1578 memset(&m, 0, sizeof(m));
1579 m.pointer_vertex = vertex3f;
1580 m.tex[0] = R_GetTexture(bumptexture);
1581 m.pointer_texcoord[0] = texcoord2f;
1582 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1583 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1584 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1585 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1587 GL_ColorMask(0,0,0,1);
1588 // this squares the result
1589 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1590 GL_LockArrays(0, numverts);
1591 R_Mesh_Draw(numverts, numtriangles, elements);
1592 GL_LockArrays(0, 0);
1594 c_rt_lighttris += numtriangles;
1596 memset(&m, 0, sizeof(m));
1597 m.pointer_vertex = vertex3f;
1599 GL_LockArrays(0, numverts);
1600 // square alpha in framebuffer a few times to make it shiny
1601 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1602 // these comments are a test run through this math for intensity 0.5
1603 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1604 // 0.25 * 0.25 = 0.0625 (this is another pass)
1605 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1606 R_Mesh_Draw(numverts, numtriangles, elements);
1608 c_rt_lighttris += numtriangles;
1609 R_Mesh_Draw(numverts, numtriangles, elements);
1611 c_rt_lighttris += numtriangles;
1612 GL_LockArrays(0, 0);
1614 memset(&m, 0, sizeof(m));
1615 m.pointer_vertex = vertex3f;
1616 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1618 m.pointer_texcoord3f[0] = vertex3f;
1619 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1621 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1622 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1625 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1626 GL_LockArrays(0, numverts);
1627 R_Mesh_Draw(numverts, numtriangles, elements);
1628 GL_LockArrays(0, 0);
1630 c_rt_lighttris += numtriangles;
1632 memset(&m, 0, sizeof(m));
1633 m.pointer_vertex = vertex3f;
1634 m.tex[0] = R_GetTexture(glosstexture);
1635 m.pointer_texcoord[0] = texcoord2f;
1638 m.texcubemap[1] = R_GetTexture(lightcubemap);
1640 m.pointer_texcoord3f[1] = vertex3f;
1641 m.texmatrix[1] = *matrix_modeltolight;
1643 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1644 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1648 GL_LockArrays(0, numverts);
1649 GL_ColorMask(1,1,1,0);
1650 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1651 VectorScale(lightcolor, colorscale, color2);
1652 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1654 color[0] = bound(0, color2[0], 1);
1655 color[1] = bound(0, color2[1], 1);
1656 color[2] = bound(0, color2[2], 1);
1657 GL_Color(color[0], color[1], color[2], 1);
1658 R_Mesh_Draw(numverts, numtriangles, elements);
1660 c_rt_lighttris += numtriangles;
1662 GL_LockArrays(0, 0);
1664 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1666 // 2/0/0/2 3D combine blendsquare path
1667 memset(&m, 0, sizeof(m));
1668 m.pointer_vertex = vertex3f;
1669 m.tex[0] = R_GetTexture(bumptexture);
1670 m.pointer_texcoord[0] = texcoord2f;
1671 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1672 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1673 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1674 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1676 GL_ColorMask(0,0,0,1);
1677 // this squares the result
1678 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1679 GL_LockArrays(0, numverts);
1680 R_Mesh_Draw(numverts, numtriangles, elements);
1681 GL_LockArrays(0, 0);
1683 c_rt_lighttris += numtriangles;
1685 memset(&m, 0, sizeof(m));
1686 m.pointer_vertex = vertex3f;
1688 GL_LockArrays(0, numverts);
1689 // square alpha in framebuffer a few times to make it shiny
1690 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1691 // these comments are a test run through this math for intensity 0.5
1692 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1693 // 0.25 * 0.25 = 0.0625 (this is another pass)
1694 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1695 R_Mesh_Draw(numverts, numtriangles, elements);
1697 c_rt_lighttris += numtriangles;
1698 R_Mesh_Draw(numverts, numtriangles, elements);
1700 c_rt_lighttris += numtriangles;
1701 GL_LockArrays(0, 0);
1703 memset(&m, 0, sizeof(m));
1704 m.pointer_vertex = vertex3f;
1705 m.tex[0] = R_GetTexture(glosstexture);
1706 m.pointer_texcoord[0] = texcoord2f;
1707 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1709 m.pointer_texcoord3f[1] = vertex3f;
1710 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1712 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1713 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1716 GL_LockArrays(0, numverts);
1717 GL_ColorMask(1,1,1,0);
1718 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1719 VectorScale(lightcolor, colorscale, color2);
1720 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1722 color[0] = bound(0, color2[0], 1);
1723 color[1] = bound(0, color2[1], 1);
1724 color[2] = bound(0, color2[2], 1);
1725 GL_Color(color[0], color[1], color[2], 1);
1726 R_Mesh_Draw(numverts, numtriangles, elements);
1728 c_rt_lighttris += numtriangles;
1730 GL_LockArrays(0, 0);
1732 else if (r_textureunits.integer >= 2 /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1734 // 2/0/0/2/2 2D combine blendsquare path
1735 memset(&m, 0, sizeof(m));
1736 m.pointer_vertex = vertex3f;
1737 m.tex[0] = R_GetTexture(bumptexture);
1738 m.pointer_texcoord[0] = texcoord2f;
1739 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1740 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1741 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1742 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1744 GL_ColorMask(0,0,0,1);
1745 // this squares the result
1746 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1747 GL_LockArrays(0, numverts);
1748 R_Mesh_Draw(numverts, numtriangles, elements);
1749 GL_LockArrays(0, 0);
1751 c_rt_lighttris += numtriangles;
1753 memset(&m, 0, sizeof(m));
1754 m.pointer_vertex = vertex3f;
1756 GL_LockArrays(0, numverts);
1757 // square alpha in framebuffer a few times to make it shiny
1758 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1759 // these comments are a test run through this math for intensity 0.5
1760 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1761 // 0.25 * 0.25 = 0.0625 (this is another pass)
1762 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1763 R_Mesh_Draw(numverts, numtriangles, elements);
1765 c_rt_lighttris += numtriangles;
1766 R_Mesh_Draw(numverts, numtriangles, elements);
1768 c_rt_lighttris += numtriangles;
1769 GL_LockArrays(0, 0);
1771 memset(&m, 0, sizeof(m));
1772 m.pointer_vertex = vertex3f;
1773 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1775 m.pointer_texcoord3f[0] = vertex3f;
1776 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1778 m.pointer_texcoord[0] = varray_texcoord2f[0];
1779 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1781 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1783 m.pointer_texcoord3f[1] = vertex3f;
1784 m.texmatrix[1] = *matrix_modeltoattenuationz;
1786 m.pointer_texcoord[1] = varray_texcoord2f[1];
1787 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1790 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1791 GL_LockArrays(0, numverts);
1792 R_Mesh_Draw(numverts, numtriangles, elements);
1793 GL_LockArrays(0, 0);
1795 c_rt_lighttris += numtriangles;
1797 memset(&m, 0, sizeof(m));
1798 m.pointer_vertex = vertex3f;
1799 m.tex[0] = R_GetTexture(glosstexture);
1800 m.pointer_texcoord[0] = texcoord2f;
1803 m.texcubemap[1] = R_GetTexture(lightcubemap);
1805 m.pointer_texcoord3f[1] = vertex3f;
1806 m.texmatrix[1] = *matrix_modeltolight;
1808 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1809 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1813 GL_LockArrays(0, numverts);
1814 GL_ColorMask(1,1,1,0);
1815 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1816 VectorScale(lightcolor, colorscale, color2);
1817 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1819 color[0] = bound(0, color2[0], 1);
1820 color[1] = bound(0, color2[1], 1);
1821 color[2] = bound(0, color2[2], 1);
1822 GL_Color(color[0], color[1], color[2], 1);
1823 R_Mesh_Draw(numverts, numtriangles, elements);
1825 c_rt_lighttris += numtriangles;
1827 GL_LockArrays(0, 0);
1833 if (lighting & LIGHTING_DIFFUSE)
1835 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1836 VectorScale(lightcolor, r_shadow_lightintensityscale.value, color2);
1837 memset(&m, 0, sizeof(m));
1838 m.pointer_vertex = vertex3f;
1839 m.pointer_color = varray_color4f;
1840 m.tex[0] = R_GetTexture(basetexture);
1841 m.pointer_texcoord[0] = texcoord2f;
1842 if (r_textureunits.integer >= 2)
1845 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1847 m.pointer_texcoord3f[1] = vertex3f;
1848 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1850 m.pointer_texcoord[1] = varray_texcoord2f[1];
1851 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1855 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1857 color[0] = bound(0, color2[0], 1);
1858 color[1] = bound(0, color2[1], 1);
1859 color[2] = bound(0, color2[2], 1);
1860 if (r_textureunits.integer >= 2)
1861 R_Shadow_VertexLightingWithXYAttenuationTexture(numverts, vertex3f, normal3f, color, matrix_modeltolight);
1863 R_Shadow_VertexLighting(numverts, vertex3f, normal3f, color, matrix_modeltolight);
1864 GL_LockArrays(0, numverts);
1865 R_Mesh_Draw(numverts, numtriangles, elements);
1866 GL_LockArrays(0, 0);
1868 c_rt_lighttris += numtriangles;
1874 void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
1878 R_RTLight_Uncompile(rtlight);
1879 memset(rtlight, 0, sizeof(*rtlight));
1881 VectorCopy(light->origin, rtlight->shadoworigin);
1882 VectorCopy(light->color, rtlight->color);
1883 rtlight->radius = light->radius;
1884 //rtlight->cullradius = rtlight->radius;
1885 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
1886 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
1887 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
1888 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
1889 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
1890 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
1891 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
1892 rtlight->cubemapname[0] = 0;
1893 if (light->cubemapname[0])
1894 strcpy(rtlight->cubemapname, light->cubemapname);
1895 else if (light->cubemapnum > 0)
1896 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
1897 rtlight->shadow = light->shadow;
1898 rtlight->corona = light->corona;
1899 rtlight->style = light->style;
1900 rtlight->isstatic = isstatic;
1901 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
1902 // ConcatScale won't work here because this needs to scale rotate and
1903 // translate, not just rotate
1904 scale = 1.0f / rtlight->radius;
1905 for (k = 0;k < 3;k++)
1906 for (j = 0;j < 4;j++)
1907 rtlight->matrix_worldtolight.m[k][j] *= scale;
1908 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationxyz, &matrix_attenuationxyz, &rtlight->matrix_worldtolight);
1909 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationz, &matrix_attenuationz, &rtlight->matrix_worldtolight);
1911 rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
1912 rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
1913 VectorScale(rtlight->color, rtlight->radius * d_lightstylevalue[rtlight->style] * 0.125f, rtlight->lightmap_light);
1914 rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
1917 rtlight_t *r_shadow_compilingrtlight;
1919 // compiles rtlight geometry
1920 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
1921 void R_RTLight_Compile(rtlight_t *rtlight)
1923 int shadowmeshes, shadowtris, lightmeshes, lighttris, numclusters, numsurfaces;
1924 entity_render_t *ent = &cl_entities[0].render;
1925 model_t *model = ent->model;
1927 // compile the light
1928 rtlight->compiled = true;
1929 rtlight->static_numclusters = 0;
1930 rtlight->static_numclusterpvsbytes = 0;
1931 rtlight->static_clusterlist = NULL;
1932 rtlight->static_clusterpvs = NULL;
1933 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
1934 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
1935 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
1936 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
1937 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
1938 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
1940 if (model && model->GetLightInfo)
1942 // this variable directs the DrawShadowVolume and DrawLight code to capture into the mesh chain instead of rendering
1943 r_shadow_compilingrtlight = rtlight;
1944 R_Shadow_EnlargeClusterBuffer(model->brush.num_pvsclusters);
1945 R_Shadow_EnlargeSurfaceBuffer(model->numsurfaces);
1946 model->GetLightInfo(ent, rtlight->shadoworigin, rtlight->radius, rtlight->cullmins, rtlight->cullmaxs, r_shadow_buffer_clusterlist, r_shadow_buffer_clusterpvs, &numclusters, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces);
1949 rtlight->static_numclusters = numclusters;
1950 rtlight->static_numclusterpvsbytes = (model->brush.num_pvsclusters + 7) >> 3;
1951 rtlight->static_clusterlist = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
1952 rtlight->static_clusterpvs = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusterpvsbytes);
1953 memcpy(rtlight->static_clusterlist, r_shadow_buffer_clusterlist, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
1954 memcpy(rtlight->static_clusterpvs, r_shadow_buffer_clusterpvs, rtlight->static_numclusterpvsbytes);
1956 if (model->DrawShadowVolume && rtlight->shadow)
1958 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
1959 model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
1960 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_shadow, false, false);
1962 if (model->DrawLight)
1964 rtlight->static_meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true);
1965 model->DrawLight(ent, rtlight->shadoworigin, vec3_origin, rtlight->radius, vec3_origin, &r_identitymatrix, &r_identitymatrix, &r_identitymatrix, NULL, numsurfaces, r_shadow_buffer_surfacelist);
1966 rtlight->static_meshchain_light = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_light, true, false);
1968 // switch back to rendering when DrawShadowVolume or DrawLight is called
1969 r_shadow_compilingrtlight = NULL;
1973 // use smallest available cullradius - box radius or light radius
1974 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
1975 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
1979 if (rtlight->static_meshchain_shadow)
1982 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
1985 shadowtris += mesh->numtriangles;
1991 if (rtlight->static_meshchain_light)
1994 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
1997 lighttris += mesh->numtriangles;
2001 Con_DPrintf("static light built: %f %f %f : %f %f %f box, %i shadow volume triangles (in %i meshes), %i light triangles (in %i meshes)\n", rtlight->cullmins[0], rtlight->cullmins[1], rtlight->cullmins[2], rtlight->cullmaxs[0], rtlight->cullmaxs[1], rtlight->cullmaxs[2], shadowtris, shadowmeshes, lighttris, lightmeshes);
2004 void R_RTLight_Uncompile(rtlight_t *rtlight)
2006 if (rtlight->compiled)
2008 if (rtlight->static_meshchain_shadow)
2009 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2010 rtlight->static_meshchain_shadow = NULL;
2011 if (rtlight->static_meshchain_light)
2012 Mod_ShadowMesh_Free(rtlight->static_meshchain_light);
2013 rtlight->static_meshchain_light = NULL;
2014 if (rtlight->static_clusterlist)
2015 Mem_Free(rtlight->static_clusterlist);
2016 rtlight->static_clusterlist = NULL;
2017 if (rtlight->static_clusterpvs)
2018 Mem_Free(rtlight->static_clusterpvs);
2019 rtlight->static_clusterpvs = NULL;
2020 rtlight->static_numclusters = 0;
2021 rtlight->static_numclusterpvsbytes = 0;
2022 rtlight->compiled = false;
2026 int shadowframecount = 0;
2028 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light);
2030 void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes)
2033 entity_render_t *ent;
2035 vec3_t relativelightorigin, relativeeyeorigin, lightcolor;
2036 rtexture_t *cubemaptexture;
2037 matrix4x4_t matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz;
2038 int numclusters, numsurfaces;
2039 int *clusterlist, *surfacelist;
2041 vec3_t cullmins, cullmaxs;
2045 if (d_lightstylevalue[rtlight->style] <= 0)
2047 cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2048 cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2049 cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2050 cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2051 cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2052 cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2053 if (R_CullBox(cullmins, cullmaxs))
2055 if (rtlight->isstatic && !rtlight->compiled && r_shadow_staticworldlights.integer)
2056 R_RTLight_Compile(rtlight);
2062 if (rtlight->compiled && r_shadow_staticworldlights.integer)
2064 numclusters = rtlight->static_numclusters;
2065 clusterlist = rtlight->static_clusterlist;
2066 clusterpvs = rtlight->static_clusterpvs;
2067 VectorCopy(rtlight->cullmins, cullmins);
2068 VectorCopy(rtlight->cullmaxs, cullmaxs);
2070 else if (cl.worldmodel && cl.worldmodel->GetLightInfo)
2072 R_Shadow_EnlargeClusterBuffer(cl.worldmodel->brush.num_pvsclusters);
2073 R_Shadow_EnlargeSurfaceBuffer(cl.worldmodel->numsurfaces);
2074 cl.worldmodel->GetLightInfo(&cl_entities[0].render, rtlight->shadoworigin, rtlight->radius, cullmins, cullmaxs, r_shadow_buffer_clusterlist, r_shadow_buffer_clusterpvs, &numclusters, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces);
2075 clusterlist = r_shadow_buffer_clusterlist;
2076 clusterpvs = r_shadow_buffer_clusterpvs;
2077 surfacelist = r_shadow_buffer_surfacelist;
2081 for (i = 0;i < numclusters;i++)
2082 if (CHECKPVSBIT(r_pvsbits, clusterlist[i]))
2084 if (i == numclusters)
2087 if (R_CullBox(cullmins, cullmaxs))
2089 if (R_Shadow_ScissorForBBox(cullmins, cullmaxs))
2092 f = d_lightstylevalue[rtlight->style] * (1.0f / 256.0f);
2093 VectorScale(rtlight->color, f, lightcolor);
2095 if (rtlight->selected)
2097 f = 2 + sin(realtime * M_PI * 4.0);
2098 VectorScale(lightcolor, f, lightcolor);
2102 if (rtlight->cubemapname[0])
2103 cubemaptexture = R_Shadow_Cubemap(rtlight->cubemapname);
2105 cubemaptexture = NULL;
2107 shadow = rtlight->shadow && (rtlight->isstatic ? r_shadow_worldshadows.integer : r_shadow_dlightshadows.integer);
2108 if (shadow && (gl_stencil || visiblevolumes))
2110 if (!visiblevolumes)
2111 R_Shadow_Stage_ShadowVolumes();
2112 ent = &cl_entities[0].render;
2113 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2115 memset(&m, 0, sizeof(m));
2116 R_Mesh_Matrix(&ent->matrix);
2117 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2119 m.pointer_vertex = mesh->vertex3f;
2121 GL_LockArrays(0, mesh->numverts);
2122 if (r_shadowstage == SHADOWSTAGE_STENCIL)
2124 // decrement stencil if frontface is behind depthbuffer
2125 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2126 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2127 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2128 c_rtcached_shadowmeshes++;
2129 c_rtcached_shadowtris += mesh->numtriangles;
2130 // increment stencil if backface is behind depthbuffer
2131 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2132 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2134 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2135 c_rtcached_shadowmeshes++;
2136 c_rtcached_shadowtris += mesh->numtriangles;
2137 GL_LockArrays(0, 0);
2142 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2143 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, numsurfaces, surfacelist);
2145 if (r_drawentities.integer)
2147 for (i = 0;i < r_refdef.numentities;i++)
2149 ent = r_refdef.entities[i];
2151 if (r_shadow_cull.integer)
2153 if (!BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs))
2155 if (cl.worldmodel != NULL && cl.worldmodel->brush.BoxTouchingPVS != NULL && !cl.worldmodel->brush.BoxTouchingPVS(cl.worldmodel, clusterpvs, ent->mins, ent->maxs))
2158 if (!(ent->flags & RENDER_SHADOW) || !ent->model || !ent->model->DrawShadowVolume)
2160 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2161 // light emitting entities should not cast their own shadow
2162 if (VectorLength2(relativelightorigin) < 0.1)
2164 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, ent->model->numsurfaces, ent->model->surfacelist);
2169 if (!visiblevolumes)
2171 if (shadow && gl_stencil)
2172 R_Shadow_Stage_LightWithShadows();
2174 R_Shadow_Stage_LightWithoutShadows();
2176 ent = &cl_entities[0].render;
2177 if (ent->model && ent->model->DrawLight)
2179 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2180 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2181 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2182 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2183 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2184 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2186 R_Mesh_Matrix(&ent->matrix);
2187 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2188 R_Shadow_RenderLighting(mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->vertex3f, mesh->svector3f, mesh->tvector3f, mesh->normal3f, mesh->texcoord2f, relativelightorigin, relativeeyeorigin, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, mesh->map_diffuse, mesh->map_normal, mesh->map_specular, cubemaptexture, LIGHTING_DIFFUSE | LIGHTING_SPECULAR);
2191 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, numsurfaces, surfacelist);
2193 if (r_drawentities.integer)
2195 for (i = 0;i < r_refdef.numentities;i++)
2197 ent = r_refdef.entities[i];
2198 if (ent->visframe == r_framecount && BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs) && ent->model && ent->model->DrawLight && (ent->flags & RENDER_LIGHT))
2200 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2201 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2202 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2203 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2204 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2205 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, ent->model->numsurfaces, ent->model->surfacelist);
2212 void R_ShadowVolumeLighting(int visiblevolumes)
2220 memset(&m, 0, sizeof(m));
2223 GL_BlendFunc(GL_ONE, GL_ONE);
2224 GL_DepthMask(false);
2225 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
2226 qglDisable(GL_CULL_FACE);
2227 GL_Color(0.0, 0.0125, 0.1, 1);
2230 R_Shadow_Stage_Begin();
2232 if (r_shadow_realtime_world.integer)
2234 R_Shadow_LoadWorldLightsIfNeeded();
2235 if (r_shadow_debuglight.integer >= 0)
2237 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2238 if (lnum == r_shadow_debuglight.integer)
2239 R_DrawRTLight(&light->rtlight, visiblevolumes);
2242 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2243 R_DrawRTLight(&light->rtlight, visiblevolumes);
2245 if (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer)
2246 for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
2247 R_DrawRTLight(&light->rtlight, visiblevolumes);
2251 qglEnable(GL_CULL_FACE);
2252 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
2255 R_Shadow_Stage_End();
2258 cvar_t r_editlights = {0, "r_editlights", "0"};
2259 cvar_t r_editlights_cursordistance = {0, "r_editlights_distance", "1024"};
2260 cvar_t r_editlights_cursorpushback = {0, "r_editlights_pushback", "0"};
2261 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_pushoff", "4"};
2262 cvar_t r_editlights_cursorgrid = {0, "r_editlights_grid", "4"};
2263 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "0.8"};
2264 cvar_t r_editlights_rtlightssizescale = {CVAR_SAVE, "r_editlights_rtlightssizescale", "0.7"};
2265 cvar_t r_editlights_rtlightscolorscale = {CVAR_SAVE, "r_editlights_rtlightscolorscale", "2"};
2266 dlight_t *r_shadow_worldlightchain;
2267 dlight_t *r_shadow_selectedlight;
2268 vec3_t r_editlights_cursorlocation;
2270 typedef struct cubemapinfo_s
2273 rtexture_t *texture;
2277 #define MAX_CUBEMAPS 128
2278 static int numcubemaps;
2279 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
2281 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2282 typedef struct suffixinfo_s
2285 int flipx, flipy, flipdiagonal;
2288 static suffixinfo_t suffix[3][6] =
2291 {"posx", false, false, false},
2292 {"negx", false, false, false},
2293 {"posy", false, false, false},
2294 {"negy", false, false, false},
2295 {"posz", false, false, false},
2296 {"negz", false, false, false}
2299 {"px", false, false, false},
2300 {"nx", false, false, false},
2301 {"py", false, false, false},
2302 {"ny", false, false, false},
2303 {"pz", false, false, false},
2304 {"nz", false, false, false}
2307 {"ft", true, false, true},
2308 {"bk", false, true, true},
2309 {"lf", true, true, false},
2310 {"rt", false, false, false},
2311 {"up", false, false, false},
2312 {"dn", false, false, false}
2316 static int componentorder[4] = {0, 1, 2, 3};
2318 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2320 int i, j, cubemapsize;
2321 qbyte *cubemappixels, *image_rgba;
2322 rtexture_t *cubemaptexture;
2324 // must start 0 so the first loadimagepixels has no requested width/height
2326 cubemappixels = NULL;
2327 cubemaptexture = NULL;
2328 for (j = 0;j < 3 && !cubemappixels;j++)
2330 for (i = 0;i < 6;i++)
2332 snprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2333 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2335 if (image_width == image_height)
2337 if (!cubemappixels && image_width >= 1)
2339 cubemapsize = image_width;
2340 // note this clears to black, so unavailable sizes are black
2341 cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2344 Image_CopyMux(cubemappixels+i*cubemapsize*cubemapsize*4, image_rgba, cubemapsize, cubemapsize, suffix[j][i].flipx, suffix[j][i].flipy, suffix[j][i].flipdiagonal, 4, 4, componentorder);
2347 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2348 Mem_Free(image_rgba);
2354 if (!r_shadow_filters_texturepool)
2355 r_shadow_filters_texturepool = R_AllocTexturePool();
2356 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
2357 Mem_Free(cubemappixels);
2361 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
2362 for (j = 0;j < 3;j++)
2363 for (i = 0;i < 6;i++)
2364 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2365 Con_Print(" and was unable to find any of them.\n");
2367 return cubemaptexture;
2370 rtexture_t *R_Shadow_Cubemap(const char *basename)
2373 for (i = 0;i < numcubemaps;i++)
2374 if (!strcasecmp(cubemaps[i].basename, basename))
2375 return cubemaps[i].texture;
2376 if (i >= MAX_CUBEMAPS)
2379 strcpy(cubemaps[i].basename, basename);
2380 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
2381 return cubemaps[i].texture;
2384 void R_Shadow_FreeCubemaps(void)
2387 R_FreeTexturePool(&r_shadow_filters_texturepool);
2390 void R_Shadow_NewWorldLight(vec3_t origin, vec3_t angles, vec3_t color, vec_t radius, vec_t corona, int style, int shadowenable, const char *cubemapname)
2394 if (radius < 15 || DotProduct(color, color) < 0.03)
2396 Con_Print("R_Shadow_NewWorldLight: refusing to create a light too small/dim\n");
2400 light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
2401 VectorCopy(origin, light->origin);
2402 VectorCopy(angles, light->angles);
2403 VectorCopy(color, light->color);
2404 light->radius = radius;
2405 light->style = style;
2406 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
2408 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
2411 light->shadow = shadowenable;
2412 light->corona = corona;
2413 if (cubemapname && cubemapname[0] && strlen(cubemapname) < sizeof(light->cubemapname))
2414 strcpy(light->cubemapname, cubemapname);
2415 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
2416 light->next = r_shadow_worldlightchain;
2417 r_shadow_worldlightchain = light;
2419 R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
2420 if (r_shadow_staticworldlights.integer)
2421 R_RTLight_Compile(&light->rtlight);
2424 void R_Shadow_FreeWorldLight(dlight_t *light)
2426 dlight_t **lightpointer;
2427 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
2428 if (*lightpointer != light)
2429 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
2430 *lightpointer = light->next;
2431 R_RTLight_Uncompile(&light->rtlight);
2435 void R_Shadow_ClearWorldLights(void)
2437 while (r_shadow_worldlightchain)
2438 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
2439 r_shadow_selectedlight = NULL;
2440 R_Shadow_FreeCubemaps();
2443 void R_Shadow_SelectLight(dlight_t *light)
2445 if (r_shadow_selectedlight)
2446 r_shadow_selectedlight->selected = false;
2447 r_shadow_selectedlight = light;
2448 if (r_shadow_selectedlight)
2449 r_shadow_selectedlight->selected = true;
2452 rtexture_t *lighttextures[5];
2454 void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
2456 float scale = r_editlights_cursorgrid.value * 0.5f;
2457 R_DrawSprite(GL_SRC_ALPHA, GL_ONE, lighttextures[0], false, r_editlights_cursorlocation, r_viewright, r_viewup, scale, -scale, -scale, scale, 1, 1, 1, 0.5f);
2460 void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
2463 const dlight_t *light;
2466 if (light->selected)
2467 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
2470 R_DrawSprite(GL_SRC_ALPHA, GL_ONE, lighttextures[calldata2], false, light->origin, r_viewright, r_viewup, 8, -8, -8, 8, intensity, intensity, intensity, 0.5);
2473 void R_Shadow_DrawLightSprites(void)
2479 for (i = 0;i < 5;i++)
2481 lighttextures[i] = NULL;
2482 if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1))))
2483 lighttextures[i] = pic->tex;
2486 for (light = r_shadow_worldlightchain;light;light = light->next)
2487 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, ((int) light) % 5);
2488 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
2491 void R_Shadow_SelectLightInView(void)
2493 float bestrating, rating, temp[3];
2494 dlight_t *best, *light;
2497 for (light = r_shadow_worldlightchain;light;light = light->next)
2499 VectorSubtract(light->origin, r_vieworigin, temp);
2500 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
2503 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
2504 if (bestrating < rating && CL_TraceLine(light->origin, r_vieworigin, NULL, NULL, true, NULL, SUPERCONTENTS_SOLID) == 1.0f)
2506 bestrating = rating;
2511 R_Shadow_SelectLight(best);
2514 void R_Shadow_LoadWorldLights(void)
2516 int n, a, style, shadow;
2517 char name[MAX_QPATH], cubemapname[MAX_QPATH], *lightsstring, *s, *t;
2518 float origin[3], radius, color[3], angles[3], corona;
2519 if (cl.worldmodel == NULL)
2521 Con_Print("No map loaded.\n");
2524 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2525 strlcat (name, ".rtlights", sizeof (name));
2526 lightsstring = FS_LoadFile(name, false);
2536 for (;COM_Parse(t, true) && strcmp(
2537 if (COM_Parse(t, true))
2539 if (com_token[0] == '!')
2542 origin[0] = atof(com_token+1);
2545 origin[0] = atof(com_token);
2550 while (*s && *s != '\n')
2556 // check for modifier flags
2562 a = sscanf(t, "%f %f %f %f %f %f %f %d %s %f %f %f %f", &origin[0], &origin[1], &origin[2], &radius, &color[0], &color[1], &color[2], &style, cubemapname, &corona, &angles[0], &angles[1], &angles[2]);
2564 VectorClear(angles);
2567 if (a < 9 || !strcmp(cubemapname, "\"\""))
2572 Con_Printf("found %d parameters on line %i, should be 8 or more parameters (origin[0] origin[1] origin[2] radius color[0] color[1] color[2] style \"cubemapname\" corona angles[0] angles[1] angles[2])\n", a, n + 1);
2575 VectorScale(color, r_editlights_rtlightscolorscale.value, color);
2576 radius *= r_editlights_rtlightssizescale.value;
2577 R_Shadow_NewWorldLight(origin, angles, color, radius, corona, style, shadow, cubemapname);
2582 Con_Printf("invalid rtlights file \"%s\"\n", name);
2583 Mem_Free(lightsstring);
2587 void R_Shadow_SaveWorldLights(void)
2590 int bufchars, bufmaxchars;
2592 char name[MAX_QPATH];
2594 if (!r_shadow_worldlightchain)
2596 if (cl.worldmodel == NULL)
2598 Con_Print("No map loaded.\n");
2601 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2602 strlcat (name, ".rtlights", sizeof (name));
2603 bufchars = bufmaxchars = 0;
2605 for (light = r_shadow_worldlightchain;light;light = light->next)
2607 sprintf(line, "%s%f %f %f %f %f %f %f %d %s %f %f %f %f\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius / r_editlights_rtlightssizescale.value, light->color[0] / r_editlights_rtlightscolorscale.value, light->color[1] / r_editlights_rtlightscolorscale.value, light->color[2] / r_editlights_rtlightscolorscale.value, light->style, light->cubemapname[0] ? light->cubemapname : "\"\"", light->corona, light->angles[0], light->angles[1], light->angles[2]);
2608 if (bufchars + (int) strlen(line) > bufmaxchars)
2610 bufmaxchars = bufchars + strlen(line) + 2048;
2612 buf = Mem_Alloc(r_shadow_mempool, bufmaxchars);
2616 memcpy(buf, oldbuf, bufchars);
2622 memcpy(buf + bufchars, line, strlen(line));
2623 bufchars += strlen(line);
2627 FS_WriteFile(name, buf, bufchars);
2632 void R_Shadow_LoadLightsFile(void)
2635 char name[MAX_QPATH], *lightsstring, *s, *t;
2636 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
2637 if (cl.worldmodel == NULL)
2639 Con_Print("No map loaded.\n");
2642 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2643 strlcat (name, ".lights", sizeof (name));
2644 lightsstring = FS_LoadFile(name, false);
2652 while (*s && *s != '\n')
2657 a = sscanf(t, "%f %f %f %f %f %f %f %f %f %f %f %f %f %d", &origin[0], &origin[1], &origin[2], &falloff, &color[0], &color[1], &color[2], &subtract, &spotdir[0], &spotdir[1], &spotdir[2], &spotcone, &distbias, &style);
2661 Con_Printf("invalid lights file, found %d parameters on line %i, should be 14 parameters (origin[0] origin[1] origin[2] falloff light[0] light[1] light[2] subtract spotdir[0] spotdir[1] spotdir[2] spotcone distancebias style)\n", a, n + 1);
2664 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
2665 radius = bound(15, radius, 4096);
2666 VectorScale(color, (2.0f / (8388608.0f)), color);
2667 R_Shadow_NewWorldLight(origin, vec3_origin, color, radius, 0, style, true, NULL);
2672 Con_Printf("invalid lights file \"%s\"\n", name);
2673 Mem_Free(lightsstring);
2677 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
2679 int entnum, style, islight, skin, pflags, effects;
2680 char key[256], value[1024];
2681 float origin[3], angles[3], radius, color[3], light, fadescale, lightscale, originhack[3], overridecolor[3];
2684 if (cl.worldmodel == NULL)
2686 Con_Print("No map loaded.\n");
2689 data = cl.worldmodel->brush.entities;
2692 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
2695 origin[0] = origin[1] = origin[2] = 0;
2696 originhack[0] = originhack[1] = originhack[2] = 0;
2697 angles[0] = angles[1] = angles[2] = 0;
2698 color[0] = color[1] = color[2] = 1;
2699 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
2709 if (!COM_ParseToken(&data, false))
2711 if (com_token[0] == '}')
2712 break; // end of entity
2713 if (com_token[0] == '_')
2714 strcpy(key, com_token + 1);
2716 strcpy(key, com_token);
2717 while (key[strlen(key)-1] == ' ') // remove trailing spaces
2718 key[strlen(key)-1] = 0;
2719 if (!COM_ParseToken(&data, false))
2721 strcpy(value, com_token);
2723 // now that we have the key pair worked out...
2724 if (!strcmp("light", key))
2725 light = atof(value);
2726 else if (!strcmp("origin", key))
2727 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
2728 else if (!strcmp("angle", key))
2729 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
2730 else if (!strcmp("angles", key))
2731 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
2732 else if (!strcmp("color", key))
2733 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
2734 else if (!strcmp("wait", key))
2735 fadescale = atof(value);
2736 else if (!strcmp("classname", key))
2738 if (!strncmp(value, "light", 5))
2741 if (!strcmp(value, "light_fluoro"))
2746 overridecolor[0] = 1;
2747 overridecolor[1] = 1;
2748 overridecolor[2] = 1;
2750 if (!strcmp(value, "light_fluorospark"))
2755 overridecolor[0] = 1;
2756 overridecolor[1] = 1;
2757 overridecolor[2] = 1;
2759 if (!strcmp(value, "light_globe"))
2764 overridecolor[0] = 1;
2765 overridecolor[1] = 0.8;
2766 overridecolor[2] = 0.4;
2768 if (!strcmp(value, "light_flame_large_yellow"))
2773 overridecolor[0] = 1;
2774 overridecolor[1] = 0.5;
2775 overridecolor[2] = 0.1;
2777 if (!strcmp(value, "light_flame_small_yellow"))
2782 overridecolor[0] = 1;
2783 overridecolor[1] = 0.5;
2784 overridecolor[2] = 0.1;
2786 if (!strcmp(value, "light_torch_small_white"))
2791 overridecolor[0] = 1;
2792 overridecolor[1] = 0.5;
2793 overridecolor[2] = 0.1;
2795 if (!strcmp(value, "light_torch_small_walltorch"))
2800 overridecolor[0] = 1;
2801 overridecolor[1] = 0.5;
2802 overridecolor[2] = 0.1;
2806 else if (!strcmp("style", key))
2807 style = atoi(value);
2808 else if (cl.worldmodel->type == mod_brushq3)
2810 if (!strcmp("scale", key))
2811 lightscale = atof(value);
2812 if (!strcmp("fade", key))
2813 fadescale = atof(value);
2815 else if (!strcmp("skin", key))
2816 skin = (int)atof(value);
2817 else if (!strcmp("pflags", key))
2818 pflags = (int)atof(value);
2819 else if (!strcmp("effects", key))
2820 effects = (int)atof(value);
2822 if (light <= 0 && islight)
2824 if (lightscale <= 0)
2828 if (gamemode == GAME_TENEBRAE)
2830 if (effects & EF_NODRAW)
2832 pflags |= PFLAGS_FULLDYNAMIC;
2833 effects &= ~EF_NODRAW;
2836 radius = min(light * r_editlights_quakelightsizescale.value * lightscale / fadescale, 1048576);
2837 light = sqrt(bound(0, light, 1048576)) * (1.0f / 16.0f);
2838 if (color[0] == 1 && color[1] == 1 && color[2] == 1)
2839 VectorCopy(overridecolor, color);
2840 VectorScale(color, light, color);
2841 VectorAdd(origin, originhack, origin);
2842 if (radius >= 15 && !(pflags & PFLAGS_FULLDYNAMIC))
2843 R_Shadow_NewWorldLight(origin, angles, color, radius, (pflags & PFLAGS_CORONA) != 0, style, (pflags & PFLAGS_NOSHADOW) == 0, skin >= 16 ? va("cubemaps/%i", skin) : NULL);
2848 void R_Shadow_SetCursorLocationForView(void)
2850 vec_t dist, push, frac;
2851 vec3_t dest, endpos, normal;
2852 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
2853 frac = CL_TraceLine(r_vieworigin, dest, endpos, normal, true, NULL, SUPERCONTENTS_SOLID);
2856 dist = frac * r_editlights_cursordistance.value;
2857 push = r_editlights_cursorpushback.value;
2861 VectorMA(endpos, push, r_viewforward, endpos);
2862 VectorMA(endpos, r_editlights_cursorpushoff.value, normal, endpos);
2864 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2865 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2866 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2869 void R_Shadow_UpdateWorldLightSelection(void)
2871 if (r_editlights.integer)
2873 R_Shadow_SetCursorLocationForView();
2874 R_Shadow_SelectLightInView();
2875 R_Shadow_DrawLightSprites();
2878 R_Shadow_SelectLight(NULL);
2881 void R_Shadow_EditLights_Clear_f(void)
2883 R_Shadow_ClearWorldLights();
2886 void R_Shadow_EditLights_Reload_f(void)
2888 r_shadow_reloadlights = true;
2891 void R_Shadow_EditLights_Save_f(void)
2894 R_Shadow_SaveWorldLights();
2897 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
2899 R_Shadow_ClearWorldLights();
2900 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
2903 void R_Shadow_EditLights_ImportLightsFile_f(void)
2905 R_Shadow_ClearWorldLights();
2906 R_Shadow_LoadLightsFile();
2909 void R_Shadow_EditLights_Spawn_f(void)
2912 if (!r_editlights.integer)
2914 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
2917 if (Cmd_Argc() != 1)
2919 Con_Print("r_editlights_spawn does not take parameters\n");
2922 color[0] = color[1] = color[2] = 1;
2923 R_Shadow_NewWorldLight(r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL);
2926 void R_Shadow_EditLights_Edit_f(void)
2928 vec3_t origin, angles, color;
2929 vec_t radius, corona;
2931 char cubemapname[1024];
2932 if (!r_editlights.integer)
2934 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
2937 if (!r_shadow_selectedlight)
2939 Con_Print("No selected light.\n");
2942 VectorCopy(r_shadow_selectedlight->origin, origin);
2943 VectorCopy(r_shadow_selectedlight->angles, angles);
2944 VectorCopy(r_shadow_selectedlight->color, color);
2945 radius = r_shadow_selectedlight->radius;
2946 style = r_shadow_selectedlight->style;
2947 if (r_shadow_selectedlight->cubemapname)
2948 strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
2951 shadows = r_shadow_selectedlight->shadow;
2952 corona = r_shadow_selectedlight->corona;
2953 if (!strcmp(Cmd_Argv(1), "origin"))
2955 if (Cmd_Argc() != 5)
2957 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
2960 origin[0] = atof(Cmd_Argv(2));
2961 origin[1] = atof(Cmd_Argv(3));
2962 origin[2] = atof(Cmd_Argv(4));
2964 else if (!strcmp(Cmd_Argv(1), "originx"))
2966 if (Cmd_Argc() != 3)
2968 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2971 origin[0] = atof(Cmd_Argv(2));
2973 else if (!strcmp(Cmd_Argv(1), "originy"))
2975 if (Cmd_Argc() != 3)
2977 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2980 origin[1] = atof(Cmd_Argv(2));
2982 else if (!strcmp(Cmd_Argv(1), "originz"))
2984 if (Cmd_Argc() != 3)
2986 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2989 origin[2] = atof(Cmd_Argv(2));
2991 else if (!strcmp(Cmd_Argv(1), "move"))
2993 if (Cmd_Argc() != 5)
2995 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
2998 origin[0] += atof(Cmd_Argv(2));
2999 origin[1] += atof(Cmd_Argv(3));
3000 origin[2] += atof(Cmd_Argv(4));
3002 else if (!strcmp(Cmd_Argv(1), "movex"))
3004 if (Cmd_Argc() != 3)
3006 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3009 origin[0] += atof(Cmd_Argv(2));
3011 else if (!strcmp(Cmd_Argv(1), "movey"))
3013 if (Cmd_Argc() != 3)
3015 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3018 origin[1] += atof(Cmd_Argv(2));
3020 else if (!strcmp(Cmd_Argv(1), "movez"))
3022 if (Cmd_Argc() != 3)
3024 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3027 origin[2] += atof(Cmd_Argv(2));
3029 else if (!strcmp(Cmd_Argv(1), "angles"))
3031 if (Cmd_Argc() != 5)
3033 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3036 angles[0] = atof(Cmd_Argv(2));
3037 angles[1] = atof(Cmd_Argv(3));
3038 angles[2] = atof(Cmd_Argv(4));
3040 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3042 if (Cmd_Argc() != 3)
3044 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3047 angles[0] = atof(Cmd_Argv(2));
3049 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3051 if (Cmd_Argc() != 3)
3053 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3056 angles[1] = atof(Cmd_Argv(2));
3058 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3060 if (Cmd_Argc() != 3)
3062 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3065 angles[2] = atof(Cmd_Argv(2));
3067 else if (!strcmp(Cmd_Argv(1), "color"))
3069 if (Cmd_Argc() != 5)
3071 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3074 color[0] = atof(Cmd_Argv(2));
3075 color[1] = atof(Cmd_Argv(3));
3076 color[2] = atof(Cmd_Argv(4));
3078 else if (!strcmp(Cmd_Argv(1), "radius"))
3080 if (Cmd_Argc() != 3)
3082 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3085 radius = atof(Cmd_Argv(2));
3087 else if (!strcmp(Cmd_Argv(1), "style"))
3089 if (Cmd_Argc() != 3)
3091 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3094 style = atoi(Cmd_Argv(2));
3096 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3100 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3103 if (Cmd_Argc() == 3)
3104 strcpy(cubemapname, Cmd_Argv(2));
3108 else if (!strcmp(Cmd_Argv(1), "shadows"))
3110 if (Cmd_Argc() != 3)
3112 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3115 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3117 else if (!strcmp(Cmd_Argv(1), "corona"))
3119 if (Cmd_Argc() != 3)
3121 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3124 corona = atof(Cmd_Argv(2));
3128 Con_Print("usage: r_editlights_edit [property] [value]\n");
3129 Con_Print("Selected light's properties:\n");
3130 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3131 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3132 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3133 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3134 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3135 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3136 Con_Printf("Shadows: %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3137 Con_Printf("Cubemap: %s\n", r_shadow_selectedlight->cubemapname);
3140 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3141 r_shadow_selectedlight = NULL;
3142 R_Shadow_NewWorldLight(origin, angles, color, radius, corona, style, shadows, cubemapname);
3145 extern int con_vislines;
3146 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3150 if (r_shadow_selectedlight == NULL)
3154 sprintf(temp, "Light properties");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3155 sprintf(temp, "Origin %f %f %f", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3156 sprintf(temp, "Angles %f %f %f", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3157 sprintf(temp, "Color %f %f %f", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3158 sprintf(temp, "Radius %f", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3159 sprintf(temp, "Corona %f", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3160 sprintf(temp, "Style %i", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3161 sprintf(temp, "Shadows %s", r_shadow_selectedlight->shadow ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3162 sprintf(temp, "Cubemap %s", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3165 void R_Shadow_EditLights_ToggleShadow_f(void)
3167 if (!r_editlights.integer)
3169 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3172 if (!r_shadow_selectedlight)
3174 Con_Print("No selected light.\n");
3177 R_Shadow_NewWorldLight(r_shadow_selectedlight->origin, r_shadow_selectedlight->angles, r_shadow_selectedlight->color, r_shadow_selectedlight->radius, r_shadow_selectedlight->corona, r_shadow_selectedlight->style, !r_shadow_selectedlight->shadow, r_shadow_selectedlight->cubemapname);
3178 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3179 r_shadow_selectedlight = NULL;
3182 void R_Shadow_EditLights_ToggleCorona_f(void)
3184 if (!r_editlights.integer)
3186 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3189 if (!r_shadow_selectedlight)
3191 Con_Print("No selected light.\n");
3194 R_Shadow_NewWorldLight(r_shadow_selectedlight->origin, r_shadow_selectedlight->angles, r_shadow_selectedlight->color, r_shadow_selectedlight->radius, !r_shadow_selectedlight->corona, r_shadow_selectedlight->style, r_shadow_selectedlight->shadow, r_shadow_selectedlight->cubemapname);
3195 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3196 r_shadow_selectedlight = NULL;
3199 void R_Shadow_EditLights_Remove_f(void)
3201 if (!r_editlights.integer)
3203 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
3206 if (!r_shadow_selectedlight)
3208 Con_Print("No selected light.\n");
3211 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3212 r_shadow_selectedlight = NULL;
3215 void R_Shadow_EditLights_Help_f(void)
3218 "Documentation on r_editlights system:\n"
3220 "r_editlights : enable/disable editing mode\n"
3221 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
3222 "r_editlights_cursorpushback : push back cursor this far from surface\n"
3223 "r_editlights_cursorpushoff : push cursor off surface this far\n"
3224 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
3225 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
3226 "r_editlights_rtlightssizescale : imported rtlight size scaling\n"
3227 "r_editlights_rtlightscolorscale : imported rtlight color scaling\n"
3229 "r_editlights_help : this help\n"
3230 "r_editlights_clear : remove all lights\n"
3231 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
3232 "r_editlights_save : save to .rtlights file\n"
3233 "r_editlights_spawn : create a light with default settings\n"
3234 "r_editlights_edit command : edit selected light - more documentation below\n"
3235 "r_editlights_remove : remove selected light\n"
3236 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
3237 "r_editlights_importlightentitiesfrommap : reload light entities\n"
3238 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
3240 "origin x y z : set light location\n"
3241 "originx x: set x component of light location\n"
3242 "originy y: set y component of light location\n"
3243 "originz z: set z component of light location\n"
3244 "move x y z : adjust light location\n"
3245 "movex x: adjust x component of light location\n"
3246 "movey y: adjust y component of light location\n"
3247 "movez z: adjust z component of light location\n"
3248 "angles x y z : set light angles\n"
3249 "anglesx x: set x component of light angles\n"
3250 "anglesy y: set y component of light angles\n"
3251 "anglesz z: set z component of light angles\n"
3252 "color r g b : set color of light (can be brighter than 1 1 1)\n"
3253 "radius radius : set radius (size) of light\n"
3254 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
3255 "cubemap basename : set filter cubemap of light (not yet supported)\n"
3256 "shadows 1/0 : turn on/off shadows\n"
3257 "corona n : set corona intensity\n"
3258 "<nothing> : print light properties to console\n"
3262 void R_Shadow_EditLights_Init(void)
3264 Cvar_RegisterVariable(&r_editlights);
3265 Cvar_RegisterVariable(&r_editlights_cursordistance);
3266 Cvar_RegisterVariable(&r_editlights_cursorpushback);
3267 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
3268 Cvar_RegisterVariable(&r_editlights_cursorgrid);
3269 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
3270 Cvar_RegisterVariable(&r_editlights_rtlightssizescale);
3271 Cvar_RegisterVariable(&r_editlights_rtlightscolorscale);
3272 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
3273 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
3274 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
3275 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
3276 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
3277 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
3278 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
3279 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
3280 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
3281 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
3282 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);