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 = {CVAR_SAVE, "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 = {CVAR_SAVE, "r_shadow_realtime_dlight", "1"};
180 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "0"};
181 cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0"};
182 cvar_t r_shadow_realtime_world_dlightshadows = {CVAR_SAVE, "r_shadow_realtime_world_dlightshadows", "1"};
183 cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0"};
184 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "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 rtlight_t *r_shadow_compilingrtlight;
209 dlight_t *r_shadow_worldlightchain;
210 dlight_t *r_shadow_selectedlight;
211 dlight_t r_shadow_bufferlight;
212 vec3_t r_editlights_cursorlocation;
214 rtexture_t *lighttextures[5];
216 extern int con_vislines;
218 typedef struct cubemapinfo_s
225 #define MAX_CUBEMAPS 256
226 static int numcubemaps;
227 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
229 void R_Shadow_UncompileWorldLights(void);
230 void R_Shadow_ClearWorldLights(void);
231 void R_Shadow_SaveWorldLights(void);
232 void R_Shadow_LoadWorldLights(void);
233 void R_Shadow_LoadLightsFile(void);
234 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
235 void R_Shadow_EditLights_Reload_f(void);
236 void R_Shadow_ValidateCvars(void);
237 static void R_Shadow_MakeTextures(void);
238 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light);
240 void r_shadow_start(void)
242 // allocate vertex processing arrays
244 r_shadow_normalcubetexture = NULL;
245 r_shadow_attenuation2dtexture = NULL;
246 r_shadow_attenuation3dtexture = NULL;
247 r_shadow_blankbumptexture = NULL;
248 r_shadow_blankglosstexture = NULL;
249 r_shadow_blankwhitetexture = NULL;
250 r_shadow_texturepool = NULL;
251 r_shadow_filters_texturepool = NULL;
252 R_Shadow_ValidateCvars();
253 R_Shadow_MakeTextures();
254 maxshadowelements = 0;
255 shadowelements = NULL;
263 shadowmarklist = NULL;
265 r_shadow_buffer_numclusterpvsbytes = 0;
266 r_shadow_buffer_clusterpvs = NULL;
267 r_shadow_buffer_clusterlist = NULL;
268 r_shadow_buffer_numsurfacepvsbytes = 0;
269 r_shadow_buffer_surfacepvs = NULL;
270 r_shadow_buffer_surfacelist = NULL;
273 void r_shadow_shutdown(void)
275 R_Shadow_UncompileWorldLights();
277 r_shadow_normalcubetexture = NULL;
278 r_shadow_attenuation2dtexture = NULL;
279 r_shadow_attenuation3dtexture = NULL;
280 r_shadow_blankbumptexture = NULL;
281 r_shadow_blankglosstexture = NULL;
282 r_shadow_blankwhitetexture = NULL;
283 R_FreeTexturePool(&r_shadow_texturepool);
284 R_FreeTexturePool(&r_shadow_filters_texturepool);
285 maxshadowelements = 0;
287 Mem_Free(shadowelements);
288 shadowelements = NULL;
291 Mem_Free(vertexupdate);
294 Mem_Free(vertexremap);
300 Mem_Free(shadowmark);
303 Mem_Free(shadowmarklist);
304 shadowmarklist = NULL;
306 r_shadow_buffer_numclusterpvsbytes = 0;
307 if (r_shadow_buffer_clusterpvs)
308 Mem_Free(r_shadow_buffer_clusterpvs);
309 r_shadow_buffer_clusterpvs = NULL;
310 if (r_shadow_buffer_clusterlist)
311 Mem_Free(r_shadow_buffer_clusterlist);
312 r_shadow_buffer_clusterlist = NULL;
313 r_shadow_buffer_numsurfacepvsbytes = 0;
314 if (r_shadow_buffer_surfacepvs)
315 Mem_Free(r_shadow_buffer_surfacepvs);
316 r_shadow_buffer_surfacepvs = NULL;
317 if (r_shadow_buffer_surfacelist)
318 Mem_Free(r_shadow_buffer_surfacelist);
319 r_shadow_buffer_surfacelist = NULL;
322 void r_shadow_newmap(void)
326 void R_Shadow_Help_f(void)
329 "Documentation on r_shadow system:\n"
331 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
332 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
333 "r_shadow_debuglight : render only this light number (-1 = all)\n"
334 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
335 "r_shadow_gloss2intensity : brightness of forced gloss\n"
336 "r_shadow_glossintensity : brightness of textured gloss\n"
337 "r_shadow_lightattenuationpower : used to generate attenuation texture\n"
338 "r_shadow_lightattenuationscale : used to generate attenuation texture\n"
339 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
340 "r_shadow_portallight : use portal visibility for static light precomputation\n"
341 "r_shadow_projectdistance : shadow volume projection distance\n"
342 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
343 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
344 "r_shadow_realtime_world : use high quality world lighting mode\n"
345 "r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n"
346 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
347 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
348 "r_shadow_scissor : use scissor optimization\n"
349 "r_shadow_shadow_polygonfactor : nudge shadow volumes closer/further\n"
350 "r_shadow_shadow_polygonoffset : nudge shadow volumes closer/further\n"
351 "r_shadow_singlepassvolumegeneration : selects shadow volume algorithm\n"
352 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
353 "r_shadow_visiblevolumes : useful for performance testing; bright = slow!\n"
355 "r_shadow_help : this help\n"
359 void R_Shadow_Init(void)
361 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
362 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
363 Cvar_RegisterVariable(&r_shadow_cull);
364 Cvar_RegisterVariable(&r_shadow_debuglight);
365 Cvar_RegisterVariable(&r_shadow_gloss);
366 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
367 Cvar_RegisterVariable(&r_shadow_glossintensity);
368 Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
369 Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
370 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
371 Cvar_RegisterVariable(&r_shadow_portallight);
372 Cvar_RegisterVariable(&r_shadow_projectdistance);
373 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
374 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
375 Cvar_RegisterVariable(&r_shadow_realtime_world);
376 Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows);
377 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
378 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
379 Cvar_RegisterVariable(&r_shadow_scissor);
380 Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor);
381 Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset);
382 Cvar_RegisterVariable(&r_shadow_singlepassvolumegeneration);
383 Cvar_RegisterVariable(&r_shadow_staticworldlights);
384 Cvar_RegisterVariable(&r_shadow_texture3d);
385 Cvar_RegisterVariable(&r_shadow_visiblevolumes);
386 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
387 if (gamemode == GAME_TENEBRAE)
389 Cvar_SetValue("r_shadow_gloss", 2);
390 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
392 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f);
393 R_Shadow_EditLights_Init();
394 r_shadow_mempool = Mem_AllocPool("R_Shadow", 0, NULL);
395 r_shadow_worldlightchain = NULL;
396 maxshadowelements = 0;
397 shadowelements = NULL;
405 shadowmarklist = NULL;
407 r_shadow_buffer_numclusterpvsbytes = 0;
408 r_shadow_buffer_clusterpvs = NULL;
409 r_shadow_buffer_clusterlist = NULL;
410 r_shadow_buffer_numsurfacepvsbytes = 0;
411 r_shadow_buffer_surfacepvs = NULL;
412 r_shadow_buffer_surfacelist = NULL;
413 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
416 matrix4x4_t matrix_attenuationxyz =
419 {0.5, 0.0, 0.0, 0.5},
420 {0.0, 0.5, 0.0, 0.5},
421 {0.0, 0.0, 0.5, 0.5},
426 matrix4x4_t matrix_attenuationz =
429 {0.0, 0.0, 0.5, 0.5},
430 {0.0, 0.0, 0.0, 0.5},
431 {0.0, 0.0, 0.0, 0.5},
436 int *R_Shadow_ResizeShadowElements(int numtris)
438 // make sure shadowelements is big enough for this volume
439 if (maxshadowelements < numtris * 24)
441 maxshadowelements = numtris * 24;
443 Mem_Free(shadowelements);
444 shadowelements = Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int));
446 return shadowelements;
449 void R_Shadow_EnlargeClusterBuffer(int numclusters)
451 int numclusterpvsbytes = (((numclusters + 7) >> 3) + 255) & ~255;
452 if (r_shadow_buffer_numclusterpvsbytes < numclusterpvsbytes)
454 if (r_shadow_buffer_clusterpvs)
455 Mem_Free(r_shadow_buffer_clusterpvs);
456 if (r_shadow_buffer_clusterlist)
457 Mem_Free(r_shadow_buffer_clusterlist);
458 r_shadow_buffer_numclusterpvsbytes = numclusterpvsbytes;
459 r_shadow_buffer_clusterpvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numclusterpvsbytes);
460 r_shadow_buffer_clusterlist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numclusterpvsbytes * 8 * sizeof(*r_shadow_buffer_clusterlist));
464 void R_Shadow_EnlargeSurfaceBuffer(int numsurfaces)
466 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
467 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
469 if (r_shadow_buffer_surfacepvs)
470 Mem_Free(r_shadow_buffer_surfacepvs);
471 if (r_shadow_buffer_surfacelist)
472 Mem_Free(r_shadow_buffer_surfacelist);
473 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
474 r_shadow_buffer_surfacepvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes);
475 r_shadow_buffer_surfacelist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
479 void R_Shadow_PrepareShadowMark(int numtris)
481 // make sure shadowmark is big enough for this volume
482 if (maxshadowmark < numtris)
484 maxshadowmark = numtris;
486 Mem_Free(shadowmark);
488 Mem_Free(shadowmarklist);
489 shadowmark = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmark));
490 shadowmarklist = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmarklist));
494 // if shadowmarkcount wrapped we clear the array and adjust accordingly
495 if (shadowmarkcount == 0)
498 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
503 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)
505 int i, j, tris = 0, vr[3], t, outvertices = 0;
509 if (maxvertexupdate < innumvertices)
511 maxvertexupdate = innumvertices;
513 Mem_Free(vertexupdate);
515 Mem_Free(vertexremap);
516 vertexupdate = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
517 vertexremap = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
521 if (vertexupdatenum == 0)
524 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
525 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
528 for (i = 0;i < numshadowmarktris;i++)
529 shadowmark[shadowmarktris[i]] = shadowmarkcount;
531 for (i = 0;i < numshadowmarktris;i++)
533 t = shadowmarktris[i];
534 e = inelement3i + t * 3;
535 n = inneighbor3i + t * 3;
536 // make sure the vertices are created
537 for (j = 0;j < 3;j++)
539 if (vertexupdate[e[j]] != vertexupdatenum)
541 vertexupdate[e[j]] = vertexupdatenum;
542 vertexremap[e[j]] = outvertices;
543 VectorSubtract(invertex3f + e[j] * 3, projectorigin, temp);
544 f = projectdistance / VectorLength(temp);
545 VectorCopy(invertex3f + e[j] * 3, outvertex3f);
546 VectorMA(projectorigin, f, temp, (outvertex3f + 3));
551 // output the front and back triangles
552 outelement3i[0] = vertexremap[e[0]];
553 outelement3i[1] = vertexremap[e[1]];
554 outelement3i[2] = vertexremap[e[2]];
555 outelement3i[3] = vertexremap[e[2]] + 1;
556 outelement3i[4] = vertexremap[e[1]] + 1;
557 outelement3i[5] = vertexremap[e[0]] + 1;
560 // output the sides (facing outward from this triangle)
561 if (shadowmark[n[0]] != shadowmarkcount)
563 vr[0] = vertexremap[e[0]];
564 vr[1] = vertexremap[e[1]];
565 outelement3i[0] = vr[1];
566 outelement3i[1] = vr[0];
567 outelement3i[2] = vr[0] + 1;
568 outelement3i[3] = vr[1];
569 outelement3i[4] = vr[0] + 1;
570 outelement3i[5] = vr[1] + 1;
574 if (shadowmark[n[1]] != shadowmarkcount)
576 vr[1] = vertexremap[e[1]];
577 vr[2] = vertexremap[e[2]];
578 outelement3i[0] = vr[2];
579 outelement3i[1] = vr[1];
580 outelement3i[2] = vr[1] + 1;
581 outelement3i[3] = vr[2];
582 outelement3i[4] = vr[1] + 1;
583 outelement3i[5] = vr[2] + 1;
587 if (shadowmark[n[2]] != shadowmarkcount)
589 vr[0] = vertexremap[e[0]];
590 vr[2] = vertexremap[e[2]];
591 outelement3i[0] = vr[0];
592 outelement3i[1] = vr[2];
593 outelement3i[2] = vr[2] + 1;
594 outelement3i[3] = vr[0];
595 outelement3i[4] = vr[2] + 1;
596 outelement3i[5] = vr[0] + 1;
602 *outnumvertices = outvertices;
606 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)
609 if (projectdistance < 0.1)
611 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
614 if (!numverts || !nummarktris)
616 // make sure shadowelements is big enough for this volume
617 if (maxshadowelements < nummarktris * 24)
618 R_Shadow_ResizeShadowElements((nummarktris + 256) * 24);
619 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, varray_vertex3f2, projectorigin, projectdistance, nummarktris, marktris);
620 R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements);
623 void R_Shadow_MarkVolumeFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const vec3_t projectorigin, vec3_t lightmins, vec3_t lightmaxs, vec3_t surfacemins, vec3_t surfacemaxs)
628 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
630 tend = firsttriangle + numtris;
631 if (surfacemins[0] >= lightmins[0] && surfacemaxs[0] <= lightmaxs[0]
632 && surfacemins[1] >= lightmins[1] && surfacemaxs[1] <= lightmaxs[1]
633 && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2])
635 // surface box entirely inside light box, no box cull
636 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
637 if (PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
638 shadowmarklist[numshadowmark++] = t;
642 // surface box not entirely inside light box, cull each triangle
643 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
645 v[0] = invertex3f + e[0] * 3;
646 v[1] = invertex3f + e[1] * 3;
647 v[2] = invertex3f + e[2] * 3;
648 if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
649 && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
650 && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
651 && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
652 && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
653 && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
654 && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
655 shadowmarklist[numshadowmark++] = t;
660 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
663 if (r_shadow_compilingrtlight)
665 // if we're compiling an rtlight, capture the mesh
666 Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
669 memset(&m, 0, sizeof(m));
670 m.pointer_vertex = vertex3f;
672 GL_LockArrays(0, numvertices);
673 if (r_shadowstage == SHADOWSTAGE_STENCIL)
675 // increment stencil if backface is behind depthbuffer
676 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
677 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
678 R_Mesh_Draw(numvertices, numtriangles, element3i);
680 c_rt_shadowtris += numtriangles;
681 // decrement stencil if frontface is behind depthbuffer
682 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
683 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
685 R_Mesh_Draw(numvertices, numtriangles, element3i);
687 c_rt_shadowtris += numtriangles;
691 static void R_Shadow_MakeTextures(void)
693 int x, y, z, d, side;
694 float v[3], s, t, intensity;
696 R_FreeTexturePool(&r_shadow_texturepool);
697 r_shadow_texturepool = R_AllocTexturePool();
698 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
699 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
701 #define ATTEN2DSIZE 64
702 #define ATTEN3DSIZE 32
703 data = Mem_Alloc(tempmempool, max(6*NORMSIZE*NORMSIZE*4, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4)));
708 r_shadow_blankbumptexture = R_LoadTexture2D(r_shadow_texturepool, "blankbump", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
713 r_shadow_blankglosstexture = R_LoadTexture2D(r_shadow_texturepool, "blankgloss", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
718 r_shadow_blankwhitetexture = R_LoadTexture2D(r_shadow_texturepool, "blankwhite", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
719 if (gl_texturecubemap)
721 for (side = 0;side < 6;side++)
723 for (y = 0;y < NORMSIZE;y++)
725 for (x = 0;x < NORMSIZE;x++)
727 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
728 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
762 intensity = 127.0f / sqrt(DotProduct(v, v));
763 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+0] = 128.0f + intensity * v[0];
764 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+1] = 128.0f + intensity * v[1];
765 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+2] = 128.0f + intensity * v[2];
766 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+3] = 255;
770 r_shadow_normalcubetexture = R_LoadTextureCubeMap(r_shadow_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
773 r_shadow_normalcubetexture = NULL;
774 for (y = 0;y < ATTEN2DSIZE;y++)
776 for (x = 0;x < ATTEN2DSIZE;x++)
778 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
779 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
781 intensity = 1.0f - sqrt(DotProduct(v, v));
783 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
784 d = bound(0, intensity, 255);
785 data[(y*ATTEN2DSIZE+x)*4+0] = d;
786 data[(y*ATTEN2DSIZE+x)*4+1] = d;
787 data[(y*ATTEN2DSIZE+x)*4+2] = d;
788 data[(y*ATTEN2DSIZE+x)*4+3] = d;
791 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
792 if (r_shadow_texture3d.integer)
794 for (z = 0;z < ATTEN3DSIZE;z++)
796 for (y = 0;y < ATTEN3DSIZE;y++)
798 for (x = 0;x < ATTEN3DSIZE;x++)
800 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
801 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
802 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
803 intensity = 1.0f - sqrt(DotProduct(v, v));
805 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
806 d = bound(0, intensity, 255);
807 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
808 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
809 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
810 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
814 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
819 void R_Shadow_ValidateCvars(void)
821 if (r_shadow_texture3d.integer && !gl_texture3d)
822 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
823 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
824 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
827 void R_Shadow_Stage_Begin(void)
831 R_Shadow_ValidateCvars();
833 if (!r_shadow_attenuation2dtexture
834 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
835 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
836 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
837 R_Shadow_MakeTextures();
839 memset(&m, 0, sizeof(m));
840 GL_BlendFunc(GL_ONE, GL_ZERO);
844 GL_Color(0, 0, 0, 1);
845 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
846 qglEnable(GL_CULL_FACE);
847 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
848 r_shadowstage = SHADOWSTAGE_NONE;
850 c_rt_lights = c_rt_clears = c_rt_scissored = 0;
851 c_rt_shadowmeshes = c_rt_shadowtris = c_rt_lightmeshes = c_rt_lighttris = 0;
852 c_rtcached_shadowmeshes = c_rtcached_shadowtris = 0;
855 void R_Shadow_Stage_ShadowVolumes(void)
858 memset(&m, 0, sizeof(m));
860 GL_Color(1, 1, 1, 1);
861 GL_ColorMask(0, 0, 0, 0);
862 GL_BlendFunc(GL_ONE, GL_ZERO);
865 qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
866 //if (r_shadow_shadow_polygonoffset.value != 0)
868 // qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
869 // qglEnable(GL_POLYGON_OFFSET_FILL);
872 // qglDisable(GL_POLYGON_OFFSET_FILL);
873 qglDepthFunc(GL_LESS);
874 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
875 qglEnable(GL_STENCIL_TEST);
876 qglStencilFunc(GL_ALWAYS, 128, ~0);
877 if (gl_ext_stenciltwoside.integer)
879 r_shadowstage = SHADOWSTAGE_STENCILTWOSIDE;
880 qglDisable(GL_CULL_FACE);
881 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
882 qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
884 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
885 qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
887 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
891 r_shadowstage = SHADOWSTAGE_STENCIL;
892 qglEnable(GL_CULL_FACE);
894 // this is changed by every shadow render so its value here is unimportant
895 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
897 GL_Clear(GL_STENCIL_BUFFER_BIT);
899 // LordHavoc note: many shadow volumes reside entirely inside the world
900 // (that is to say they are entirely bounded by their lit surfaces),
901 // which can be optimized by handling things as an inverted light volume,
902 // with the shadow boundaries of the world being simulated by an altered
903 // (129) bias to stencil clearing on such lights
904 // FIXME: generate inverted light volumes for use as shadow volumes and
905 // optimize for them as noted above
908 void R_Shadow_Stage_Light(int shadowtest)
911 memset(&m, 0, sizeof(m));
913 GL_BlendFunc(GL_ONE, GL_ONE);
916 qglPolygonOffset(0, 0);
917 //qglDisable(GL_POLYGON_OFFSET_FILL);
918 GL_Color(1, 1, 1, 1);
919 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
920 qglDepthFunc(GL_EQUAL);
921 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
922 qglEnable(GL_CULL_FACE);
924 qglEnable(GL_STENCIL_TEST);
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 // only draw light where this geometry was already rendered AND the
932 // stencil is 128 (values other than this mean shadow)
933 qglStencilFunc(GL_EQUAL, 128, ~0);
934 r_shadowstage = SHADOWSTAGE_LIGHT;
938 void R_Shadow_Stage_End(void)
941 memset(&m, 0, sizeof(m));
943 GL_BlendFunc(GL_ONE, GL_ZERO);
946 qglPolygonOffset(0, 0);
947 //qglDisable(GL_POLYGON_OFFSET_FILL);
948 GL_Color(1, 1, 1, 1);
949 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
950 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
951 qglDepthFunc(GL_LEQUAL);
952 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
953 qglDisable(GL_STENCIL_TEST);
954 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
955 if (gl_support_stenciltwoside)
956 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
958 qglStencilFunc(GL_ALWAYS, 128, ~0);
959 r_shadowstage = SHADOWSTAGE_NONE;
962 int R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
964 int i, ix1, iy1, ix2, iy2;
965 float x1, y1, x2, y2, x, y, f;
968 if (!r_shadow_scissor.integer)
970 // if view is inside the box, just say yes it's visible
971 if (BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
973 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
976 for (i = 0;i < 3;i++)
978 if (r_viewforward[i] >= 0)
989 f = DotProduct(r_viewforward, r_vieworigin) + 1;
990 if (DotProduct(r_viewforward, v2) <= f)
992 // entirely behind nearclip plane
995 if (DotProduct(r_viewforward, v) >= f)
997 // entirely infront of nearclip plane
998 x1 = y1 = x2 = y2 = 0;
999 for (i = 0;i < 8;i++)
1001 v[0] = (i & 1) ? mins[0] : maxs[0];
1002 v[1] = (i & 2) ? mins[1] : maxs[1];
1003 v[2] = (i & 4) ? mins[2] : maxs[2];
1005 GL_TransformToScreen(v, v2);
1006 //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]);
1025 // clipped by nearclip plane
1026 // this is nasty and crude...
1027 // create viewspace bbox
1028 for (i = 0;i < 8;i++)
1030 v[0] = ((i & 1) ? mins[0] : maxs[0]) - r_vieworigin[0];
1031 v[1] = ((i & 2) ? mins[1] : maxs[1]) - r_vieworigin[1];
1032 v[2] = ((i & 4) ? mins[2] : maxs[2]) - r_vieworigin[2];
1033 v2[0] = -DotProduct(v, r_viewleft);
1034 v2[1] = DotProduct(v, r_viewup);
1035 v2[2] = DotProduct(v, r_viewforward);
1038 if (smins[0] > v2[0]) smins[0] = v2[0];
1039 if (smaxs[0] < v2[0]) smaxs[0] = v2[0];
1040 if (smins[1] > v2[1]) smins[1] = v2[1];
1041 if (smaxs[1] < v2[1]) smaxs[1] = v2[1];
1042 if (smins[2] > v2[2]) smins[2] = v2[2];
1043 if (smaxs[2] < v2[2]) smaxs[2] = v2[2];
1047 smins[0] = smaxs[0] = v2[0];
1048 smins[1] = smaxs[1] = v2[1];
1049 smins[2] = smaxs[2] = v2[2];
1052 // now we have a bbox in viewspace
1053 // clip it to the view plane
1056 // return true if that culled the box
1057 if (smins[2] >= smaxs[2])
1059 // ok some of it is infront of the view, transform each corner back to
1060 // worldspace and then to screenspace and make screen rect
1061 // initialize these variables just to avoid compiler warnings
1062 x1 = y1 = x2 = y2 = 0;
1063 for (i = 0;i < 8;i++)
1065 v2[0] = (i & 1) ? smins[0] : smaxs[0];
1066 v2[1] = (i & 2) ? smins[1] : smaxs[1];
1067 v2[2] = (i & 4) ? smins[2] : smaxs[2];
1068 v[0] = v2[0] * -r_viewleft[0] + v2[1] * r_viewup[0] + v2[2] * r_viewforward[0] + r_vieworigin[0];
1069 v[1] = v2[0] * -r_viewleft[1] + v2[1] * r_viewup[1] + v2[2] * r_viewforward[1] + r_vieworigin[1];
1070 v[2] = v2[0] * -r_viewleft[2] + v2[1] * r_viewup[2] + v2[2] * r_viewforward[2] + r_vieworigin[2];
1072 GL_TransformToScreen(v, v2);
1073 //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]);
1090 // this code doesn't handle boxes with any points behind view properly
1091 x1 = 1000;x2 = -1000;
1092 y1 = 1000;y2 = -1000;
1093 for (i = 0;i < 8;i++)
1095 v[0] = (i & 1) ? mins[0] : maxs[0];
1096 v[1] = (i & 2) ? mins[1] : maxs[1];
1097 v[2] = (i & 4) ? mins[2] : maxs[2];
1099 GL_TransformToScreen(v, v2);
1100 //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]);
1118 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1119 if (ix1 < r_view_x) ix1 = r_view_x;
1120 if (iy1 < r_view_y) iy1 = r_view_y;
1121 if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
1122 if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
1123 if (ix2 <= ix1 || iy2 <= iy1)
1125 // set up the scissor rectangle
1126 GL_Scissor(ix1, vid.realheight - iy2, ix2 - ix1, iy2 - iy1);
1127 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1128 //qglEnable(GL_SCISSOR_TEST);
1133 static void R_Shadow_VertexShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1135 float *color4f = varray_color4f;
1136 float dist, dot, intensity, v[3], n[3];
1137 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1139 Matrix4x4_Transform(m, vertex3f, v);
1140 if ((dist = DotProduct(v, v)) < 1)
1142 Matrix4x4_Transform3x3(m, normal3f, n);
1143 if ((dot = DotProduct(n, v)) > 0)
1146 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1147 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1148 VectorScale(lightcolor, intensity, color4f);
1153 VectorClear(color4f);
1159 VectorClear(color4f);
1165 static void R_Shadow_VertexShadingWithZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1167 float *color4f = varray_color4f;
1168 float dist, dot, intensity, v[3], n[3];
1169 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1171 Matrix4x4_Transform(m, vertex3f, v);
1172 if ((dist = fabs(v[2])) < 1)
1174 Matrix4x4_Transform3x3(m, normal3f, n);
1175 if ((dot = DotProduct(n, v)) > 0)
1177 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1178 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1179 VectorScale(lightcolor, intensity, color4f);
1184 VectorClear(color4f);
1190 VectorClear(color4f);
1196 static void R_Shadow_VertexShading(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1198 float *color4f = varray_color4f;
1199 float dot, intensity, v[3], n[3];
1200 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1202 Matrix4x4_Transform(m, vertex3f, v);
1203 Matrix4x4_Transform3x3(m, normal3f, n);
1204 if ((dot = DotProduct(n, v)) > 0)
1206 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1207 VectorScale(lightcolor, intensity, color4f);
1212 VectorClear(color4f);
1218 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1219 #define USETEXMATRIX
1221 #ifndef USETEXMATRIX
1222 // this should be done in a texture matrix or vertex program when possible, but here's code to do it manually
1223 // if hardware texcoord manipulation is not available (or not suitable, this would really benefit from 3DNow! or SSE
1224 static void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1228 tc3f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1229 tc3f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1230 tc3f[2] = vertex3f[0] * matrix->m[2][0] + vertex3f[1] * matrix->m[2][1] + vertex3f[2] * matrix->m[2][2] + matrix->m[2][3];
1237 static void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1241 tc2f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1242 tc2f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1250 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)
1254 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1256 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1257 // the cubemap normalizes this for us
1258 out3f[0] = DotProduct(svector3f, lightdir);
1259 out3f[1] = DotProduct(tvector3f, lightdir);
1260 out3f[2] = DotProduct(normal3f, lightdir);
1264 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)
1267 float lightdir[3], eyedir[3], halfdir[3];
1268 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1270 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1271 VectorNormalizeFast(lightdir);
1272 VectorSubtract(vertex3f, relativeeyeorigin, eyedir);
1273 VectorNormalizeFast(eyedir);
1274 VectorAdd(lightdir, eyedir, halfdir);
1275 // the cubemap normalizes this for us
1276 out3f[0] = DotProduct(svector3f, halfdir);
1277 out3f[1] = DotProduct(tvector3f, halfdir);
1278 out3f[2] = DotProduct(normal3f, halfdir);
1282 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)
1285 float color[3], color2[3], colorscale;
1288 bumptexture = r_shadow_blankbumptexture;
1290 glosstexture = r_shadow_blankglosstexture;
1291 // FIXME: support EF_NODEPTHTEST
1292 GL_DepthMask(false);
1294 if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
1296 if (lighting & LIGHTING_DIFFUSE)
1299 colorscale = r_shadow_lightintensityscale.value;
1300 // colorscale accounts for how much we multiply the brightness
1303 // mult is how many times the final pass of the lighting will be
1304 // performed to get more brightness than otherwise possible.
1306 // Limit mult to 64 for sanity sake.
1307 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1309 // 3/2 3D combine path (Geforce3, Radeon 8500)
1310 memset(&m, 0, sizeof(m));
1311 m.pointer_vertex = vertex3f;
1312 m.tex[0] = R_GetTexture(bumptexture);
1313 m.texcombinergb[0] = GL_REPLACE;
1314 m.pointer_texcoord[0] = texcoord2f;
1315 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1316 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1317 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1318 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1319 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1321 m.pointer_texcoord3f[2] = vertex3f;
1322 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
1324 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1325 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1328 GL_ColorMask(0,0,0,1);
1329 GL_BlendFunc(GL_ONE, GL_ZERO);
1330 GL_LockArrays(0, numverts);
1331 R_Mesh_Draw(numverts, numtriangles, elements);
1332 GL_LockArrays(0, 0);
1334 c_rt_lighttris += numtriangles;
1336 memset(&m, 0, sizeof(m));
1337 m.pointer_vertex = vertex3f;
1338 m.tex[0] = R_GetTexture(basetexture);
1339 m.pointer_texcoord[0] = texcoord2f;
1342 m.texcubemap[1] = R_GetTexture(lightcubemap);
1344 m.pointer_texcoord3f[1] = vertex3f;
1345 m.texmatrix[1] = *matrix_modeltolight;
1347 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1348 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1352 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap)
1354 // 1/2/2 3D combine path (original Radeon)
1355 memset(&m, 0, sizeof(m));
1356 m.pointer_vertex = vertex3f;
1357 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1359 m.pointer_texcoord3f[0] = vertex3f;
1360 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1362 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1363 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1366 GL_ColorMask(0,0,0,1);
1367 GL_BlendFunc(GL_ONE, GL_ZERO);
1368 GL_LockArrays(0, numverts);
1369 R_Mesh_Draw(numverts, numtriangles, elements);
1370 GL_LockArrays(0, 0);
1372 c_rt_lighttris += numtriangles;
1374 memset(&m, 0, sizeof(m));
1375 m.pointer_vertex = vertex3f;
1376 m.tex[0] = R_GetTexture(bumptexture);
1377 m.texcombinergb[0] = GL_REPLACE;
1378 m.pointer_texcoord[0] = texcoord2f;
1379 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1380 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1381 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1382 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1384 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1385 GL_LockArrays(0, numverts);
1386 R_Mesh_Draw(numverts, numtriangles, elements);
1387 GL_LockArrays(0, 0);
1389 c_rt_lighttris += numtriangles;
1391 memset(&m, 0, sizeof(m));
1392 m.pointer_vertex = vertex3f;
1393 m.tex[0] = R_GetTexture(basetexture);
1394 m.pointer_texcoord[0] = texcoord2f;
1397 m.texcubemap[1] = R_GetTexture(lightcubemap);
1399 m.pointer_texcoord3f[1] = vertex3f;
1400 m.texmatrix[1] = *matrix_modeltolight;
1402 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1403 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1407 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap)
1409 // 2/2 3D combine path (original Radeon)
1410 memset(&m, 0, sizeof(m));
1411 m.pointer_vertex = vertex3f;
1412 m.tex[0] = R_GetTexture(bumptexture);
1413 m.texcombinergb[0] = GL_REPLACE;
1414 m.pointer_texcoord[0] = texcoord2f;
1415 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1416 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1417 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1418 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1420 GL_ColorMask(0,0,0,1);
1421 GL_BlendFunc(GL_ONE, GL_ZERO);
1422 GL_LockArrays(0, numverts);
1423 R_Mesh_Draw(numverts, numtriangles, elements);
1424 GL_LockArrays(0, 0);
1426 c_rt_lighttris += numtriangles;
1428 memset(&m, 0, sizeof(m));
1429 m.pointer_vertex = vertex3f;
1430 m.tex[0] = R_GetTexture(basetexture);
1431 m.pointer_texcoord[0] = texcoord2f;
1432 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1434 m.pointer_texcoord3f[1] = vertex3f;
1435 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1437 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1438 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1441 else if (r_textureunits.integer >= 4)
1443 // 4/2 2D combine path (Geforce3, Radeon 8500)
1444 memset(&m, 0, sizeof(m));
1445 m.pointer_vertex = vertex3f;
1446 m.tex[0] = R_GetTexture(bumptexture);
1447 m.texcombinergb[0] = GL_REPLACE;
1448 m.pointer_texcoord[0] = texcoord2f;
1449 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1450 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1451 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1452 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1453 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1455 m.pointer_texcoord3f[2] = vertex3f;
1456 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
1458 m.pointer_texcoord[2] = varray_texcoord2f[2];
1459 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1461 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1463 m.pointer_texcoord3f[3] = vertex3f;
1464 m.texmatrix[3] = *matrix_modeltoattenuationz;
1466 m.pointer_texcoord[3] = varray_texcoord2f[3];
1467 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[3], numverts, vertex3f, matrix_modeltoattenuationz);
1470 GL_ColorMask(0,0,0,1);
1471 GL_BlendFunc(GL_ONE, GL_ZERO);
1472 GL_LockArrays(0, numverts);
1473 R_Mesh_Draw(numverts, numtriangles, elements);
1474 GL_LockArrays(0, 0);
1476 c_rt_lighttris += numtriangles;
1478 memset(&m, 0, sizeof(m));
1479 m.pointer_vertex = vertex3f;
1480 m.tex[0] = R_GetTexture(basetexture);
1481 m.pointer_texcoord[0] = texcoord2f;
1484 m.texcubemap[1] = R_GetTexture(lightcubemap);
1486 m.pointer_texcoord3f[1] = vertex3f;
1487 m.texmatrix[1] = *matrix_modeltolight;
1489 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1490 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1496 // 2/2/2 2D combine path (any dot3 card)
1497 memset(&m, 0, sizeof(m));
1498 m.pointer_vertex = vertex3f;
1499 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1501 m.pointer_texcoord3f[0] = vertex3f;
1502 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1504 m.pointer_texcoord[0] = varray_texcoord2f[0];
1505 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1507 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1509 m.pointer_texcoord3f[1] = vertex3f;
1510 m.texmatrix[1] = *matrix_modeltoattenuationz;
1512 m.pointer_texcoord[1] = varray_texcoord2f[1];
1513 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1516 GL_ColorMask(0,0,0,1);
1517 GL_BlendFunc(GL_ONE, GL_ZERO);
1518 GL_LockArrays(0, numverts);
1519 R_Mesh_Draw(numverts, numtriangles, elements);
1520 GL_LockArrays(0, 0);
1522 c_rt_lighttris += numtriangles;
1524 memset(&m, 0, sizeof(m));
1525 m.pointer_vertex = vertex3f;
1526 m.tex[0] = R_GetTexture(bumptexture);
1527 m.texcombinergb[0] = GL_REPLACE;
1528 m.pointer_texcoord[0] = texcoord2f;
1529 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1530 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1531 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1532 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1534 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1535 GL_LockArrays(0, numverts);
1536 R_Mesh_Draw(numverts, numtriangles, elements);
1537 GL_LockArrays(0, 0);
1539 c_rt_lighttris += numtriangles;
1541 memset(&m, 0, sizeof(m));
1542 m.pointer_vertex = vertex3f;
1543 m.tex[0] = R_GetTexture(basetexture);
1544 m.pointer_texcoord[0] = texcoord2f;
1547 m.texcubemap[1] = R_GetTexture(lightcubemap);
1549 m.pointer_texcoord3f[1] = vertex3f;
1550 m.texmatrix[1] = *matrix_modeltolight;
1552 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1553 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1557 // this final code is shared
1559 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1560 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1561 VectorScale(lightcolor, colorscale, color2);
1562 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1564 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1565 GL_LockArrays(0, numverts);
1566 R_Mesh_Draw(numverts, numtriangles, elements);
1567 GL_LockArrays(0, 0);
1569 c_rt_lighttris += numtriangles;
1572 if ((lighting & LIGHTING_SPECULAR) && (r_shadow_gloss.integer >= 2 || (r_shadow_gloss.integer >= 1 && glosstexture != r_shadow_blankglosstexture)))
1574 // FIXME: detect blendsquare!
1575 //if (gl_support_blendsquare)
1577 colorscale = r_shadow_lightintensityscale.value * r_shadow_glossintensity.value;
1578 if (glosstexture == r_shadow_blankglosstexture)
1579 colorscale *= r_shadow_gloss2intensity.value;
1581 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1583 // 2/0/0/1/2 3D combine blendsquare path
1584 memset(&m, 0, sizeof(m));
1585 m.pointer_vertex = vertex3f;
1586 m.tex[0] = R_GetTexture(bumptexture);
1587 m.pointer_texcoord[0] = texcoord2f;
1588 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1589 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1590 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1591 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1593 GL_ColorMask(0,0,0,1);
1594 // this squares the result
1595 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1596 GL_LockArrays(0, numverts);
1597 R_Mesh_Draw(numverts, numtriangles, elements);
1598 GL_LockArrays(0, 0);
1600 c_rt_lighttris += numtriangles;
1602 memset(&m, 0, sizeof(m));
1603 m.pointer_vertex = vertex3f;
1605 GL_LockArrays(0, numverts);
1606 // square alpha in framebuffer a few times to make it shiny
1607 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1608 // these comments are a test run through this math for intensity 0.5
1609 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1610 // 0.25 * 0.25 = 0.0625 (this is another pass)
1611 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1612 R_Mesh_Draw(numverts, numtriangles, elements);
1614 c_rt_lighttris += numtriangles;
1615 R_Mesh_Draw(numverts, numtriangles, elements);
1617 c_rt_lighttris += numtriangles;
1618 GL_LockArrays(0, 0);
1620 memset(&m, 0, sizeof(m));
1621 m.pointer_vertex = vertex3f;
1622 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1624 m.pointer_texcoord3f[0] = vertex3f;
1625 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1627 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1628 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1631 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1632 GL_LockArrays(0, numverts);
1633 R_Mesh_Draw(numverts, numtriangles, elements);
1634 GL_LockArrays(0, 0);
1636 c_rt_lighttris += numtriangles;
1638 memset(&m, 0, sizeof(m));
1639 m.pointer_vertex = vertex3f;
1640 m.tex[0] = R_GetTexture(glosstexture);
1641 m.pointer_texcoord[0] = texcoord2f;
1644 m.texcubemap[1] = R_GetTexture(lightcubemap);
1646 m.pointer_texcoord3f[1] = vertex3f;
1647 m.texmatrix[1] = *matrix_modeltolight;
1649 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1650 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1654 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1656 // 2/0/0/2 3D combine blendsquare path
1657 memset(&m, 0, sizeof(m));
1658 m.pointer_vertex = vertex3f;
1659 m.tex[0] = R_GetTexture(bumptexture);
1660 m.pointer_texcoord[0] = texcoord2f;
1661 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1662 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1663 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1664 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1666 GL_ColorMask(0,0,0,1);
1667 // this squares the result
1668 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1669 GL_LockArrays(0, numverts);
1670 R_Mesh_Draw(numverts, numtriangles, elements);
1671 GL_LockArrays(0, 0);
1673 c_rt_lighttris += numtriangles;
1675 memset(&m, 0, sizeof(m));
1676 m.pointer_vertex = vertex3f;
1678 GL_LockArrays(0, numverts);
1679 // square alpha in framebuffer a few times to make it shiny
1680 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1681 // these comments are a test run through this math for intensity 0.5
1682 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1683 // 0.25 * 0.25 = 0.0625 (this is another pass)
1684 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1685 R_Mesh_Draw(numverts, numtriangles, elements);
1687 c_rt_lighttris += numtriangles;
1688 R_Mesh_Draw(numverts, numtriangles, elements);
1690 c_rt_lighttris += numtriangles;
1691 GL_LockArrays(0, 0);
1693 memset(&m, 0, sizeof(m));
1694 m.pointer_vertex = vertex3f;
1695 m.tex[0] = R_GetTexture(glosstexture);
1696 m.pointer_texcoord[0] = texcoord2f;
1697 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1699 m.pointer_texcoord3f[1] = vertex3f;
1700 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1702 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1703 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1708 // 2/0/0/2/2 2D combine blendsquare path
1709 memset(&m, 0, sizeof(m));
1710 m.pointer_vertex = vertex3f;
1711 m.tex[0] = R_GetTexture(bumptexture);
1712 m.pointer_texcoord[0] = texcoord2f;
1713 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1714 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1715 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1716 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1718 GL_ColorMask(0,0,0,1);
1719 // this squares the result
1720 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1721 GL_LockArrays(0, numverts);
1722 R_Mesh_Draw(numverts, numtriangles, elements);
1723 GL_LockArrays(0, 0);
1725 c_rt_lighttris += numtriangles;
1727 memset(&m, 0, sizeof(m));
1728 m.pointer_vertex = vertex3f;
1730 GL_LockArrays(0, numverts);
1731 // square alpha in framebuffer a few times to make it shiny
1732 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1733 // these comments are a test run through this math for intensity 0.5
1734 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1735 // 0.25 * 0.25 = 0.0625 (this is another pass)
1736 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1737 R_Mesh_Draw(numverts, numtriangles, elements);
1739 c_rt_lighttris += numtriangles;
1740 R_Mesh_Draw(numverts, numtriangles, elements);
1742 c_rt_lighttris += numtriangles;
1743 GL_LockArrays(0, 0);
1745 memset(&m, 0, sizeof(m));
1746 m.pointer_vertex = vertex3f;
1747 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1749 m.pointer_texcoord3f[0] = vertex3f;
1750 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1752 m.pointer_texcoord[0] = varray_texcoord2f[0];
1753 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1755 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1757 m.pointer_texcoord3f[1] = vertex3f;
1758 m.texmatrix[1] = *matrix_modeltoattenuationz;
1760 m.pointer_texcoord[1] = varray_texcoord2f[1];
1761 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1764 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1765 GL_LockArrays(0, numverts);
1766 R_Mesh_Draw(numverts, numtriangles, elements);
1767 GL_LockArrays(0, 0);
1769 c_rt_lighttris += numtriangles;
1771 memset(&m, 0, sizeof(m));
1772 m.pointer_vertex = vertex3f;
1773 m.tex[0] = R_GetTexture(glosstexture);
1774 m.pointer_texcoord[0] = texcoord2f;
1777 m.texcubemap[1] = R_GetTexture(lightcubemap);
1779 m.pointer_texcoord3f[1] = vertex3f;
1780 m.texmatrix[1] = *matrix_modeltolight;
1782 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1783 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1789 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1790 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1791 VectorScale(lightcolor, colorscale, color2);
1792 GL_LockArrays(0, numverts);
1793 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1795 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1796 R_Mesh_Draw(numverts, numtriangles, elements);
1798 c_rt_lighttris += numtriangles;
1800 GL_LockArrays(0, 0);
1805 if (lighting & LIGHTING_DIFFUSE)
1807 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1808 VectorScale(lightcolor, r_shadow_lightintensityscale.value, color2);
1809 memset(&m, 0, sizeof(m));
1810 m.pointer_vertex = vertex3f;
1811 m.pointer_color = varray_color4f;
1812 m.tex[0] = R_GetTexture(basetexture);
1813 m.pointer_texcoord[0] = texcoord2f;
1814 if (r_textureunits.integer >= 2)
1817 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1819 m.pointer_texcoord3f[1] = vertex3f;
1820 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1822 m.pointer_texcoord[1] = varray_texcoord2f[1];
1823 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1825 if (r_textureunits.integer >= 3)
1827 // Geforce3/Radeon class but not using dot3
1828 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1830 m.pointer_texcoord3f[2] = vertex3f;
1831 m.texmatrix[2] = *matrix_modeltoattenuationz;
1833 m.pointer_texcoord[2] = varray_texcoord2f[2];
1834 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationz);
1839 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1841 color[0] = bound(0, color2[0], 1);
1842 color[1] = bound(0, color2[1], 1);
1843 color[2] = bound(0, color2[2], 1);
1844 if (r_textureunits.integer >= 3)
1845 R_Shadow_VertexShading(numverts, vertex3f, normal3f, color, matrix_modeltolight);
1846 else if (r_textureunits.integer >= 2)
1847 R_Shadow_VertexShadingWithZAttenuation(numverts, vertex3f, normal3f, color, matrix_modeltolight);
1849 R_Shadow_VertexShadingWithXYZAttenuation(numverts, vertex3f, normal3f, color, matrix_modeltolight);
1850 GL_LockArrays(0, numverts);
1851 R_Mesh_Draw(numverts, numtriangles, elements);
1852 GL_LockArrays(0, 0);
1854 c_rt_lighttris += numtriangles;
1860 void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
1864 R_RTLight_Uncompile(rtlight);
1865 memset(rtlight, 0, sizeof(*rtlight));
1867 VectorCopy(light->origin, rtlight->shadoworigin);
1868 VectorCopy(light->color, rtlight->color);
1869 rtlight->radius = light->radius;
1870 //rtlight->cullradius = rtlight->radius;
1871 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
1872 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
1873 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
1874 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
1875 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
1876 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
1877 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
1878 rtlight->cubemapname[0] = 0;
1879 if (light->cubemapname[0])
1880 strcpy(rtlight->cubemapname, light->cubemapname);
1881 else if (light->cubemapnum > 0)
1882 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
1883 rtlight->shadow = light->shadow;
1884 rtlight->corona = light->corona;
1885 rtlight->style = light->style;
1886 rtlight->isstatic = isstatic;
1887 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
1888 // ConcatScale won't work here because this needs to scale rotate and
1889 // translate, not just rotate
1890 scale = 1.0f / rtlight->radius;
1891 for (k = 0;k < 3;k++)
1892 for (j = 0;j < 4;j++)
1893 rtlight->matrix_worldtolight.m[k][j] *= scale;
1894 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationxyz, &matrix_attenuationxyz, &rtlight->matrix_worldtolight);
1895 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationz, &matrix_attenuationz, &rtlight->matrix_worldtolight);
1897 rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
1898 rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
1899 VectorScale(rtlight->color, rtlight->radius * d_lightstylevalue[rtlight->style] * 0.125f, rtlight->lightmap_light);
1900 rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
1903 // compiles rtlight geometry
1904 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
1905 void R_RTLight_Compile(rtlight_t *rtlight)
1907 int shadowmeshes, shadowtris, lightmeshes, lighttris, numclusters, numsurfaces;
1908 entity_render_t *ent = &cl_entities[0].render;
1909 model_t *model = ent->model;
1911 // compile the light
1912 rtlight->compiled = true;
1913 rtlight->static_numclusters = 0;
1914 rtlight->static_numclusterpvsbytes = 0;
1915 rtlight->static_clusterlist = NULL;
1916 rtlight->static_clusterpvs = NULL;
1917 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
1918 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
1919 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
1920 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
1921 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
1922 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
1924 if (model && model->GetLightInfo)
1926 // this variable directs the DrawShadowVolume and DrawLight code to capture into the mesh chain instead of rendering
1927 r_shadow_compilingrtlight = rtlight;
1928 R_Shadow_EnlargeClusterBuffer(model->brush.num_pvsclusters);
1929 R_Shadow_EnlargeSurfaceBuffer(model->nummodelsurfaces);
1930 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);
1933 rtlight->static_numclusters = numclusters;
1934 rtlight->static_numclusterpvsbytes = (model->brush.num_pvsclusters + 7) >> 3;
1935 rtlight->static_clusterlist = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
1936 rtlight->static_clusterpvs = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusterpvsbytes);
1937 memcpy(rtlight->static_clusterlist, r_shadow_buffer_clusterlist, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
1938 memcpy(rtlight->static_clusterpvs, r_shadow_buffer_clusterpvs, rtlight->static_numclusterpvsbytes);
1940 if (model->DrawShadowVolume && rtlight->shadow)
1942 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
1943 model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
1944 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_shadow, false, false);
1946 if (model->DrawLight)
1948 rtlight->static_meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true);
1949 model->DrawLight(ent, rtlight->shadoworigin, vec3_origin, rtlight->radius, vec3_origin, &r_identitymatrix, &r_identitymatrix, &r_identitymatrix, NULL, numsurfaces, r_shadow_buffer_surfacelist);
1950 rtlight->static_meshchain_light = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_light, true, false);
1952 // switch back to rendering when DrawShadowVolume or DrawLight is called
1953 r_shadow_compilingrtlight = NULL;
1957 // use smallest available cullradius - box radius or light radius
1958 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
1959 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
1963 if (rtlight->static_meshchain_shadow)
1966 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
1969 shadowtris += mesh->numtriangles;
1975 if (rtlight->static_meshchain_light)
1978 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
1981 lighttris += mesh->numtriangles;
1985 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);
1988 void R_RTLight_Uncompile(rtlight_t *rtlight)
1990 if (rtlight->compiled)
1992 if (rtlight->static_meshchain_shadow)
1993 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
1994 rtlight->static_meshchain_shadow = NULL;
1995 if (rtlight->static_meshchain_light)
1996 Mod_ShadowMesh_Free(rtlight->static_meshchain_light);
1997 rtlight->static_meshchain_light = NULL;
1998 if (rtlight->static_clusterlist)
1999 Mem_Free(rtlight->static_clusterlist);
2000 rtlight->static_clusterlist = NULL;
2001 if (rtlight->static_clusterpvs)
2002 Mem_Free(rtlight->static_clusterpvs);
2003 rtlight->static_clusterpvs = NULL;
2004 rtlight->static_numclusters = 0;
2005 rtlight->static_numclusterpvsbytes = 0;
2006 rtlight->compiled = false;
2010 void R_Shadow_UncompileWorldLights(void)
2013 for (light = r_shadow_worldlightchain;light;light = light->next)
2014 R_RTLight_Uncompile(&light->rtlight);
2017 void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes)
2020 entity_render_t *ent;
2022 vec3_t relativelightorigin, relativeeyeorigin, lightcolor, lightcolor2;
2023 rtexture_t *cubemaptexture;
2024 matrix4x4_t matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz;
2025 int numclusters, numsurfaces;
2026 int *clusterlist, *surfacelist;
2028 vec3_t cullmins, cullmaxs;
2032 // loading is done before visibility checks because loading should happen
2033 // all at once at the start of a level, not when it stalls gameplay.
2034 // (especially important to benchmarks)
2035 if (rtlight->isstatic && !rtlight->compiled && r_shadow_staticworldlights.integer)
2036 R_RTLight_Compile(rtlight);
2037 if (rtlight->cubemapname[0])
2038 cubemaptexture = R_Shadow_Cubemap(rtlight->cubemapname);
2040 cubemaptexture = NULL;
2042 cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2043 cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2044 cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2045 cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2046 cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2047 cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2048 if (d_lightstylevalue[rtlight->style] <= 0)
2055 if (rtlight->compiled && r_shadow_staticworldlights.integer)
2057 // compiled light, world available and can receive realtime lighting
2058 // retrieve cluster information
2059 numclusters = rtlight->static_numclusters;
2060 clusterlist = rtlight->static_clusterlist;
2061 clusterpvs = rtlight->static_clusterpvs;
2062 VectorCopy(rtlight->cullmins, cullmins);
2063 VectorCopy(rtlight->cullmaxs, cullmaxs);
2065 else if (cl.worldmodel && cl.worldmodel->GetLightInfo)
2067 // dynamic light, world available and can receive realtime lighting
2068 // if the light box is offscreen, skip it right away
2069 if (R_CullBox(cullmins, cullmaxs))
2071 // calculate lit surfaces and clusters
2072 R_Shadow_EnlargeClusterBuffer(cl.worldmodel->brush.num_pvsclusters);
2073 R_Shadow_EnlargeSurfaceBuffer(cl.worldmodel->nummodelsurfaces);
2074 cl.worldmodel->GetLightInfo(&cl_entities[0].render, rtlight->shadoworigin, rtlight->radius, cullmins, cullmaxs, r_shadow_buffer_clusterlist, r_shadow_buffer_clusterpvs, &numclusters, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces);
2075 clusterlist = r_shadow_buffer_clusterlist;
2076 clusterpvs = r_shadow_buffer_clusterpvs;
2077 surfacelist = r_shadow_buffer_surfacelist;
2079 // if the reduced cluster bounds are offscreen, skip it
2080 if (R_CullBox(cullmins, cullmaxs))
2082 // check if light is illuminating any visible clusters
2085 for (i = 0;i < numclusters;i++)
2086 if (CHECKPVSBIT(r_pvsbits, clusterlist[i]))
2088 if (i == numclusters)
2091 // set up a scissor rectangle for this light
2092 if (R_Shadow_ScissorForBBox(cullmins, cullmaxs))
2095 f = d_lightstylevalue[rtlight->style] * (1.0f / 256.0f);
2096 VectorScale(rtlight->color, f, lightcolor);
2098 if (rtlight->selected)
2100 f = 2 + sin(realtime * M_PI * 4.0);
2101 VectorScale(lightcolor, f, lightcolor);
2105 shadow = rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows);
2107 if (shadow && (gl_stencil || visiblevolumes))
2109 if (!visiblevolumes)
2110 R_Shadow_Stage_ShadowVolumes();
2111 ent = &cl_entities[0].render;
2112 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2114 memset(&m, 0, sizeof(m));
2115 R_Mesh_Matrix(&ent->matrix);
2116 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2118 m.pointer_vertex = mesh->vertex3f;
2120 GL_LockArrays(0, mesh->numverts);
2121 if (r_shadowstage == SHADOWSTAGE_STENCIL)
2123 // decrement stencil if frontface is behind depthbuffer
2124 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2125 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2126 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2127 c_rtcached_shadowmeshes++;
2128 c_rtcached_shadowtris += mesh->numtriangles;
2129 // increment stencil if backface is behind depthbuffer
2130 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2131 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2133 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2134 c_rtcached_shadowmeshes++;
2135 c_rtcached_shadowtris += mesh->numtriangles;
2136 GL_LockArrays(0, 0);
2141 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2142 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, numsurfaces, surfacelist);
2144 if (r_drawentities.integer)
2146 for (i = 0;i < r_refdef.numentities;i++)
2148 ent = r_refdef.entities[i];
2150 if (r_shadow_cull.integer)
2152 if (!BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs))
2154 if (cl.worldmodel != NULL && cl.worldmodel->brush.BoxTouchingPVS != NULL && !cl.worldmodel->brush.BoxTouchingPVS(cl.worldmodel, clusterpvs, ent->mins, ent->maxs))
2157 if (!(ent->flags & RENDER_SHADOW) || !ent->model || !ent->model->DrawShadowVolume)
2159 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2160 // light emitting entities should not cast their own shadow
2161 if (VectorLength2(relativelightorigin) < 0.1)
2163 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, ent->model->nummodelsurfaces, ent->model->surfacelist);
2168 if (!visiblevolumes)
2170 R_Shadow_Stage_Light(shadow && gl_stencil);
2172 ent = &cl_entities[0].render;
2173 if (ent->model && ent->model->DrawLight && (ent->flags & RENDER_LIGHT))
2175 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2176 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2177 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2178 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2179 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2180 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2182 R_Mesh_Matrix(&ent->matrix);
2183 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2184 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);
2187 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, numsurfaces, surfacelist);
2189 if (r_drawentities.integer)
2191 for (i = 0;i < r_refdef.numentities;i++)
2193 ent = r_refdef.entities[i];
2194 // can't draw transparent entity lighting here because
2195 // transparent meshes are deferred for later
2196 if (ent->visframe == r_framecount && BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs) && ent->model && ent->model->DrawLight && (ent->flags & (RENDER_LIGHT | RENDER_TRANSPARENT)) == RENDER_LIGHT)
2198 VectorScale(lightcolor, ent->alpha, lightcolor2);
2199 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2200 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2201 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2202 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2203 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2204 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor2, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, ent->model->nummodelsurfaces, ent->model->surfacelist);
2211 void R_ShadowVolumeLighting(int visiblevolumes)
2217 if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2218 R_Shadow_EditLights_Reload_f();
2222 memset(&m, 0, sizeof(m));
2225 GL_BlendFunc(GL_ONE, GL_ONE);
2226 GL_DepthMask(false);
2227 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
2228 qglDisable(GL_CULL_FACE);
2229 GL_Color(0.0, 0.0125, 0.1, 1);
2232 R_Shadow_Stage_Begin();
2235 if (r_shadow_debuglight.integer >= 0)
2237 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2238 if (lnum == r_shadow_debuglight.integer)
2239 R_DrawRTLight(&light->rtlight, visiblevolumes);
2242 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2243 R_DrawRTLight(&light->rtlight, visiblevolumes);
2246 for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
2247 R_DrawRTLight(&light->rtlight, visiblevolumes);
2251 qglEnable(GL_CULL_FACE);
2252 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
2255 R_Shadow_Stage_End();
2258 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2259 typedef struct suffixinfo_s
2262 qboolean flipx, flipy, flipdiagonal;
2265 static suffixinfo_t suffix[3][6] =
2268 {"px", false, false, false},
2269 {"nx", false, false, false},
2270 {"py", false, false, false},
2271 {"ny", false, false, false},
2272 {"pz", false, false, false},
2273 {"nz", false, false, false}
2276 {"posx", false, false, false},
2277 {"negx", false, false, false},
2278 {"posy", false, false, false},
2279 {"negy", false, false, false},
2280 {"posz", false, false, false},
2281 {"negz", false, false, false}
2284 {"rt", true, false, true},
2285 {"lf", false, true, true},
2286 {"ft", true, true, false},
2287 {"bk", false, false, false},
2288 {"up", true, false, true},
2289 {"dn", true, false, true}
2293 static int componentorder[4] = {0, 1, 2, 3};
2295 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2297 int i, j, cubemapsize;
2298 qbyte *cubemappixels, *image_rgba;
2299 rtexture_t *cubemaptexture;
2301 // must start 0 so the first loadimagepixels has no requested width/height
2303 cubemappixels = NULL;
2304 cubemaptexture = NULL;
2305 // keep trying different suffix groups (posx, px, rt) until one loads
2306 for (j = 0;j < 3 && !cubemappixels;j++)
2308 // load the 6 images in the suffix group
2309 for (i = 0;i < 6;i++)
2311 // generate an image name based on the base and and suffix
2312 snprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2314 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2316 // an image loaded, make sure width and height are equal
2317 if (image_width == image_height)
2319 // if this is the first image to load successfully, allocate the cubemap memory
2320 if (!cubemappixels && image_width >= 1)
2322 cubemapsize = image_width;
2323 // note this clears to black, so unavailable sides are black
2324 cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2326 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2328 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);
2331 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2333 Mem_Free(image_rgba);
2337 // if a cubemap loaded, upload it
2340 if (!r_shadow_filters_texturepool)
2341 r_shadow_filters_texturepool = R_AllocTexturePool();
2342 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
2343 Mem_Free(cubemappixels);
2347 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
2348 for (j = 0;j < 3;j++)
2349 for (i = 0;i < 6;i++)
2350 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2351 Con_Print(" and was unable to find any of them.\n");
2353 return cubemaptexture;
2356 rtexture_t *R_Shadow_Cubemap(const char *basename)
2359 for (i = 0;i < numcubemaps;i++)
2360 if (!strcasecmp(cubemaps[i].basename, basename))
2361 return cubemaps[i].texture;
2362 if (i >= MAX_CUBEMAPS)
2365 strcpy(cubemaps[i].basename, basename);
2366 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
2367 return cubemaps[i].texture;
2370 void R_Shadow_FreeCubemaps(void)
2373 R_FreeTexturePool(&r_shadow_filters_texturepool);
2376 dlight_t *R_Shadow_NewWorldLight(void)
2379 light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
2380 light->next = r_shadow_worldlightchain;
2381 r_shadow_worldlightchain = light;
2385 void R_Shadow_UpdateWorldLight(dlight_t *light, vec3_t origin, vec3_t angles, vec3_t color, vec_t radius, vec_t corona, int style, int shadowenable, const char *cubemapname)
2387 VectorCopy(origin, light->origin);
2388 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
2389 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
2390 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
2391 light->color[0] = max(color[0], 0);
2392 light->color[1] = max(color[1], 0);
2393 light->color[2] = max(color[2], 0);
2394 light->radius = max(radius, 0);
2395 light->style = style;
2396 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
2398 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
2401 light->shadow = shadowenable;
2402 light->corona = corona;
2405 strlcpy(light->cubemapname, cubemapname, strlen(light->cubemapname));
2406 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
2408 R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
2411 void R_Shadow_FreeWorldLight(dlight_t *light)
2413 dlight_t **lightpointer;
2414 R_RTLight_Uncompile(&light->rtlight);
2415 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
2416 if (*lightpointer != light)
2417 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
2418 *lightpointer = light->next;
2422 void R_Shadow_ClearWorldLights(void)
2424 while (r_shadow_worldlightchain)
2425 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
2426 r_shadow_selectedlight = NULL;
2427 R_Shadow_FreeCubemaps();
2430 void R_Shadow_SelectLight(dlight_t *light)
2432 if (r_shadow_selectedlight)
2433 r_shadow_selectedlight->selected = false;
2434 r_shadow_selectedlight = light;
2435 if (r_shadow_selectedlight)
2436 r_shadow_selectedlight->selected = true;
2439 void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
2441 float scale = r_editlights_cursorgrid.value * 0.5f;
2442 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);
2445 void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
2448 const dlight_t *light;
2451 if (light->selected)
2452 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
2455 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);
2458 void R_Shadow_DrawLightSprites(void)
2464 for (i = 0;i < 5;i++)
2466 lighttextures[i] = NULL;
2467 if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1))))
2468 lighttextures[i] = pic->tex;
2471 for (light = r_shadow_worldlightchain;light;light = light->next)
2472 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, ((int) light) % 5);
2473 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
2476 void R_Shadow_SelectLightInView(void)
2478 float bestrating, rating, temp[3];
2479 dlight_t *best, *light;
2482 for (light = r_shadow_worldlightchain;light;light = light->next)
2484 VectorSubtract(light->origin, r_vieworigin, temp);
2485 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
2488 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
2489 if (bestrating < rating && CL_TraceLine(light->origin, r_vieworigin, NULL, NULL, true, NULL, SUPERCONTENTS_SOLID) == 1.0f)
2491 bestrating = rating;
2496 R_Shadow_SelectLight(best);
2499 void R_Shadow_LoadWorldLights(void)
2501 int n, a, style, shadow;
2502 char name[MAX_QPATH], cubemapname[MAX_QPATH], *lightsstring, *s, *t;
2503 float origin[3], radius, color[3], angles[3], corona;
2504 if (cl.worldmodel == NULL)
2506 Con_Print("No map loaded.\n");
2509 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2510 strlcat (name, ".rtlights", sizeof (name));
2511 lightsstring = FS_LoadFile(name, tempmempool, false);
2521 for (;COM_Parse(t, true) && strcmp(
2522 if (COM_Parse(t, true))
2524 if (com_token[0] == '!')
2527 origin[0] = atof(com_token+1);
2530 origin[0] = atof(com_token);
2535 while (*s && *s != '\n')
2541 // check for modifier flags
2547 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]);
2549 VectorClear(angles);
2552 if (a < 9 || !strcmp(cubemapname, "\"\""))
2557 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);
2560 VectorScale(color, r_editlights_rtlightscolorscale.value, color);
2561 radius *= r_editlights_rtlightssizescale.value;
2562 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname);
2567 Con_Printf("invalid rtlights file \"%s\"\n", name);
2568 Mem_Free(lightsstring);
2572 void R_Shadow_SaveWorldLights(void)
2575 int bufchars, bufmaxchars;
2577 char name[MAX_QPATH];
2579 if (!r_shadow_worldlightchain)
2581 if (cl.worldmodel == NULL)
2583 Con_Print("No map loaded.\n");
2586 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2587 strlcat (name, ".rtlights", sizeof (name));
2588 bufchars = bufmaxchars = 0;
2590 for (light = r_shadow_worldlightchain;light;light = light->next)
2592 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]);
2593 if (bufchars + (int) strlen(line) > bufmaxchars)
2595 bufmaxchars = bufchars + strlen(line) + 2048;
2597 buf = Mem_Alloc(r_shadow_mempool, bufmaxchars);
2601 memcpy(buf, oldbuf, bufchars);
2607 memcpy(buf + bufchars, line, strlen(line));
2608 bufchars += strlen(line);
2612 FS_WriteFile(name, buf, bufchars);
2617 void R_Shadow_LoadLightsFile(void)
2620 char name[MAX_QPATH], *lightsstring, *s, *t;
2621 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
2622 if (cl.worldmodel == NULL)
2624 Con_Print("No map loaded.\n");
2627 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2628 strlcat (name, ".lights", sizeof (name));
2629 lightsstring = FS_LoadFile(name, tempmempool, false);
2637 while (*s && *s != '\n')
2642 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);
2646 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);
2649 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
2650 radius = bound(15, radius, 4096);
2651 VectorScale(color, (2.0f / (8388608.0f)), color);
2652 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL);
2657 Con_Printf("invalid lights file \"%s\"\n", name);
2658 Mem_Free(lightsstring);
2662 // tyrlite/hmap2 light types in the delay field
2663 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
2665 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
2667 int entnum, style, islight, skin, pflags, effects, type, n;
2668 char key[256], value[1024];
2669 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
2672 if (cl.worldmodel == NULL)
2674 Con_Print("No map loaded.\n");
2677 data = cl.worldmodel->brush.entities;
2680 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
2682 type = LIGHTTYPE_MINUSX;
2683 origin[0] = origin[1] = origin[2] = 0;
2684 originhack[0] = originhack[1] = originhack[2] = 0;
2685 angles[0] = angles[1] = angles[2] = 0;
2686 color[0] = color[1] = color[2] = 1;
2687 light[0] = light[1] = light[2] = 1;light[3] = 300;
2688 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
2698 if (!COM_ParseToken(&data, false))
2700 if (com_token[0] == '}')
2701 break; // end of entity
2702 if (com_token[0] == '_')
2703 strcpy(key, com_token + 1);
2705 strcpy(key, com_token);
2706 while (key[strlen(key)-1] == ' ') // remove trailing spaces
2707 key[strlen(key)-1] = 0;
2708 if (!COM_ParseToken(&data, false))
2710 strcpy(value, com_token);
2712 // now that we have the key pair worked out...
2713 if (!strcmp("light", key))
2715 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
2719 light[0] = vec[0] * (1.0f / 256.0f);
2720 light[1] = vec[0] * (1.0f / 256.0f);
2721 light[2] = vec[0] * (1.0f / 256.0f);
2727 light[0] = vec[0] * (1.0f / 255.0f);
2728 light[1] = vec[1] * (1.0f / 255.0f);
2729 light[2] = vec[2] * (1.0f / 255.0f);
2733 else if (!strcmp("delay", key))
2735 else if (!strcmp("origin", key))
2736 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
2737 else if (!strcmp("angle", key))
2738 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
2739 else if (!strcmp("angles", key))
2740 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
2741 else if (!strcmp("color", key))
2742 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
2743 else if (!strcmp("wait", key))
2744 fadescale = atof(value);
2745 else if (!strcmp("classname", key))
2747 if (!strncmp(value, "light", 5))
2750 if (!strcmp(value, "light_fluoro"))
2755 overridecolor[0] = 1;
2756 overridecolor[1] = 1;
2757 overridecolor[2] = 1;
2759 if (!strcmp(value, "light_fluorospark"))
2764 overridecolor[0] = 1;
2765 overridecolor[1] = 1;
2766 overridecolor[2] = 1;
2768 if (!strcmp(value, "light_globe"))
2773 overridecolor[0] = 1;
2774 overridecolor[1] = 0.8;
2775 overridecolor[2] = 0.4;
2777 if (!strcmp(value, "light_flame_large_yellow"))
2782 overridecolor[0] = 1;
2783 overridecolor[1] = 0.5;
2784 overridecolor[2] = 0.1;
2786 if (!strcmp(value, "light_flame_small_yellow"))
2791 overridecolor[0] = 1;
2792 overridecolor[1] = 0.5;
2793 overridecolor[2] = 0.1;
2795 if (!strcmp(value, "light_torch_small_white"))
2800 overridecolor[0] = 1;
2801 overridecolor[1] = 0.5;
2802 overridecolor[2] = 0.1;
2804 if (!strcmp(value, "light_torch_small_walltorch"))
2809 overridecolor[0] = 1;
2810 overridecolor[1] = 0.5;
2811 overridecolor[2] = 0.1;
2815 else if (!strcmp("style", key))
2816 style = atoi(value);
2817 else if (cl.worldmodel->type == mod_brushq3)
2819 if (!strcmp("scale", key))
2820 lightscale = atof(value);
2821 if (!strcmp("fade", key))
2822 fadescale = atof(value);
2824 else if (!strcmp("skin", key))
2825 skin = (int)atof(value);
2826 else if (!strcmp("pflags", key))
2827 pflags = (int)atof(value);
2828 else if (!strcmp("effects", key))
2829 effects = (int)atof(value);
2833 if (lightscale <= 0)
2837 if (color[0] == color[1] && color[0] == color[2])
2839 color[0] *= overridecolor[0];
2840 color[1] *= overridecolor[1];
2841 color[2] *= overridecolor[2];
2843 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
2844 color[0] = color[0] * light[0];
2845 color[1] = color[1] * light[1];
2846 color[2] = color[2] * light[2];
2849 case LIGHTTYPE_MINUSX:
2851 case LIGHTTYPE_RECIPX:
2853 VectorScale(color, (1.0f / 16.0f), color);
2855 case LIGHTTYPE_RECIPXX:
2857 VectorScale(color, (1.0f / 16.0f), color);
2860 case LIGHTTYPE_NONE:
2864 case LIGHTTYPE_MINUSXX:
2867 VectorAdd(origin, originhack, origin);
2869 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, (pflags & PFLAGS_CORONA) != 0, style, (pflags & PFLAGS_NOSHADOW) == 0, skin >= 16 ? va("cubemaps/%i", skin) : NULL);
2874 void R_Shadow_SetCursorLocationForView(void)
2876 vec_t dist, push, frac;
2877 vec3_t dest, endpos, normal;
2878 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
2879 frac = CL_TraceLine(r_vieworigin, dest, endpos, normal, true, NULL, SUPERCONTENTS_SOLID);
2882 dist = frac * r_editlights_cursordistance.value;
2883 push = r_editlights_cursorpushback.value;
2887 VectorMA(endpos, push, r_viewforward, endpos);
2888 VectorMA(endpos, r_editlights_cursorpushoff.value, normal, endpos);
2890 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2891 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2892 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2895 void R_Shadow_UpdateWorldLightSelection(void)
2897 if (r_editlights.integer)
2899 R_Shadow_SetCursorLocationForView();
2900 R_Shadow_SelectLightInView();
2901 R_Shadow_DrawLightSprites();
2904 R_Shadow_SelectLight(NULL);
2907 void R_Shadow_EditLights_Clear_f(void)
2909 R_Shadow_ClearWorldLights();
2912 void R_Shadow_EditLights_Reload_f(void)
2916 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
2917 R_Shadow_ClearWorldLights();
2918 R_Shadow_LoadWorldLights();
2919 if (r_shadow_worldlightchain == NULL)
2921 R_Shadow_LoadLightsFile();
2922 if (r_shadow_worldlightchain == NULL)
2923 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
2927 void R_Shadow_EditLights_Save_f(void)
2931 R_Shadow_SaveWorldLights();
2934 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
2936 R_Shadow_ClearWorldLights();
2937 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
2940 void R_Shadow_EditLights_ImportLightsFile_f(void)
2942 R_Shadow_ClearWorldLights();
2943 R_Shadow_LoadLightsFile();
2946 void R_Shadow_EditLights_Spawn_f(void)
2949 if (!r_editlights.integer)
2951 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
2954 if (Cmd_Argc() != 1)
2956 Con_Print("r_editlights_spawn does not take parameters\n");
2959 color[0] = color[1] = color[2] = 1;
2960 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL);
2963 void R_Shadow_EditLights_Edit_f(void)
2965 vec3_t origin, angles, color;
2966 vec_t radius, corona;
2968 char cubemapname[1024];
2969 if (!r_editlights.integer)
2971 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
2974 if (!r_shadow_selectedlight)
2976 Con_Print("No selected light.\n");
2979 VectorCopy(r_shadow_selectedlight->origin, origin);
2980 VectorCopy(r_shadow_selectedlight->angles, angles);
2981 VectorCopy(r_shadow_selectedlight->color, color);
2982 radius = r_shadow_selectedlight->radius;
2983 style = r_shadow_selectedlight->style;
2984 if (r_shadow_selectedlight->cubemapname)
2985 strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
2988 shadows = r_shadow_selectedlight->shadow;
2989 corona = r_shadow_selectedlight->corona;
2990 if (!strcmp(Cmd_Argv(1), "origin"))
2992 if (Cmd_Argc() != 5)
2994 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
2997 origin[0] = atof(Cmd_Argv(2));
2998 origin[1] = atof(Cmd_Argv(3));
2999 origin[2] = atof(Cmd_Argv(4));
3001 else if (!strcmp(Cmd_Argv(1), "originx"))
3003 if (Cmd_Argc() != 3)
3005 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3008 origin[0] = atof(Cmd_Argv(2));
3010 else if (!strcmp(Cmd_Argv(1), "originy"))
3012 if (Cmd_Argc() != 3)
3014 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3017 origin[1] = atof(Cmd_Argv(2));
3019 else if (!strcmp(Cmd_Argv(1), "originz"))
3021 if (Cmd_Argc() != 3)
3023 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3026 origin[2] = atof(Cmd_Argv(2));
3028 else if (!strcmp(Cmd_Argv(1), "move"))
3030 if (Cmd_Argc() != 5)
3032 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3035 origin[0] += atof(Cmd_Argv(2));
3036 origin[1] += atof(Cmd_Argv(3));
3037 origin[2] += atof(Cmd_Argv(4));
3039 else if (!strcmp(Cmd_Argv(1), "movex"))
3041 if (Cmd_Argc() != 3)
3043 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3046 origin[0] += atof(Cmd_Argv(2));
3048 else if (!strcmp(Cmd_Argv(1), "movey"))
3050 if (Cmd_Argc() != 3)
3052 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3055 origin[1] += atof(Cmd_Argv(2));
3057 else if (!strcmp(Cmd_Argv(1), "movez"))
3059 if (Cmd_Argc() != 3)
3061 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3064 origin[2] += atof(Cmd_Argv(2));
3066 else if (!strcmp(Cmd_Argv(1), "angles"))
3068 if (Cmd_Argc() != 5)
3070 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3073 angles[0] = atof(Cmd_Argv(2));
3074 angles[1] = atof(Cmd_Argv(3));
3075 angles[2] = atof(Cmd_Argv(4));
3077 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3079 if (Cmd_Argc() != 3)
3081 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3084 angles[0] = atof(Cmd_Argv(2));
3086 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3088 if (Cmd_Argc() != 3)
3090 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3093 angles[1] = atof(Cmd_Argv(2));
3095 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3097 if (Cmd_Argc() != 3)
3099 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3102 angles[2] = atof(Cmd_Argv(2));
3104 else if (!strcmp(Cmd_Argv(1), "color"))
3106 if (Cmd_Argc() != 5)
3108 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3111 color[0] = atof(Cmd_Argv(2));
3112 color[1] = atof(Cmd_Argv(3));
3113 color[2] = atof(Cmd_Argv(4));
3115 else if (!strcmp(Cmd_Argv(1), "radius"))
3117 if (Cmd_Argc() != 3)
3119 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3122 radius = atof(Cmd_Argv(2));
3124 else if (!strcmp(Cmd_Argv(1), "style"))
3126 if (Cmd_Argc() != 3)
3128 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3131 style = atoi(Cmd_Argv(2));
3133 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3137 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3140 if (Cmd_Argc() == 3)
3141 strcpy(cubemapname, Cmd_Argv(2));
3145 else if (!strcmp(Cmd_Argv(1), "shadows"))
3147 if (Cmd_Argc() != 3)
3149 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3152 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3154 else if (!strcmp(Cmd_Argv(1), "corona"))
3156 if (Cmd_Argc() != 3)
3158 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3161 corona = atof(Cmd_Argv(2));
3165 Con_Print("usage: r_editlights_edit [property] [value]\n");
3166 Con_Print("Selected light's properties:\n");
3167 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3168 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3169 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3170 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3171 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3172 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3173 Con_Printf("Shadows: %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3174 Con_Printf("Cubemap: %s\n", r_shadow_selectedlight->cubemapname);
3177 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname);
3180 void R_Shadow_EditLights_EditAll_f(void)
3184 if (!r_editlights.integer)
3186 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
3190 for (light = r_shadow_worldlightchain;light;light = light->next)
3192 R_Shadow_SelectLight(light);
3193 R_Shadow_EditLights_Edit_f();
3197 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3201 if (!r_editlights.integer)
3205 sprintf(temp, "Cursor %f %f %f", r_editlights_cursorlocation[0], r_editlights_cursorlocation[1], r_editlights_cursorlocation[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3206 if (r_shadow_selectedlight == NULL)
3208 sprintf(temp, "Light properties");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3209 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;
3210 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;
3211 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;
3212 sprintf(temp, "Radius %f", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3213 sprintf(temp, "Corona %f", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3214 sprintf(temp, "Style %i", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3215 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;
3216 sprintf(temp, "Cubemap %s", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3219 void R_Shadow_EditLights_ToggleShadow_f(void)
3221 if (!r_editlights.integer)
3223 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3226 if (!r_shadow_selectedlight)
3228 Con_Print("No selected light.\n");
3231 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, 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);
3234 void R_Shadow_EditLights_ToggleCorona_f(void)
3236 if (!r_editlights.integer)
3238 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3241 if (!r_shadow_selectedlight)
3243 Con_Print("No selected light.\n");
3246 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, r_shadow_selectedlight->origin, r_shadow_selectedlight->angles, r_shadow_selectedlight->color, r_shadow_selectedlight->radius, !r_shadow_selectedlight->corona, r_shadow_selectedlight->style, r_shadow_selectedlight->shadow, r_shadow_selectedlight->cubemapname);
3249 void R_Shadow_EditLights_Remove_f(void)
3251 if (!r_editlights.integer)
3253 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
3256 if (!r_shadow_selectedlight)
3258 Con_Print("No selected light.\n");
3261 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3262 r_shadow_selectedlight = NULL;
3265 void R_Shadow_EditLights_Help_f(void)
3268 "Documentation on r_editlights system:\n"
3270 "r_editlights : enable/disable editing mode\n"
3271 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
3272 "r_editlights_cursorpushback : push back cursor this far from surface\n"
3273 "r_editlights_cursorpushoff : push cursor off surface this far\n"
3274 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
3275 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
3276 "r_editlights_rtlightssizescale : imported rtlight size scaling\n"
3277 "r_editlights_rtlightscolorscale : imported rtlight color scaling\n"
3279 "r_editlights_help : this help\n"
3280 "r_editlights_clear : remove all lights\n"
3281 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
3282 "r_editlights_save : save to .rtlights file\n"
3283 "r_editlights_spawn : create a light with default settings\n"
3284 "r_editlights_edit command : edit selected light - more documentation below\n"
3285 "r_editlights_remove : remove selected light\n"
3286 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
3287 "r_editlights_importlightentitiesfrommap : reload light entities\n"
3288 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
3290 "origin x y z : set light location\n"
3291 "originx x: set x component of light location\n"
3292 "originy y: set y component of light location\n"
3293 "originz z: set z component of light location\n"
3294 "move x y z : adjust light location\n"
3295 "movex x: adjust x component of light location\n"
3296 "movey y: adjust y component of light location\n"
3297 "movez z: adjust z component of light location\n"
3298 "angles x y z : set light angles\n"
3299 "anglesx x: set x component of light angles\n"
3300 "anglesy y: set y component of light angles\n"
3301 "anglesz z: set z component of light angles\n"
3302 "color r g b : set color of light (can be brighter than 1 1 1)\n"
3303 "radius radius : set radius (size) of light\n"
3304 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
3305 "cubemap basename : set filter cubemap of light (not yet supported)\n"
3306 "shadows 1/0 : turn on/off shadows\n"
3307 "corona n : set corona intensity\n"
3308 "<nothing> : print light properties to console\n"
3312 void R_Shadow_EditLights_CopyInfo_f(void)
3314 if (!r_editlights.integer)
3316 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
3319 if (!r_shadow_selectedlight)
3321 Con_Print("No selected light.\n");
3324 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
3325 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
3326 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
3327 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
3328 if (r_shadow_selectedlight->cubemapname)
3329 strcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname);
3331 r_shadow_bufferlight.cubemapname[0] = 0;
3332 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
3333 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
3336 void R_Shadow_EditLights_PasteInfo_f(void)
3338 if (!r_editlights.integer)
3340 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
3343 if (!r_shadow_selectedlight)
3345 Con_Print("No selected light.\n");
3348 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, r_shadow_selectedlight->origin, r_shadow_bufferlight.angles, r_shadow_bufferlight.color, r_shadow_bufferlight.radius, r_shadow_bufferlight.corona, r_shadow_bufferlight.style, r_shadow_bufferlight.shadow, r_shadow_bufferlight.cubemapname);
3351 void R_Shadow_EditLights_Init(void)
3353 Cvar_RegisterVariable(&r_editlights);
3354 Cvar_RegisterVariable(&r_editlights_cursordistance);
3355 Cvar_RegisterVariable(&r_editlights_cursorpushback);
3356 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
3357 Cvar_RegisterVariable(&r_editlights_cursorgrid);
3358 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
3359 Cvar_RegisterVariable(&r_editlights_rtlightssizescale);
3360 Cvar_RegisterVariable(&r_editlights_rtlightscolorscale);
3361 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
3362 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
3363 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
3364 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
3365 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
3366 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
3367 Cmd_AddCommand("r_editlights_editall", R_Shadow_EditLights_EditAll_f);
3368 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
3369 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
3370 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
3371 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
3372 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);
3373 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f);
3374 Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f);