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 #define USETEXMATRIX 1
1243 #ifndef USETEXMATRIX
1244 // FIXME: this should be done in a texture matrix or vertex program when possible
1245 // FIXME: if vertex program not available, this would really benefit from 3DNow! or SSE
1246 static void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1250 tc3f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1251 tc3f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1252 tc3f[2] = vertex3f[0] * matrix->m[2][0] + vertex3f[1] * matrix->m[2][1] + vertex3f[2] * matrix->m[2][2] + matrix->m[2][3];
1259 static void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1263 tc2f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1264 tc2f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1272 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)
1276 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1278 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1279 // the cubemap normalizes this for us
1280 out3f[0] = DotProduct(svector3f, lightdir);
1281 out3f[1] = DotProduct(tvector3f, lightdir);
1282 out3f[2] = DotProduct(normal3f, lightdir);
1286 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)
1289 float lightdir[3], eyedir[3], halfdir[3];
1290 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1292 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1293 VectorNormalizeFast(lightdir);
1294 VectorSubtract(vertex3f, relativeeyeorigin, eyedir);
1295 VectorNormalizeFast(eyedir);
1296 VectorAdd(lightdir, eyedir, halfdir);
1297 // the cubemap normalizes this for us
1298 out3f[0] = DotProduct(svector3f, halfdir);
1299 out3f[1] = DotProduct(tvector3f, halfdir);
1300 out3f[2] = DotProduct(normal3f, halfdir);
1304 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)
1307 float color[3], color2[3], colorscale;
1310 bumptexture = r_shadow_blankbumptexture;
1312 glosstexture = r_shadow_blankglosstexture;
1313 GL_DepthMask(false);
1315 if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
1317 if (lighting & LIGHTING_DIFFUSE)
1320 colorscale = r_shadow_lightintensityscale.value;
1321 // colorscale accounts for how much we multiply the brightness
1324 // mult is how many times the final pass of the lighting will be
1325 // performed to get more brightness than otherwise possible.
1327 // Limit mult to 64 for sanity sake.
1328 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1330 // 3/2 3D combine path (Geforce3, Radeon 8500)
1331 memset(&m, 0, sizeof(m));
1332 m.pointer_vertex = vertex3f;
1333 m.tex[0] = R_GetTexture(bumptexture);
1334 m.texcombinergb[0] = GL_REPLACE;
1335 m.pointer_texcoord[0] = texcoord2f;
1336 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1337 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1338 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1339 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1340 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1342 m.pointer_texcoord3f[2] = vertex3f;
1343 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
1345 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1346 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1349 GL_ColorMask(0,0,0,1);
1350 GL_BlendFunc(GL_ONE, GL_ZERO);
1351 GL_LockArrays(0, numverts);
1352 R_Mesh_Draw(numverts, numtriangles, elements);
1353 GL_LockArrays(0, 0);
1355 c_rt_lighttris += numtriangles;
1357 memset(&m, 0, sizeof(m));
1358 m.pointer_vertex = vertex3f;
1359 m.tex[0] = R_GetTexture(basetexture);
1360 m.pointer_texcoord[0] = texcoord2f;
1363 m.texcubemap[1] = R_GetTexture(lightcubemap);
1365 m.pointer_texcoord3f[1] = vertex3f;
1366 m.texmatrix[1] = *matrix_modeltolight;
1368 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1369 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1373 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap)
1375 // 1/2/2 3D combine path (original Radeon)
1376 memset(&m, 0, sizeof(m));
1377 m.pointer_vertex = vertex3f;
1378 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1380 m.pointer_texcoord3f[0] = vertex3f;
1381 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1383 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1384 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1387 GL_ColorMask(0,0,0,1);
1388 GL_BlendFunc(GL_ONE, GL_ZERO);
1389 GL_LockArrays(0, numverts);
1390 R_Mesh_Draw(numverts, numtriangles, elements);
1391 GL_LockArrays(0, 0);
1393 c_rt_lighttris += numtriangles;
1395 memset(&m, 0, sizeof(m));
1396 m.pointer_vertex = vertex3f;
1397 m.tex[0] = R_GetTexture(bumptexture);
1398 m.texcombinergb[0] = GL_REPLACE;
1399 m.pointer_texcoord[0] = texcoord2f;
1400 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1401 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1402 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1403 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1405 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1406 GL_LockArrays(0, numverts);
1407 R_Mesh_Draw(numverts, numtriangles, elements);
1408 GL_LockArrays(0, 0);
1410 c_rt_lighttris += numtriangles;
1412 memset(&m, 0, sizeof(m));
1413 m.pointer_vertex = vertex3f;
1414 m.tex[0] = R_GetTexture(basetexture);
1415 m.pointer_texcoord[0] = texcoord2f;
1418 m.texcubemap[1] = R_GetTexture(lightcubemap);
1420 m.pointer_texcoord3f[1] = vertex3f;
1421 m.texmatrix[1] = *matrix_modeltolight;
1423 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1424 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1428 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap)
1430 // 2/2 3D combine path (original Radeon)
1431 memset(&m, 0, sizeof(m));
1432 m.pointer_vertex = vertex3f;
1433 m.tex[0] = R_GetTexture(bumptexture);
1434 m.texcombinergb[0] = GL_REPLACE;
1435 m.pointer_texcoord[0] = texcoord2f;
1436 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1437 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1438 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1439 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1441 GL_ColorMask(0,0,0,1);
1442 GL_BlendFunc(GL_ONE, GL_ZERO);
1443 GL_LockArrays(0, numverts);
1444 R_Mesh_Draw(numverts, numtriangles, elements);
1445 GL_LockArrays(0, 0);
1447 c_rt_lighttris += numtriangles;
1449 memset(&m, 0, sizeof(m));
1450 m.pointer_vertex = vertex3f;
1451 m.tex[0] = R_GetTexture(basetexture);
1452 m.pointer_texcoord[0] = texcoord2f;
1453 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1455 m.pointer_texcoord3f[1] = vertex3f;
1456 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1458 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1459 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1462 else if (r_textureunits.integer >= 4)
1464 // 4/2 2D combine path (Geforce3, Radeon 8500)
1465 memset(&m, 0, sizeof(m));
1466 m.pointer_vertex = vertex3f;
1467 m.tex[0] = R_GetTexture(bumptexture);
1468 m.texcombinergb[0] = GL_REPLACE;
1469 m.pointer_texcoord[0] = texcoord2f;
1470 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1471 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1472 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1473 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1474 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1476 m.pointer_texcoord3f[2] = vertex3f;
1477 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
1479 m.pointer_texcoord[2] = varray_texcoord2f[2];
1480 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1482 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1484 m.pointer_texcoord3f[3] = vertex3f;
1485 m.texmatrix[3] = *matrix_modeltoattenuationz;
1487 m.pointer_texcoord[3] = varray_texcoord2f[3];
1488 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[3], numverts, vertex3f, matrix_modeltoattenuationz);
1491 GL_ColorMask(0,0,0,1);
1492 GL_BlendFunc(GL_ONE, GL_ZERO);
1493 GL_LockArrays(0, numverts);
1494 R_Mesh_Draw(numverts, numtriangles, elements);
1495 GL_LockArrays(0, 0);
1497 c_rt_lighttris += numtriangles;
1499 memset(&m, 0, sizeof(m));
1500 m.pointer_vertex = vertex3f;
1501 m.tex[0] = R_GetTexture(basetexture);
1502 m.pointer_texcoord[0] = texcoord2f;
1505 m.texcubemap[1] = R_GetTexture(lightcubemap);
1507 m.pointer_texcoord3f[1] = vertex3f;
1508 m.texmatrix[1] = *matrix_modeltolight;
1510 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1511 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1517 // 2/2/2 2D combine path (any dot3 card)
1518 memset(&m, 0, sizeof(m));
1519 m.pointer_vertex = vertex3f;
1520 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1522 m.pointer_texcoord3f[0] = vertex3f;
1523 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1525 m.pointer_texcoord[0] = varray_texcoord2f[0];
1526 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1528 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1530 m.pointer_texcoord3f[1] = vertex3f;
1531 m.texmatrix[1] = *matrix_modeltoattenuationz;
1533 m.pointer_texcoord[1] = varray_texcoord2f[1];
1534 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1537 GL_ColorMask(0,0,0,1);
1538 GL_BlendFunc(GL_ONE, GL_ZERO);
1539 GL_LockArrays(0, numverts);
1540 R_Mesh_Draw(numverts, numtriangles, elements);
1541 GL_LockArrays(0, 0);
1543 c_rt_lighttris += numtriangles;
1545 memset(&m, 0, sizeof(m));
1546 m.pointer_vertex = vertex3f;
1547 m.tex[0] = R_GetTexture(bumptexture);
1548 m.texcombinergb[0] = GL_REPLACE;
1549 m.pointer_texcoord[0] = texcoord2f;
1550 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1551 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1552 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1553 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1555 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1556 GL_LockArrays(0, numverts);
1557 R_Mesh_Draw(numverts, numtriangles, elements);
1558 GL_LockArrays(0, 0);
1560 c_rt_lighttris += numtriangles;
1562 memset(&m, 0, sizeof(m));
1563 m.pointer_vertex = vertex3f;
1564 m.tex[0] = R_GetTexture(basetexture);
1565 m.pointer_texcoord[0] = texcoord2f;
1568 m.texcubemap[1] = R_GetTexture(lightcubemap);
1570 m.pointer_texcoord3f[1] = vertex3f;
1571 m.texmatrix[1] = *matrix_modeltolight;
1573 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1574 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1578 // this final code is shared
1580 GL_ColorMask(1,1,1,0);
1581 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1582 VectorScale(lightcolor, colorscale, color2);
1583 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1585 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1586 GL_LockArrays(0, numverts);
1587 R_Mesh_Draw(numverts, numtriangles, elements);
1588 GL_LockArrays(0, 0);
1590 c_rt_lighttris += numtriangles;
1593 if ((lighting & LIGHTING_SPECULAR) && (r_shadow_gloss.integer >= 2 || (r_shadow_gloss.integer >= 1 && glosstexture != r_shadow_blankglosstexture)))
1595 // FIXME: detect blendsquare!
1596 //if (gl_support_blendsquare)
1598 colorscale = r_shadow_lightintensityscale.value * r_shadow_glossintensity.value;
1599 if (glosstexture == r_shadow_blankglosstexture)
1600 colorscale *= r_shadow_gloss2intensity.value;
1602 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1604 // 2/0/0/1/2 3D combine blendsquare path
1605 memset(&m, 0, sizeof(m));
1606 m.pointer_vertex = vertex3f;
1607 m.tex[0] = R_GetTexture(bumptexture);
1608 m.pointer_texcoord[0] = texcoord2f;
1609 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1610 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1611 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1612 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1614 GL_ColorMask(0,0,0,1);
1615 // this squares the result
1616 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1617 GL_LockArrays(0, numverts);
1618 R_Mesh_Draw(numverts, numtriangles, elements);
1619 GL_LockArrays(0, 0);
1621 c_rt_lighttris += numtriangles;
1623 memset(&m, 0, sizeof(m));
1624 m.pointer_vertex = vertex3f;
1626 GL_LockArrays(0, numverts);
1627 // square alpha in framebuffer a few times to make it shiny
1628 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1629 // these comments are a test run through this math for intensity 0.5
1630 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1631 // 0.25 * 0.25 = 0.0625 (this is another pass)
1632 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1633 R_Mesh_Draw(numverts, numtriangles, elements);
1635 c_rt_lighttris += numtriangles;
1636 R_Mesh_Draw(numverts, numtriangles, elements);
1638 c_rt_lighttris += numtriangles;
1639 GL_LockArrays(0, 0);
1641 memset(&m, 0, sizeof(m));
1642 m.pointer_vertex = vertex3f;
1643 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1645 m.pointer_texcoord3f[0] = vertex3f;
1646 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1648 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1649 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1652 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1653 GL_LockArrays(0, numverts);
1654 R_Mesh_Draw(numverts, numtriangles, elements);
1655 GL_LockArrays(0, 0);
1657 c_rt_lighttris += numtriangles;
1659 memset(&m, 0, sizeof(m));
1660 m.pointer_vertex = vertex3f;
1661 m.tex[0] = R_GetTexture(glosstexture);
1662 m.pointer_texcoord[0] = texcoord2f;
1665 m.texcubemap[1] = R_GetTexture(lightcubemap);
1667 m.pointer_texcoord3f[1] = vertex3f;
1668 m.texmatrix[1] = *matrix_modeltolight;
1670 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1671 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1675 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1677 // 2/0/0/2 3D combine blendsquare path
1678 memset(&m, 0, sizeof(m));
1679 m.pointer_vertex = vertex3f;
1680 m.tex[0] = R_GetTexture(bumptexture);
1681 m.pointer_texcoord[0] = texcoord2f;
1682 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1683 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1684 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1685 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1687 GL_ColorMask(0,0,0,1);
1688 // this squares the result
1689 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1690 GL_LockArrays(0, numverts);
1691 R_Mesh_Draw(numverts, numtriangles, elements);
1692 GL_LockArrays(0, 0);
1694 c_rt_lighttris += numtriangles;
1696 memset(&m, 0, sizeof(m));
1697 m.pointer_vertex = vertex3f;
1699 GL_LockArrays(0, numverts);
1700 // square alpha in framebuffer a few times to make it shiny
1701 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1702 // these comments are a test run through this math for intensity 0.5
1703 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1704 // 0.25 * 0.25 = 0.0625 (this is another pass)
1705 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1706 R_Mesh_Draw(numverts, numtriangles, elements);
1708 c_rt_lighttris += numtriangles;
1709 R_Mesh_Draw(numverts, numtriangles, elements);
1711 c_rt_lighttris += numtriangles;
1712 GL_LockArrays(0, 0);
1714 memset(&m, 0, sizeof(m));
1715 m.pointer_vertex = vertex3f;
1716 m.tex[0] = R_GetTexture(glosstexture);
1717 m.pointer_texcoord[0] = texcoord2f;
1718 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1720 m.pointer_texcoord3f[1] = vertex3f;
1721 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1723 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1724 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1729 // 2/0/0/2/2 2D combine blendsquare path
1730 memset(&m, 0, sizeof(m));
1731 m.pointer_vertex = vertex3f;
1732 m.tex[0] = R_GetTexture(bumptexture);
1733 m.pointer_texcoord[0] = texcoord2f;
1734 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1735 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1736 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1737 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1739 GL_ColorMask(0,0,0,1);
1740 // this squares the result
1741 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1742 GL_LockArrays(0, numverts);
1743 R_Mesh_Draw(numverts, numtriangles, elements);
1744 GL_LockArrays(0, 0);
1746 c_rt_lighttris += numtriangles;
1748 memset(&m, 0, sizeof(m));
1749 m.pointer_vertex = vertex3f;
1751 GL_LockArrays(0, numverts);
1752 // square alpha in framebuffer a few times to make it shiny
1753 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1754 // these comments are a test run through this math for intensity 0.5
1755 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1756 // 0.25 * 0.25 = 0.0625 (this is another pass)
1757 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1758 R_Mesh_Draw(numverts, numtriangles, elements);
1760 c_rt_lighttris += numtriangles;
1761 R_Mesh_Draw(numverts, numtriangles, elements);
1763 c_rt_lighttris += numtriangles;
1764 GL_LockArrays(0, 0);
1766 memset(&m, 0, sizeof(m));
1767 m.pointer_vertex = vertex3f;
1768 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1770 m.pointer_texcoord3f[0] = vertex3f;
1771 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1773 m.pointer_texcoord[0] = varray_texcoord2f[0];
1774 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1776 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1778 m.pointer_texcoord3f[1] = vertex3f;
1779 m.texmatrix[1] = *matrix_modeltoattenuationz;
1781 m.pointer_texcoord[1] = varray_texcoord2f[1];
1782 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1785 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1786 GL_LockArrays(0, numverts);
1787 R_Mesh_Draw(numverts, numtriangles, elements);
1788 GL_LockArrays(0, 0);
1790 c_rt_lighttris += numtriangles;
1792 memset(&m, 0, sizeof(m));
1793 m.pointer_vertex = vertex3f;
1794 m.tex[0] = R_GetTexture(glosstexture);
1795 m.pointer_texcoord[0] = texcoord2f;
1798 m.texcubemap[1] = R_GetTexture(lightcubemap);
1800 m.pointer_texcoord3f[1] = vertex3f;
1801 m.texmatrix[1] = *matrix_modeltolight;
1803 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1804 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1810 GL_ColorMask(1,1,1,0);
1811 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1812 VectorScale(lightcolor, colorscale, color2);
1813 GL_LockArrays(0, numverts);
1814 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1816 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1817 R_Mesh_Draw(numverts, numtriangles, elements);
1819 c_rt_lighttris += numtriangles;
1821 GL_LockArrays(0, 0);
1826 if (lighting & LIGHTING_DIFFUSE)
1828 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1829 VectorScale(lightcolor, r_shadow_lightintensityscale.value, color2);
1830 memset(&m, 0, sizeof(m));
1831 m.pointer_vertex = vertex3f;
1832 m.pointer_color = varray_color4f;
1833 m.tex[0] = R_GetTexture(basetexture);
1834 m.pointer_texcoord[0] = texcoord2f;
1835 if (r_textureunits.integer >= 2)
1838 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1840 m.pointer_texcoord3f[1] = vertex3f;
1841 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1843 m.pointer_texcoord[1] = varray_texcoord2f[1];
1844 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1846 if (r_textureunits.integer >= 3)
1848 // Geforce3/Radeon class but not using dot3
1849 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1851 m.pointer_texcoord3f[2] = vertex3f;
1852 m.texmatrix[2] = *matrix_modeltoattenuationz;
1854 m.pointer_texcoord[2] = varray_texcoord2f[2];
1855 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationz);
1860 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1862 color[0] = bound(0, color2[0], 1);
1863 color[1] = bound(0, color2[1], 1);
1864 color[2] = bound(0, color2[2], 1);
1865 if (r_textureunits.integer >= 3)
1866 R_Shadow_VertexShading(numverts, vertex3f, normal3f, color, matrix_modeltolight);
1867 else if (r_textureunits.integer >= 2)
1868 R_Shadow_VertexShadingWithZAttenuation(numverts, vertex3f, normal3f, color, matrix_modeltolight);
1870 R_Shadow_VertexShadingWithXYZAttenuation(numverts, vertex3f, normal3f, color, matrix_modeltolight);
1871 GL_LockArrays(0, numverts);
1872 R_Mesh_Draw(numverts, numtriangles, elements);
1873 GL_LockArrays(0, 0);
1875 c_rt_lighttris += numtriangles;
1881 void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
1885 R_RTLight_Uncompile(rtlight);
1886 memset(rtlight, 0, sizeof(*rtlight));
1888 VectorCopy(light->origin, rtlight->shadoworigin);
1889 VectorCopy(light->color, rtlight->color);
1890 rtlight->radius = light->radius;
1891 //rtlight->cullradius = rtlight->radius;
1892 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
1893 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
1894 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
1895 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
1896 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
1897 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
1898 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
1899 rtlight->cubemapname[0] = 0;
1900 if (light->cubemapname[0])
1901 strcpy(rtlight->cubemapname, light->cubemapname);
1902 else if (light->cubemapnum > 0)
1903 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
1904 rtlight->shadow = light->shadow;
1905 rtlight->corona = light->corona;
1906 rtlight->style = light->style;
1907 rtlight->isstatic = isstatic;
1908 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
1909 // ConcatScale won't work here because this needs to scale rotate and
1910 // translate, not just rotate
1911 scale = 1.0f / rtlight->radius;
1912 for (k = 0;k < 3;k++)
1913 for (j = 0;j < 4;j++)
1914 rtlight->matrix_worldtolight.m[k][j] *= scale;
1915 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationxyz, &matrix_attenuationxyz, &rtlight->matrix_worldtolight);
1916 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationz, &matrix_attenuationz, &rtlight->matrix_worldtolight);
1918 rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
1919 rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
1920 VectorScale(rtlight->color, rtlight->radius * d_lightstylevalue[rtlight->style] * 0.125f, rtlight->lightmap_light);
1921 rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
1924 // compiles rtlight geometry
1925 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
1926 void R_RTLight_Compile(rtlight_t *rtlight)
1928 int shadowmeshes, shadowtris, lightmeshes, lighttris, numclusters, numsurfaces;
1929 entity_render_t *ent = &cl_entities[0].render;
1930 model_t *model = ent->model;
1932 // compile the light
1933 rtlight->compiled = true;
1934 rtlight->static_numclusters = 0;
1935 rtlight->static_numclusterpvsbytes = 0;
1936 rtlight->static_clusterlist = NULL;
1937 rtlight->static_clusterpvs = NULL;
1938 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
1939 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
1940 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
1941 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
1942 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
1943 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
1945 if (model && model->GetLightInfo)
1947 // this variable directs the DrawShadowVolume and DrawLight code to capture into the mesh chain instead of rendering
1948 r_shadow_compilingrtlight = rtlight;
1949 R_Shadow_EnlargeClusterBuffer(model->brush.num_pvsclusters);
1950 R_Shadow_EnlargeSurfaceBuffer(model->nummodelsurfaces);
1951 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);
1954 rtlight->static_numclusters = numclusters;
1955 rtlight->static_numclusterpvsbytes = (model->brush.num_pvsclusters + 7) >> 3;
1956 rtlight->static_clusterlist = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
1957 rtlight->static_clusterpvs = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusterpvsbytes);
1958 memcpy(rtlight->static_clusterlist, r_shadow_buffer_clusterlist, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
1959 memcpy(rtlight->static_clusterpvs, r_shadow_buffer_clusterpvs, rtlight->static_numclusterpvsbytes);
1961 if (model->DrawShadowVolume && rtlight->shadow)
1963 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
1964 model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
1965 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_shadow, false, false);
1967 if (model->DrawLight)
1969 rtlight->static_meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true);
1970 model->DrawLight(ent, rtlight->shadoworigin, vec3_origin, rtlight->radius, vec3_origin, &r_identitymatrix, &r_identitymatrix, &r_identitymatrix, NULL, numsurfaces, r_shadow_buffer_surfacelist);
1971 rtlight->static_meshchain_light = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_light, true, false);
1973 // switch back to rendering when DrawShadowVolume or DrawLight is called
1974 r_shadow_compilingrtlight = NULL;
1978 // use smallest available cullradius - box radius or light radius
1979 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
1980 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
1984 if (rtlight->static_meshchain_shadow)
1987 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
1990 shadowtris += mesh->numtriangles;
1996 if (rtlight->static_meshchain_light)
1999 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2002 lighttris += mesh->numtriangles;
2006 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);
2009 void R_RTLight_Uncompile(rtlight_t *rtlight)
2011 if (rtlight->compiled)
2013 if (rtlight->static_meshchain_shadow)
2014 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2015 rtlight->static_meshchain_shadow = NULL;
2016 if (rtlight->static_meshchain_light)
2017 Mod_ShadowMesh_Free(rtlight->static_meshchain_light);
2018 rtlight->static_meshchain_light = NULL;
2019 if (rtlight->static_clusterlist)
2020 Mem_Free(rtlight->static_clusterlist);
2021 rtlight->static_clusterlist = NULL;
2022 if (rtlight->static_clusterpvs)
2023 Mem_Free(rtlight->static_clusterpvs);
2024 rtlight->static_clusterpvs = NULL;
2025 rtlight->static_numclusters = 0;
2026 rtlight->static_numclusterpvsbytes = 0;
2027 rtlight->compiled = false;
2031 void R_Shadow_UncompileWorldLights(void)
2034 for (light = r_shadow_worldlightchain;light;light = light->next)
2035 R_RTLight_Uncompile(&light->rtlight);
2038 void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes)
2041 entity_render_t *ent;
2043 vec3_t relativelightorigin, relativeeyeorigin, lightcolor;
2044 rtexture_t *cubemaptexture;
2045 matrix4x4_t matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz;
2046 int numclusters, numsurfaces;
2047 int *clusterlist, *surfacelist;
2049 vec3_t cullmins, cullmaxs;
2053 // loading is done before visibility checks because loading should happen
2054 // all at once at the start of a level, not when it stalls gameplay.
2055 // (especially important to benchmarks)
2056 if (rtlight->isstatic && !rtlight->compiled && r_shadow_staticworldlights.integer)
2057 R_RTLight_Compile(rtlight);
2058 if (rtlight->cubemapname[0])
2059 cubemaptexture = R_Shadow_Cubemap(rtlight->cubemapname);
2061 cubemaptexture = NULL;
2063 cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2064 cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2065 cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2066 cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2067 cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2068 cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2069 if (d_lightstylevalue[rtlight->style] <= 0)
2076 if (rtlight->compiled && r_shadow_staticworldlights.integer)
2078 // compiled light, world available and can receive realtime lighting
2079 // retrieve cluster information
2080 numclusters = rtlight->static_numclusters;
2081 clusterlist = rtlight->static_clusterlist;
2082 clusterpvs = rtlight->static_clusterpvs;
2083 VectorCopy(rtlight->cullmins, cullmins);
2084 VectorCopy(rtlight->cullmaxs, cullmaxs);
2086 else if (cl.worldmodel && cl.worldmodel->GetLightInfo)
2088 // dynamic light, world available and can receive realtime lighting
2089 // if the light box is offscreen, skip it right away
2090 if (R_CullBox(cullmins, cullmaxs))
2092 // calculate lit surfaces and clusters
2093 R_Shadow_EnlargeClusterBuffer(cl.worldmodel->brush.num_pvsclusters);
2094 R_Shadow_EnlargeSurfaceBuffer(cl.worldmodel->nummodelsurfaces);
2095 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);
2096 clusterlist = r_shadow_buffer_clusterlist;
2097 clusterpvs = r_shadow_buffer_clusterpvs;
2098 surfacelist = r_shadow_buffer_surfacelist;
2100 // if the reduced cluster bounds are offscreen, skip it
2101 if (R_CullBox(cullmins, cullmaxs))
2103 // check if light is illuminating any visible clusters
2106 for (i = 0;i < numclusters;i++)
2107 if (CHECKPVSBIT(r_pvsbits, clusterlist[i]))
2109 if (i == numclusters)
2112 // set up a scissor rectangle for this light
2113 if (R_Shadow_ScissorForBBox(cullmins, cullmaxs))
2116 f = d_lightstylevalue[rtlight->style] * (1.0f / 256.0f);
2117 VectorScale(rtlight->color, f, lightcolor);
2119 if (rtlight->selected)
2121 f = 2 + sin(realtime * M_PI * 4.0);
2122 VectorScale(lightcolor, f, lightcolor);
2127 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));
2130 if (rtlight->shadow)
2132 if (rtlight->isstatic)
2133 shadow = r_shadow_realtime_world_shadows.integer;
2136 if (r_shadow_realtime_world.integer)
2137 shadow = r_shadow_realtime_world_dlightshadows.integer;
2139 shadow = r_shadow_realtime_dlight_shadows.integer;
2144 if (shadow && (gl_stencil || visiblevolumes))
2146 if (!visiblevolumes)
2147 R_Shadow_Stage_ShadowVolumes();
2148 ent = &cl_entities[0].render;
2149 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2151 memset(&m, 0, sizeof(m));
2152 R_Mesh_Matrix(&ent->matrix);
2153 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2155 m.pointer_vertex = mesh->vertex3f;
2157 GL_LockArrays(0, mesh->numverts);
2158 if (r_shadowstage == SHADOWSTAGE_STENCIL)
2160 // decrement stencil if frontface is behind depthbuffer
2161 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2162 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2163 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2164 c_rtcached_shadowmeshes++;
2165 c_rtcached_shadowtris += mesh->numtriangles;
2166 // increment stencil if backface is behind depthbuffer
2167 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2168 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2170 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2171 c_rtcached_shadowmeshes++;
2172 c_rtcached_shadowtris += mesh->numtriangles;
2173 GL_LockArrays(0, 0);
2178 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2179 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, numsurfaces, surfacelist);
2181 if (r_drawentities.integer)
2183 for (i = 0;i < r_refdef.numentities;i++)
2185 ent = r_refdef.entities[i];
2187 if (r_shadow_cull.integer)
2189 if (!BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs))
2191 if (cl.worldmodel != NULL && cl.worldmodel->brush.BoxTouchingPVS != NULL && !cl.worldmodel->brush.BoxTouchingPVS(cl.worldmodel, clusterpvs, ent->mins, ent->maxs))
2194 if (!(ent->flags & RENDER_SHADOW) || !ent->model || !ent->model->DrawShadowVolume)
2196 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2197 // light emitting entities should not cast their own shadow
2198 if (VectorLength2(relativelightorigin) < 0.1)
2200 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, ent->model->nummodelsurfaces, ent->model->surfacelist);
2205 if (!visiblevolumes)
2207 if (shadow && gl_stencil)
2208 R_Shadow_Stage_LightWithShadows();
2210 R_Shadow_Stage_LightWithoutShadows();
2212 ent = &cl_entities[0].render;
2213 if (ent->model && ent->model->DrawLight)
2215 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2216 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2217 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2218 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2219 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2220 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2222 R_Mesh_Matrix(&ent->matrix);
2223 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2224 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);
2227 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, numsurfaces, surfacelist);
2229 if (r_drawentities.integer)
2231 for (i = 0;i < r_refdef.numentities;i++)
2233 ent = r_refdef.entities[i];
2234 if (ent->visframe == r_framecount && BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs) && ent->model && ent->model->DrawLight && (ent->flags & RENDER_LIGHT))
2236 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2237 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2238 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2239 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2240 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2241 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, ent->model->nummodelsurfaces, ent->model->surfacelist);
2248 void R_ShadowVolumeLighting(int visiblevolumes)
2254 if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2255 R_Shadow_EditLights_Reload_f();
2259 memset(&m, 0, sizeof(m));
2262 GL_BlendFunc(GL_ONE, GL_ONE);
2263 GL_DepthMask(false);
2264 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
2265 qglDisable(GL_CULL_FACE);
2266 GL_Color(0.0, 0.0125, 0.1, 1);
2269 R_Shadow_Stage_Begin();
2270 if (r_shadow_realtime_world.integer)
2272 if (r_shadow_debuglight.integer >= 0)
2274 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2275 if (lnum == r_shadow_debuglight.integer)
2276 R_DrawRTLight(&light->rtlight, visiblevolumes);
2279 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2280 R_DrawRTLight(&light->rtlight, visiblevolumes);
2282 if (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer)
2283 for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
2284 R_DrawRTLight(&light->rtlight, visiblevolumes);
2288 qglEnable(GL_CULL_FACE);
2289 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
2292 R_Shadow_Stage_End();
2295 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2296 typedef struct suffixinfo_s
2299 qboolean flipx, flipy, flipdiagonal;
2302 static suffixinfo_t suffix[3][6] =
2305 {"px", false, false, false},
2306 {"nx", false, false, false},
2307 {"py", false, false, false},
2308 {"ny", false, false, false},
2309 {"pz", false, false, false},
2310 {"nz", false, false, false}
2313 {"posx", false, false, false},
2314 {"negx", false, false, false},
2315 {"posy", false, false, false},
2316 {"negy", false, false, false},
2317 {"posz", false, false, false},
2318 {"negz", false, false, false}
2321 {"rt", true, false, true},
2322 {"lf", false, true, true},
2323 {"ft", true, true, false},
2324 {"bk", false, false, false},
2325 {"up", true, false, true},
2326 {"dn", true, false, true}
2330 static int componentorder[4] = {0, 1, 2, 3};
2332 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2334 int i, j, cubemapsize;
2335 qbyte *cubemappixels, *image_rgba;
2336 rtexture_t *cubemaptexture;
2338 // must start 0 so the first loadimagepixels has no requested width/height
2340 cubemappixels = NULL;
2341 cubemaptexture = NULL;
2342 // keep trying different suffix groups (posx, px, rt) until one loads
2343 for (j = 0;j < 3 && !cubemappixels;j++)
2345 // load the 6 images in the suffix group
2346 for (i = 0;i < 6;i++)
2348 // generate an image name based on the base and and suffix
2349 snprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2351 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2353 // an image loaded, make sure width and height are equal
2354 if (image_width == image_height)
2356 // if this is the first image to load successfully, allocate the cubemap memory
2357 if (!cubemappixels && image_width >= 1)
2359 cubemapsize = image_width;
2360 // note this clears to black, so unavailable sides are black
2361 cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2363 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2365 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);
2368 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2370 Mem_Free(image_rgba);
2374 // if a cubemap loaded, upload it
2377 if (!r_shadow_filters_texturepool)
2378 r_shadow_filters_texturepool = R_AllocTexturePool();
2379 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
2380 Mem_Free(cubemappixels);
2384 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
2385 for (j = 0;j < 3;j++)
2386 for (i = 0;i < 6;i++)
2387 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2388 Con_Print(" and was unable to find any of them.\n");
2390 return cubemaptexture;
2393 rtexture_t *R_Shadow_Cubemap(const char *basename)
2396 for (i = 0;i < numcubemaps;i++)
2397 if (!strcasecmp(cubemaps[i].basename, basename))
2398 return cubemaps[i].texture;
2399 if (i >= MAX_CUBEMAPS)
2402 strcpy(cubemaps[i].basename, basename);
2403 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
2404 return cubemaps[i].texture;
2407 void R_Shadow_FreeCubemaps(void)
2410 R_FreeTexturePool(&r_shadow_filters_texturepool);
2413 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)
2417 if (radius < 15 || DotProduct(color, color) < 0.03)
2419 Con_Print("R_Shadow_NewWorldLight: refusing to create a light too small/dim\n");
2423 light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
2424 VectorCopy(origin, light->origin);
2425 VectorCopy(angles, light->angles);
2426 VectorCopy(color, light->color);
2427 light->radius = radius;
2428 light->style = style;
2429 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
2431 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
2434 light->shadow = shadowenable;
2435 light->corona = corona;
2436 if (cubemapname && cubemapname[0] && strlen(cubemapname) < sizeof(light->cubemapname))
2437 strcpy(light->cubemapname, cubemapname);
2438 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
2439 light->next = r_shadow_worldlightchain;
2440 r_shadow_worldlightchain = light;
2442 R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
2445 void R_Shadow_FreeWorldLight(dlight_t *light)
2447 dlight_t **lightpointer;
2448 R_RTLight_Uncompile(&light->rtlight);
2449 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
2450 if (*lightpointer != light)
2451 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
2452 *lightpointer = light->next;
2456 void R_Shadow_ClearWorldLights(void)
2458 while (r_shadow_worldlightchain)
2459 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
2460 r_shadow_selectedlight = NULL;
2461 R_Shadow_FreeCubemaps();
2464 void R_Shadow_SelectLight(dlight_t *light)
2466 if (r_shadow_selectedlight)
2467 r_shadow_selectedlight->selected = false;
2468 r_shadow_selectedlight = light;
2469 if (r_shadow_selectedlight)
2470 r_shadow_selectedlight->selected = true;
2473 void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
2475 float scale = r_editlights_cursorgrid.value * 0.5f;
2476 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);
2479 void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
2482 const dlight_t *light;
2485 if (light->selected)
2486 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
2489 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);
2492 void R_Shadow_DrawLightSprites(void)
2498 for (i = 0;i < 5;i++)
2500 lighttextures[i] = NULL;
2501 if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1))))
2502 lighttextures[i] = pic->tex;
2505 for (light = r_shadow_worldlightchain;light;light = light->next)
2506 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, ((int) light) % 5);
2507 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
2510 void R_Shadow_SelectLightInView(void)
2512 float bestrating, rating, temp[3];
2513 dlight_t *best, *light;
2516 for (light = r_shadow_worldlightchain;light;light = light->next)
2518 VectorSubtract(light->origin, r_vieworigin, temp);
2519 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
2522 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
2523 if (bestrating < rating && CL_TraceLine(light->origin, r_vieworigin, NULL, NULL, true, NULL, SUPERCONTENTS_SOLID) == 1.0f)
2525 bestrating = rating;
2530 R_Shadow_SelectLight(best);
2533 void R_Shadow_LoadWorldLights(void)
2535 int n, a, style, shadow;
2536 char name[MAX_QPATH], cubemapname[MAX_QPATH], *lightsstring, *s, *t;
2537 float origin[3], radius, color[3], angles[3], corona;
2538 if (cl.worldmodel == NULL)
2540 Con_Print("No map loaded.\n");
2543 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2544 strlcat (name, ".rtlights", sizeof (name));
2545 lightsstring = FS_LoadFile(name, tempmempool, false);
2555 for (;COM_Parse(t, true) && strcmp(
2556 if (COM_Parse(t, true))
2558 if (com_token[0] == '!')
2561 origin[0] = atof(com_token+1);
2564 origin[0] = atof(com_token);
2569 while (*s && *s != '\n')
2575 // check for modifier flags
2581 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]);
2583 VectorClear(angles);
2586 if (a < 9 || !strcmp(cubemapname, "\"\""))
2591 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);
2594 VectorScale(color, r_editlights_rtlightscolorscale.value, color);
2595 radius *= r_editlights_rtlightssizescale.value;
2596 R_Shadow_NewWorldLight(origin, angles, color, radius, corona, style, shadow, cubemapname);
2601 Con_Printf("invalid rtlights file \"%s\"\n", name);
2602 Mem_Free(lightsstring);
2606 void R_Shadow_SaveWorldLights(void)
2609 int bufchars, bufmaxchars;
2611 char name[MAX_QPATH];
2613 if (!r_shadow_worldlightchain)
2615 if (cl.worldmodel == NULL)
2617 Con_Print("No map loaded.\n");
2620 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2621 strlcat (name, ".rtlights", sizeof (name));
2622 bufchars = bufmaxchars = 0;
2624 for (light = r_shadow_worldlightchain;light;light = light->next)
2626 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]);
2627 if (bufchars + (int) strlen(line) > bufmaxchars)
2629 bufmaxchars = bufchars + strlen(line) + 2048;
2631 buf = Mem_Alloc(r_shadow_mempool, bufmaxchars);
2635 memcpy(buf, oldbuf, bufchars);
2641 memcpy(buf + bufchars, line, strlen(line));
2642 bufchars += strlen(line);
2646 FS_WriteFile(name, buf, bufchars);
2651 void R_Shadow_LoadLightsFile(void)
2654 char name[MAX_QPATH], *lightsstring, *s, *t;
2655 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
2656 if (cl.worldmodel == NULL)
2658 Con_Print("No map loaded.\n");
2661 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2662 strlcat (name, ".lights", sizeof (name));
2663 lightsstring = FS_LoadFile(name, tempmempool, false);
2671 while (*s && *s != '\n')
2676 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);
2680 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);
2683 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
2684 radius = bound(15, radius, 4096);
2685 VectorScale(color, (2.0f / (8388608.0f)), color);
2686 R_Shadow_NewWorldLight(origin, vec3_origin, color, radius, 0, style, true, NULL);
2691 Con_Printf("invalid lights file \"%s\"\n", name);
2692 Mem_Free(lightsstring);
2696 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
2698 int entnum, style, islight, skin, pflags, effects;
2699 char key[256], value[1024];
2700 float origin[3], angles[3], radius, color[3], light, fadescale, lightscale, originhack[3], overridecolor[3];
2703 if (cl.worldmodel == NULL)
2705 Con_Print("No map loaded.\n");
2708 data = cl.worldmodel->brush.entities;
2711 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
2714 origin[0] = origin[1] = origin[2] = 0;
2715 originhack[0] = originhack[1] = originhack[2] = 0;
2716 angles[0] = angles[1] = angles[2] = 0;
2717 color[0] = color[1] = color[2] = 1;
2718 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
2728 if (!COM_ParseToken(&data, false))
2730 if (com_token[0] == '}')
2731 break; // end of entity
2732 if (com_token[0] == '_')
2733 strcpy(key, com_token + 1);
2735 strcpy(key, com_token);
2736 while (key[strlen(key)-1] == ' ') // remove trailing spaces
2737 key[strlen(key)-1] = 0;
2738 if (!COM_ParseToken(&data, false))
2740 strcpy(value, com_token);
2742 // now that we have the key pair worked out...
2743 if (!strcmp("light", key))
2744 light = atof(value);
2745 else if (!strcmp("origin", key))
2746 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
2747 else if (!strcmp("angle", key))
2748 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
2749 else if (!strcmp("angles", key))
2750 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
2751 else if (!strcmp("color", key))
2752 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
2753 else if (!strcmp("wait", key))
2754 fadescale = atof(value);
2755 else if (!strcmp("classname", key))
2757 if (!strncmp(value, "light", 5))
2760 if (!strcmp(value, "light_fluoro"))
2765 overridecolor[0] = 1;
2766 overridecolor[1] = 1;
2767 overridecolor[2] = 1;
2769 if (!strcmp(value, "light_fluorospark"))
2774 overridecolor[0] = 1;
2775 overridecolor[1] = 1;
2776 overridecolor[2] = 1;
2778 if (!strcmp(value, "light_globe"))
2783 overridecolor[0] = 1;
2784 overridecolor[1] = 0.8;
2785 overridecolor[2] = 0.4;
2787 if (!strcmp(value, "light_flame_large_yellow"))
2792 overridecolor[0] = 1;
2793 overridecolor[1] = 0.5;
2794 overridecolor[2] = 0.1;
2796 if (!strcmp(value, "light_flame_small_yellow"))
2801 overridecolor[0] = 1;
2802 overridecolor[1] = 0.5;
2803 overridecolor[2] = 0.1;
2805 if (!strcmp(value, "light_torch_small_white"))
2810 overridecolor[0] = 1;
2811 overridecolor[1] = 0.5;
2812 overridecolor[2] = 0.1;
2814 if (!strcmp(value, "light_torch_small_walltorch"))
2819 overridecolor[0] = 1;
2820 overridecolor[1] = 0.5;
2821 overridecolor[2] = 0.1;
2825 else if (!strcmp("style", key))
2826 style = atoi(value);
2827 else if (cl.worldmodel->type == mod_brushq3)
2829 if (!strcmp("scale", key))
2830 lightscale = atof(value);
2831 if (!strcmp("fade", key))
2832 fadescale = atof(value);
2834 else if (!strcmp("skin", key))
2835 skin = (int)atof(value);
2836 else if (!strcmp("pflags", key))
2837 pflags = (int)atof(value);
2838 else if (!strcmp("effects", key))
2839 effects = (int)atof(value);
2841 if (light <= 0 && islight)
2843 if (lightscale <= 0)
2847 if (gamemode == GAME_TENEBRAE)
2849 if (effects & EF_NODRAW)
2851 pflags |= PFLAGS_FULLDYNAMIC;
2852 effects &= ~EF_NODRAW;
2855 radius = min(light * r_editlights_quakelightsizescale.value * lightscale / fadescale, 1048576);
2856 light = sqrt(bound(0, light, 1048576)) * (1.0f / 16.0f);
2857 if (color[0] == 1 && color[1] == 1 && color[2] == 1)
2858 VectorCopy(overridecolor, color);
2859 VectorScale(color, light, color);
2860 VectorAdd(origin, originhack, origin);
2861 if (radius >= 15 && !(pflags & PFLAGS_FULLDYNAMIC))
2862 R_Shadow_NewWorldLight(origin, angles, color, radius, (pflags & PFLAGS_CORONA) != 0, style, (pflags & PFLAGS_NOSHADOW) == 0, skin >= 16 ? va("cubemaps/%i", skin) : NULL);
2867 void R_Shadow_SetCursorLocationForView(void)
2869 vec_t dist, push, frac;
2870 vec3_t dest, endpos, normal;
2871 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
2872 frac = CL_TraceLine(r_vieworigin, dest, endpos, normal, true, NULL, SUPERCONTENTS_SOLID);
2875 dist = frac * r_editlights_cursordistance.value;
2876 push = r_editlights_cursorpushback.value;
2880 VectorMA(endpos, push, r_viewforward, endpos);
2881 VectorMA(endpos, r_editlights_cursorpushoff.value, normal, endpos);
2883 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2884 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2885 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2888 void R_Shadow_UpdateWorldLightSelection(void)
2890 if (r_editlights.integer)
2892 R_Shadow_SetCursorLocationForView();
2893 R_Shadow_SelectLightInView();
2894 R_Shadow_DrawLightSprites();
2897 R_Shadow_SelectLight(NULL);
2900 void R_Shadow_EditLights_Clear_f(void)
2902 R_Shadow_ClearWorldLights();
2905 void R_Shadow_EditLights_Reload_f(void)
2909 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
2910 R_Shadow_ClearWorldLights();
2911 R_Shadow_LoadWorldLights();
2912 if (r_shadow_worldlightchain == NULL)
2914 R_Shadow_LoadLightsFile();
2915 if (r_shadow_worldlightchain == NULL)
2916 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
2920 void R_Shadow_EditLights_Save_f(void)
2924 R_Shadow_SaveWorldLights();
2927 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
2929 R_Shadow_ClearWorldLights();
2930 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
2933 void R_Shadow_EditLights_ImportLightsFile_f(void)
2935 R_Shadow_ClearWorldLights();
2936 R_Shadow_LoadLightsFile();
2939 void R_Shadow_EditLights_Spawn_f(void)
2942 if (!r_editlights.integer)
2944 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
2947 if (Cmd_Argc() != 1)
2949 Con_Print("r_editlights_spawn does not take parameters\n");
2952 color[0] = color[1] = color[2] = 1;
2953 R_Shadow_NewWorldLight(r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL);
2956 void R_Shadow_EditLights_Edit_f(void)
2958 vec3_t origin, angles, color;
2959 vec_t radius, corona;
2961 char cubemapname[1024];
2962 if (!r_editlights.integer)
2964 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
2967 if (!r_shadow_selectedlight)
2969 Con_Print("No selected light.\n");
2972 VectorCopy(r_shadow_selectedlight->origin, origin);
2973 VectorCopy(r_shadow_selectedlight->angles, angles);
2974 VectorCopy(r_shadow_selectedlight->color, color);
2975 radius = r_shadow_selectedlight->radius;
2976 style = r_shadow_selectedlight->style;
2977 if (r_shadow_selectedlight->cubemapname)
2978 strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
2981 shadows = r_shadow_selectedlight->shadow;
2982 corona = r_shadow_selectedlight->corona;
2983 if (!strcmp(Cmd_Argv(1), "origin"))
2985 if (Cmd_Argc() != 5)
2987 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
2990 origin[0] = atof(Cmd_Argv(2));
2991 origin[1] = atof(Cmd_Argv(3));
2992 origin[2] = atof(Cmd_Argv(4));
2994 else if (!strcmp(Cmd_Argv(1), "originx"))
2996 if (Cmd_Argc() != 3)
2998 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3001 origin[0] = atof(Cmd_Argv(2));
3003 else if (!strcmp(Cmd_Argv(1), "originy"))
3005 if (Cmd_Argc() != 3)
3007 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3010 origin[1] = atof(Cmd_Argv(2));
3012 else if (!strcmp(Cmd_Argv(1), "originz"))
3014 if (Cmd_Argc() != 3)
3016 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3019 origin[2] = atof(Cmd_Argv(2));
3021 else if (!strcmp(Cmd_Argv(1), "move"))
3023 if (Cmd_Argc() != 5)
3025 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3028 origin[0] += atof(Cmd_Argv(2));
3029 origin[1] += atof(Cmd_Argv(3));
3030 origin[2] += atof(Cmd_Argv(4));
3032 else if (!strcmp(Cmd_Argv(1), "movex"))
3034 if (Cmd_Argc() != 3)
3036 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3039 origin[0] += atof(Cmd_Argv(2));
3041 else if (!strcmp(Cmd_Argv(1), "movey"))
3043 if (Cmd_Argc() != 3)
3045 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3048 origin[1] += atof(Cmd_Argv(2));
3050 else if (!strcmp(Cmd_Argv(1), "movez"))
3052 if (Cmd_Argc() != 3)
3054 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3057 origin[2] += atof(Cmd_Argv(2));
3059 else if (!strcmp(Cmd_Argv(1), "angles"))
3061 if (Cmd_Argc() != 5)
3063 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3066 angles[0] = atof(Cmd_Argv(2));
3067 angles[1] = atof(Cmd_Argv(3));
3068 angles[2] = atof(Cmd_Argv(4));
3070 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3072 if (Cmd_Argc() != 3)
3074 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3077 angles[0] = atof(Cmd_Argv(2));
3079 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3081 if (Cmd_Argc() != 3)
3083 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3086 angles[1] = atof(Cmd_Argv(2));
3088 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3090 if (Cmd_Argc() != 3)
3092 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3095 angles[2] = atof(Cmd_Argv(2));
3097 else if (!strcmp(Cmd_Argv(1), "color"))
3099 if (Cmd_Argc() != 5)
3101 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3104 color[0] = atof(Cmd_Argv(2));
3105 color[1] = atof(Cmd_Argv(3));
3106 color[2] = atof(Cmd_Argv(4));
3108 else if (!strcmp(Cmd_Argv(1), "radius"))
3110 if (Cmd_Argc() != 3)
3112 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3115 radius = atof(Cmd_Argv(2));
3117 else if (!strcmp(Cmd_Argv(1), "style"))
3119 if (Cmd_Argc() != 3)
3121 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3124 style = atoi(Cmd_Argv(2));
3126 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3130 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3133 if (Cmd_Argc() == 3)
3134 strcpy(cubemapname, Cmd_Argv(2));
3138 else if (!strcmp(Cmd_Argv(1), "shadows"))
3140 if (Cmd_Argc() != 3)
3142 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3145 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3147 else if (!strcmp(Cmd_Argv(1), "corona"))
3149 if (Cmd_Argc() != 3)
3151 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3154 corona = atof(Cmd_Argv(2));
3158 Con_Print("usage: r_editlights_edit [property] [value]\n");
3159 Con_Print("Selected light's properties:\n");
3160 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3161 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3162 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3163 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3164 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3165 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3166 Con_Printf("Shadows: %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3167 Con_Printf("Cubemap: %s\n", r_shadow_selectedlight->cubemapname);
3170 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3171 r_shadow_selectedlight = NULL;
3172 R_Shadow_NewWorldLight(origin, angles, color, radius, corona, style, shadows, cubemapname);
3175 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3179 if (r_shadow_selectedlight == NULL)
3183 sprintf(temp, "Light properties");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3184 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;
3185 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;
3186 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;
3187 sprintf(temp, "Radius %f", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3188 sprintf(temp, "Corona %f", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3189 sprintf(temp, "Style %i", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3190 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;
3191 sprintf(temp, "Cubemap %s", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3194 void R_Shadow_EditLights_ToggleShadow_f(void)
3196 if (!r_editlights.integer)
3198 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3201 if (!r_shadow_selectedlight)
3203 Con_Print("No selected light.\n");
3206 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);
3207 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3208 r_shadow_selectedlight = NULL;
3211 void R_Shadow_EditLights_ToggleCorona_f(void)
3213 if (!r_editlights.integer)
3215 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3218 if (!r_shadow_selectedlight)
3220 Con_Print("No selected light.\n");
3223 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);
3224 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3225 r_shadow_selectedlight = NULL;
3228 void R_Shadow_EditLights_Remove_f(void)
3230 if (!r_editlights.integer)
3232 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
3235 if (!r_shadow_selectedlight)
3237 Con_Print("No selected light.\n");
3240 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3241 r_shadow_selectedlight = NULL;
3244 void R_Shadow_EditLights_Help_f(void)
3247 "Documentation on r_editlights system:\n"
3249 "r_editlights : enable/disable editing mode\n"
3250 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
3251 "r_editlights_cursorpushback : push back cursor this far from surface\n"
3252 "r_editlights_cursorpushoff : push cursor off surface this far\n"
3253 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
3254 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
3255 "r_editlights_rtlightssizescale : imported rtlight size scaling\n"
3256 "r_editlights_rtlightscolorscale : imported rtlight color scaling\n"
3258 "r_editlights_help : this help\n"
3259 "r_editlights_clear : remove all lights\n"
3260 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
3261 "r_editlights_save : save to .rtlights file\n"
3262 "r_editlights_spawn : create a light with default settings\n"
3263 "r_editlights_edit command : edit selected light - more documentation below\n"
3264 "r_editlights_remove : remove selected light\n"
3265 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
3266 "r_editlights_importlightentitiesfrommap : reload light entities\n"
3267 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
3269 "origin x y z : set light location\n"
3270 "originx x: set x component of light location\n"
3271 "originy y: set y component of light location\n"
3272 "originz z: set z component of light location\n"
3273 "move x y z : adjust light location\n"
3274 "movex x: adjust x component of light location\n"
3275 "movey y: adjust y component of light location\n"
3276 "movez z: adjust z component of light location\n"
3277 "angles x y z : set light angles\n"
3278 "anglesx x: set x component of light angles\n"
3279 "anglesy y: set y component of light angles\n"
3280 "anglesz z: set z component of light angles\n"
3281 "color r g b : set color of light (can be brighter than 1 1 1)\n"
3282 "radius radius : set radius (size) of light\n"
3283 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
3284 "cubemap basename : set filter cubemap of light (not yet supported)\n"
3285 "shadows 1/0 : turn on/off shadows\n"
3286 "corona n : set corona intensity\n"
3287 "<nothing> : print light properties to console\n"
3291 void R_Shadow_EditLights_Init(void)
3293 Cvar_RegisterVariable(&r_editlights);
3294 Cvar_RegisterVariable(&r_editlights_cursordistance);
3295 Cvar_RegisterVariable(&r_editlights_cursorpushback);
3296 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
3297 Cvar_RegisterVariable(&r_editlights_cursorgrid);
3298 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
3299 Cvar_RegisterVariable(&r_editlights_rtlightssizescale);
3300 Cvar_RegisterVariable(&r_editlights_rtlightscolorscale);
3301 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
3302 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
3303 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
3304 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
3305 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
3306 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
3307 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
3308 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
3309 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
3310 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
3311 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);