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;
129 mempool_t *r_shadow_mempool;
131 int maxshadowelements;
145 int r_shadow_buffer_numclusterpvsbytes;
146 qbyte *r_shadow_buffer_clusterpvs;
147 int *r_shadow_buffer_clusterlist;
149 int r_shadow_buffer_numsurfacepvsbytes;
150 qbyte *r_shadow_buffer_surfacepvs;
151 int *r_shadow_buffer_surfacelist;
153 rtexturepool_t *r_shadow_texturepool;
154 rtexture_t *r_shadow_normalcubetexture;
155 rtexture_t *r_shadow_attenuation2dtexture;
156 rtexture_t *r_shadow_attenuation3dtexture;
157 rtexture_t *r_shadow_blankbumptexture;
158 rtexture_t *r_shadow_blankglosstexture;
159 rtexture_t *r_shadow_blankwhitetexture;
161 // lights are reloaded when this changes
162 char r_shadow_mapname[MAX_QPATH];
164 // used only for light filters (cubemaps)
165 rtexturepool_t *r_shadow_filters_texturepool;
167 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0"};
168 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4"};
169 cvar_t r_shadow_cull = {0, "r_shadow_cull", "1"};
170 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1"};
171 cvar_t r_shadow_gloss = {0, "r_shadow_gloss", "1"};
172 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.25"};
173 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1"};
174 cvar_t r_shadow_lightattenuationpower = {0, "r_shadow_lightattenuationpower", "0.5"};
175 cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1"};
176 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1"};
177 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1"};
178 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000"};
179 cvar_t r_shadow_realtime_dlight = {0, "r_shadow_realtime_dlight", "1"};
180 cvar_t r_shadow_realtime_dlight_shadows = {0, "r_shadow_realtime_dlight_shadows", "0"};
181 cvar_t r_shadow_realtime_world = {0, "r_shadow_realtime_world", "0"};
182 cvar_t r_shadow_realtime_world_dlightshadows = {0, "r_shadow_realtime_world_dlightshadows", "1"};
183 cvar_t r_shadow_realtime_world_lightmaps = {0, "r_shadow_realtime_world_lightmaps", "0"};
184 cvar_t r_shadow_realtime_world_shadows = {0, "r_shadow_realtime_world_shadows", "1"};
185 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1"};
186 cvar_t r_shadow_shadow_polygonfactor = {0, "r_shadow_shadow_polygonfactor", "0"};
187 cvar_t r_shadow_shadow_polygonoffset = {0, "r_shadow_shadow_polygonoffset", "1"};
188 cvar_t r_shadow_singlepassvolumegeneration = {0, "r_shadow_singlepassvolumegeneration", "1"};
189 cvar_t r_shadow_staticworldlights = {0, "r_shadow_staticworldlights", "1"};
190 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1"};
191 cvar_t r_shadow_visiblevolumes = {0, "r_shadow_visiblevolumes", "0"};
192 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1"};
193 cvar_t r_editlights = {0, "r_editlights", "0"};
194 cvar_t r_editlights_cursordistance = {0, "r_editlights_distance", "1024"};
195 cvar_t r_editlights_cursorpushback = {0, "r_editlights_pushback", "0"};
196 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_pushoff", "4"};
197 cvar_t r_editlights_cursorgrid = {0, "r_editlights_grid", "4"};
198 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "0.8"};
199 cvar_t r_editlights_rtlightssizescale = {CVAR_SAVE, "r_editlights_rtlightssizescale", "0.7"};
200 cvar_t r_editlights_rtlightscolorscale = {CVAR_SAVE, "r_editlights_rtlightscolorscale", "2"};
202 int c_rt_lights, c_rt_clears, c_rt_scissored;
203 int c_rt_shadowmeshes, c_rt_shadowtris, c_rt_lightmeshes, c_rt_lighttris;
204 int c_rtcached_shadowmeshes, c_rtcached_shadowtris;
206 float r_shadow_attenpower, r_shadow_attenscale;
208 float varray_vertex3f2[65536*3];
210 rtlight_t *r_shadow_compilingrtlight;
211 dlight_t *r_shadow_worldlightchain;
212 dlight_t *r_shadow_selectedlight;
213 vec3_t r_editlights_cursorlocation;
215 rtexture_t *lighttextures[5];
217 extern int con_vislines;
219 typedef struct cubemapinfo_s
226 #define MAX_CUBEMAPS 256
227 static int numcubemaps;
228 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
230 void R_Shadow_UncompileWorldLights(void);
231 void R_Shadow_ClearWorldLights(void);
232 void R_Shadow_SaveWorldLights(void);
233 void R_Shadow_LoadWorldLights(void);
234 void R_Shadow_LoadLightsFile(void);
235 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
236 void R_Shadow_EditLights_Reload_f(void);
237 void R_Shadow_ValidateCvars(void);
238 static void R_Shadow_MakeTextures(void);
239 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light);
241 void r_shadow_start(void)
243 // allocate vertex processing arrays
245 r_shadow_normalcubetexture = NULL;
246 r_shadow_attenuation2dtexture = NULL;
247 r_shadow_attenuation3dtexture = NULL;
248 r_shadow_blankbumptexture = NULL;
249 r_shadow_blankglosstexture = NULL;
250 r_shadow_blankwhitetexture = NULL;
251 r_shadow_texturepool = NULL;
252 r_shadow_filters_texturepool = NULL;
253 R_Shadow_ValidateCvars();
254 R_Shadow_MakeTextures();
255 maxshadowelements = 0;
256 shadowelements = NULL;
264 shadowmarklist = NULL;
266 r_shadow_buffer_numclusterpvsbytes = 0;
267 r_shadow_buffer_clusterpvs = NULL;
268 r_shadow_buffer_clusterlist = NULL;
269 r_shadow_buffer_numsurfacepvsbytes = 0;
270 r_shadow_buffer_surfacepvs = NULL;
271 r_shadow_buffer_surfacelist = NULL;
274 void r_shadow_shutdown(void)
276 R_Shadow_UncompileWorldLights();
278 r_shadow_normalcubetexture = NULL;
279 r_shadow_attenuation2dtexture = NULL;
280 r_shadow_attenuation3dtexture = NULL;
281 r_shadow_blankbumptexture = NULL;
282 r_shadow_blankglosstexture = NULL;
283 r_shadow_blankwhitetexture = NULL;
284 R_FreeTexturePool(&r_shadow_texturepool);
285 R_FreeTexturePool(&r_shadow_filters_texturepool);
286 maxshadowelements = 0;
288 Mem_Free(shadowelements);
289 shadowelements = NULL;
292 Mem_Free(vertexupdate);
295 Mem_Free(vertexremap);
301 Mem_Free(shadowmark);
304 Mem_Free(shadowmarklist);
305 shadowmarklist = NULL;
307 r_shadow_buffer_numclusterpvsbytes = 0;
308 if (r_shadow_buffer_clusterpvs)
309 Mem_Free(r_shadow_buffer_clusterpvs);
310 r_shadow_buffer_clusterpvs = NULL;
311 if (r_shadow_buffer_clusterlist)
312 Mem_Free(r_shadow_buffer_clusterlist);
313 r_shadow_buffer_clusterlist = NULL;
314 r_shadow_buffer_numsurfacepvsbytes = 0;
315 if (r_shadow_buffer_surfacepvs)
316 Mem_Free(r_shadow_buffer_surfacepvs);
317 r_shadow_buffer_surfacepvs = NULL;
318 if (r_shadow_buffer_surfacelist)
319 Mem_Free(r_shadow_buffer_surfacelist);
320 r_shadow_buffer_surfacelist = NULL;
323 void r_shadow_newmap(void)
327 void R_Shadow_Help_f(void)
330 "Documentation on r_shadow system:\n"
332 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
333 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
334 "r_shadow_debuglight : render only this light number (-1 = all)\n"
335 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
336 "r_shadow_gloss2intensity : brightness of forced gloss\n"
337 "r_shadow_glossintensity : brightness of textured gloss\n"
338 "r_shadow_lightattenuationpower : used to generate attenuation texture\n"
339 "r_shadow_lightattenuationscale : used to generate attenuation texture\n"
340 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
341 "r_shadow_portallight : use portal visibility for static light precomputation\n"
342 "r_shadow_projectdistance : shadow volume projection distance\n"
343 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
344 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
345 "r_shadow_realtime_world : use high quality world lighting mode\n"
346 "r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n"
347 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
348 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
349 "r_shadow_scissor : use scissor optimization\n"
350 "r_shadow_shadow_polygonfactor : nudge shadow volumes closer/further\n"
351 "r_shadow_shadow_polygonoffset : nudge shadow volumes closer/further\n"
352 "r_shadow_singlepassvolumegeneration : selects shadow volume algorithm\n"
353 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
354 "r_shadow_visiblevolumes : useful for performance testing; bright = slow!\n"
356 "r_shadow_help : this help\n"
360 void R_Shadow_Init(void)
362 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
363 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
364 Cvar_RegisterVariable(&r_shadow_cull);
365 Cvar_RegisterVariable(&r_shadow_debuglight);
366 Cvar_RegisterVariable(&r_shadow_gloss);
367 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
368 Cvar_RegisterVariable(&r_shadow_glossintensity);
369 Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
370 Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
371 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
372 Cvar_RegisterVariable(&r_shadow_portallight);
373 Cvar_RegisterVariable(&r_shadow_projectdistance);
374 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
375 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
376 Cvar_RegisterVariable(&r_shadow_realtime_world);
377 Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows);
378 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
379 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
380 Cvar_RegisterVariable(&r_shadow_scissor);
381 Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor);
382 Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset);
383 Cvar_RegisterVariable(&r_shadow_singlepassvolumegeneration);
384 Cvar_RegisterVariable(&r_shadow_staticworldlights);
385 Cvar_RegisterVariable(&r_shadow_texture3d);
386 Cvar_RegisterVariable(&r_shadow_visiblevolumes);
387 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
388 if (gamemode == GAME_TENEBRAE)
390 Cvar_SetValue("r_shadow_gloss", 2);
391 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
393 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f);
394 R_Shadow_EditLights_Init();
395 r_shadow_mempool = Mem_AllocPool("R_Shadow");
396 r_shadow_worldlightchain = NULL;
397 maxshadowelements = 0;
398 shadowelements = NULL;
406 shadowmarklist = NULL;
408 r_shadow_buffer_numclusterpvsbytes = 0;
409 r_shadow_buffer_clusterpvs = NULL;
410 r_shadow_buffer_clusterlist = NULL;
411 r_shadow_buffer_numsurfacepvsbytes = 0;
412 r_shadow_buffer_surfacepvs = NULL;
413 r_shadow_buffer_surfacelist = NULL;
414 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
417 matrix4x4_t matrix_attenuationxyz =
420 {0.5, 0.0, 0.0, 0.5},
421 {0.0, 0.5, 0.0, 0.5},
422 {0.0, 0.0, 0.5, 0.5},
427 matrix4x4_t matrix_attenuationz =
430 {0.0, 0.0, 0.5, 0.5},
431 {0.0, 0.0, 0.0, 0.5},
432 {0.0, 0.0, 0.0, 0.5},
437 int *R_Shadow_ResizeShadowElements(int numtris)
439 // make sure shadowelements is big enough for this volume
440 if (maxshadowelements < numtris * 24)
442 maxshadowelements = numtris * 24;
444 Mem_Free(shadowelements);
445 shadowelements = Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int));
447 return shadowelements;
450 void R_Shadow_EnlargeClusterBuffer(int numclusters)
452 int numclusterpvsbytes = (((numclusters + 7) >> 3) + 255) & ~255;
453 if (r_shadow_buffer_numclusterpvsbytes < numclusterpvsbytes)
455 if (r_shadow_buffer_clusterpvs)
456 Mem_Free(r_shadow_buffer_clusterpvs);
457 if (r_shadow_buffer_clusterlist)
458 Mem_Free(r_shadow_buffer_clusterlist);
459 r_shadow_buffer_numclusterpvsbytes = numclusterpvsbytes;
460 r_shadow_buffer_clusterpvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numclusterpvsbytes);
461 r_shadow_buffer_clusterlist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numclusterpvsbytes * 8 * sizeof(*r_shadow_buffer_clusterlist));
465 void R_Shadow_EnlargeSurfaceBuffer(int numsurfaces)
467 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
468 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
470 if (r_shadow_buffer_surfacepvs)
471 Mem_Free(r_shadow_buffer_surfacepvs);
472 if (r_shadow_buffer_surfacelist)
473 Mem_Free(r_shadow_buffer_surfacelist);
474 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
475 r_shadow_buffer_surfacepvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes);
476 r_shadow_buffer_surfacelist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
480 void R_Shadow_PrepareShadowMark(int numtris)
482 // make sure shadowmark is big enough for this volume
483 if (maxshadowmark < numtris)
485 maxshadowmark = numtris;
487 Mem_Free(shadowmark);
489 Mem_Free(shadowmarklist);
490 shadowmark = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmark));
491 shadowmarklist = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmarklist));
495 // if shadowmarkcount wrapped we clear the array and adjust accordingly
496 if (shadowmarkcount == 0)
499 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
504 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)
506 int i, j, tris = 0, vr[3], t, outvertices = 0;
510 if (maxvertexupdate < innumvertices)
512 maxvertexupdate = innumvertices;
514 Mem_Free(vertexupdate);
516 Mem_Free(vertexremap);
517 vertexupdate = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
518 vertexremap = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
522 if (vertexupdatenum == 0)
525 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
526 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
529 for (i = 0;i < numshadowmarktris;i++)
531 t = shadowmarktris[i];
532 shadowmark[t] = shadowmarkcount;
533 e = inelement3i + t * 3;
534 // make sure the vertices are created
535 for (j = 0;j < 3;j++)
537 if (vertexupdate[e[j]] != vertexupdatenum)
539 vertexupdate[e[j]] = vertexupdatenum;
540 vertexremap[e[j]] = outvertices;
541 VectorSubtract(invertex3f + e[j] * 3, projectorigin, temp);
542 f = projectdistance / VectorLength(temp);
543 VectorCopy(invertex3f + e[j] * 3, outvertex3f);
544 VectorMA(projectorigin, f, temp, (outvertex3f + 3));
549 // output the front and back triangles
550 outelement3i[0] = vertexremap[e[0]];
551 outelement3i[1] = vertexremap[e[1]];
552 outelement3i[2] = vertexremap[e[2]];
553 outelement3i[3] = vertexremap[e[2]] + 1;
554 outelement3i[4] = vertexremap[e[1]] + 1;
555 outelement3i[5] = vertexremap[e[0]] + 1;
560 for (i = 0;i < numshadowmarktris;i++)
562 t = shadowmarktris[i];
563 e = inelement3i + t * 3;
564 n = inneighbor3i + t * 3;
565 // output the sides (facing outward from this triangle)
566 if (shadowmark[n[0]] != shadowmarkcount)
568 vr[0] = vertexremap[e[0]];
569 vr[1] = vertexremap[e[1]];
570 outelement3i[0] = vr[1];
571 outelement3i[1] = vr[0];
572 outelement3i[2] = vr[0] + 1;
573 outelement3i[3] = vr[1];
574 outelement3i[4] = vr[0] + 1;
575 outelement3i[5] = vr[1] + 1;
579 if (shadowmark[n[1]] != shadowmarkcount)
581 vr[1] = vertexremap[e[1]];
582 vr[2] = vertexremap[e[2]];
583 outelement3i[0] = vr[2];
584 outelement3i[1] = vr[1];
585 outelement3i[2] = vr[1] + 1;
586 outelement3i[3] = vr[2];
587 outelement3i[4] = vr[1] + 1;
588 outelement3i[5] = vr[2] + 1;
592 if (shadowmark[n[2]] != shadowmarkcount)
594 vr[0] = vertexremap[e[0]];
595 vr[2] = vertexremap[e[2]];
596 outelement3i[0] = vr[0];
597 outelement3i[1] = vr[2];
598 outelement3i[2] = vr[2] + 1;
599 outelement3i[3] = vr[0];
600 outelement3i[4] = vr[2] + 1;
601 outelement3i[5] = vr[0] + 1;
607 *outnumvertices = outvertices;
611 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)
614 if (projectdistance < 0.1)
616 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
619 if (!numverts || !nummarktris)
621 // make sure shadowelements is big enough for this volume
622 if (maxshadowelements < nummarktris * 24)
623 R_Shadow_ResizeShadowElements((nummarktris + 256) * 24);
624 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, varray_vertex3f2, projectorigin, projectdistance, nummarktris, marktris);
625 R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements);
628 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)
633 // check which triangles are facing the , and then output
634 // triangle elements and vertices... by clever use of elements we
635 // can construct the whole shadow from the unprojected vertices and
636 // the projected vertices
638 // identify lit faces within the bounding box
639 R_Shadow_PrepareShadowMark(numtris);
640 for (i = 0;i < numtris;i++)
642 v[0] = invertex3f + elements[i*3+0] * 3;
643 v[1] = invertex3f + elements[i*3+1] * 3;
644 v[2] = invertex3f + elements[i*3+2] * 3;
645 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])))
646 shadowmarklist[numshadowmark++] = i;
648 R_Shadow_VolumeFromList(numverts, numtris, invertex3f, elements, neighbors, projectorigin, projectdistance, numshadowmark, shadowmarklist);
651 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)
654 mins[0] = projectorigin[0] - radius;
655 mins[1] = projectorigin[1] - radius;
656 mins[2] = projectorigin[2] - radius;
657 maxs[0] = projectorigin[0] + radius;
658 maxs[1] = projectorigin[1] + radius;
659 maxs[2] = projectorigin[2] + radius;
660 R_Shadow_VolumeFromBox(numverts, numtris, invertex3f, elements, neighbors, projectorigin, projectdistance, mins, maxs);
663 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
666 if (r_shadow_compilingrtlight)
668 // if we're compiling an rtlight, capture the mesh
669 Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
672 memset(&m, 0, sizeof(m));
673 m.pointer_vertex = vertex3f;
675 GL_LockArrays(0, numvertices);
676 if (r_shadowstage == SHADOWSTAGE_STENCIL)
678 // increment stencil if backface is behind depthbuffer
679 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
680 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
681 R_Mesh_Draw(numvertices, numtriangles, element3i);
683 c_rt_shadowtris += numtriangles;
684 // decrement stencil if frontface is behind depthbuffer
685 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
686 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
688 R_Mesh_Draw(numvertices, numtriangles, element3i);
690 c_rt_shadowtris += numtriangles;
694 static void R_Shadow_MakeTextures(void)
696 int x, y, z, d, side;
697 float v[3], s, t, intensity;
699 R_FreeTexturePool(&r_shadow_texturepool);
700 r_shadow_texturepool = R_AllocTexturePool();
701 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
702 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
704 #define ATTEN2DSIZE 64
705 #define ATTEN3DSIZE 32
706 data = Mem_Alloc(tempmempool, max(6*NORMSIZE*NORMSIZE*4, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4)));
711 r_shadow_blankbumptexture = R_LoadTexture2D(r_shadow_texturepool, "blankbump", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
716 r_shadow_blankglosstexture = R_LoadTexture2D(r_shadow_texturepool, "blankgloss", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
721 r_shadow_blankwhitetexture = R_LoadTexture2D(r_shadow_texturepool, "blankwhite", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
722 if (gl_texturecubemap)
724 for (side = 0;side < 6;side++)
726 for (y = 0;y < NORMSIZE;y++)
728 for (x = 0;x < NORMSIZE;x++)
730 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
731 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
765 intensity = 127.0f / sqrt(DotProduct(v, v));
766 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+0] = 128.0f + intensity * v[0];
767 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+1] = 128.0f + intensity * v[1];
768 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+2] = 128.0f + intensity * v[2];
769 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+3] = 255;
773 r_shadow_normalcubetexture = R_LoadTextureCubeMap(r_shadow_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
776 r_shadow_normalcubetexture = NULL;
777 for (y = 0;y < ATTEN2DSIZE;y++)
779 for (x = 0;x < ATTEN2DSIZE;x++)
781 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
782 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
784 intensity = 1.0f - sqrt(DotProduct(v, v));
786 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
787 d = bound(0, intensity, 255);
788 data[(y*ATTEN2DSIZE+x)*4+0] = d;
789 data[(y*ATTEN2DSIZE+x)*4+1] = d;
790 data[(y*ATTEN2DSIZE+x)*4+2] = d;
791 data[(y*ATTEN2DSIZE+x)*4+3] = d;
794 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
795 if (r_shadow_texture3d.integer)
797 for (z = 0;z < ATTEN3DSIZE;z++)
799 for (y = 0;y < ATTEN3DSIZE;y++)
801 for (x = 0;x < ATTEN3DSIZE;x++)
803 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
804 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
805 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
806 intensity = 1.0f - sqrt(DotProduct(v, v));
808 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
809 d = bound(0, intensity, 255);
810 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
811 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
812 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
813 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
817 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
822 void R_Shadow_ValidateCvars(void)
824 if (r_shadow_texture3d.integer && !gl_texture3d)
825 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
826 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
827 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
830 void R_Shadow_Stage_Begin(void)
834 R_Shadow_ValidateCvars();
836 if (!r_shadow_attenuation2dtexture
837 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
838 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
839 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
840 R_Shadow_MakeTextures();
842 memset(&m, 0, sizeof(m));
843 GL_BlendFunc(GL_ONE, GL_ZERO);
847 GL_Color(0, 0, 0, 1);
848 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
849 qglEnable(GL_CULL_FACE);
850 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
851 r_shadowstage = SHADOWSTAGE_NONE;
853 c_rt_lights = c_rt_clears = c_rt_scissored = 0;
854 c_rt_shadowmeshes = c_rt_shadowtris = c_rt_lightmeshes = c_rt_lighttris = 0;
855 c_rtcached_shadowmeshes = c_rtcached_shadowtris = 0;
858 void R_Shadow_Stage_ShadowVolumes(void)
861 memset(&m, 0, sizeof(m));
863 GL_Color(1, 1, 1, 1);
864 GL_ColorMask(0, 0, 0, 0);
865 GL_BlendFunc(GL_ONE, GL_ZERO);
868 qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
869 //if (r_shadow_shadow_polygonoffset.value != 0)
871 // qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
872 // qglEnable(GL_POLYGON_OFFSET_FILL);
875 // qglDisable(GL_POLYGON_OFFSET_FILL);
876 qglDepthFunc(GL_LESS);
877 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
878 qglEnable(GL_STENCIL_TEST);
879 qglStencilFunc(GL_ALWAYS, 128, ~0);
880 if (gl_ext_stenciltwoside.integer)
882 r_shadowstage = SHADOWSTAGE_STENCILTWOSIDE;
883 qglDisable(GL_CULL_FACE);
884 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
885 qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
887 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
888 qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
890 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
894 r_shadowstage = SHADOWSTAGE_STENCIL;
895 qglEnable(GL_CULL_FACE);
897 // this is changed by every shadow render so its value here is unimportant
898 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
900 GL_Clear(GL_STENCIL_BUFFER_BIT);
902 // LordHavoc note: many shadow volumes reside entirely inside the world
903 // (that is to say they are entirely bounded by their lit surfaces),
904 // which can be optimized by handling things as an inverted light volume,
905 // with the shadow boundaries of the world being simulated by an altered
906 // (129) bias to stencil clearing on such lights
907 // FIXME: generate inverted light volumes for use as shadow volumes and
908 // optimize for them as noted above
911 void R_Shadow_Stage_LightWithoutShadows(void)
914 memset(&m, 0, sizeof(m));
916 GL_BlendFunc(GL_ONE, GL_ONE);
919 qglPolygonOffset(0, 0);
920 //qglDisable(GL_POLYGON_OFFSET_FILL);
921 GL_Color(1, 1, 1, 1);
922 GL_ColorMask(1, 1, 1, 1);
923 qglDepthFunc(GL_EQUAL);
924 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
925 qglEnable(GL_CULL_FACE);
926 qglDisable(GL_STENCIL_TEST);
927 if (gl_support_stenciltwoside)
928 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
930 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
931 qglStencilFunc(GL_EQUAL, 128, ~0);
932 r_shadowstage = SHADOWSTAGE_LIGHT;
936 void R_Shadow_Stage_LightWithShadows(void)
939 memset(&m, 0, sizeof(m));
941 GL_BlendFunc(GL_ONE, GL_ONE);
944 qglPolygonOffset(0, 0);
945 //qglDisable(GL_POLYGON_OFFSET_FILL);
946 GL_Color(1, 1, 1, 1);
947 GL_ColorMask(1, 1, 1, 1);
948 qglDepthFunc(GL_EQUAL);
949 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
950 qglEnable(GL_STENCIL_TEST);
951 if (gl_support_stenciltwoside)
952 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
954 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
955 // only draw light where this geometry was already rendered AND the
956 // stencil is 128 (values other than this mean shadow)
957 qglStencilFunc(GL_EQUAL, 128, ~0);
958 r_shadowstage = SHADOWSTAGE_LIGHT;
962 void R_Shadow_Stage_End(void)
965 memset(&m, 0, sizeof(m));
967 GL_BlendFunc(GL_ONE, GL_ZERO);
970 qglPolygonOffset(0, 0);
971 //qglDisable(GL_POLYGON_OFFSET_FILL);
972 GL_Color(1, 1, 1, 1);
973 GL_ColorMask(1, 1, 1, 1);
974 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
975 qglDepthFunc(GL_LEQUAL);
976 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
977 qglDisable(GL_STENCIL_TEST);
978 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
979 if (gl_support_stenciltwoside)
980 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
982 qglStencilFunc(GL_ALWAYS, 128, ~0);
983 r_shadowstage = SHADOWSTAGE_NONE;
986 int R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
988 int i, ix1, iy1, ix2, iy2;
989 float x1, y1, x2, y2, x, y, f;
992 if (!r_shadow_scissor.integer)
994 // if view is inside the box, just say yes it's visible
995 if (BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
997 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1000 for (i = 0;i < 3;i++)
1002 if (r_viewforward[i] >= 0)
1013 f = DotProduct(r_viewforward, r_vieworigin) + 1;
1014 if (DotProduct(r_viewforward, v2) <= f)
1016 // entirely behind nearclip plane
1019 if (DotProduct(r_viewforward, v) >= f)
1021 // entirely infront of nearclip plane
1022 x1 = y1 = x2 = y2 = 0;
1023 for (i = 0;i < 8;i++)
1025 v[0] = (i & 1) ? mins[0] : maxs[0];
1026 v[1] = (i & 2) ? mins[1] : maxs[1];
1027 v[2] = (i & 4) ? mins[2] : maxs[2];
1029 GL_TransformToScreen(v, v2);
1030 //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]);
1049 // clipped by nearclip plane
1050 // this is nasty and crude...
1051 // create viewspace bbox
1052 for (i = 0;i < 8;i++)
1054 v[0] = ((i & 1) ? mins[0] : maxs[0]) - r_vieworigin[0];
1055 v[1] = ((i & 2) ? mins[1] : maxs[1]) - r_vieworigin[1];
1056 v[2] = ((i & 4) ? mins[2] : maxs[2]) - r_vieworigin[2];
1057 v2[0] = -DotProduct(v, r_viewleft);
1058 v2[1] = DotProduct(v, r_viewup);
1059 v2[2] = DotProduct(v, r_viewforward);
1062 if (smins[0] > v2[0]) smins[0] = v2[0];
1063 if (smaxs[0] < v2[0]) smaxs[0] = v2[0];
1064 if (smins[1] > v2[1]) smins[1] = v2[1];
1065 if (smaxs[1] < v2[1]) smaxs[1] = v2[1];
1066 if (smins[2] > v2[2]) smins[2] = v2[2];
1067 if (smaxs[2] < v2[2]) smaxs[2] = v2[2];
1071 smins[0] = smaxs[0] = v2[0];
1072 smins[1] = smaxs[1] = v2[1];
1073 smins[2] = smaxs[2] = v2[2];
1076 // now we have a bbox in viewspace
1077 // clip it to the view plane
1080 // return true if that culled the box
1081 if (smins[2] >= smaxs[2])
1083 // ok some of it is infront of the view, transform each corner back to
1084 // worldspace and then to screenspace and make screen rect
1085 // initialize these variables just to avoid compiler warnings
1086 x1 = y1 = x2 = y2 = 0;
1087 for (i = 0;i < 8;i++)
1089 v2[0] = (i & 1) ? smins[0] : smaxs[0];
1090 v2[1] = (i & 2) ? smins[1] : smaxs[1];
1091 v2[2] = (i & 4) ? smins[2] : smaxs[2];
1092 v[0] = v2[0] * -r_viewleft[0] + v2[1] * r_viewup[0] + v2[2] * r_viewforward[0] + r_vieworigin[0];
1093 v[1] = v2[0] * -r_viewleft[1] + v2[1] * r_viewup[1] + v2[2] * r_viewforward[1] + r_vieworigin[1];
1094 v[2] = v2[0] * -r_viewleft[2] + v2[1] * r_viewup[2] + v2[2] * r_viewforward[2] + r_vieworigin[2];
1096 GL_TransformToScreen(v, v2);
1097 //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]);
1114 // this code doesn't handle boxes with any points behind view properly
1115 x1 = 1000;x2 = -1000;
1116 y1 = 1000;y2 = -1000;
1117 for (i = 0;i < 8;i++)
1119 v[0] = (i & 1) ? mins[0] : maxs[0];
1120 v[1] = (i & 2) ? mins[1] : maxs[1];
1121 v[2] = (i & 4) ? mins[2] : maxs[2];
1123 GL_TransformToScreen(v, v2);
1124 //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]);
1142 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1143 if (ix1 < r_view_x) ix1 = r_view_x;
1144 if (iy1 < r_view_y) iy1 = r_view_y;
1145 if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
1146 if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
1147 if (ix2 <= ix1 || iy2 <= iy1)
1149 // set up the scissor rectangle
1150 GL_Scissor(ix1, vid.realheight - iy2, ix2 - ix1, iy2 - iy1);
1151 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1152 //qglEnable(GL_SCISSOR_TEST);
1157 static void R_Shadow_VertexShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1159 float *color4f = varray_color4f;
1160 float dist, dot, intensity, v[3], n[3];
1161 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1163 Matrix4x4_Transform(m, vertex3f, v);
1164 if ((dist = DotProduct(v, v)) < 1)
1166 Matrix4x4_Transform3x3(m, normal3f, n);
1167 if ((dot = DotProduct(n, v)) > 0)
1170 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1171 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1172 VectorScale(lightcolor, intensity, color4f);
1177 VectorClear(color4f);
1183 VectorClear(color4f);
1189 static void R_Shadow_VertexShadingWithZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1191 float *color4f = varray_color4f;
1192 float dist, dot, intensity, v[3], n[3];
1193 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1195 Matrix4x4_Transform(m, vertex3f, v);
1196 if ((dist = fabs(v[2])) < 1)
1198 Matrix4x4_Transform3x3(m, normal3f, n);
1199 if ((dot = DotProduct(n, v)) > 0)
1201 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1202 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1203 VectorScale(lightcolor, intensity, color4f);
1208 VectorClear(color4f);
1214 VectorClear(color4f);
1220 static void R_Shadow_VertexShading(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1222 float *color4f = varray_color4f;
1223 float dot, intensity, v[3], n[3];
1224 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1226 Matrix4x4_Transform(m, vertex3f, v);
1227 Matrix4x4_Transform3x3(m, normal3f, n);
1228 if ((dot = DotProduct(n, v)) > 0)
1230 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1231 VectorScale(lightcolor, intensity, color4f);
1236 VectorClear(color4f);
1242 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1243 #define USETEXMATRIX
1245 #ifndef USETEXMATRIX
1246 // this should be done in a texture matrix or vertex program when possible, but here's code to do it manually
1247 // if hardware texcoord manipulation is not available (or not suitable, this would really benefit from 3DNow! or SSE
1248 static void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1252 tc3f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1253 tc3f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1254 tc3f[2] = vertex3f[0] * matrix->m[2][0] + vertex3f[1] * matrix->m[2][1] + vertex3f[2] * matrix->m[2][2] + matrix->m[2][3];
1261 static void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1265 tc2f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1266 tc2f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1274 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)
1278 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1280 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1281 // the cubemap normalizes this for us
1282 out3f[0] = DotProduct(svector3f, lightdir);
1283 out3f[1] = DotProduct(tvector3f, lightdir);
1284 out3f[2] = DotProduct(normal3f, lightdir);
1288 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)
1291 float lightdir[3], eyedir[3], halfdir[3];
1292 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1294 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1295 VectorNormalizeFast(lightdir);
1296 VectorSubtract(vertex3f, relativeeyeorigin, eyedir);
1297 VectorNormalizeFast(eyedir);
1298 VectorAdd(lightdir, eyedir, halfdir);
1299 // the cubemap normalizes this for us
1300 out3f[0] = DotProduct(svector3f, halfdir);
1301 out3f[1] = DotProduct(tvector3f, halfdir);
1302 out3f[2] = DotProduct(normal3f, halfdir);
1306 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)
1309 float color[3], color2[3], colorscale;
1312 bumptexture = r_shadow_blankbumptexture;
1314 glosstexture = r_shadow_blankglosstexture;
1315 GL_DepthMask(false);
1317 if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
1319 if (lighting & LIGHTING_DIFFUSE)
1322 colorscale = r_shadow_lightintensityscale.value;
1323 // colorscale accounts for how much we multiply the brightness
1326 // mult is how many times the final pass of the lighting will be
1327 // performed to get more brightness than otherwise possible.
1329 // Limit mult to 64 for sanity sake.
1330 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1332 // 3/2 3D combine path (Geforce3, Radeon 8500)
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);
1342 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1344 m.pointer_texcoord3f[2] = vertex3f;
1345 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
1347 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1348 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1351 GL_ColorMask(0,0,0,1);
1352 GL_BlendFunc(GL_ONE, GL_ZERO);
1353 GL_LockArrays(0, numverts);
1354 R_Mesh_Draw(numverts, numtriangles, elements);
1355 GL_LockArrays(0, 0);
1357 c_rt_lighttris += numtriangles;
1359 memset(&m, 0, sizeof(m));
1360 m.pointer_vertex = vertex3f;
1361 m.tex[0] = R_GetTexture(basetexture);
1362 m.pointer_texcoord[0] = texcoord2f;
1365 m.texcubemap[1] = R_GetTexture(lightcubemap);
1367 m.pointer_texcoord3f[1] = vertex3f;
1368 m.texmatrix[1] = *matrix_modeltolight;
1370 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1371 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1375 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap)
1377 // 1/2/2 3D combine path (original Radeon)
1378 memset(&m, 0, sizeof(m));
1379 m.pointer_vertex = vertex3f;
1380 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1382 m.pointer_texcoord3f[0] = vertex3f;
1383 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1385 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1386 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1389 GL_ColorMask(0,0,0,1);
1390 GL_BlendFunc(GL_ONE, GL_ZERO);
1391 GL_LockArrays(0, numverts);
1392 R_Mesh_Draw(numverts, numtriangles, elements);
1393 GL_LockArrays(0, 0);
1395 c_rt_lighttris += numtriangles;
1397 memset(&m, 0, sizeof(m));
1398 m.pointer_vertex = vertex3f;
1399 m.tex[0] = R_GetTexture(bumptexture);
1400 m.texcombinergb[0] = GL_REPLACE;
1401 m.pointer_texcoord[0] = texcoord2f;
1402 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1403 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1404 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1405 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1407 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1408 GL_LockArrays(0, numverts);
1409 R_Mesh_Draw(numverts, numtriangles, elements);
1410 GL_LockArrays(0, 0);
1412 c_rt_lighttris += numtriangles;
1414 memset(&m, 0, sizeof(m));
1415 m.pointer_vertex = vertex3f;
1416 m.tex[0] = R_GetTexture(basetexture);
1417 m.pointer_texcoord[0] = texcoord2f;
1420 m.texcubemap[1] = R_GetTexture(lightcubemap);
1422 m.pointer_texcoord3f[1] = vertex3f;
1423 m.texmatrix[1] = *matrix_modeltolight;
1425 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1426 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1430 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap)
1432 // 2/2 3D combine path (original Radeon)
1433 memset(&m, 0, sizeof(m));
1434 m.pointer_vertex = vertex3f;
1435 m.tex[0] = R_GetTexture(bumptexture);
1436 m.texcombinergb[0] = GL_REPLACE;
1437 m.pointer_texcoord[0] = texcoord2f;
1438 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1439 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1440 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1441 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1443 GL_ColorMask(0,0,0,1);
1444 GL_BlendFunc(GL_ONE, GL_ZERO);
1445 GL_LockArrays(0, numverts);
1446 R_Mesh_Draw(numverts, numtriangles, elements);
1447 GL_LockArrays(0, 0);
1449 c_rt_lighttris += numtriangles;
1451 memset(&m, 0, sizeof(m));
1452 m.pointer_vertex = vertex3f;
1453 m.tex[0] = R_GetTexture(basetexture);
1454 m.pointer_texcoord[0] = texcoord2f;
1455 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1457 m.pointer_texcoord3f[1] = vertex3f;
1458 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1460 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1461 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1464 else if (r_textureunits.integer >= 4)
1466 // 4/2 2D combine path (Geforce3, Radeon 8500)
1467 memset(&m, 0, sizeof(m));
1468 m.pointer_vertex = vertex3f;
1469 m.tex[0] = R_GetTexture(bumptexture);
1470 m.texcombinergb[0] = GL_REPLACE;
1471 m.pointer_texcoord[0] = texcoord2f;
1472 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1473 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1474 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1475 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1476 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1478 m.pointer_texcoord3f[2] = vertex3f;
1479 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
1481 m.pointer_texcoord[2] = varray_texcoord2f[2];
1482 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1484 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1486 m.pointer_texcoord3f[3] = vertex3f;
1487 m.texmatrix[3] = *matrix_modeltoattenuationz;
1489 m.pointer_texcoord[3] = varray_texcoord2f[3];
1490 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[3], numverts, vertex3f, matrix_modeltoattenuationz);
1493 GL_ColorMask(0,0,0,1);
1494 GL_BlendFunc(GL_ONE, GL_ZERO);
1495 GL_LockArrays(0, numverts);
1496 R_Mesh_Draw(numverts, numtriangles, elements);
1497 GL_LockArrays(0, 0);
1499 c_rt_lighttris += numtriangles;
1501 memset(&m, 0, sizeof(m));
1502 m.pointer_vertex = vertex3f;
1503 m.tex[0] = R_GetTexture(basetexture);
1504 m.pointer_texcoord[0] = texcoord2f;
1507 m.texcubemap[1] = R_GetTexture(lightcubemap);
1509 m.pointer_texcoord3f[1] = vertex3f;
1510 m.texmatrix[1] = *matrix_modeltolight;
1512 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1513 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1519 // 2/2/2 2D combine path (any dot3 card)
1520 memset(&m, 0, sizeof(m));
1521 m.pointer_vertex = vertex3f;
1522 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1524 m.pointer_texcoord3f[0] = vertex3f;
1525 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1527 m.pointer_texcoord[0] = varray_texcoord2f[0];
1528 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1530 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1532 m.pointer_texcoord3f[1] = vertex3f;
1533 m.texmatrix[1] = *matrix_modeltoattenuationz;
1535 m.pointer_texcoord[1] = varray_texcoord2f[1];
1536 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1539 GL_ColorMask(0,0,0,1);
1540 GL_BlendFunc(GL_ONE, GL_ZERO);
1541 GL_LockArrays(0, numverts);
1542 R_Mesh_Draw(numverts, numtriangles, elements);
1543 GL_LockArrays(0, 0);
1545 c_rt_lighttris += numtriangles;
1547 memset(&m, 0, sizeof(m));
1548 m.pointer_vertex = vertex3f;
1549 m.tex[0] = R_GetTexture(bumptexture);
1550 m.texcombinergb[0] = GL_REPLACE;
1551 m.pointer_texcoord[0] = texcoord2f;
1552 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1553 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1554 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1555 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1557 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1558 GL_LockArrays(0, numverts);
1559 R_Mesh_Draw(numverts, numtriangles, elements);
1560 GL_LockArrays(0, 0);
1562 c_rt_lighttris += numtriangles;
1564 memset(&m, 0, sizeof(m));
1565 m.pointer_vertex = vertex3f;
1566 m.tex[0] = R_GetTexture(basetexture);
1567 m.pointer_texcoord[0] = texcoord2f;
1570 m.texcubemap[1] = R_GetTexture(lightcubemap);
1572 m.pointer_texcoord3f[1] = vertex3f;
1573 m.texmatrix[1] = *matrix_modeltolight;
1575 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1576 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1580 // this final code is shared
1582 GL_ColorMask(1,1,1,0);
1583 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1584 VectorScale(lightcolor, colorscale, color2);
1585 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1587 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1588 GL_LockArrays(0, numverts);
1589 R_Mesh_Draw(numverts, numtriangles, elements);
1590 GL_LockArrays(0, 0);
1592 c_rt_lighttris += numtriangles;
1595 if ((lighting & LIGHTING_SPECULAR) && (r_shadow_gloss.integer >= 2 || (r_shadow_gloss.integer >= 1 && glosstexture != r_shadow_blankglosstexture)))
1597 // FIXME: detect blendsquare!
1598 //if (gl_support_blendsquare)
1600 colorscale = r_shadow_lightintensityscale.value * r_shadow_glossintensity.value;
1601 if (glosstexture == r_shadow_blankglosstexture)
1602 colorscale *= r_shadow_gloss2intensity.value;
1604 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1606 // 2/0/0/1/2 3D combine blendsquare path
1607 memset(&m, 0, sizeof(m));
1608 m.pointer_vertex = vertex3f;
1609 m.tex[0] = R_GetTexture(bumptexture);
1610 m.pointer_texcoord[0] = texcoord2f;
1611 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1612 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1613 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1614 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1616 GL_ColorMask(0,0,0,1);
1617 // this squares the result
1618 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1619 GL_LockArrays(0, numverts);
1620 R_Mesh_Draw(numverts, numtriangles, elements);
1621 GL_LockArrays(0, 0);
1623 c_rt_lighttris += numtriangles;
1625 memset(&m, 0, sizeof(m));
1626 m.pointer_vertex = vertex3f;
1628 GL_LockArrays(0, numverts);
1629 // square alpha in framebuffer a few times to make it shiny
1630 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1631 // these comments are a test run through this math for intensity 0.5
1632 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1633 // 0.25 * 0.25 = 0.0625 (this is another pass)
1634 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1635 R_Mesh_Draw(numverts, numtriangles, elements);
1637 c_rt_lighttris += numtriangles;
1638 R_Mesh_Draw(numverts, numtriangles, elements);
1640 c_rt_lighttris += numtriangles;
1641 GL_LockArrays(0, 0);
1643 memset(&m, 0, sizeof(m));
1644 m.pointer_vertex = vertex3f;
1645 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1647 m.pointer_texcoord3f[0] = vertex3f;
1648 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1650 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1651 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1654 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1655 GL_LockArrays(0, numverts);
1656 R_Mesh_Draw(numverts, numtriangles, elements);
1657 GL_LockArrays(0, 0);
1659 c_rt_lighttris += numtriangles;
1661 memset(&m, 0, sizeof(m));
1662 m.pointer_vertex = vertex3f;
1663 m.tex[0] = R_GetTexture(glosstexture);
1664 m.pointer_texcoord[0] = texcoord2f;
1667 m.texcubemap[1] = R_GetTexture(lightcubemap);
1669 m.pointer_texcoord3f[1] = vertex3f;
1670 m.texmatrix[1] = *matrix_modeltolight;
1672 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1673 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1677 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1679 // 2/0/0/2 3D combine blendsquare path
1680 memset(&m, 0, sizeof(m));
1681 m.pointer_vertex = vertex3f;
1682 m.tex[0] = R_GetTexture(bumptexture);
1683 m.pointer_texcoord[0] = texcoord2f;
1684 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1685 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1686 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1687 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1689 GL_ColorMask(0,0,0,1);
1690 // this squares the result
1691 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1692 GL_LockArrays(0, numverts);
1693 R_Mesh_Draw(numverts, numtriangles, elements);
1694 GL_LockArrays(0, 0);
1696 c_rt_lighttris += numtriangles;
1698 memset(&m, 0, sizeof(m));
1699 m.pointer_vertex = vertex3f;
1701 GL_LockArrays(0, numverts);
1702 // square alpha in framebuffer a few times to make it shiny
1703 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1704 // these comments are a test run through this math for intensity 0.5
1705 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1706 // 0.25 * 0.25 = 0.0625 (this is another pass)
1707 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1708 R_Mesh_Draw(numverts, numtriangles, elements);
1710 c_rt_lighttris += numtriangles;
1711 R_Mesh_Draw(numverts, numtriangles, elements);
1713 c_rt_lighttris += numtriangles;
1714 GL_LockArrays(0, 0);
1716 memset(&m, 0, sizeof(m));
1717 m.pointer_vertex = vertex3f;
1718 m.tex[0] = R_GetTexture(glosstexture);
1719 m.pointer_texcoord[0] = texcoord2f;
1720 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1722 m.pointer_texcoord3f[1] = vertex3f;
1723 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1725 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1726 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1731 // 2/0/0/2/2 2D combine blendsquare path
1732 memset(&m, 0, sizeof(m));
1733 m.pointer_vertex = vertex3f;
1734 m.tex[0] = R_GetTexture(bumptexture);
1735 m.pointer_texcoord[0] = texcoord2f;
1736 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1737 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1738 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1739 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1741 GL_ColorMask(0,0,0,1);
1742 // this squares the result
1743 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1744 GL_LockArrays(0, numverts);
1745 R_Mesh_Draw(numverts, numtriangles, elements);
1746 GL_LockArrays(0, 0);
1748 c_rt_lighttris += numtriangles;
1750 memset(&m, 0, sizeof(m));
1751 m.pointer_vertex = vertex3f;
1753 GL_LockArrays(0, numverts);
1754 // square alpha in framebuffer a few times to make it shiny
1755 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1756 // these comments are a test run through this math for intensity 0.5
1757 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1758 // 0.25 * 0.25 = 0.0625 (this is another pass)
1759 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1760 R_Mesh_Draw(numverts, numtriangles, elements);
1762 c_rt_lighttris += numtriangles;
1763 R_Mesh_Draw(numverts, numtriangles, elements);
1765 c_rt_lighttris += numtriangles;
1766 GL_LockArrays(0, 0);
1768 memset(&m, 0, sizeof(m));
1769 m.pointer_vertex = vertex3f;
1770 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1772 m.pointer_texcoord3f[0] = vertex3f;
1773 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1775 m.pointer_texcoord[0] = varray_texcoord2f[0];
1776 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1778 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1780 m.pointer_texcoord3f[1] = vertex3f;
1781 m.texmatrix[1] = *matrix_modeltoattenuationz;
1783 m.pointer_texcoord[1] = varray_texcoord2f[1];
1784 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1787 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1788 GL_LockArrays(0, numverts);
1789 R_Mesh_Draw(numverts, numtriangles, elements);
1790 GL_LockArrays(0, 0);
1792 c_rt_lighttris += numtriangles;
1794 memset(&m, 0, sizeof(m));
1795 m.pointer_vertex = vertex3f;
1796 m.tex[0] = R_GetTexture(glosstexture);
1797 m.pointer_texcoord[0] = texcoord2f;
1800 m.texcubemap[1] = R_GetTexture(lightcubemap);
1802 m.pointer_texcoord3f[1] = vertex3f;
1803 m.texmatrix[1] = *matrix_modeltolight;
1805 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1806 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1812 GL_ColorMask(1,1,1,0);
1813 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1814 VectorScale(lightcolor, colorscale, color2);
1815 GL_LockArrays(0, numverts);
1816 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1818 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1819 R_Mesh_Draw(numverts, numtriangles, elements);
1821 c_rt_lighttris += numtriangles;
1823 GL_LockArrays(0, 0);
1828 if (lighting & LIGHTING_DIFFUSE)
1830 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1831 VectorScale(lightcolor, r_shadow_lightintensityscale.value, color2);
1832 memset(&m, 0, sizeof(m));
1833 m.pointer_vertex = vertex3f;
1834 m.pointer_color = varray_color4f;
1835 m.tex[0] = R_GetTexture(basetexture);
1836 m.pointer_texcoord[0] = texcoord2f;
1837 if (r_textureunits.integer >= 2)
1840 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1842 m.pointer_texcoord3f[1] = vertex3f;
1843 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1845 m.pointer_texcoord[1] = varray_texcoord2f[1];
1846 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1848 if (r_textureunits.integer >= 3)
1850 // Geforce3/Radeon class but not using dot3
1851 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1853 m.pointer_texcoord3f[2] = vertex3f;
1854 m.texmatrix[2] = *matrix_modeltoattenuationz;
1856 m.pointer_texcoord[2] = varray_texcoord2f[2];
1857 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationz);
1862 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1864 color[0] = bound(0, color2[0], 1);
1865 color[1] = bound(0, color2[1], 1);
1866 color[2] = bound(0, color2[2], 1);
1867 if (r_textureunits.integer >= 3)
1868 R_Shadow_VertexShading(numverts, vertex3f, normal3f, color, matrix_modeltolight);
1869 else if (r_textureunits.integer >= 2)
1870 R_Shadow_VertexShadingWithZAttenuation(numverts, vertex3f, normal3f, color, matrix_modeltolight);
1872 R_Shadow_VertexShadingWithXYZAttenuation(numverts, vertex3f, normal3f, color, matrix_modeltolight);
1873 GL_LockArrays(0, numverts);
1874 R_Mesh_Draw(numverts, numtriangles, elements);
1875 GL_LockArrays(0, 0);
1877 c_rt_lighttris += numtriangles;
1883 void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
1887 R_RTLight_Uncompile(rtlight);
1888 memset(rtlight, 0, sizeof(*rtlight));
1890 VectorCopy(light->origin, rtlight->shadoworigin);
1891 VectorCopy(light->color, rtlight->color);
1892 rtlight->radius = light->radius;
1893 //rtlight->cullradius = rtlight->radius;
1894 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
1895 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
1896 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
1897 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
1898 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
1899 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
1900 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
1901 rtlight->cubemapname[0] = 0;
1902 if (light->cubemapname[0])
1903 strcpy(rtlight->cubemapname, light->cubemapname);
1904 else if (light->cubemapnum > 0)
1905 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
1906 rtlight->shadow = light->shadow;
1907 rtlight->corona = light->corona;
1908 rtlight->style = light->style;
1909 rtlight->isstatic = isstatic;
1910 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
1911 // ConcatScale won't work here because this needs to scale rotate and
1912 // translate, not just rotate
1913 scale = 1.0f / rtlight->radius;
1914 for (k = 0;k < 3;k++)
1915 for (j = 0;j < 4;j++)
1916 rtlight->matrix_worldtolight.m[k][j] *= scale;
1917 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationxyz, &matrix_attenuationxyz, &rtlight->matrix_worldtolight);
1918 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationz, &matrix_attenuationz, &rtlight->matrix_worldtolight);
1920 rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
1921 rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
1922 VectorScale(rtlight->color, rtlight->radius * d_lightstylevalue[rtlight->style] * 0.125f, rtlight->lightmap_light);
1923 rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
1926 // compiles rtlight geometry
1927 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
1928 void R_RTLight_Compile(rtlight_t *rtlight)
1930 int shadowmeshes, shadowtris, lightmeshes, lighttris, numclusters, numsurfaces;
1931 entity_render_t *ent = &cl_entities[0].render;
1932 model_t *model = ent->model;
1934 // compile the light
1935 rtlight->compiled = true;
1936 rtlight->static_numclusters = 0;
1937 rtlight->static_numclusterpvsbytes = 0;
1938 rtlight->static_clusterlist = NULL;
1939 rtlight->static_clusterpvs = NULL;
1940 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
1941 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
1942 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
1943 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
1944 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
1945 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
1947 if (model && model->GetLightInfo)
1949 // this variable directs the DrawShadowVolume and DrawLight code to capture into the mesh chain instead of rendering
1950 r_shadow_compilingrtlight = rtlight;
1951 R_Shadow_EnlargeClusterBuffer(model->brush.num_pvsclusters);
1952 R_Shadow_EnlargeSurfaceBuffer(model->nummodelsurfaces);
1953 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);
1956 rtlight->static_numclusters = numclusters;
1957 rtlight->static_numclusterpvsbytes = (model->brush.num_pvsclusters + 7) >> 3;
1958 rtlight->static_clusterlist = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
1959 rtlight->static_clusterpvs = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusterpvsbytes);
1960 memcpy(rtlight->static_clusterlist, r_shadow_buffer_clusterlist, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
1961 memcpy(rtlight->static_clusterpvs, r_shadow_buffer_clusterpvs, rtlight->static_numclusterpvsbytes);
1963 if (model->DrawShadowVolume && rtlight->shadow)
1965 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
1966 model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
1967 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_shadow, false, false);
1969 if (model->DrawLight)
1971 rtlight->static_meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true);
1972 model->DrawLight(ent, rtlight->shadoworigin, vec3_origin, rtlight->radius, vec3_origin, &r_identitymatrix, &r_identitymatrix, &r_identitymatrix, NULL, numsurfaces, r_shadow_buffer_surfacelist);
1973 rtlight->static_meshchain_light = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_light, true, false);
1975 // switch back to rendering when DrawShadowVolume or DrawLight is called
1976 r_shadow_compilingrtlight = NULL;
1980 // use smallest available cullradius - box radius or light radius
1981 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
1982 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
1986 if (rtlight->static_meshchain_shadow)
1989 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
1992 shadowtris += mesh->numtriangles;
1998 if (rtlight->static_meshchain_light)
2001 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2004 lighttris += mesh->numtriangles;
2008 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);
2011 void R_RTLight_Uncompile(rtlight_t *rtlight)
2013 if (rtlight->compiled)
2015 if (rtlight->static_meshchain_shadow)
2016 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2017 rtlight->static_meshchain_shadow = NULL;
2018 if (rtlight->static_meshchain_light)
2019 Mod_ShadowMesh_Free(rtlight->static_meshchain_light);
2020 rtlight->static_meshchain_light = NULL;
2021 if (rtlight->static_clusterlist)
2022 Mem_Free(rtlight->static_clusterlist);
2023 rtlight->static_clusterlist = NULL;
2024 if (rtlight->static_clusterpvs)
2025 Mem_Free(rtlight->static_clusterpvs);
2026 rtlight->static_clusterpvs = NULL;
2027 rtlight->static_numclusters = 0;
2028 rtlight->static_numclusterpvsbytes = 0;
2029 rtlight->compiled = false;
2033 void R_Shadow_UncompileWorldLights(void)
2036 for (light = r_shadow_worldlightchain;light;light = light->next)
2037 R_RTLight_Uncompile(&light->rtlight);
2040 void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes)
2043 entity_render_t *ent;
2045 vec3_t relativelightorigin, relativeeyeorigin, lightcolor;
2046 rtexture_t *cubemaptexture;
2047 matrix4x4_t matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz;
2048 int numclusters, numsurfaces;
2049 int *clusterlist, *surfacelist;
2051 vec3_t cullmins, cullmaxs;
2055 // loading is done before visibility checks because loading should happen
2056 // all at once at the start of a level, not when it stalls gameplay.
2057 // (especially important to benchmarks)
2058 if (rtlight->isstatic && !rtlight->compiled && r_shadow_staticworldlights.integer)
2059 R_RTLight_Compile(rtlight);
2060 if (rtlight->cubemapname[0])
2061 cubemaptexture = R_Shadow_Cubemap(rtlight->cubemapname);
2063 cubemaptexture = NULL;
2065 cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2066 cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2067 cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2068 cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2069 cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2070 cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2071 if (d_lightstylevalue[rtlight->style] <= 0)
2078 if (rtlight->compiled && r_shadow_staticworldlights.integer)
2080 // compiled light, world available and can receive realtime lighting
2081 // retrieve cluster information
2082 numclusters = rtlight->static_numclusters;
2083 clusterlist = rtlight->static_clusterlist;
2084 clusterpvs = rtlight->static_clusterpvs;
2085 VectorCopy(rtlight->cullmins, cullmins);
2086 VectorCopy(rtlight->cullmaxs, cullmaxs);
2088 else if (cl.worldmodel && cl.worldmodel->GetLightInfo)
2090 // dynamic light, world available and can receive realtime lighting
2091 // if the light box is offscreen, skip it right away
2092 if (R_CullBox(cullmins, cullmaxs))
2094 // calculate lit surfaces and clusters
2095 R_Shadow_EnlargeClusterBuffer(cl.worldmodel->brush.num_pvsclusters);
2096 R_Shadow_EnlargeSurfaceBuffer(cl.worldmodel->nummodelsurfaces);
2097 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);
2098 clusterlist = r_shadow_buffer_clusterlist;
2099 clusterpvs = r_shadow_buffer_clusterpvs;
2100 surfacelist = r_shadow_buffer_surfacelist;
2102 // if the reduced cluster bounds are offscreen, skip it
2103 if (R_CullBox(cullmins, cullmaxs))
2105 // check if light is illuminating any visible clusters
2108 for (i = 0;i < numclusters;i++)
2109 if (CHECKPVSBIT(r_pvsbits, clusterlist[i]))
2111 if (i == numclusters)
2114 // set up a scissor rectangle for this light
2115 if (R_Shadow_ScissorForBBox(cullmins, cullmaxs))
2118 f = d_lightstylevalue[rtlight->style] * (1.0f / 256.0f);
2119 VectorScale(rtlight->color, f, lightcolor);
2121 if (rtlight->selected)
2123 f = 2 + sin(realtime * M_PI * 4.0);
2124 VectorScale(lightcolor, f, lightcolor);
2129 shadow = rtlight->shadow && (rtlight->isstatic ? r_shadow_realtime_world_shadows.integer : (r_shadow_realtime_world.integer ? r_shadow_realtime_world_dlightshadows.integer : r_shadow_realtime_dlight_shadows.integer));
2132 if (rtlight->shadow)
2134 if (rtlight->isstatic)
2135 shadow = r_shadow_realtime_world_shadows.integer;
2138 if (r_shadow_realtime_world.integer)
2139 shadow = r_shadow_realtime_world_dlightshadows.integer;
2141 shadow = r_shadow_realtime_dlight_shadows.integer;
2146 if (shadow && (gl_stencil || visiblevolumes))
2148 if (!visiblevolumes)
2149 R_Shadow_Stage_ShadowVolumes();
2150 ent = &cl_entities[0].render;
2151 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2153 memset(&m, 0, sizeof(m));
2154 R_Mesh_Matrix(&ent->matrix);
2155 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2157 m.pointer_vertex = mesh->vertex3f;
2159 GL_LockArrays(0, mesh->numverts);
2160 if (r_shadowstage == SHADOWSTAGE_STENCIL)
2162 // decrement stencil if frontface is behind depthbuffer
2163 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2164 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2165 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2166 c_rtcached_shadowmeshes++;
2167 c_rtcached_shadowtris += mesh->numtriangles;
2168 // increment stencil if backface is behind depthbuffer
2169 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2170 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2172 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2173 c_rtcached_shadowmeshes++;
2174 c_rtcached_shadowtris += mesh->numtriangles;
2175 GL_LockArrays(0, 0);
2180 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2181 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, numsurfaces, surfacelist);
2183 if (r_drawentities.integer)
2185 for (i = 0;i < r_refdef.numentities;i++)
2187 ent = r_refdef.entities[i];
2189 if (r_shadow_cull.integer)
2191 if (!BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs))
2193 if (cl.worldmodel != NULL && cl.worldmodel->brush.BoxTouchingPVS != NULL && !cl.worldmodel->brush.BoxTouchingPVS(cl.worldmodel, clusterpvs, ent->mins, ent->maxs))
2196 if (!(ent->flags & RENDER_SHADOW) || !ent->model || !ent->model->DrawShadowVolume)
2198 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2199 // light emitting entities should not cast their own shadow
2200 if (VectorLength2(relativelightorigin) < 0.1)
2202 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, ent->model->nummodelsurfaces, ent->model->surfacelist);
2207 if (!visiblevolumes)
2209 if (shadow && gl_stencil)
2210 R_Shadow_Stage_LightWithShadows();
2212 R_Shadow_Stage_LightWithoutShadows();
2214 ent = &cl_entities[0].render;
2215 if (ent->model && ent->model->DrawLight)
2217 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2218 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2219 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2220 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2221 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2222 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2224 R_Mesh_Matrix(&ent->matrix);
2225 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2226 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);
2229 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, numsurfaces, surfacelist);
2231 if (r_drawentities.integer)
2233 for (i = 0;i < r_refdef.numentities;i++)
2235 ent = r_refdef.entities[i];
2236 if (ent->visframe == r_framecount && BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs) && ent->model && ent->model->DrawLight && (ent->flags & RENDER_LIGHT))
2238 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2239 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2240 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2241 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2242 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2243 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, ent->model->nummodelsurfaces, ent->model->surfacelist);
2250 void R_ShadowVolumeLighting(int visiblevolumes)
2256 if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2257 R_Shadow_EditLights_Reload_f();
2261 memset(&m, 0, sizeof(m));
2264 GL_BlendFunc(GL_ONE, GL_ONE);
2265 GL_DepthMask(false);
2266 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
2267 qglDisable(GL_CULL_FACE);
2268 GL_Color(0.0, 0.0125, 0.1, 1);
2271 R_Shadow_Stage_Begin();
2272 if (r_shadow_realtime_world.integer)
2274 if (r_shadow_debuglight.integer >= 0)
2276 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2277 if (lnum == r_shadow_debuglight.integer)
2278 R_DrawRTLight(&light->rtlight, visiblevolumes);
2281 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2282 R_DrawRTLight(&light->rtlight, visiblevolumes);
2284 if (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer)
2285 for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
2286 R_DrawRTLight(&light->rtlight, visiblevolumes);
2290 qglEnable(GL_CULL_FACE);
2291 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
2294 R_Shadow_Stage_End();
2297 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2298 typedef struct suffixinfo_s
2301 qboolean flipx, flipy, flipdiagonal;
2304 static suffixinfo_t suffix[3][6] =
2307 {"px", false, false, false},
2308 {"nx", false, false, false},
2309 {"py", false, false, false},
2310 {"ny", false, false, false},
2311 {"pz", false, false, false},
2312 {"nz", false, false, false}
2315 {"posx", false, false, false},
2316 {"negx", false, false, false},
2317 {"posy", false, false, false},
2318 {"negy", false, false, false},
2319 {"posz", false, false, false},
2320 {"negz", false, false, false}
2323 {"rt", true, false, true},
2324 {"lf", false, true, true},
2325 {"ft", true, true, false},
2326 {"bk", false, false, false},
2327 {"up", true, false, true},
2328 {"dn", true, false, true}
2332 static int componentorder[4] = {0, 1, 2, 3};
2334 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2336 int i, j, cubemapsize;
2337 qbyte *cubemappixels, *image_rgba;
2338 rtexture_t *cubemaptexture;
2340 // must start 0 so the first loadimagepixels has no requested width/height
2342 cubemappixels = NULL;
2343 cubemaptexture = NULL;
2344 // keep trying different suffix groups (posx, px, rt) until one loads
2345 for (j = 0;j < 3 && !cubemappixels;j++)
2347 // load the 6 images in the suffix group
2348 for (i = 0;i < 6;i++)
2350 // generate an image name based on the base and and suffix
2351 snprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2353 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2355 // an image loaded, make sure width and height are equal
2356 if (image_width == image_height)
2358 // if this is the first image to load successfully, allocate the cubemap memory
2359 if (!cubemappixels && image_width >= 1)
2361 cubemapsize = image_width;
2362 // note this clears to black, so unavailable sides are black
2363 cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2365 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2367 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);
2370 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2372 Mem_Free(image_rgba);
2376 // if a cubemap loaded, upload it
2379 if (!r_shadow_filters_texturepool)
2380 r_shadow_filters_texturepool = R_AllocTexturePool();
2381 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
2382 Mem_Free(cubemappixels);
2386 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
2387 for (j = 0;j < 3;j++)
2388 for (i = 0;i < 6;i++)
2389 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2390 Con_Print(" and was unable to find any of them.\n");
2392 return cubemaptexture;
2395 rtexture_t *R_Shadow_Cubemap(const char *basename)
2398 for (i = 0;i < numcubemaps;i++)
2399 if (!strcasecmp(cubemaps[i].basename, basename))
2400 return cubemaps[i].texture;
2401 if (i >= MAX_CUBEMAPS)
2404 strcpy(cubemaps[i].basename, basename);
2405 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
2406 return cubemaps[i].texture;
2409 void R_Shadow_FreeCubemaps(void)
2412 R_FreeTexturePool(&r_shadow_filters_texturepool);
2415 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)
2419 if (radius < 15 || DotProduct(color, color) < 0.03)
2421 Con_Print("R_Shadow_NewWorldLight: refusing to create a light too small/dim\n");
2425 light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
2426 VectorCopy(origin, light->origin);
2427 VectorCopy(angles, light->angles);
2428 VectorCopy(color, light->color);
2429 light->radius = radius;
2430 light->style = style;
2431 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
2433 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
2436 light->shadow = shadowenable;
2437 light->corona = corona;
2438 if (cubemapname && cubemapname[0] && strlen(cubemapname) < sizeof(light->cubemapname))
2439 strcpy(light->cubemapname, cubemapname);
2440 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
2441 light->next = r_shadow_worldlightchain;
2442 r_shadow_worldlightchain = light;
2444 R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
2447 void R_Shadow_FreeWorldLight(dlight_t *light)
2449 dlight_t **lightpointer;
2450 R_RTLight_Uncompile(&light->rtlight);
2451 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
2452 if (*lightpointer != light)
2453 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
2454 *lightpointer = light->next;
2458 void R_Shadow_ClearWorldLights(void)
2460 while (r_shadow_worldlightchain)
2461 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
2462 r_shadow_selectedlight = NULL;
2463 R_Shadow_FreeCubemaps();
2466 void R_Shadow_SelectLight(dlight_t *light)
2468 if (r_shadow_selectedlight)
2469 r_shadow_selectedlight->selected = false;
2470 r_shadow_selectedlight = light;
2471 if (r_shadow_selectedlight)
2472 r_shadow_selectedlight->selected = true;
2475 void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
2477 float scale = r_editlights_cursorgrid.value * 0.5f;
2478 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);
2481 void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
2484 const dlight_t *light;
2487 if (light->selected)
2488 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
2491 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);
2494 void R_Shadow_DrawLightSprites(void)
2500 for (i = 0;i < 5;i++)
2502 lighttextures[i] = NULL;
2503 if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1))))
2504 lighttextures[i] = pic->tex;
2507 for (light = r_shadow_worldlightchain;light;light = light->next)
2508 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, ((int) light) % 5);
2509 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
2512 void R_Shadow_SelectLightInView(void)
2514 float bestrating, rating, temp[3];
2515 dlight_t *best, *light;
2518 for (light = r_shadow_worldlightchain;light;light = light->next)
2520 VectorSubtract(light->origin, r_vieworigin, temp);
2521 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
2524 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
2525 if (bestrating < rating && CL_TraceLine(light->origin, r_vieworigin, NULL, NULL, true, NULL, SUPERCONTENTS_SOLID) == 1.0f)
2527 bestrating = rating;
2532 R_Shadow_SelectLight(best);
2535 void R_Shadow_LoadWorldLights(void)
2537 int n, a, style, shadow;
2538 char name[MAX_QPATH], cubemapname[MAX_QPATH], *lightsstring, *s, *t;
2539 float origin[3], radius, color[3], angles[3], corona;
2540 if (cl.worldmodel == NULL)
2542 Con_Print("No map loaded.\n");
2545 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2546 strlcat (name, ".rtlights", sizeof (name));
2547 lightsstring = FS_LoadFile(name, tempmempool, false);
2557 for (;COM_Parse(t, true) && strcmp(
2558 if (COM_Parse(t, true))
2560 if (com_token[0] == '!')
2563 origin[0] = atof(com_token+1);
2566 origin[0] = atof(com_token);
2571 while (*s && *s != '\n')
2577 // check for modifier flags
2583 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]);
2585 VectorClear(angles);
2588 if (a < 9 || !strcmp(cubemapname, "\"\""))
2593 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);
2596 VectorScale(color, r_editlights_rtlightscolorscale.value, color);
2597 radius *= r_editlights_rtlightssizescale.value;
2598 R_Shadow_NewWorldLight(origin, angles, color, radius, corona, style, shadow, cubemapname);
2603 Con_Printf("invalid rtlights file \"%s\"\n", name);
2604 Mem_Free(lightsstring);
2608 void R_Shadow_SaveWorldLights(void)
2611 int bufchars, bufmaxchars;
2613 char name[MAX_QPATH];
2615 if (!r_shadow_worldlightchain)
2617 if (cl.worldmodel == NULL)
2619 Con_Print("No map loaded.\n");
2622 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2623 strlcat (name, ".rtlights", sizeof (name));
2624 bufchars = bufmaxchars = 0;
2626 for (light = r_shadow_worldlightchain;light;light = light->next)
2628 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]);
2629 if (bufchars + (int) strlen(line) > bufmaxchars)
2631 bufmaxchars = bufchars + strlen(line) + 2048;
2633 buf = Mem_Alloc(r_shadow_mempool, bufmaxchars);
2637 memcpy(buf, oldbuf, bufchars);
2643 memcpy(buf + bufchars, line, strlen(line));
2644 bufchars += strlen(line);
2648 FS_WriteFile(name, buf, bufchars);
2653 void R_Shadow_LoadLightsFile(void)
2656 char name[MAX_QPATH], *lightsstring, *s, *t;
2657 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
2658 if (cl.worldmodel == NULL)
2660 Con_Print("No map loaded.\n");
2663 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2664 strlcat (name, ".lights", sizeof (name));
2665 lightsstring = FS_LoadFile(name, tempmempool, false);
2673 while (*s && *s != '\n')
2678 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);
2682 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);
2685 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
2686 radius = bound(15, radius, 4096);
2687 VectorScale(color, (2.0f / (8388608.0f)), color);
2688 R_Shadow_NewWorldLight(origin, vec3_origin, color, radius, 0, style, true, NULL);
2693 Con_Printf("invalid lights file \"%s\"\n", name);
2694 Mem_Free(lightsstring);
2698 // tyrlite/hmap2 light types in the delay field
2699 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
2701 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
2703 int entnum, style, islight, skin, pflags, effects, type, n;
2704 char key[256], value[1024];
2705 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
2708 if (cl.worldmodel == NULL)
2710 Con_Print("No map loaded.\n");
2713 data = cl.worldmodel->brush.entities;
2716 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
2718 type = LIGHTTYPE_MINUSX;
2719 origin[0] = origin[1] = origin[2] = 0;
2720 originhack[0] = originhack[1] = originhack[2] = 0;
2721 angles[0] = angles[1] = angles[2] = 0;
2722 light[0] = light[1] = light[2] = 1;light[3] = 300;
2723 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
2733 if (!COM_ParseToken(&data, false))
2735 if (com_token[0] == '}')
2736 break; // end of entity
2737 if (com_token[0] == '_')
2738 strcpy(key, com_token + 1);
2740 strcpy(key, com_token);
2741 while (key[strlen(key)-1] == ' ') // remove trailing spaces
2742 key[strlen(key)-1] = 0;
2743 if (!COM_ParseToken(&data, false))
2745 strcpy(value, com_token);
2747 // now that we have the key pair worked out...
2748 if (!strcmp("light", key))
2750 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
2754 light[0] = vec[0] * (1.0f / 256.0f);
2755 light[1] = vec[0] * (1.0f / 256.0f);
2756 light[2] = vec[0] * (1.0f / 256.0f);
2762 light[0] = vec[0] * (1.0f / 255.0f);
2763 light[1] = vec[1] * (1.0f / 255.0f);
2764 light[2] = vec[2] * (1.0f / 255.0f);
2768 else if (!strcmp("delay", key))
2770 else if (!strcmp("origin", key))
2771 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
2772 else if (!strcmp("angle", key))
2773 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
2774 else if (!strcmp("angles", key))
2775 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
2776 else if (!strcmp("color", key))
2777 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
2778 else if (!strcmp("wait", key))
2779 fadescale = atof(value);
2780 else if (!strcmp("classname", key))
2782 if (!strncmp(value, "light", 5))
2785 if (!strcmp(value, "light_fluoro"))
2790 overridecolor[0] = 1;
2791 overridecolor[1] = 1;
2792 overridecolor[2] = 1;
2794 if (!strcmp(value, "light_fluorospark"))
2799 overridecolor[0] = 1;
2800 overridecolor[1] = 1;
2801 overridecolor[2] = 1;
2803 if (!strcmp(value, "light_globe"))
2808 overridecolor[0] = 1;
2809 overridecolor[1] = 0.8;
2810 overridecolor[2] = 0.4;
2812 if (!strcmp(value, "light_flame_large_yellow"))
2817 overridecolor[0] = 1;
2818 overridecolor[1] = 0.5;
2819 overridecolor[2] = 0.1;
2821 if (!strcmp(value, "light_flame_small_yellow"))
2826 overridecolor[0] = 1;
2827 overridecolor[1] = 0.5;
2828 overridecolor[2] = 0.1;
2830 if (!strcmp(value, "light_torch_small_white"))
2835 overridecolor[0] = 1;
2836 overridecolor[1] = 0.5;
2837 overridecolor[2] = 0.1;
2839 if (!strcmp(value, "light_torch_small_walltorch"))
2844 overridecolor[0] = 1;
2845 overridecolor[1] = 0.5;
2846 overridecolor[2] = 0.1;
2850 else if (!strcmp("style", key))
2851 style = atoi(value);
2852 else if (cl.worldmodel->type == mod_brushq3)
2854 if (!strcmp("scale", key))
2855 lightscale = atof(value);
2856 if (!strcmp("fade", key))
2857 fadescale = atof(value);
2859 else if (!strcmp("skin", key))
2860 skin = (int)atof(value);
2861 else if (!strcmp("pflags", key))
2862 pflags = (int)atof(value);
2863 else if (!strcmp("effects", key))
2864 effects = (int)atof(value);
2868 if (lightscale <= 0)
2872 if (color[0] == color[1] && color[0] == color[2])
2874 color[0] *= overridecolor[0];
2875 color[1] *= overridecolor[1];
2876 color[2] *= overridecolor[2];
2878 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
2879 color[0] = color[0] * light[0];
2880 color[1] = color[1] * light[1];
2881 color[2] = color[2] * light[2];
2884 case LIGHTTYPE_MINUSX:
2886 case LIGHTTYPE_RECIPX:
2888 VectorScale(color, (1.0f / 16.0f), color);
2890 case LIGHTTYPE_RECIPXX:
2892 VectorScale(color, (1.0f / 16.0f), color);
2895 case LIGHTTYPE_NONE:
2899 case LIGHTTYPE_MINUSXX:
2902 VectorAdd(origin, originhack, origin);
2904 R_Shadow_NewWorldLight(origin, angles, color, radius, (pflags & PFLAGS_CORONA) != 0, style, (pflags & PFLAGS_NOSHADOW) == 0, skin >= 16 ? va("cubemaps/%i", skin) : NULL);
2909 void R_Shadow_SetCursorLocationForView(void)
2911 vec_t dist, push, frac;
2912 vec3_t dest, endpos, normal;
2913 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
2914 frac = CL_TraceLine(r_vieworigin, dest, endpos, normal, true, NULL, SUPERCONTENTS_SOLID);
2917 dist = frac * r_editlights_cursordistance.value;
2918 push = r_editlights_cursorpushback.value;
2922 VectorMA(endpos, push, r_viewforward, endpos);
2923 VectorMA(endpos, r_editlights_cursorpushoff.value, normal, endpos);
2925 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2926 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2927 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2930 void R_Shadow_UpdateWorldLightSelection(void)
2932 if (r_editlights.integer)
2934 R_Shadow_SetCursorLocationForView();
2935 R_Shadow_SelectLightInView();
2936 R_Shadow_DrawLightSprites();
2939 R_Shadow_SelectLight(NULL);
2942 void R_Shadow_EditLights_Clear_f(void)
2944 R_Shadow_ClearWorldLights();
2947 void R_Shadow_EditLights_Reload_f(void)
2951 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
2952 R_Shadow_ClearWorldLights();
2953 R_Shadow_LoadWorldLights();
2954 if (r_shadow_worldlightchain == NULL)
2956 R_Shadow_LoadLightsFile();
2957 if (r_shadow_worldlightchain == NULL)
2958 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
2962 void R_Shadow_EditLights_Save_f(void)
2966 R_Shadow_SaveWorldLights();
2969 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
2971 R_Shadow_ClearWorldLights();
2972 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
2975 void R_Shadow_EditLights_ImportLightsFile_f(void)
2977 R_Shadow_ClearWorldLights();
2978 R_Shadow_LoadLightsFile();
2981 void R_Shadow_EditLights_Spawn_f(void)
2984 if (!r_editlights.integer)
2986 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
2989 if (Cmd_Argc() != 1)
2991 Con_Print("r_editlights_spawn does not take parameters\n");
2994 color[0] = color[1] = color[2] = 1;
2995 R_Shadow_NewWorldLight(r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL);
2998 void R_Shadow_EditLights_Edit_f(void)
3000 vec3_t origin, angles, color;
3001 vec_t radius, corona;
3003 char cubemapname[1024];
3004 if (!r_editlights.integer)
3006 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3009 if (!r_shadow_selectedlight)
3011 Con_Print("No selected light.\n");
3014 VectorCopy(r_shadow_selectedlight->origin, origin);
3015 VectorCopy(r_shadow_selectedlight->angles, angles);
3016 VectorCopy(r_shadow_selectedlight->color, color);
3017 radius = r_shadow_selectedlight->radius;
3018 style = r_shadow_selectedlight->style;
3019 if (r_shadow_selectedlight->cubemapname)
3020 strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
3023 shadows = r_shadow_selectedlight->shadow;
3024 corona = r_shadow_selectedlight->corona;
3025 if (!strcmp(Cmd_Argv(1), "origin"))
3027 if (Cmd_Argc() != 5)
3029 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3032 origin[0] = atof(Cmd_Argv(2));
3033 origin[1] = atof(Cmd_Argv(3));
3034 origin[2] = atof(Cmd_Argv(4));
3036 else if (!strcmp(Cmd_Argv(1), "originx"))
3038 if (Cmd_Argc() != 3)
3040 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3043 origin[0] = atof(Cmd_Argv(2));
3045 else if (!strcmp(Cmd_Argv(1), "originy"))
3047 if (Cmd_Argc() != 3)
3049 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3052 origin[1] = atof(Cmd_Argv(2));
3054 else if (!strcmp(Cmd_Argv(1), "originz"))
3056 if (Cmd_Argc() != 3)
3058 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3061 origin[2] = atof(Cmd_Argv(2));
3063 else if (!strcmp(Cmd_Argv(1), "move"))
3065 if (Cmd_Argc() != 5)
3067 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3070 origin[0] += atof(Cmd_Argv(2));
3071 origin[1] += atof(Cmd_Argv(3));
3072 origin[2] += atof(Cmd_Argv(4));
3074 else if (!strcmp(Cmd_Argv(1), "movex"))
3076 if (Cmd_Argc() != 3)
3078 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3081 origin[0] += atof(Cmd_Argv(2));
3083 else if (!strcmp(Cmd_Argv(1), "movey"))
3085 if (Cmd_Argc() != 3)
3087 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3090 origin[1] += atof(Cmd_Argv(2));
3092 else if (!strcmp(Cmd_Argv(1), "movez"))
3094 if (Cmd_Argc() != 3)
3096 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3099 origin[2] += atof(Cmd_Argv(2));
3101 else if (!strcmp(Cmd_Argv(1), "angles"))
3103 if (Cmd_Argc() != 5)
3105 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3108 angles[0] = atof(Cmd_Argv(2));
3109 angles[1] = atof(Cmd_Argv(3));
3110 angles[2] = atof(Cmd_Argv(4));
3112 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3114 if (Cmd_Argc() != 3)
3116 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3119 angles[0] = atof(Cmd_Argv(2));
3121 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3123 if (Cmd_Argc() != 3)
3125 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3128 angles[1] = atof(Cmd_Argv(2));
3130 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3132 if (Cmd_Argc() != 3)
3134 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3137 angles[2] = atof(Cmd_Argv(2));
3139 else if (!strcmp(Cmd_Argv(1), "color"))
3141 if (Cmd_Argc() != 5)
3143 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3146 color[0] = atof(Cmd_Argv(2));
3147 color[1] = atof(Cmd_Argv(3));
3148 color[2] = atof(Cmd_Argv(4));
3150 else if (!strcmp(Cmd_Argv(1), "radius"))
3152 if (Cmd_Argc() != 3)
3154 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3157 radius = atof(Cmd_Argv(2));
3159 else if (!strcmp(Cmd_Argv(1), "style"))
3161 if (Cmd_Argc() != 3)
3163 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3166 style = atoi(Cmd_Argv(2));
3168 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3172 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3175 if (Cmd_Argc() == 3)
3176 strcpy(cubemapname, Cmd_Argv(2));
3180 else if (!strcmp(Cmd_Argv(1), "shadows"))
3182 if (Cmd_Argc() != 3)
3184 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3187 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3189 else if (!strcmp(Cmd_Argv(1), "corona"))
3191 if (Cmd_Argc() != 3)
3193 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3196 corona = atof(Cmd_Argv(2));
3200 Con_Print("usage: r_editlights_edit [property] [value]\n");
3201 Con_Print("Selected light's properties:\n");
3202 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3203 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3204 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3205 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3206 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3207 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3208 Con_Printf("Shadows: %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3209 Con_Printf("Cubemap: %s\n", r_shadow_selectedlight->cubemapname);
3212 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3213 r_shadow_selectedlight = NULL;
3214 R_Shadow_NewWorldLight(origin, angles, color, radius, corona, style, shadows, cubemapname);
3217 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3221 if (r_shadow_selectedlight == NULL)
3225 sprintf(temp, "Light properties");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3226 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;
3227 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;
3228 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;
3229 sprintf(temp, "Radius %f", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3230 sprintf(temp, "Corona %f", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3231 sprintf(temp, "Style %i", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3232 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;
3233 sprintf(temp, "Cubemap %s", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3236 void R_Shadow_EditLights_ToggleShadow_f(void)
3238 if (!r_editlights.integer)
3240 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3243 if (!r_shadow_selectedlight)
3245 Con_Print("No selected light.\n");
3248 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);
3249 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3250 r_shadow_selectedlight = NULL;
3253 void R_Shadow_EditLights_ToggleCorona_f(void)
3255 if (!r_editlights.integer)
3257 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3260 if (!r_shadow_selectedlight)
3262 Con_Print("No selected light.\n");
3265 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);
3266 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3267 r_shadow_selectedlight = NULL;
3270 void R_Shadow_EditLights_Remove_f(void)
3272 if (!r_editlights.integer)
3274 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
3277 if (!r_shadow_selectedlight)
3279 Con_Print("No selected light.\n");
3282 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3283 r_shadow_selectedlight = NULL;
3286 void R_Shadow_EditLights_Help_f(void)
3289 "Documentation on r_editlights system:\n"
3291 "r_editlights : enable/disable editing mode\n"
3292 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
3293 "r_editlights_cursorpushback : push back cursor this far from surface\n"
3294 "r_editlights_cursorpushoff : push cursor off surface this far\n"
3295 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
3296 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
3297 "r_editlights_rtlightssizescale : imported rtlight size scaling\n"
3298 "r_editlights_rtlightscolorscale : imported rtlight color scaling\n"
3300 "r_editlights_help : this help\n"
3301 "r_editlights_clear : remove all lights\n"
3302 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
3303 "r_editlights_save : save to .rtlights file\n"
3304 "r_editlights_spawn : create a light with default settings\n"
3305 "r_editlights_edit command : edit selected light - more documentation below\n"
3306 "r_editlights_remove : remove selected light\n"
3307 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
3308 "r_editlights_importlightentitiesfrommap : reload light entities\n"
3309 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
3311 "origin x y z : set light location\n"
3312 "originx x: set x component of light location\n"
3313 "originy y: set y component of light location\n"
3314 "originz z: set z component of light location\n"
3315 "move x y z : adjust light location\n"
3316 "movex x: adjust x component of light location\n"
3317 "movey y: adjust y component of light location\n"
3318 "movez z: adjust z component of light location\n"
3319 "angles x y z : set light angles\n"
3320 "anglesx x: set x component of light angles\n"
3321 "anglesy y: set y component of light angles\n"
3322 "anglesz z: set z component of light angles\n"
3323 "color r g b : set color of light (can be brighter than 1 1 1)\n"
3324 "radius radius : set radius (size) of light\n"
3325 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
3326 "cubemap basename : set filter cubemap of light (not yet supported)\n"
3327 "shadows 1/0 : turn on/off shadows\n"
3328 "corona n : set corona intensity\n"
3329 "<nothing> : print light properties to console\n"
3333 void R_Shadow_EditLights_Init(void)
3335 Cvar_RegisterVariable(&r_editlights);
3336 Cvar_RegisterVariable(&r_editlights_cursordistance);
3337 Cvar_RegisterVariable(&r_editlights_cursorpushback);
3338 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
3339 Cvar_RegisterVariable(&r_editlights_cursorgrid);
3340 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
3341 Cvar_RegisterVariable(&r_editlights_rtlightssizescale);
3342 Cvar_RegisterVariable(&r_editlights_rtlightscolorscale);
3343 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
3344 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
3345 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
3346 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
3347 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
3348 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
3349 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
3350 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
3351 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
3352 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
3353 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);