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", "1"};
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", "1000000"};
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 if (BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
935 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
938 for (i = 0;i < 3;i++)
940 if (r_viewforward[i] >= 0)
951 f = DotProduct(r_viewforward, r_vieworigin) + 1;
952 if (DotProduct(r_viewforward, v2) <= f)
954 // entirely behind nearclip plane
957 if (DotProduct(r_viewforward, v) >= f)
959 // entirely infront of nearclip plane
960 x1 = y1 = x2 = y2 = 0;
961 for (i = 0;i < 8;i++)
963 v[0] = (i & 1) ? mins[0] : maxs[0];
964 v[1] = (i & 2) ? mins[1] : maxs[1];
965 v[2] = (i & 4) ? mins[2] : maxs[2];
967 GL_TransformToScreen(v, v2);
968 //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]);
987 // clipped by nearclip plane
988 // this is nasty and crude...
989 // create viewspace bbox
990 for (i = 0;i < 8;i++)
992 v[0] = ((i & 1) ? mins[0] : maxs[0]) - r_vieworigin[0];
993 v[1] = ((i & 2) ? mins[1] : maxs[1]) - r_vieworigin[1];
994 v[2] = ((i & 4) ? mins[2] : maxs[2]) - r_vieworigin[2];
995 v2[0] = -DotProduct(v, r_viewleft);
996 v2[1] = DotProduct(v, r_viewup);
997 v2[2] = DotProduct(v, r_viewforward);
1000 if (smins[0] > v2[0]) smins[0] = v2[0];
1001 if (smaxs[0] < v2[0]) smaxs[0] = v2[0];
1002 if (smins[1] > v2[1]) smins[1] = v2[1];
1003 if (smaxs[1] < v2[1]) smaxs[1] = v2[1];
1004 if (smins[2] > v2[2]) smins[2] = v2[2];
1005 if (smaxs[2] < v2[2]) smaxs[2] = v2[2];
1009 smins[0] = smaxs[0] = v2[0];
1010 smins[1] = smaxs[1] = v2[1];
1011 smins[2] = smaxs[2] = v2[2];
1014 // now we have a bbox in viewspace
1015 // clip it to the view plane
1018 // return true if that culled the box
1019 if (smins[2] >= smaxs[2])
1021 // ok some of it is infront of the view, transform each corner back to
1022 // worldspace and then to screenspace and make screen rect
1023 // initialize these variables just to avoid compiler warnings
1024 x1 = y1 = x2 = y2 = 0;
1025 for (i = 0;i < 8;i++)
1027 v2[0] = (i & 1) ? smins[0] : smaxs[0];
1028 v2[1] = (i & 2) ? smins[1] : smaxs[1];
1029 v2[2] = (i & 4) ? smins[2] : smaxs[2];
1030 v[0] = v2[0] * -r_viewleft[0] + v2[1] * r_viewup[0] + v2[2] * r_viewforward[0] + r_vieworigin[0];
1031 v[1] = v2[0] * -r_viewleft[1] + v2[1] * r_viewup[1] + v2[2] * r_viewforward[1] + r_vieworigin[1];
1032 v[2] = v2[0] * -r_viewleft[2] + v2[1] * r_viewup[2] + v2[2] * r_viewforward[2] + r_vieworigin[2];
1034 GL_TransformToScreen(v, v2);
1035 //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]);
1052 // this code doesn't handle boxes with any points behind view properly
1053 x1 = 1000;x2 = -1000;
1054 y1 = 1000;y2 = -1000;
1055 for (i = 0;i < 8;i++)
1057 v[0] = (i & 1) ? mins[0] : maxs[0];
1058 v[1] = (i & 2) ? mins[1] : maxs[1];
1059 v[2] = (i & 4) ? mins[2] : maxs[2];
1061 GL_TransformToScreen(v, v2);
1062 //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]);
1080 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1081 if (ix1 < r_view_x) ix1 = r_view_x;
1082 if (iy1 < r_view_y) iy1 = r_view_y;
1083 if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
1084 if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
1085 if (ix2 <= ix1 || iy2 <= iy1)
1087 // set up the scissor rectangle
1088 GL_Scissor(ix1, vid.realheight - iy2, ix2 - ix1, iy2 - iy1);
1089 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1090 //qglEnable(GL_SCISSOR_TEST);
1095 static void R_Shadow_VertexShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1097 float *color4f = varray_color4f;
1098 float dist, dot, intensity, v[3], n[3];
1099 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1101 Matrix4x4_Transform(m, vertex3f, v);
1102 if ((dist = DotProduct(v, v)) < 1)
1104 Matrix4x4_Transform3x3(m, normal3f, n);
1105 if ((dot = DotProduct(n, v)) > 0)
1108 intensity = dot / (VectorLength(v) * VectorLength(n));
1109 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1110 VectorScale(lightcolor, intensity, color4f);
1115 VectorClear(color4f);
1121 VectorClear(color4f);
1127 static void R_Shadow_VertexShadingWithZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1129 float *color4f = varray_color4f;
1130 float dist, dot, intensity, v[3], n[3];
1131 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1133 Matrix4x4_Transform(m, vertex3f, v);
1134 if ((dist = fabs(v[2])) < 1)
1136 Matrix4x4_Transform3x3(m, normal3f, n);
1137 if ((dot = DotProduct(n, v)) > 0)
1139 intensity = dot / (VectorLength(v) * VectorLength(n));
1140 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1141 VectorScale(lightcolor, intensity, color4f);
1146 VectorClear(color4f);
1152 VectorClear(color4f);
1158 static void R_Shadow_VertexShading(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1160 float *color4f = varray_color4f;
1161 float dot, intensity, v[3], n[3];
1162 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1164 Matrix4x4_Transform(m, vertex3f, v);
1165 Matrix4x4_Transform3x3(m, normal3f, n);
1166 if ((dot = DotProduct(n, v)) > 0)
1168 intensity = dot / (VectorLength(v) * VectorLength(n));
1169 VectorScale(lightcolor, intensity, color4f);
1174 VectorClear(color4f);
1180 #define USETEXMATRIX 1
1181 #ifndef USETEXMATRIX
1182 // FIXME: this should be done in a texture matrix or vertex program when possible
1183 // FIXME: if vertex program not available, this would really benefit from 3DNow! or SSE
1184 static void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1188 tc3f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1189 tc3f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1190 tc3f[2] = vertex3f[0] * matrix->m[2][0] + vertex3f[1] * matrix->m[2][1] + vertex3f[2] * matrix->m[2][2] + matrix->m[2][3];
1197 static void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1201 tc2f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1202 tc2f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1210 static 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)
1214 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1216 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1217 // the cubemap normalizes this for us
1218 out3f[0] = DotProduct(svector3f, lightdir);
1219 out3f[1] = DotProduct(tvector3f, lightdir);
1220 out3f[2] = DotProduct(normal3f, lightdir);
1224 static 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)
1227 float lightdir[3], eyedir[3], halfdir[3];
1228 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1230 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1231 VectorNormalizeFast(lightdir);
1232 VectorSubtract(vertex3f, relativeeyeorigin, eyedir);
1233 VectorNormalizeFast(eyedir);
1234 VectorAdd(lightdir, eyedir, halfdir);
1235 // the cubemap normalizes this for us
1236 out3f[0] = DotProduct(svector3f, halfdir);
1237 out3f[1] = DotProduct(tvector3f, halfdir);
1238 out3f[2] = DotProduct(normal3f, halfdir);
1242 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)
1245 float color[3], color2[3], colorscale;
1248 bumptexture = r_shadow_blankbumptexture;
1250 glosstexture = r_shadow_blankglosstexture;
1251 GL_DepthMask(false);
1253 if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
1255 if (lighting & LIGHTING_DIFFUSE)
1258 colorscale = r_shadow_lightintensityscale.value;
1259 // colorscale accounts for how much we multiply the brightness
1262 // mult is how many times the final pass of the lighting will be
1263 // performed to get more brightness than otherwise possible.
1265 // Limit mult to 64 for sanity sake.
1266 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1268 // 3/2 3D combine path (Geforce3, Radeon 8500)
1269 memset(&m, 0, sizeof(m));
1270 m.pointer_vertex = vertex3f;
1271 m.tex[0] = R_GetTexture(bumptexture);
1272 m.texcombinergb[0] = GL_REPLACE;
1273 m.pointer_texcoord[0] = texcoord2f;
1274 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1275 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1276 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1277 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1278 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1280 m.pointer_texcoord3f[2] = vertex3f;
1281 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
1283 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1284 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1287 GL_ColorMask(0,0,0,1);
1288 GL_BlendFunc(GL_ONE, GL_ZERO);
1289 GL_LockArrays(0, numverts);
1290 R_Mesh_Draw(numverts, numtriangles, elements);
1291 GL_LockArrays(0, 0);
1293 c_rt_lighttris += numtriangles;
1295 memset(&m, 0, sizeof(m));
1296 m.pointer_vertex = vertex3f;
1297 m.tex[0] = R_GetTexture(basetexture);
1298 m.pointer_texcoord[0] = texcoord2f;
1301 m.texcubemap[1] = R_GetTexture(lightcubemap);
1303 m.pointer_texcoord3f[1] = vertex3f;
1304 m.texmatrix[1] = *matrix_modeltolight;
1306 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1307 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1311 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap)
1313 // 1/2/2 3D combine path (original Radeon)
1314 memset(&m, 0, sizeof(m));
1315 m.pointer_vertex = vertex3f;
1316 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1318 m.pointer_texcoord3f[0] = vertex3f;
1319 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1321 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1322 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1325 GL_ColorMask(0,0,0,1);
1326 GL_BlendFunc(GL_ONE, GL_ZERO);
1327 GL_LockArrays(0, numverts);
1328 R_Mesh_Draw(numverts, numtriangles, elements);
1329 GL_LockArrays(0, 0);
1331 c_rt_lighttris += numtriangles;
1333 memset(&m, 0, sizeof(m));
1334 m.pointer_vertex = vertex3f;
1335 m.tex[0] = R_GetTexture(bumptexture);
1336 m.texcombinergb[0] = GL_REPLACE;
1337 m.pointer_texcoord[0] = texcoord2f;
1338 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1339 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1340 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1341 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1343 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1344 GL_LockArrays(0, numverts);
1345 R_Mesh_Draw(numverts, numtriangles, elements);
1346 GL_LockArrays(0, 0);
1348 c_rt_lighttris += numtriangles;
1350 memset(&m, 0, sizeof(m));
1351 m.pointer_vertex = vertex3f;
1352 m.tex[0] = R_GetTexture(basetexture);
1353 m.pointer_texcoord[0] = texcoord2f;
1356 m.texcubemap[1] = R_GetTexture(lightcubemap);
1358 m.pointer_texcoord3f[1] = vertex3f;
1359 m.texmatrix[1] = *matrix_modeltolight;
1361 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1362 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1366 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap)
1368 // 2/2 3D combine path (original Radeon)
1369 memset(&m, 0, sizeof(m));
1370 m.pointer_vertex = vertex3f;
1371 m.tex[0] = R_GetTexture(bumptexture);
1372 m.texcombinergb[0] = GL_REPLACE;
1373 m.pointer_texcoord[0] = texcoord2f;
1374 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1375 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1376 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1377 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1379 GL_ColorMask(0,0,0,1);
1380 GL_BlendFunc(GL_ONE, GL_ZERO);
1381 GL_LockArrays(0, numverts);
1382 R_Mesh_Draw(numverts, numtriangles, elements);
1383 GL_LockArrays(0, 0);
1385 c_rt_lighttris += numtriangles;
1387 memset(&m, 0, sizeof(m));
1388 m.pointer_vertex = vertex3f;
1389 m.tex[0] = R_GetTexture(basetexture);
1390 m.pointer_texcoord[0] = texcoord2f;
1391 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1393 m.pointer_texcoord3f[1] = vertex3f;
1394 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1396 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1397 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1400 else if (r_textureunits.integer >= 4)
1402 // 4/2 2D combine path (Geforce3, Radeon 8500)
1403 memset(&m, 0, sizeof(m));
1404 m.pointer_vertex = vertex3f;
1405 m.tex[0] = R_GetTexture(bumptexture);
1406 m.texcombinergb[0] = GL_REPLACE;
1407 m.pointer_texcoord[0] = texcoord2f;
1408 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1409 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1410 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1411 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1412 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1414 m.pointer_texcoord3f[2] = vertex3f;
1415 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
1417 m.pointer_texcoord[2] = varray_texcoord2f[2];
1418 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1420 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1422 m.pointer_texcoord3f[3] = vertex3f;
1423 m.texmatrix[3] = *matrix_modeltoattenuationz;
1425 m.pointer_texcoord[3] = varray_texcoord2f[3];
1426 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[3], numverts, vertex3f, matrix_modeltoattenuationz);
1429 GL_ColorMask(0,0,0,1);
1430 GL_BlendFunc(GL_ONE, GL_ZERO);
1431 GL_LockArrays(0, numverts);
1432 R_Mesh_Draw(numverts, numtriangles, elements);
1433 GL_LockArrays(0, 0);
1435 c_rt_lighttris += numtriangles;
1437 memset(&m, 0, sizeof(m));
1438 m.pointer_vertex = vertex3f;
1439 m.tex[0] = R_GetTexture(basetexture);
1440 m.pointer_texcoord[0] = texcoord2f;
1443 m.texcubemap[1] = R_GetTexture(lightcubemap);
1445 m.pointer_texcoord3f[1] = vertex3f;
1446 m.texmatrix[1] = *matrix_modeltolight;
1448 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1449 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1455 // 2/2/2 2D combine path (any dot3 card)
1456 memset(&m, 0, sizeof(m));
1457 m.pointer_vertex = vertex3f;
1458 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1460 m.pointer_texcoord3f[0] = vertex3f;
1461 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1463 m.pointer_texcoord[0] = varray_texcoord2f[0];
1464 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1466 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1468 m.pointer_texcoord3f[1] = vertex3f;
1469 m.texmatrix[1] = *matrix_modeltoattenuationz;
1471 m.pointer_texcoord[1] = varray_texcoord2f[1];
1472 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1475 GL_ColorMask(0,0,0,1);
1476 GL_BlendFunc(GL_ONE, GL_ZERO);
1477 GL_LockArrays(0, numverts);
1478 R_Mesh_Draw(numverts, numtriangles, elements);
1479 GL_LockArrays(0, 0);
1481 c_rt_lighttris += numtriangles;
1483 memset(&m, 0, sizeof(m));
1484 m.pointer_vertex = vertex3f;
1485 m.tex[0] = R_GetTexture(bumptexture);
1486 m.texcombinergb[0] = GL_REPLACE;
1487 m.pointer_texcoord[0] = texcoord2f;
1488 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1489 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1490 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1491 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1493 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1494 GL_LockArrays(0, numverts);
1495 R_Mesh_Draw(numverts, numtriangles, elements);
1496 GL_LockArrays(0, 0);
1498 c_rt_lighttris += numtriangles;
1500 memset(&m, 0, sizeof(m));
1501 m.pointer_vertex = vertex3f;
1502 m.tex[0] = R_GetTexture(basetexture);
1503 m.pointer_texcoord[0] = texcoord2f;
1506 m.texcubemap[1] = R_GetTexture(lightcubemap);
1508 m.pointer_texcoord3f[1] = vertex3f;
1509 m.texmatrix[1] = *matrix_modeltolight;
1511 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1512 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1516 // this final code is shared
1518 GL_ColorMask(1,1,1,0);
1519 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1520 VectorScale(lightcolor, colorscale, color2);
1521 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1523 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1524 GL_LockArrays(0, numverts);
1525 R_Mesh_Draw(numverts, numtriangles, elements);
1526 GL_LockArrays(0, 0);
1528 c_rt_lighttris += numtriangles;
1531 if ((lighting & LIGHTING_SPECULAR) && (r_shadow_gloss.integer >= 2 || (r_shadow_gloss.integer >= 1 && glosstexture != r_shadow_blankglosstexture)))
1533 // FIXME: detect blendsquare!
1534 //if (gl_support_blendsquare)
1536 colorscale = r_shadow_lightintensityscale.value * r_shadow_glossintensity.value;
1537 if (glosstexture == r_shadow_blankglosstexture)
1538 colorscale *= r_shadow_gloss2intensity.value;
1540 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1542 // 2/0/0/1/2 3D combine blendsquare path
1543 memset(&m, 0, sizeof(m));
1544 m.pointer_vertex = vertex3f;
1545 m.tex[0] = R_GetTexture(bumptexture);
1546 m.pointer_texcoord[0] = texcoord2f;
1547 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1548 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1549 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1550 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1552 GL_ColorMask(0,0,0,1);
1553 // this squares the result
1554 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1555 GL_LockArrays(0, numverts);
1556 R_Mesh_Draw(numverts, numtriangles, elements);
1557 GL_LockArrays(0, 0);
1559 c_rt_lighttris += numtriangles;
1561 memset(&m, 0, sizeof(m));
1562 m.pointer_vertex = vertex3f;
1564 GL_LockArrays(0, numverts);
1565 // square alpha in framebuffer a few times to make it shiny
1566 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1567 // these comments are a test run through this math for intensity 0.5
1568 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1569 // 0.25 * 0.25 = 0.0625 (this is another pass)
1570 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1571 R_Mesh_Draw(numverts, numtriangles, elements);
1573 c_rt_lighttris += numtriangles;
1574 R_Mesh_Draw(numverts, numtriangles, elements);
1576 c_rt_lighttris += numtriangles;
1577 GL_LockArrays(0, 0);
1579 memset(&m, 0, sizeof(m));
1580 m.pointer_vertex = vertex3f;
1581 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1583 m.pointer_texcoord3f[0] = vertex3f;
1584 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1586 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1587 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1590 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1591 GL_LockArrays(0, numverts);
1592 R_Mesh_Draw(numverts, numtriangles, elements);
1593 GL_LockArrays(0, 0);
1595 c_rt_lighttris += numtriangles;
1597 memset(&m, 0, sizeof(m));
1598 m.pointer_vertex = vertex3f;
1599 m.tex[0] = R_GetTexture(glosstexture);
1600 m.pointer_texcoord[0] = texcoord2f;
1603 m.texcubemap[1] = R_GetTexture(lightcubemap);
1605 m.pointer_texcoord3f[1] = vertex3f;
1606 m.texmatrix[1] = *matrix_modeltolight;
1608 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1609 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1613 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1615 // 2/0/0/2 3D combine blendsquare path
1616 memset(&m, 0, sizeof(m));
1617 m.pointer_vertex = vertex3f;
1618 m.tex[0] = R_GetTexture(bumptexture);
1619 m.pointer_texcoord[0] = texcoord2f;
1620 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1621 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1622 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1623 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1625 GL_ColorMask(0,0,0,1);
1626 // this squares the result
1627 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1628 GL_LockArrays(0, numverts);
1629 R_Mesh_Draw(numverts, numtriangles, elements);
1630 GL_LockArrays(0, 0);
1632 c_rt_lighttris += numtriangles;
1634 memset(&m, 0, sizeof(m));
1635 m.pointer_vertex = vertex3f;
1637 GL_LockArrays(0, numverts);
1638 // square alpha in framebuffer a few times to make it shiny
1639 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1640 // these comments are a test run through this math for intensity 0.5
1641 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1642 // 0.25 * 0.25 = 0.0625 (this is another pass)
1643 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1644 R_Mesh_Draw(numverts, numtriangles, elements);
1646 c_rt_lighttris += numtriangles;
1647 R_Mesh_Draw(numverts, numtriangles, elements);
1649 c_rt_lighttris += numtriangles;
1650 GL_LockArrays(0, 0);
1652 memset(&m, 0, sizeof(m));
1653 m.pointer_vertex = vertex3f;
1654 m.tex[0] = R_GetTexture(glosstexture);
1655 m.pointer_texcoord[0] = texcoord2f;
1656 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1658 m.pointer_texcoord3f[1] = vertex3f;
1659 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1661 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1662 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1667 // 2/0/0/2/2 2D combine blendsquare path
1668 memset(&m, 0, sizeof(m));
1669 m.pointer_vertex = vertex3f;
1670 m.tex[0] = R_GetTexture(bumptexture);
1671 m.pointer_texcoord[0] = texcoord2f;
1672 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1673 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1674 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1675 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1677 GL_ColorMask(0,0,0,1);
1678 // this squares the result
1679 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1680 GL_LockArrays(0, numverts);
1681 R_Mesh_Draw(numverts, numtriangles, elements);
1682 GL_LockArrays(0, 0);
1684 c_rt_lighttris += numtriangles;
1686 memset(&m, 0, sizeof(m));
1687 m.pointer_vertex = vertex3f;
1689 GL_LockArrays(0, numverts);
1690 // square alpha in framebuffer a few times to make it shiny
1691 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1692 // these comments are a test run through this math for intensity 0.5
1693 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1694 // 0.25 * 0.25 = 0.0625 (this is another pass)
1695 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1696 R_Mesh_Draw(numverts, numtriangles, elements);
1698 c_rt_lighttris += numtriangles;
1699 R_Mesh_Draw(numverts, numtriangles, elements);
1701 c_rt_lighttris += numtriangles;
1702 GL_LockArrays(0, 0);
1704 memset(&m, 0, sizeof(m));
1705 m.pointer_vertex = vertex3f;
1706 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1708 m.pointer_texcoord3f[0] = vertex3f;
1709 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1711 m.pointer_texcoord[0] = varray_texcoord2f[0];
1712 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1714 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1716 m.pointer_texcoord3f[1] = vertex3f;
1717 m.texmatrix[1] = *matrix_modeltoattenuationz;
1719 m.pointer_texcoord[1] = varray_texcoord2f[1];
1720 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1723 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1724 GL_LockArrays(0, numverts);
1725 R_Mesh_Draw(numverts, numtriangles, elements);
1726 GL_LockArrays(0, 0);
1728 c_rt_lighttris += numtriangles;
1730 memset(&m, 0, sizeof(m));
1731 m.pointer_vertex = vertex3f;
1732 m.tex[0] = R_GetTexture(glosstexture);
1733 m.pointer_texcoord[0] = texcoord2f;
1736 m.texcubemap[1] = R_GetTexture(lightcubemap);
1738 m.pointer_texcoord3f[1] = vertex3f;
1739 m.texmatrix[1] = *matrix_modeltolight;
1741 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1742 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1748 GL_ColorMask(1,1,1,0);
1749 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1750 VectorScale(lightcolor, colorscale, color2);
1751 GL_LockArrays(0, numverts);
1752 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1754 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1755 R_Mesh_Draw(numverts, numtriangles, elements);
1757 c_rt_lighttris += numtriangles;
1759 GL_LockArrays(0, 0);
1764 if (lighting & LIGHTING_DIFFUSE)
1766 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1767 VectorScale(lightcolor, r_shadow_lightintensityscale.value, color2);
1768 memset(&m, 0, sizeof(m));
1769 m.pointer_vertex = vertex3f;
1770 m.pointer_color = varray_color4f;
1771 m.tex[0] = R_GetTexture(basetexture);
1772 m.pointer_texcoord[0] = texcoord2f;
1773 if (r_textureunits.integer >= 2)
1776 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1778 m.pointer_texcoord3f[1] = vertex3f;
1779 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1781 m.pointer_texcoord[1] = varray_texcoord2f[1];
1782 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1784 if (r_textureunits.integer >= 3)
1786 // Geforce3/Radeon class but not using dot3
1787 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1789 m.pointer_texcoord3f[2] = vertex3f;
1790 m.texmatrix[2] = *matrix_modeltoattenuationz;
1792 m.pointer_texcoord[2] = varray_texcoord2f[2];
1793 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationz);
1798 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1800 color[0] = bound(0, color2[0], 1);
1801 color[1] = bound(0, color2[1], 1);
1802 color[2] = bound(0, color2[2], 1);
1803 if (r_textureunits.integer >= 3)
1804 R_Shadow_VertexShading(numverts, vertex3f, normal3f, color, matrix_modeltolight);
1805 else if (r_textureunits.integer >= 2)
1806 R_Shadow_VertexShadingWithZAttenuation(numverts, vertex3f, normal3f, color, matrix_modeltolight);
1808 R_Shadow_VertexShadingWithXYZAttenuation(numverts, vertex3f, normal3f, color, matrix_modeltolight);
1809 GL_LockArrays(0, numverts);
1810 R_Mesh_Draw(numverts, numtriangles, elements);
1811 GL_LockArrays(0, 0);
1813 c_rt_lighttris += numtriangles;
1819 void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
1823 R_RTLight_Uncompile(rtlight);
1824 memset(rtlight, 0, sizeof(*rtlight));
1826 VectorCopy(light->origin, rtlight->shadoworigin);
1827 VectorCopy(light->color, rtlight->color);
1828 rtlight->radius = light->radius;
1829 //rtlight->cullradius = rtlight->radius;
1830 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
1831 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
1832 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
1833 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
1834 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
1835 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
1836 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
1837 rtlight->cubemapname[0] = 0;
1838 if (light->cubemapname[0])
1839 strcpy(rtlight->cubemapname, light->cubemapname);
1840 else if (light->cubemapnum > 0)
1841 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
1842 rtlight->shadow = light->shadow;
1843 rtlight->corona = light->corona;
1844 rtlight->style = light->style;
1845 rtlight->isstatic = isstatic;
1846 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
1847 // ConcatScale won't work here because this needs to scale rotate and
1848 // translate, not just rotate
1849 scale = 1.0f / rtlight->radius;
1850 for (k = 0;k < 3;k++)
1851 for (j = 0;j < 4;j++)
1852 rtlight->matrix_worldtolight.m[k][j] *= scale;
1853 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationxyz, &matrix_attenuationxyz, &rtlight->matrix_worldtolight);
1854 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationz, &matrix_attenuationz, &rtlight->matrix_worldtolight);
1856 rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
1857 rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
1858 VectorScale(rtlight->color, rtlight->radius * d_lightstylevalue[rtlight->style] * 0.125f, rtlight->lightmap_light);
1859 rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
1862 rtlight_t *r_shadow_compilingrtlight;
1864 // compiles rtlight geometry
1865 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
1866 void R_RTLight_Compile(rtlight_t *rtlight)
1868 int shadowmeshes, shadowtris, lightmeshes, lighttris, numclusters, numsurfaces;
1869 entity_render_t *ent = &cl_entities[0].render;
1870 model_t *model = ent->model;
1872 // compile the light
1873 rtlight->compiled = true;
1874 rtlight->static_numclusters = 0;
1875 rtlight->static_numclusterpvsbytes = 0;
1876 rtlight->static_clusterlist = NULL;
1877 rtlight->static_clusterpvs = NULL;
1878 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
1879 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
1880 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
1881 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
1882 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
1883 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
1885 if (model && model->GetLightInfo)
1887 // this variable directs the DrawShadowVolume and DrawLight code to capture into the mesh chain instead of rendering
1888 r_shadow_compilingrtlight = rtlight;
1889 R_Shadow_EnlargeClusterBuffer(model->brush.num_pvsclusters);
1890 R_Shadow_EnlargeSurfaceBuffer(model->nummodelsurfaces);
1891 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);
1894 rtlight->static_numclusters = numclusters;
1895 rtlight->static_numclusterpvsbytes = (model->brush.num_pvsclusters + 7) >> 3;
1896 rtlight->static_clusterlist = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
1897 rtlight->static_clusterpvs = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusterpvsbytes);
1898 memcpy(rtlight->static_clusterlist, r_shadow_buffer_clusterlist, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
1899 memcpy(rtlight->static_clusterpvs, r_shadow_buffer_clusterpvs, rtlight->static_numclusterpvsbytes);
1901 if (model->DrawShadowVolume && rtlight->shadow)
1903 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
1904 model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
1905 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_shadow, false, false);
1907 if (model->DrawLight)
1909 rtlight->static_meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true);
1910 model->DrawLight(ent, rtlight->shadoworigin, vec3_origin, rtlight->radius, vec3_origin, &r_identitymatrix, &r_identitymatrix, &r_identitymatrix, NULL, numsurfaces, r_shadow_buffer_surfacelist);
1911 rtlight->static_meshchain_light = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_light, true, false);
1913 // switch back to rendering when DrawShadowVolume or DrawLight is called
1914 r_shadow_compilingrtlight = NULL;
1918 // use smallest available cullradius - box radius or light radius
1919 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
1920 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
1924 if (rtlight->static_meshchain_shadow)
1927 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
1930 shadowtris += mesh->numtriangles;
1936 if (rtlight->static_meshchain_light)
1939 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
1942 lighttris += mesh->numtriangles;
1946 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);
1949 void R_RTLight_Uncompile(rtlight_t *rtlight)
1951 if (rtlight->compiled)
1953 if (rtlight->static_meshchain_shadow)
1954 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
1955 rtlight->static_meshchain_shadow = NULL;
1956 if (rtlight->static_meshchain_light)
1957 Mod_ShadowMesh_Free(rtlight->static_meshchain_light);
1958 rtlight->static_meshchain_light = NULL;
1959 if (rtlight->static_clusterlist)
1960 Mem_Free(rtlight->static_clusterlist);
1961 rtlight->static_clusterlist = NULL;
1962 if (rtlight->static_clusterpvs)
1963 Mem_Free(rtlight->static_clusterpvs);
1964 rtlight->static_clusterpvs = NULL;
1965 rtlight->static_numclusters = 0;
1966 rtlight->static_numclusterpvsbytes = 0;
1967 rtlight->compiled = false;
1971 int shadowframecount = 0;
1973 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light);
1975 void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes)
1978 entity_render_t *ent;
1980 vec3_t relativelightorigin, relativeeyeorigin, lightcolor;
1981 rtexture_t *cubemaptexture;
1982 matrix4x4_t matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz;
1983 int numclusters, numsurfaces;
1984 int *clusterlist, *surfacelist;
1986 vec3_t cullmins, cullmaxs;
1990 if (d_lightstylevalue[rtlight->style] <= 0)
1992 cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
1993 cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
1994 cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
1995 cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
1996 cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
1997 cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
1998 if (R_CullBox(cullmins, cullmaxs))
2000 if (rtlight->isstatic && !rtlight->compiled && r_shadow_staticworldlights.integer)
2001 R_RTLight_Compile(rtlight);
2007 if (rtlight->compiled && r_shadow_staticworldlights.integer)
2009 numclusters = rtlight->static_numclusters;
2010 clusterlist = rtlight->static_clusterlist;
2011 clusterpvs = rtlight->static_clusterpvs;
2012 VectorCopy(rtlight->cullmins, cullmins);
2013 VectorCopy(rtlight->cullmaxs, cullmaxs);
2015 else if (cl.worldmodel && cl.worldmodel->GetLightInfo)
2017 R_Shadow_EnlargeClusterBuffer(cl.worldmodel->brush.num_pvsclusters);
2018 R_Shadow_EnlargeSurfaceBuffer(cl.worldmodel->nummodelsurfaces);
2019 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);
2020 clusterlist = r_shadow_buffer_clusterlist;
2021 clusterpvs = r_shadow_buffer_clusterpvs;
2022 surfacelist = r_shadow_buffer_surfacelist;
2026 for (i = 0;i < numclusters;i++)
2027 if (CHECKPVSBIT(r_pvsbits, clusterlist[i]))
2029 if (i == numclusters)
2032 if (R_CullBox(cullmins, cullmaxs))
2034 if (R_Shadow_ScissorForBBox(cullmins, cullmaxs))
2037 f = d_lightstylevalue[rtlight->style] * (1.0f / 256.0f);
2038 VectorScale(rtlight->color, f, lightcolor);
2040 if (rtlight->selected)
2042 f = 2 + sin(realtime * M_PI * 4.0);
2043 VectorScale(lightcolor, f, lightcolor);
2047 if (rtlight->cubemapname[0])
2048 cubemaptexture = R_Shadow_Cubemap(rtlight->cubemapname);
2050 cubemaptexture = NULL;
2052 shadow = rtlight->shadow && (rtlight->isstatic ? r_shadow_worldshadows.integer : r_shadow_dlightshadows.integer);
2053 if (shadow && (gl_stencil || visiblevolumes))
2055 if (!visiblevolumes)
2056 R_Shadow_Stage_ShadowVolumes();
2057 ent = &cl_entities[0].render;
2058 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2060 memset(&m, 0, sizeof(m));
2061 R_Mesh_Matrix(&ent->matrix);
2062 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2064 m.pointer_vertex = mesh->vertex3f;
2066 GL_LockArrays(0, mesh->numverts);
2067 if (r_shadowstage == SHADOWSTAGE_STENCIL)
2069 // decrement stencil if frontface is behind depthbuffer
2070 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2071 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2072 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2073 c_rtcached_shadowmeshes++;
2074 c_rtcached_shadowtris += mesh->numtriangles;
2075 // increment stencil if backface is behind depthbuffer
2076 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2077 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2079 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2080 c_rtcached_shadowmeshes++;
2081 c_rtcached_shadowtris += mesh->numtriangles;
2082 GL_LockArrays(0, 0);
2087 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2088 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, numsurfaces, surfacelist);
2090 if (r_drawentities.integer)
2092 for (i = 0;i < r_refdef.numentities;i++)
2094 ent = r_refdef.entities[i];
2096 if (r_shadow_cull.integer)
2098 if (!BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs))
2100 if (cl.worldmodel != NULL && cl.worldmodel->brush.BoxTouchingPVS != NULL && !cl.worldmodel->brush.BoxTouchingPVS(cl.worldmodel, clusterpvs, ent->mins, ent->maxs))
2103 if (!(ent->flags & RENDER_SHADOW) || !ent->model || !ent->model->DrawShadowVolume)
2105 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2106 // light emitting entities should not cast their own shadow
2107 if (VectorLength2(relativelightorigin) < 0.1)
2109 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, ent->model->nummodelsurfaces, ent->model->surfacelist);
2114 if (!visiblevolumes)
2116 if (shadow && gl_stencil)
2117 R_Shadow_Stage_LightWithShadows();
2119 R_Shadow_Stage_LightWithoutShadows();
2121 ent = &cl_entities[0].render;
2122 if (ent->model && ent->model->DrawLight)
2124 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2125 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2126 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2127 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2128 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2129 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2131 R_Mesh_Matrix(&ent->matrix);
2132 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2133 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);
2136 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, numsurfaces, surfacelist);
2138 if (r_drawentities.integer)
2140 for (i = 0;i < r_refdef.numentities;i++)
2142 ent = r_refdef.entities[i];
2143 if (ent->visframe == r_framecount && BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs) && ent->model && ent->model->DrawLight && (ent->flags & RENDER_LIGHT))
2145 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2146 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2147 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2148 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2149 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2150 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, ent->model->nummodelsurfaces, ent->model->surfacelist);
2157 void R_ShadowVolumeLighting(int visiblevolumes)
2165 memset(&m, 0, sizeof(m));
2168 GL_BlendFunc(GL_ONE, GL_ONE);
2169 GL_DepthMask(false);
2170 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
2171 qglDisable(GL_CULL_FACE);
2172 GL_Color(0.0, 0.0125, 0.1, 1);
2175 R_Shadow_Stage_Begin();
2177 if (r_shadow_realtime_world.integer)
2179 R_Shadow_LoadWorldLightsIfNeeded();
2180 if (r_shadow_debuglight.integer >= 0)
2182 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2183 if (lnum == r_shadow_debuglight.integer)
2184 R_DrawRTLight(&light->rtlight, visiblevolumes);
2187 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2188 R_DrawRTLight(&light->rtlight, visiblevolumes);
2190 if (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer)
2191 for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
2192 R_DrawRTLight(&light->rtlight, visiblevolumes);
2196 qglEnable(GL_CULL_FACE);
2197 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
2200 R_Shadow_Stage_End();
2203 cvar_t r_editlights = {0, "r_editlights", "0"};
2204 cvar_t r_editlights_cursordistance = {0, "r_editlights_distance", "1024"};
2205 cvar_t r_editlights_cursorpushback = {0, "r_editlights_pushback", "0"};
2206 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_pushoff", "4"};
2207 cvar_t r_editlights_cursorgrid = {0, "r_editlights_grid", "4"};
2208 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "0.8"};
2209 cvar_t r_editlights_rtlightssizescale = {CVAR_SAVE, "r_editlights_rtlightssizescale", "0.7"};
2210 cvar_t r_editlights_rtlightscolorscale = {CVAR_SAVE, "r_editlights_rtlightscolorscale", "2"};
2211 dlight_t *r_shadow_worldlightchain;
2212 dlight_t *r_shadow_selectedlight;
2213 vec3_t r_editlights_cursorlocation;
2215 typedef struct cubemapinfo_s
2218 rtexture_t *texture;
2222 #define MAX_CUBEMAPS 128
2223 static int numcubemaps;
2224 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
2226 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2227 typedef struct suffixinfo_s
2230 int flipx, flipy, flipdiagonal;
2233 static suffixinfo_t suffix[3][6] =
2236 {"posx", false, false, false},
2237 {"negx", false, false, false},
2238 {"posy", false, false, false},
2239 {"negy", false, false, false},
2240 {"posz", false, false, false},
2241 {"negz", false, false, false}
2244 {"px", false, false, false},
2245 {"nx", false, false, false},
2246 {"py", false, false, false},
2247 {"ny", false, false, false},
2248 {"pz", false, false, false},
2249 {"nz", false, false, false}
2252 {"ft", true, false, true},
2253 {"bk", false, true, true},
2254 {"lf", true, true, false},
2255 {"rt", false, false, false},
2256 {"up", false, false, false},
2257 {"dn", false, false, false}
2261 static int componentorder[4] = {0, 1, 2, 3};
2263 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2265 int i, j, cubemapsize;
2266 qbyte *cubemappixels, *image_rgba;
2267 rtexture_t *cubemaptexture;
2269 // must start 0 so the first loadimagepixels has no requested width/height
2271 cubemappixels = NULL;
2272 cubemaptexture = NULL;
2273 for (j = 0;j < 3 && !cubemappixels;j++)
2275 for (i = 0;i < 6;i++)
2277 snprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2278 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2280 if (image_width == image_height)
2282 if (!cubemappixels && image_width >= 1)
2284 cubemapsize = image_width;
2285 // note this clears to black, so unavailable sizes are black
2286 cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2289 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);
2292 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2293 Mem_Free(image_rgba);
2299 if (!r_shadow_filters_texturepool)
2300 r_shadow_filters_texturepool = R_AllocTexturePool();
2301 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
2302 Mem_Free(cubemappixels);
2306 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
2307 for (j = 0;j < 3;j++)
2308 for (i = 0;i < 6;i++)
2309 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2310 Con_Print(" and was unable to find any of them.\n");
2312 return cubemaptexture;
2315 rtexture_t *R_Shadow_Cubemap(const char *basename)
2318 for (i = 0;i < numcubemaps;i++)
2319 if (!strcasecmp(cubemaps[i].basename, basename))
2320 return cubemaps[i].texture;
2321 if (i >= MAX_CUBEMAPS)
2324 strcpy(cubemaps[i].basename, basename);
2325 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
2326 return cubemaps[i].texture;
2329 void R_Shadow_FreeCubemaps(void)
2332 R_FreeTexturePool(&r_shadow_filters_texturepool);
2335 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)
2339 if (radius < 15 || DotProduct(color, color) < 0.03)
2341 Con_Print("R_Shadow_NewWorldLight: refusing to create a light too small/dim\n");
2345 light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
2346 VectorCopy(origin, light->origin);
2347 VectorCopy(angles, light->angles);
2348 VectorCopy(color, light->color);
2349 light->radius = radius;
2350 light->style = style;
2351 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
2353 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
2356 light->shadow = shadowenable;
2357 light->corona = corona;
2358 if (cubemapname && cubemapname[0] && strlen(cubemapname) < sizeof(light->cubemapname))
2359 strcpy(light->cubemapname, cubemapname);
2360 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
2361 light->next = r_shadow_worldlightchain;
2362 r_shadow_worldlightchain = light;
2364 R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
2365 if (r_shadow_staticworldlights.integer)
2366 R_RTLight_Compile(&light->rtlight);
2369 void R_Shadow_FreeWorldLight(dlight_t *light)
2371 dlight_t **lightpointer;
2372 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
2373 if (*lightpointer != light)
2374 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
2375 *lightpointer = light->next;
2376 R_RTLight_Uncompile(&light->rtlight);
2380 void R_Shadow_ClearWorldLights(void)
2382 while (r_shadow_worldlightchain)
2383 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
2384 r_shadow_selectedlight = NULL;
2385 R_Shadow_FreeCubemaps();
2388 void R_Shadow_SelectLight(dlight_t *light)
2390 if (r_shadow_selectedlight)
2391 r_shadow_selectedlight->selected = false;
2392 r_shadow_selectedlight = light;
2393 if (r_shadow_selectedlight)
2394 r_shadow_selectedlight->selected = true;
2397 rtexture_t *lighttextures[5];
2399 void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
2401 float scale = r_editlights_cursorgrid.value * 0.5f;
2402 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);
2405 void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
2408 const dlight_t *light;
2411 if (light->selected)
2412 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
2415 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);
2418 void R_Shadow_DrawLightSprites(void)
2424 for (i = 0;i < 5;i++)
2426 lighttextures[i] = NULL;
2427 if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1))))
2428 lighttextures[i] = pic->tex;
2431 for (light = r_shadow_worldlightchain;light;light = light->next)
2432 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, ((int) light) % 5);
2433 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
2436 void R_Shadow_SelectLightInView(void)
2438 float bestrating, rating, temp[3];
2439 dlight_t *best, *light;
2442 for (light = r_shadow_worldlightchain;light;light = light->next)
2444 VectorSubtract(light->origin, r_vieworigin, temp);
2445 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
2448 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
2449 if (bestrating < rating && CL_TraceLine(light->origin, r_vieworigin, NULL, NULL, true, NULL, SUPERCONTENTS_SOLID) == 1.0f)
2451 bestrating = rating;
2456 R_Shadow_SelectLight(best);
2459 void R_Shadow_LoadWorldLights(void)
2461 int n, a, style, shadow;
2462 char name[MAX_QPATH], cubemapname[MAX_QPATH], *lightsstring, *s, *t;
2463 float origin[3], radius, color[3], angles[3], corona;
2464 if (cl.worldmodel == NULL)
2466 Con_Print("No map loaded.\n");
2469 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2470 strlcat (name, ".rtlights", sizeof (name));
2471 lightsstring = FS_LoadFile(name, tempmempool, false);
2481 for (;COM_Parse(t, true) && strcmp(
2482 if (COM_Parse(t, true))
2484 if (com_token[0] == '!')
2487 origin[0] = atof(com_token+1);
2490 origin[0] = atof(com_token);
2495 while (*s && *s != '\n')
2501 // check for modifier flags
2507 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]);
2509 VectorClear(angles);
2512 if (a < 9 || !strcmp(cubemapname, "\"\""))
2517 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);
2520 VectorScale(color, r_editlights_rtlightscolorscale.value, color);
2521 radius *= r_editlights_rtlightssizescale.value;
2522 R_Shadow_NewWorldLight(origin, angles, color, radius, corona, style, shadow, cubemapname);
2527 Con_Printf("invalid rtlights file \"%s\"\n", name);
2528 Mem_Free(lightsstring);
2532 void R_Shadow_SaveWorldLights(void)
2535 int bufchars, bufmaxchars;
2537 char name[MAX_QPATH];
2539 if (!r_shadow_worldlightchain)
2541 if (cl.worldmodel == NULL)
2543 Con_Print("No map loaded.\n");
2546 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2547 strlcat (name, ".rtlights", sizeof (name));
2548 bufchars = bufmaxchars = 0;
2550 for (light = r_shadow_worldlightchain;light;light = light->next)
2552 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]);
2553 if (bufchars + (int) strlen(line) > bufmaxchars)
2555 bufmaxchars = bufchars + strlen(line) + 2048;
2557 buf = Mem_Alloc(r_shadow_mempool, bufmaxchars);
2561 memcpy(buf, oldbuf, bufchars);
2567 memcpy(buf + bufchars, line, strlen(line));
2568 bufchars += strlen(line);
2572 FS_WriteFile(name, buf, bufchars);
2577 void R_Shadow_LoadLightsFile(void)
2580 char name[MAX_QPATH], *lightsstring, *s, *t;
2581 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
2582 if (cl.worldmodel == NULL)
2584 Con_Print("No map loaded.\n");
2587 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2588 strlcat (name, ".lights", sizeof (name));
2589 lightsstring = FS_LoadFile(name, tempmempool, false);
2597 while (*s && *s != '\n')
2602 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);
2606 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);
2609 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
2610 radius = bound(15, radius, 4096);
2611 VectorScale(color, (2.0f / (8388608.0f)), color);
2612 R_Shadow_NewWorldLight(origin, vec3_origin, color, radius, 0, style, true, NULL);
2617 Con_Printf("invalid lights file \"%s\"\n", name);
2618 Mem_Free(lightsstring);
2622 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
2624 int entnum, style, islight, skin, pflags, effects;
2625 char key[256], value[1024];
2626 float origin[3], angles[3], radius, color[3], light, fadescale, lightscale, originhack[3], overridecolor[3];
2629 if (cl.worldmodel == NULL)
2631 Con_Print("No map loaded.\n");
2634 data = cl.worldmodel->brush.entities;
2637 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
2640 origin[0] = origin[1] = origin[2] = 0;
2641 originhack[0] = originhack[1] = originhack[2] = 0;
2642 angles[0] = angles[1] = angles[2] = 0;
2643 color[0] = color[1] = color[2] = 1;
2644 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
2654 if (!COM_ParseToken(&data, false))
2656 if (com_token[0] == '}')
2657 break; // end of entity
2658 if (com_token[0] == '_')
2659 strcpy(key, com_token + 1);
2661 strcpy(key, com_token);
2662 while (key[strlen(key)-1] == ' ') // remove trailing spaces
2663 key[strlen(key)-1] = 0;
2664 if (!COM_ParseToken(&data, false))
2666 strcpy(value, com_token);
2668 // now that we have the key pair worked out...
2669 if (!strcmp("light", key))
2670 light = atof(value);
2671 else if (!strcmp("origin", key))
2672 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
2673 else if (!strcmp("angle", key))
2674 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
2675 else if (!strcmp("angles", key))
2676 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
2677 else if (!strcmp("color", key))
2678 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
2679 else if (!strcmp("wait", key))
2680 fadescale = atof(value);
2681 else if (!strcmp("classname", key))
2683 if (!strncmp(value, "light", 5))
2686 if (!strcmp(value, "light_fluoro"))
2691 overridecolor[0] = 1;
2692 overridecolor[1] = 1;
2693 overridecolor[2] = 1;
2695 if (!strcmp(value, "light_fluorospark"))
2700 overridecolor[0] = 1;
2701 overridecolor[1] = 1;
2702 overridecolor[2] = 1;
2704 if (!strcmp(value, "light_globe"))
2709 overridecolor[0] = 1;
2710 overridecolor[1] = 0.8;
2711 overridecolor[2] = 0.4;
2713 if (!strcmp(value, "light_flame_large_yellow"))
2718 overridecolor[0] = 1;
2719 overridecolor[1] = 0.5;
2720 overridecolor[2] = 0.1;
2722 if (!strcmp(value, "light_flame_small_yellow"))
2727 overridecolor[0] = 1;
2728 overridecolor[1] = 0.5;
2729 overridecolor[2] = 0.1;
2731 if (!strcmp(value, "light_torch_small_white"))
2736 overridecolor[0] = 1;
2737 overridecolor[1] = 0.5;
2738 overridecolor[2] = 0.1;
2740 if (!strcmp(value, "light_torch_small_walltorch"))
2745 overridecolor[0] = 1;
2746 overridecolor[1] = 0.5;
2747 overridecolor[2] = 0.1;
2751 else if (!strcmp("style", key))
2752 style = atoi(value);
2753 else if (cl.worldmodel->type == mod_brushq3)
2755 if (!strcmp("scale", key))
2756 lightscale = atof(value);
2757 if (!strcmp("fade", key))
2758 fadescale = atof(value);
2760 else if (!strcmp("skin", key))
2761 skin = (int)atof(value);
2762 else if (!strcmp("pflags", key))
2763 pflags = (int)atof(value);
2764 else if (!strcmp("effects", key))
2765 effects = (int)atof(value);
2767 if (light <= 0 && islight)
2769 if (lightscale <= 0)
2773 if (gamemode == GAME_TENEBRAE)
2775 if (effects & EF_NODRAW)
2777 pflags |= PFLAGS_FULLDYNAMIC;
2778 effects &= ~EF_NODRAW;
2781 radius = min(light * r_editlights_quakelightsizescale.value * lightscale / fadescale, 1048576);
2782 light = sqrt(bound(0, light, 1048576)) * (1.0f / 16.0f);
2783 if (color[0] == 1 && color[1] == 1 && color[2] == 1)
2784 VectorCopy(overridecolor, color);
2785 VectorScale(color, light, color);
2786 VectorAdd(origin, originhack, origin);
2787 if (radius >= 15 && !(pflags & PFLAGS_FULLDYNAMIC))
2788 R_Shadow_NewWorldLight(origin, angles, color, radius, (pflags & PFLAGS_CORONA) != 0, style, (pflags & PFLAGS_NOSHADOW) == 0, skin >= 16 ? va("cubemaps/%i", skin) : NULL);
2793 void R_Shadow_SetCursorLocationForView(void)
2795 vec_t dist, push, frac;
2796 vec3_t dest, endpos, normal;
2797 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
2798 frac = CL_TraceLine(r_vieworigin, dest, endpos, normal, true, NULL, SUPERCONTENTS_SOLID);
2801 dist = frac * r_editlights_cursordistance.value;
2802 push = r_editlights_cursorpushback.value;
2806 VectorMA(endpos, push, r_viewforward, endpos);
2807 VectorMA(endpos, r_editlights_cursorpushoff.value, normal, endpos);
2809 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2810 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2811 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2814 void R_Shadow_UpdateWorldLightSelection(void)
2816 if (r_editlights.integer)
2818 R_Shadow_SetCursorLocationForView();
2819 R_Shadow_SelectLightInView();
2820 R_Shadow_DrawLightSprites();
2823 R_Shadow_SelectLight(NULL);
2826 void R_Shadow_EditLights_Clear_f(void)
2828 R_Shadow_ClearWorldLights();
2831 void R_Shadow_EditLights_Reload_f(void)
2833 r_shadow_reloadlights = true;
2836 void R_Shadow_EditLights_Save_f(void)
2839 R_Shadow_SaveWorldLights();
2842 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
2844 R_Shadow_ClearWorldLights();
2845 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
2848 void R_Shadow_EditLights_ImportLightsFile_f(void)
2850 R_Shadow_ClearWorldLights();
2851 R_Shadow_LoadLightsFile();
2854 void R_Shadow_EditLights_Spawn_f(void)
2857 if (!r_editlights.integer)
2859 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
2862 if (Cmd_Argc() != 1)
2864 Con_Print("r_editlights_spawn does not take parameters\n");
2867 color[0] = color[1] = color[2] = 1;
2868 R_Shadow_NewWorldLight(r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL);
2871 void R_Shadow_EditLights_Edit_f(void)
2873 vec3_t origin, angles, color;
2874 vec_t radius, corona;
2876 char cubemapname[1024];
2877 if (!r_editlights.integer)
2879 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
2882 if (!r_shadow_selectedlight)
2884 Con_Print("No selected light.\n");
2887 VectorCopy(r_shadow_selectedlight->origin, origin);
2888 VectorCopy(r_shadow_selectedlight->angles, angles);
2889 VectorCopy(r_shadow_selectedlight->color, color);
2890 radius = r_shadow_selectedlight->radius;
2891 style = r_shadow_selectedlight->style;
2892 if (r_shadow_selectedlight->cubemapname)
2893 strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
2896 shadows = r_shadow_selectedlight->shadow;
2897 corona = r_shadow_selectedlight->corona;
2898 if (!strcmp(Cmd_Argv(1), "origin"))
2900 if (Cmd_Argc() != 5)
2902 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
2905 origin[0] = atof(Cmd_Argv(2));
2906 origin[1] = atof(Cmd_Argv(3));
2907 origin[2] = atof(Cmd_Argv(4));
2909 else if (!strcmp(Cmd_Argv(1), "originx"))
2911 if (Cmd_Argc() != 3)
2913 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2916 origin[0] = atof(Cmd_Argv(2));
2918 else if (!strcmp(Cmd_Argv(1), "originy"))
2920 if (Cmd_Argc() != 3)
2922 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2925 origin[1] = atof(Cmd_Argv(2));
2927 else if (!strcmp(Cmd_Argv(1), "originz"))
2929 if (Cmd_Argc() != 3)
2931 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2934 origin[2] = atof(Cmd_Argv(2));
2936 else if (!strcmp(Cmd_Argv(1), "move"))
2938 if (Cmd_Argc() != 5)
2940 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
2943 origin[0] += atof(Cmd_Argv(2));
2944 origin[1] += atof(Cmd_Argv(3));
2945 origin[2] += atof(Cmd_Argv(4));
2947 else if (!strcmp(Cmd_Argv(1), "movex"))
2949 if (Cmd_Argc() != 3)
2951 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2954 origin[0] += atof(Cmd_Argv(2));
2956 else if (!strcmp(Cmd_Argv(1), "movey"))
2958 if (Cmd_Argc() != 3)
2960 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2963 origin[1] += atof(Cmd_Argv(2));
2965 else if (!strcmp(Cmd_Argv(1), "movez"))
2967 if (Cmd_Argc() != 3)
2969 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2972 origin[2] += atof(Cmd_Argv(2));
2974 else if (!strcmp(Cmd_Argv(1), "angles"))
2976 if (Cmd_Argc() != 5)
2978 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
2981 angles[0] = atof(Cmd_Argv(2));
2982 angles[1] = atof(Cmd_Argv(3));
2983 angles[2] = atof(Cmd_Argv(4));
2985 else if (!strcmp(Cmd_Argv(1), "anglesx"))
2987 if (Cmd_Argc() != 3)
2989 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2992 angles[0] = atof(Cmd_Argv(2));
2994 else if (!strcmp(Cmd_Argv(1), "anglesy"))
2996 if (Cmd_Argc() != 3)
2998 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3001 angles[1] = atof(Cmd_Argv(2));
3003 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3005 if (Cmd_Argc() != 3)
3007 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3010 angles[2] = atof(Cmd_Argv(2));
3012 else if (!strcmp(Cmd_Argv(1), "color"))
3014 if (Cmd_Argc() != 5)
3016 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3019 color[0] = atof(Cmd_Argv(2));
3020 color[1] = atof(Cmd_Argv(3));
3021 color[2] = atof(Cmd_Argv(4));
3023 else if (!strcmp(Cmd_Argv(1), "radius"))
3025 if (Cmd_Argc() != 3)
3027 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3030 radius = atof(Cmd_Argv(2));
3032 else if (!strcmp(Cmd_Argv(1), "style"))
3034 if (Cmd_Argc() != 3)
3036 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3039 style = atoi(Cmd_Argv(2));
3041 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3045 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3048 if (Cmd_Argc() == 3)
3049 strcpy(cubemapname, Cmd_Argv(2));
3053 else if (!strcmp(Cmd_Argv(1), "shadows"))
3055 if (Cmd_Argc() != 3)
3057 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3060 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3062 else if (!strcmp(Cmd_Argv(1), "corona"))
3064 if (Cmd_Argc() != 3)
3066 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3069 corona = atof(Cmd_Argv(2));
3073 Con_Print("usage: r_editlights_edit [property] [value]\n");
3074 Con_Print("Selected light's properties:\n");
3075 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3076 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3077 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3078 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3079 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3080 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3081 Con_Printf("Shadows: %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3082 Con_Printf("Cubemap: %s\n", r_shadow_selectedlight->cubemapname);
3085 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3086 r_shadow_selectedlight = NULL;
3087 R_Shadow_NewWorldLight(origin, angles, color, radius, corona, style, shadows, cubemapname);
3090 extern int con_vislines;
3091 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3095 if (r_shadow_selectedlight == NULL)
3099 sprintf(temp, "Light properties");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3100 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;
3101 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;
3102 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;
3103 sprintf(temp, "Radius %f", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3104 sprintf(temp, "Corona %f", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3105 sprintf(temp, "Style %i", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3106 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;
3107 sprintf(temp, "Cubemap %s", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3110 void R_Shadow_EditLights_ToggleShadow_f(void)
3112 if (!r_editlights.integer)
3114 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3117 if (!r_shadow_selectedlight)
3119 Con_Print("No selected light.\n");
3122 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);
3123 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3124 r_shadow_selectedlight = NULL;
3127 void R_Shadow_EditLights_ToggleCorona_f(void)
3129 if (!r_editlights.integer)
3131 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3134 if (!r_shadow_selectedlight)
3136 Con_Print("No selected light.\n");
3139 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);
3140 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3141 r_shadow_selectedlight = NULL;
3144 void R_Shadow_EditLights_Remove_f(void)
3146 if (!r_editlights.integer)
3148 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
3151 if (!r_shadow_selectedlight)
3153 Con_Print("No selected light.\n");
3156 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3157 r_shadow_selectedlight = NULL;
3160 void R_Shadow_EditLights_Help_f(void)
3163 "Documentation on r_editlights system:\n"
3165 "r_editlights : enable/disable editing mode\n"
3166 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
3167 "r_editlights_cursorpushback : push back cursor this far from surface\n"
3168 "r_editlights_cursorpushoff : push cursor off surface this far\n"
3169 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
3170 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
3171 "r_editlights_rtlightssizescale : imported rtlight size scaling\n"
3172 "r_editlights_rtlightscolorscale : imported rtlight color scaling\n"
3174 "r_editlights_help : this help\n"
3175 "r_editlights_clear : remove all lights\n"
3176 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
3177 "r_editlights_save : save to .rtlights file\n"
3178 "r_editlights_spawn : create a light with default settings\n"
3179 "r_editlights_edit command : edit selected light - more documentation below\n"
3180 "r_editlights_remove : remove selected light\n"
3181 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
3182 "r_editlights_importlightentitiesfrommap : reload light entities\n"
3183 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
3185 "origin x y z : set light location\n"
3186 "originx x: set x component of light location\n"
3187 "originy y: set y component of light location\n"
3188 "originz z: set z component of light location\n"
3189 "move x y z : adjust light location\n"
3190 "movex x: adjust x component of light location\n"
3191 "movey y: adjust y component of light location\n"
3192 "movez z: adjust z component of light location\n"
3193 "angles x y z : set light angles\n"
3194 "anglesx x: set x component of light angles\n"
3195 "anglesy y: set y component of light angles\n"
3196 "anglesz z: set z component of light angles\n"
3197 "color r g b : set color of light (can be brighter than 1 1 1)\n"
3198 "radius radius : set radius (size) of light\n"
3199 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
3200 "cubemap basename : set filter cubemap of light (not yet supported)\n"
3201 "shadows 1/0 : turn on/off shadows\n"
3202 "corona n : set corona intensity\n"
3203 "<nothing> : print light properties to console\n"
3207 void R_Shadow_EditLights_Init(void)
3209 Cvar_RegisterVariable(&r_editlights);
3210 Cvar_RegisterVariable(&r_editlights_cursordistance);
3211 Cvar_RegisterVariable(&r_editlights_cursorpushback);
3212 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
3213 Cvar_RegisterVariable(&r_editlights_cursorgrid);
3214 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
3215 Cvar_RegisterVariable(&r_editlights_rtlightssizescale);
3216 Cvar_RegisterVariable(&r_editlights_rtlightscolorscale);
3217 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
3218 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
3219 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
3220 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
3221 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
3222 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
3223 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
3224 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
3225 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
3226 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
3227 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);