3 Terminology: Stencil Shadow Volume (sometimes called Stencil Shadows)
4 An extrusion of the lit faces, beginning at the original geometry and ending
5 further from the light source than the original geometry (presumably at least
6 as far as the light's radius, if the light has a radius at all), capped at
7 both front and back to avoid any problems (extrusion from dark faces also
8 works but has a different set of problems)
10 This is rendered using Carmack's Reverse technique, in which backfaces behind
11 zbuffer (zfail) increment the stencil, and frontfaces behind zbuffer (zfail)
12 decrement the stencil, the result is a stencil value of zero where shadows
13 did not intersect the visible geometry, suitable as a stencil mask for
14 rendering lighting everywhere but shadow.
16 In our case we use a biased stencil clear of 128 to avoid requiring the
17 stencil wrap extension (but probably should support it), and to address
18 Creative's patent on this sort of technology we also draw the frontfaces
19 first, and backfaces second (decrement, increment).
22 This algorithm may be covered by Creative's patent (US Patent #6384822)
23 on Carmack's Reverse paper (which I have not read), however that patent
24 seems to be about drawing a stencil shadow from a model in an otherwise
25 unshadowed scene, where as realtime lighting technology draws light where
30 Terminology: Stencil Light Volume (sometimes called Light Volumes)
31 Similar to a Stencil Shadow Volume, but inverted; rather than containing the
32 areas in shadow it contanis the areas in light, this can only be built
33 quickly for certain limited cases (such as portal visibility from a point),
34 but is quite useful for some effects (sunlight coming from sky polygons is
35 one possible example, translucent occluders is another example).
39 Terminology: Optimized Stencil Shadow Volume
40 A Stencil Shadow Volume that has been processed sufficiently to ensure it has
41 no duplicate coverage of areas (no need to shadow an area twice), often this
42 greatly improves performance but is an operation too costly to use on moving
43 lights (however completely optimal Stencil Light Volumes can be constructed
48 Terminology: Per Pixel Lighting (sometimes abbreviated PPL)
49 Per pixel evaluation of lighting equations, at a bare minimum this involves
50 DOT3 shading of diffuse lighting (per pixel dotproduct of negated incidence
51 vector and surface normal, using a texture of the surface bumps, called a
52 NormalMap) if supported by hardware; in our case there is support for cards
53 which are incapable of DOT3, the quality is quite poor however. Additionally
54 it is desirable to have specular evaluation per pixel, per vertex
55 normalization of specular halfangle vectors causes noticable distortion but
56 is unavoidable on hardware without GL_ARB_fragment_program.
60 Terminology: Normalization CubeMap
61 A cubemap containing normalized dot3-encoded (vectors of length 1 or less
62 encoded as RGB colors) for any possible direction, this technique allows per
63 pixel calculation of incidence vector for per pixel lighting purposes, which
64 would not otherwise be possible per pixel without GL_ARB_fragment_program.
68 Terminology: 2D Attenuation Texturing
69 A very crude approximation of light attenuation with distance which results
70 in cylindrical light shapes which fade vertically as a streak (some games
71 such as Doom3 allow this to be rotated to be less noticable in specific
72 cases), the technique is simply modulating lighting by two 2D textures (which
73 can be the same) on different axes of projection (XY and Z, typically), this
74 is the best technique available without 3D Attenuation Texturing or
75 GL_ARB_fragment_program technology.
79 Terminology: 3D Attenuation Texturing
80 A slightly crude approximation of light attenuation with distance, its flaws
81 are limited radius and resolution (performance tradeoffs).
85 Terminology: 3D Attenuation-Normalization Texturing
86 A 3D Attenuation Texture merged with a Normalization CubeMap, by making the
87 vectors shorter the lighting becomes darker, a very effective optimization of
88 diffuse lighting if 3D Attenuation Textures are already used.
92 Terminology: Light Cubemap Filtering
93 A technique for modeling non-uniform light distribution according to
94 direction, for example projecting a stained glass window image onto a wall,
95 this is done by texturing the lighting with a cubemap.
99 Terminology: Light Projection Filtering
100 A technique for modeling shadowing of light passing through translucent
101 surfaces, allowing stained glass windows and other effects to be done more
102 elegantly than possible with Light Cubemap Filtering by applying an occluder
103 texture to the lighting combined with a stencil light volume to limit the lit
104 area (this allows evaluating multiple translucent occluders in a scene).
108 Terminology: Doom3 Lighting
109 A combination of Stencil Shadow Volume, Per Pixel Lighting, Normalization
110 CubeMap, 2D Attenuation Texturing, and Light Filtering, as demonstrated by
111 the (currently upcoming) game Doom3.
114 #include "quakedef.h"
115 #include "r_shadow.h"
116 #include "cl_collision.h"
120 extern void R_Shadow_EditLights_Init(void);
122 #define SHADOWSTAGE_NONE 0
123 #define SHADOWSTAGE_STENCIL 1
124 #define SHADOWSTAGE_LIGHT 2
125 #define SHADOWSTAGE_STENCILTWOSIDE 3
127 int r_shadowstage = SHADOWSTAGE_NONE;
129 mempool_t *r_shadow_mempool;
131 int maxshadowelements;
145 int r_shadow_buffer_numclusterpvsbytes;
146 qbyte *r_shadow_buffer_clusterpvs;
147 int *r_shadow_buffer_clusterlist;
149 int r_shadow_buffer_numsurfacepvsbytes;
150 qbyte *r_shadow_buffer_surfacepvs;
151 int *r_shadow_buffer_surfacelist;
153 rtexturepool_t *r_shadow_texturepool;
154 rtexture_t *r_shadow_normalcubetexture;
155 rtexture_t *r_shadow_attenuation2dtexture;
156 rtexture_t *r_shadow_attenuation3dtexture;
157 rtexture_t *r_shadow_blankbumptexture;
158 rtexture_t *r_shadow_blankglosstexture;
159 rtexture_t *r_shadow_blankwhitetexture;
161 // lights are reloaded when this changes
162 char r_shadow_mapname[MAX_QPATH];
164 // used only for light filters (cubemaps)
165 rtexturepool_t *r_shadow_filters_texturepool;
167 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0"};
168 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4"};
169 cvar_t r_shadow_cull = {0, "r_shadow_cull", "1"};
170 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1"};
171 cvar_t r_shadow_gloss = {0, "r_shadow_gloss", "1"};
172 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.25"};
173 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1"};
174 cvar_t r_shadow_lightattenuationpower = {0, "r_shadow_lightattenuationpower", "0.5"};
175 cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1"};
176 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1"};
177 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1"};
178 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000"};
179 cvar_t r_shadow_realtime_dlight = {0, "r_shadow_realtime_dlight", "1"};
180 cvar_t r_shadow_realtime_dlight_shadows = {0, "r_shadow_realtime_dlight_shadows", "0"};
181 cvar_t r_shadow_realtime_world = {0, "r_shadow_realtime_world", "0"};
182 cvar_t r_shadow_realtime_world_dlightshadows = {0, "r_shadow_realtime_world_dlightshadows", "1"};
183 cvar_t r_shadow_realtime_world_lightmaps = {0, "r_shadow_realtime_world_lightmaps", "0"};
184 cvar_t r_shadow_realtime_world_shadows = {0, "r_shadow_realtime_world_shadows", "1"};
185 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1"};
186 cvar_t r_shadow_shadow_polygonfactor = {0, "r_shadow_shadow_polygonfactor", "0"};
187 cvar_t r_shadow_shadow_polygonoffset = {0, "r_shadow_shadow_polygonoffset", "1"};
188 cvar_t r_shadow_singlepassvolumegeneration = {0, "r_shadow_singlepassvolumegeneration", "1"};
189 cvar_t r_shadow_staticworldlights = {0, "r_shadow_staticworldlights", "1"};
190 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1"};
191 cvar_t r_shadow_visiblevolumes = {0, "r_shadow_visiblevolumes", "0"};
192 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1"};
193 cvar_t r_editlights = {0, "r_editlights", "0"};
194 cvar_t r_editlights_cursordistance = {0, "r_editlights_distance", "1024"};
195 cvar_t r_editlights_cursorpushback = {0, "r_editlights_pushback", "0"};
196 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_pushoff", "4"};
197 cvar_t r_editlights_cursorgrid = {0, "r_editlights_grid", "4"};
198 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "0.8"};
199 cvar_t r_editlights_rtlightssizescale = {CVAR_SAVE, "r_editlights_rtlightssizescale", "0.7"};
200 cvar_t r_editlights_rtlightscolorscale = {CVAR_SAVE, "r_editlights_rtlightscolorscale", "2"};
202 int c_rt_lights, c_rt_clears, c_rt_scissored;
203 int c_rt_shadowmeshes, c_rt_shadowtris, c_rt_lightmeshes, c_rt_lighttris;
204 int c_rtcached_shadowmeshes, c_rtcached_shadowtris;
206 float r_shadow_attenpower, r_shadow_attenscale;
208 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++)
530 t = shadowmarktris[i];
531 shadowmark[t] = shadowmarkcount;
532 e = inelement3i + t * 3;
533 // make sure the vertices are created
534 for (j = 0;j < 3;j++)
536 if (vertexupdate[e[j]] != vertexupdatenum)
538 vertexupdate[e[j]] = vertexupdatenum;
539 vertexremap[e[j]] = outvertices;
540 VectorSubtract(invertex3f + e[j] * 3, projectorigin, temp);
541 f = projectdistance / VectorLength(temp);
542 VectorCopy(invertex3f + e[j] * 3, outvertex3f);
543 VectorMA(projectorigin, f, temp, (outvertex3f + 3));
548 // output the front and back triangles
549 outelement3i[0] = vertexremap[e[0]];
550 outelement3i[1] = vertexremap[e[1]];
551 outelement3i[2] = vertexremap[e[2]];
552 outelement3i[3] = vertexremap[e[2]] + 1;
553 outelement3i[4] = vertexremap[e[1]] + 1;
554 outelement3i[5] = vertexremap[e[0]] + 1;
559 for (i = 0;i < numshadowmarktris;i++)
561 t = shadowmarktris[i];
562 e = inelement3i + t * 3;
563 n = inneighbor3i + t * 3;
564 // output the sides (facing outward from this triangle)
565 if (shadowmark[n[0]] != shadowmarkcount)
567 vr[0] = vertexremap[e[0]];
568 vr[1] = vertexremap[e[1]];
569 outelement3i[0] = vr[1];
570 outelement3i[1] = vr[0];
571 outelement3i[2] = vr[0] + 1;
572 outelement3i[3] = vr[1];
573 outelement3i[4] = vr[0] + 1;
574 outelement3i[5] = vr[1] + 1;
578 if (shadowmark[n[1]] != shadowmarkcount)
580 vr[1] = vertexremap[e[1]];
581 vr[2] = vertexremap[e[2]];
582 outelement3i[0] = vr[2];
583 outelement3i[1] = vr[1];
584 outelement3i[2] = vr[1] + 1;
585 outelement3i[3] = vr[2];
586 outelement3i[4] = vr[1] + 1;
587 outelement3i[5] = vr[2] + 1;
591 if (shadowmark[n[2]] != shadowmarkcount)
593 vr[0] = vertexremap[e[0]];
594 vr[2] = vertexremap[e[2]];
595 outelement3i[0] = vr[0];
596 outelement3i[1] = vr[2];
597 outelement3i[2] = vr[2] + 1;
598 outelement3i[3] = vr[0];
599 outelement3i[4] = vr[2] + 1;
600 outelement3i[5] = vr[0] + 1;
606 *outnumvertices = outvertices;
610 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)
613 if (projectdistance < 0.1)
615 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
618 if (!numverts || !nummarktris)
620 // make sure shadowelements is big enough for this volume
621 if (maxshadowelements < nummarktris * 24)
622 R_Shadow_ResizeShadowElements((nummarktris + 256) * 24);
623 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, varray_vertex3f2, projectorigin, projectdistance, nummarktris, marktris);
624 R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements);
627 void R_Shadow_VolumeFromBox(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, float projectdistance, const vec3_t mins, const vec3_t maxs)
632 // check which triangles are facing the , and then output
633 // triangle elements and vertices... by clever use of elements we
634 // can construct the whole shadow from the unprojected vertices and
635 // the projected vertices
637 // identify lit faces within the bounding box
638 R_Shadow_PrepareShadowMark(numtris);
639 for (i = 0;i < numtris;i++)
641 v[0] = invertex3f + elements[i*3+0] * 3;
642 v[1] = invertex3f + elements[i*3+1] * 3;
643 v[2] = invertex3f + elements[i*3+2] * 3;
644 if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]) && maxs[0] > min(v[0][0], min(v[1][0], v[2][0])) && mins[0] < max(v[0][0], max(v[1][0], v[2][0])) && maxs[1] > min(v[0][1], min(v[1][1], v[2][1])) && mins[1] < max(v[0][1], max(v[1][1], v[2][1])) && maxs[2] > min(v[0][2], min(v[1][2], v[2][2])) && mins[2] < max(v[0][2], max(v[1][2], v[2][2])))
645 shadowmarklist[numshadowmark++] = i;
647 R_Shadow_VolumeFromList(numverts, numtris, invertex3f, elements, neighbors, projectorigin, projectdistance, numshadowmark, shadowmarklist);
650 void R_Shadow_VolumeFromSphere(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, float projectdistance, float radius)
653 mins[0] = projectorigin[0] - radius;
654 mins[1] = projectorigin[1] - radius;
655 mins[2] = projectorigin[2] - radius;
656 maxs[0] = projectorigin[0] + radius;
657 maxs[1] = projectorigin[1] + radius;
658 maxs[2] = projectorigin[2] + radius;
659 R_Shadow_VolumeFromBox(numverts, numtris, invertex3f, elements, neighbors, projectorigin, projectdistance, mins, maxs);
662 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
665 if (r_shadow_compilingrtlight)
667 // if we're compiling an rtlight, capture the mesh
668 Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
671 memset(&m, 0, sizeof(m));
672 m.pointer_vertex = vertex3f;
674 GL_LockArrays(0, numvertices);
675 if (r_shadowstage == SHADOWSTAGE_STENCIL)
677 // increment stencil if backface is behind depthbuffer
678 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
679 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
680 R_Mesh_Draw(numvertices, numtriangles, element3i);
682 c_rt_shadowtris += numtriangles;
683 // decrement stencil if frontface is behind depthbuffer
684 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
685 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
687 R_Mesh_Draw(numvertices, numtriangles, element3i);
689 c_rt_shadowtris += numtriangles;
693 static void R_Shadow_MakeTextures(void)
695 int x, y, z, d, side;
696 float v[3], s, t, intensity;
698 R_FreeTexturePool(&r_shadow_texturepool);
699 r_shadow_texturepool = R_AllocTexturePool();
700 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
701 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
703 #define ATTEN2DSIZE 64
704 #define ATTEN3DSIZE 32
705 data = Mem_Alloc(tempmempool, max(6*NORMSIZE*NORMSIZE*4, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4)));
710 r_shadow_blankbumptexture = R_LoadTexture2D(r_shadow_texturepool, "blankbump", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
715 r_shadow_blankglosstexture = R_LoadTexture2D(r_shadow_texturepool, "blankgloss", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
720 r_shadow_blankwhitetexture = R_LoadTexture2D(r_shadow_texturepool, "blankwhite", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
721 if (gl_texturecubemap)
723 for (side = 0;side < 6;side++)
725 for (y = 0;y < NORMSIZE;y++)
727 for (x = 0;x < NORMSIZE;x++)
729 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
730 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
764 intensity = 127.0f / sqrt(DotProduct(v, v));
765 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+0] = 128.0f + intensity * v[0];
766 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+1] = 128.0f + intensity * v[1];
767 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+2] = 128.0f + intensity * v[2];
768 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+3] = 255;
772 r_shadow_normalcubetexture = R_LoadTextureCubeMap(r_shadow_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
775 r_shadow_normalcubetexture = NULL;
776 for (y = 0;y < ATTEN2DSIZE;y++)
778 for (x = 0;x < ATTEN2DSIZE;x++)
780 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
781 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
783 intensity = 1.0f - sqrt(DotProduct(v, v));
785 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
786 d = bound(0, intensity, 255);
787 data[(y*ATTEN2DSIZE+x)*4+0] = d;
788 data[(y*ATTEN2DSIZE+x)*4+1] = d;
789 data[(y*ATTEN2DSIZE+x)*4+2] = d;
790 data[(y*ATTEN2DSIZE+x)*4+3] = d;
793 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
794 if (r_shadow_texture3d.integer)
796 for (z = 0;z < ATTEN3DSIZE;z++)
798 for (y = 0;y < ATTEN3DSIZE;y++)
800 for (x = 0;x < ATTEN3DSIZE;x++)
802 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
803 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
804 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
805 intensity = 1.0f - sqrt(DotProduct(v, v));
807 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
808 d = bound(0, intensity, 255);
809 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
810 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
811 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
812 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
816 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
821 void R_Shadow_ValidateCvars(void)
823 if (r_shadow_texture3d.integer && !gl_texture3d)
824 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
825 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
826 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
829 void R_Shadow_Stage_Begin(void)
833 R_Shadow_ValidateCvars();
835 if (!r_shadow_attenuation2dtexture
836 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
837 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
838 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
839 R_Shadow_MakeTextures();
841 memset(&m, 0, sizeof(m));
842 GL_BlendFunc(GL_ONE, GL_ZERO);
846 GL_Color(0, 0, 0, 1);
847 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
848 qglEnable(GL_CULL_FACE);
849 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
850 r_shadowstage = SHADOWSTAGE_NONE;
852 c_rt_lights = c_rt_clears = c_rt_scissored = 0;
853 c_rt_shadowmeshes = c_rt_shadowtris = c_rt_lightmeshes = c_rt_lighttris = 0;
854 c_rtcached_shadowmeshes = c_rtcached_shadowtris = 0;
857 void R_Shadow_Stage_ShadowVolumes(void)
860 memset(&m, 0, sizeof(m));
862 GL_Color(1, 1, 1, 1);
863 GL_ColorMask(0, 0, 0, 0);
864 GL_BlendFunc(GL_ONE, GL_ZERO);
867 qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
868 //if (r_shadow_shadow_polygonoffset.value != 0)
870 // qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
871 // qglEnable(GL_POLYGON_OFFSET_FILL);
874 // qglDisable(GL_POLYGON_OFFSET_FILL);
875 qglDepthFunc(GL_LESS);
876 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
877 qglEnable(GL_STENCIL_TEST);
878 qglStencilFunc(GL_ALWAYS, 128, ~0);
879 if (gl_ext_stenciltwoside.integer)
881 r_shadowstage = SHADOWSTAGE_STENCILTWOSIDE;
882 qglDisable(GL_CULL_FACE);
883 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
884 qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
886 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
887 qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
889 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
893 r_shadowstage = SHADOWSTAGE_STENCIL;
894 qglEnable(GL_CULL_FACE);
896 // this is changed by every shadow render so its value here is unimportant
897 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
899 GL_Clear(GL_STENCIL_BUFFER_BIT);
901 // LordHavoc note: many shadow volumes reside entirely inside the world
902 // (that is to say they are entirely bounded by their lit surfaces),
903 // which can be optimized by handling things as an inverted light volume,
904 // with the shadow boundaries of the world being simulated by an altered
905 // (129) bias to stencil clearing on such lights
906 // FIXME: generate inverted light volumes for use as shadow volumes and
907 // optimize for them as noted above
910 void R_Shadow_Stage_Light(int shadowtest)
913 memset(&m, 0, sizeof(m));
915 GL_BlendFunc(GL_ONE, GL_ONE);
918 qglPolygonOffset(0, 0);
919 //qglDisable(GL_POLYGON_OFFSET_FILL);
920 GL_Color(1, 1, 1, 1);
921 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
922 qglDepthFunc(GL_EQUAL);
923 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
924 qglEnable(GL_CULL_FACE);
926 qglEnable(GL_STENCIL_TEST);
928 qglDisable(GL_STENCIL_TEST);
929 if (gl_support_stenciltwoside)
930 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
932 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
933 // only draw light where this geometry was already rendered AND the
934 // stencil is 128 (values other than this mean shadow)
935 qglStencilFunc(GL_EQUAL, 128, ~0);
936 r_shadowstage = SHADOWSTAGE_LIGHT;
940 void R_Shadow_Stage_End(void)
943 memset(&m, 0, sizeof(m));
945 GL_BlendFunc(GL_ONE, GL_ZERO);
948 qglPolygonOffset(0, 0);
949 //qglDisable(GL_POLYGON_OFFSET_FILL);
950 GL_Color(1, 1, 1, 1);
951 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
952 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
953 qglDepthFunc(GL_LEQUAL);
954 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
955 qglDisable(GL_STENCIL_TEST);
956 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
957 if (gl_support_stenciltwoside)
958 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
960 qglStencilFunc(GL_ALWAYS, 128, ~0);
961 r_shadowstage = SHADOWSTAGE_NONE;
964 int R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
966 int i, ix1, iy1, ix2, iy2;
967 float x1, y1, x2, y2, x, y, f;
970 if (!r_shadow_scissor.integer)
972 // if view is inside the box, just say yes it's visible
973 if (BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
975 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
978 for (i = 0;i < 3;i++)
980 if (r_viewforward[i] >= 0)
991 f = DotProduct(r_viewforward, r_vieworigin) + 1;
992 if (DotProduct(r_viewforward, v2) <= f)
994 // entirely behind nearclip plane
997 if (DotProduct(r_viewforward, v) >= f)
999 // entirely infront of nearclip plane
1000 x1 = y1 = x2 = y2 = 0;
1001 for (i = 0;i < 8;i++)
1003 v[0] = (i & 1) ? mins[0] : maxs[0];
1004 v[1] = (i & 2) ? mins[1] : maxs[1];
1005 v[2] = (i & 4) ? mins[2] : maxs[2];
1007 GL_TransformToScreen(v, v2);
1008 //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]);
1027 // clipped by nearclip plane
1028 // this is nasty and crude...
1029 // create viewspace bbox
1030 for (i = 0;i < 8;i++)
1032 v[0] = ((i & 1) ? mins[0] : maxs[0]) - r_vieworigin[0];
1033 v[1] = ((i & 2) ? mins[1] : maxs[1]) - r_vieworigin[1];
1034 v[2] = ((i & 4) ? mins[2] : maxs[2]) - r_vieworigin[2];
1035 v2[0] = -DotProduct(v, r_viewleft);
1036 v2[1] = DotProduct(v, r_viewup);
1037 v2[2] = DotProduct(v, r_viewforward);
1040 if (smins[0] > v2[0]) smins[0] = v2[0];
1041 if (smaxs[0] < v2[0]) smaxs[0] = v2[0];
1042 if (smins[1] > v2[1]) smins[1] = v2[1];
1043 if (smaxs[1] < v2[1]) smaxs[1] = v2[1];
1044 if (smins[2] > v2[2]) smins[2] = v2[2];
1045 if (smaxs[2] < v2[2]) smaxs[2] = v2[2];
1049 smins[0] = smaxs[0] = v2[0];
1050 smins[1] = smaxs[1] = v2[1];
1051 smins[2] = smaxs[2] = v2[2];
1054 // now we have a bbox in viewspace
1055 // clip it to the view plane
1058 // return true if that culled the box
1059 if (smins[2] >= smaxs[2])
1061 // ok some of it is infront of the view, transform each corner back to
1062 // worldspace and then to screenspace and make screen rect
1063 // initialize these variables just to avoid compiler warnings
1064 x1 = y1 = x2 = y2 = 0;
1065 for (i = 0;i < 8;i++)
1067 v2[0] = (i & 1) ? smins[0] : smaxs[0];
1068 v2[1] = (i & 2) ? smins[1] : smaxs[1];
1069 v2[2] = (i & 4) ? smins[2] : smaxs[2];
1070 v[0] = v2[0] * -r_viewleft[0] + v2[1] * r_viewup[0] + v2[2] * r_viewforward[0] + r_vieworigin[0];
1071 v[1] = v2[0] * -r_viewleft[1] + v2[1] * r_viewup[1] + v2[2] * r_viewforward[1] + r_vieworigin[1];
1072 v[2] = v2[0] * -r_viewleft[2] + v2[1] * r_viewup[2] + v2[2] * r_viewforward[2] + r_vieworigin[2];
1074 GL_TransformToScreen(v, v2);
1075 //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]);
1092 // this code doesn't handle boxes with any points behind view properly
1093 x1 = 1000;x2 = -1000;
1094 y1 = 1000;y2 = -1000;
1095 for (i = 0;i < 8;i++)
1097 v[0] = (i & 1) ? mins[0] : maxs[0];
1098 v[1] = (i & 2) ? mins[1] : maxs[1];
1099 v[2] = (i & 4) ? mins[2] : maxs[2];
1101 GL_TransformToScreen(v, v2);
1102 //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]);
1120 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1121 if (ix1 < r_view_x) ix1 = r_view_x;
1122 if (iy1 < r_view_y) iy1 = r_view_y;
1123 if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
1124 if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
1125 if (ix2 <= ix1 || iy2 <= iy1)
1127 // set up the scissor rectangle
1128 GL_Scissor(ix1, vid.realheight - iy2, ix2 - ix1, iy2 - iy1);
1129 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1130 //qglEnable(GL_SCISSOR_TEST);
1135 static void R_Shadow_VertexShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1137 float *color4f = varray_color4f;
1138 float dist, dot, intensity, v[3], n[3];
1139 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1141 Matrix4x4_Transform(m, vertex3f, v);
1142 if ((dist = DotProduct(v, v)) < 1)
1144 Matrix4x4_Transform3x3(m, normal3f, n);
1145 if ((dot = DotProduct(n, v)) > 0)
1148 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1149 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1150 VectorScale(lightcolor, intensity, color4f);
1155 VectorClear(color4f);
1161 VectorClear(color4f);
1167 static void R_Shadow_VertexShadingWithZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1169 float *color4f = varray_color4f;
1170 float dist, dot, intensity, v[3], n[3];
1171 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1173 Matrix4x4_Transform(m, vertex3f, v);
1174 if ((dist = fabs(v[2])) < 1)
1176 Matrix4x4_Transform3x3(m, normal3f, n);
1177 if ((dot = DotProduct(n, v)) > 0)
1179 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1180 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1181 VectorScale(lightcolor, intensity, color4f);
1186 VectorClear(color4f);
1192 VectorClear(color4f);
1198 static void R_Shadow_VertexShading(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1200 float *color4f = varray_color4f;
1201 float dot, intensity, v[3], n[3];
1202 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1204 Matrix4x4_Transform(m, vertex3f, v);
1205 Matrix4x4_Transform3x3(m, normal3f, n);
1206 if ((dot = DotProduct(n, v)) > 0)
1208 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1209 VectorScale(lightcolor, intensity, color4f);
1214 VectorClear(color4f);
1220 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1221 #define USETEXMATRIX
1223 #ifndef USETEXMATRIX
1224 // this should be done in a texture matrix or vertex program when possible, but here's code to do it manually
1225 // if hardware texcoord manipulation is not available (or not suitable, this would really benefit from 3DNow! or SSE
1226 static void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1230 tc3f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1231 tc3f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1232 tc3f[2] = vertex3f[0] * matrix->m[2][0] + vertex3f[1] * matrix->m[2][1] + vertex3f[2] * matrix->m[2][2] + matrix->m[2][3];
1239 static void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1243 tc2f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1244 tc2f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1252 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)
1256 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1258 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1259 // the cubemap normalizes this for us
1260 out3f[0] = DotProduct(svector3f, lightdir);
1261 out3f[1] = DotProduct(tvector3f, lightdir);
1262 out3f[2] = DotProduct(normal3f, lightdir);
1266 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)
1269 float lightdir[3], eyedir[3], halfdir[3];
1270 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1272 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1273 VectorNormalizeFast(lightdir);
1274 VectorSubtract(vertex3f, relativeeyeorigin, eyedir);
1275 VectorNormalizeFast(eyedir);
1276 VectorAdd(lightdir, eyedir, halfdir);
1277 // the cubemap normalizes this for us
1278 out3f[0] = DotProduct(svector3f, halfdir);
1279 out3f[1] = DotProduct(tvector3f, halfdir);
1280 out3f[2] = DotProduct(normal3f, halfdir);
1284 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)
1287 float color[3], color2[3], colorscale;
1290 bumptexture = r_shadow_blankbumptexture;
1292 glosstexture = r_shadow_blankglosstexture;
1293 GL_DepthMask(false);
1295 if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
1297 if (lighting & LIGHTING_DIFFUSE)
1300 colorscale = r_shadow_lightintensityscale.value;
1301 // colorscale accounts for how much we multiply the brightness
1304 // mult is how many times the final pass of the lighting will be
1305 // performed to get more brightness than otherwise possible.
1307 // Limit mult to 64 for sanity sake.
1308 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1310 // 3/2 3D combine path (Geforce3, Radeon 8500)
1311 memset(&m, 0, sizeof(m));
1312 m.pointer_vertex = vertex3f;
1313 m.tex[0] = R_GetTexture(bumptexture);
1314 m.texcombinergb[0] = GL_REPLACE;
1315 m.pointer_texcoord[0] = texcoord2f;
1316 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1317 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1318 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1319 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1320 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1322 m.pointer_texcoord3f[2] = vertex3f;
1323 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
1325 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1326 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1329 GL_ColorMask(0,0,0,1);
1330 GL_BlendFunc(GL_ONE, GL_ZERO);
1331 GL_LockArrays(0, numverts);
1332 R_Mesh_Draw(numverts, numtriangles, elements);
1333 GL_LockArrays(0, 0);
1335 c_rt_lighttris += numtriangles;
1337 memset(&m, 0, sizeof(m));
1338 m.pointer_vertex = vertex3f;
1339 m.tex[0] = R_GetTexture(basetexture);
1340 m.pointer_texcoord[0] = texcoord2f;
1343 m.texcubemap[1] = R_GetTexture(lightcubemap);
1345 m.pointer_texcoord3f[1] = vertex3f;
1346 m.texmatrix[1] = *matrix_modeltolight;
1348 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1349 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1353 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap)
1355 // 1/2/2 3D combine path (original Radeon)
1356 memset(&m, 0, sizeof(m));
1357 m.pointer_vertex = vertex3f;
1358 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1360 m.pointer_texcoord3f[0] = vertex3f;
1361 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1363 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1364 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1367 GL_ColorMask(0,0,0,1);
1368 GL_BlendFunc(GL_ONE, GL_ZERO);
1369 GL_LockArrays(0, numverts);
1370 R_Mesh_Draw(numverts, numtriangles, elements);
1371 GL_LockArrays(0, 0);
1373 c_rt_lighttris += numtriangles;
1375 memset(&m, 0, sizeof(m));
1376 m.pointer_vertex = vertex3f;
1377 m.tex[0] = R_GetTexture(bumptexture);
1378 m.texcombinergb[0] = GL_REPLACE;
1379 m.pointer_texcoord[0] = texcoord2f;
1380 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1381 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1382 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1383 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1385 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1386 GL_LockArrays(0, numverts);
1387 R_Mesh_Draw(numverts, numtriangles, elements);
1388 GL_LockArrays(0, 0);
1390 c_rt_lighttris += numtriangles;
1392 memset(&m, 0, sizeof(m));
1393 m.pointer_vertex = vertex3f;
1394 m.tex[0] = R_GetTexture(basetexture);
1395 m.pointer_texcoord[0] = texcoord2f;
1398 m.texcubemap[1] = R_GetTexture(lightcubemap);
1400 m.pointer_texcoord3f[1] = vertex3f;
1401 m.texmatrix[1] = *matrix_modeltolight;
1403 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1404 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1408 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap)
1410 // 2/2 3D combine path (original Radeon)
1411 memset(&m, 0, sizeof(m));
1412 m.pointer_vertex = vertex3f;
1413 m.tex[0] = R_GetTexture(bumptexture);
1414 m.texcombinergb[0] = GL_REPLACE;
1415 m.pointer_texcoord[0] = texcoord2f;
1416 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1417 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1418 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1419 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1421 GL_ColorMask(0,0,0,1);
1422 GL_BlendFunc(GL_ONE, GL_ZERO);
1423 GL_LockArrays(0, numverts);
1424 R_Mesh_Draw(numverts, numtriangles, elements);
1425 GL_LockArrays(0, 0);
1427 c_rt_lighttris += numtriangles;
1429 memset(&m, 0, sizeof(m));
1430 m.pointer_vertex = vertex3f;
1431 m.tex[0] = R_GetTexture(basetexture);
1432 m.pointer_texcoord[0] = texcoord2f;
1433 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1435 m.pointer_texcoord3f[1] = vertex3f;
1436 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1438 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1439 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1442 else if (r_textureunits.integer >= 4)
1444 // 4/2 2D combine path (Geforce3, Radeon 8500)
1445 memset(&m, 0, sizeof(m));
1446 m.pointer_vertex = vertex3f;
1447 m.tex[0] = R_GetTexture(bumptexture);
1448 m.texcombinergb[0] = GL_REPLACE;
1449 m.pointer_texcoord[0] = texcoord2f;
1450 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1451 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1452 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1453 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1454 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1456 m.pointer_texcoord3f[2] = vertex3f;
1457 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
1459 m.pointer_texcoord[2] = varray_texcoord2f[2];
1460 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1462 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1464 m.pointer_texcoord3f[3] = vertex3f;
1465 m.texmatrix[3] = *matrix_modeltoattenuationz;
1467 m.pointer_texcoord[3] = varray_texcoord2f[3];
1468 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[3], numverts, vertex3f, matrix_modeltoattenuationz);
1471 GL_ColorMask(0,0,0,1);
1472 GL_BlendFunc(GL_ONE, GL_ZERO);
1473 GL_LockArrays(0, numverts);
1474 R_Mesh_Draw(numverts, numtriangles, elements);
1475 GL_LockArrays(0, 0);
1477 c_rt_lighttris += numtriangles;
1479 memset(&m, 0, sizeof(m));
1480 m.pointer_vertex = vertex3f;
1481 m.tex[0] = R_GetTexture(basetexture);
1482 m.pointer_texcoord[0] = texcoord2f;
1485 m.texcubemap[1] = R_GetTexture(lightcubemap);
1487 m.pointer_texcoord3f[1] = vertex3f;
1488 m.texmatrix[1] = *matrix_modeltolight;
1490 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1491 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1497 // 2/2/2 2D combine path (any dot3 card)
1498 memset(&m, 0, sizeof(m));
1499 m.pointer_vertex = vertex3f;
1500 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1502 m.pointer_texcoord3f[0] = vertex3f;
1503 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1505 m.pointer_texcoord[0] = varray_texcoord2f[0];
1506 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1508 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1510 m.pointer_texcoord3f[1] = vertex3f;
1511 m.texmatrix[1] = *matrix_modeltoattenuationz;
1513 m.pointer_texcoord[1] = varray_texcoord2f[1];
1514 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1517 GL_ColorMask(0,0,0,1);
1518 GL_BlendFunc(GL_ONE, GL_ZERO);
1519 GL_LockArrays(0, numverts);
1520 R_Mesh_Draw(numverts, numtriangles, elements);
1521 GL_LockArrays(0, 0);
1523 c_rt_lighttris += numtriangles;
1525 memset(&m, 0, sizeof(m));
1526 m.pointer_vertex = vertex3f;
1527 m.tex[0] = R_GetTexture(bumptexture);
1528 m.texcombinergb[0] = GL_REPLACE;
1529 m.pointer_texcoord[0] = texcoord2f;
1530 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1531 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1532 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1533 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1535 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1536 GL_LockArrays(0, numverts);
1537 R_Mesh_Draw(numverts, numtriangles, elements);
1538 GL_LockArrays(0, 0);
1540 c_rt_lighttris += numtriangles;
1542 memset(&m, 0, sizeof(m));
1543 m.pointer_vertex = vertex3f;
1544 m.tex[0] = R_GetTexture(basetexture);
1545 m.pointer_texcoord[0] = texcoord2f;
1548 m.texcubemap[1] = R_GetTexture(lightcubemap);
1550 m.pointer_texcoord3f[1] = vertex3f;
1551 m.texmatrix[1] = *matrix_modeltolight;
1553 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1554 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1558 // this final code is shared
1560 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1561 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1562 VectorScale(lightcolor, colorscale, color2);
1563 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1565 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1566 GL_LockArrays(0, numverts);
1567 R_Mesh_Draw(numverts, numtriangles, elements);
1568 GL_LockArrays(0, 0);
1570 c_rt_lighttris += numtriangles;
1573 if ((lighting & LIGHTING_SPECULAR) && (r_shadow_gloss.integer >= 2 || (r_shadow_gloss.integer >= 1 && glosstexture != r_shadow_blankglosstexture)))
1575 // FIXME: detect blendsquare!
1576 //if (gl_support_blendsquare)
1578 colorscale = r_shadow_lightintensityscale.value * r_shadow_glossintensity.value;
1579 if (glosstexture == r_shadow_blankglosstexture)
1580 colorscale *= r_shadow_gloss2intensity.value;
1582 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1584 // 2/0/0/1/2 3D combine blendsquare path
1585 memset(&m, 0, sizeof(m));
1586 m.pointer_vertex = vertex3f;
1587 m.tex[0] = R_GetTexture(bumptexture);
1588 m.pointer_texcoord[0] = texcoord2f;
1589 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1590 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1591 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1592 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1594 GL_ColorMask(0,0,0,1);
1595 // this squares the result
1596 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1597 GL_LockArrays(0, numverts);
1598 R_Mesh_Draw(numverts, numtriangles, elements);
1599 GL_LockArrays(0, 0);
1601 c_rt_lighttris += numtriangles;
1603 memset(&m, 0, sizeof(m));
1604 m.pointer_vertex = vertex3f;
1606 GL_LockArrays(0, numverts);
1607 // square alpha in framebuffer a few times to make it shiny
1608 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1609 // these comments are a test run through this math for intensity 0.5
1610 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1611 // 0.25 * 0.25 = 0.0625 (this is another pass)
1612 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1613 R_Mesh_Draw(numverts, numtriangles, elements);
1615 c_rt_lighttris += numtriangles;
1616 R_Mesh_Draw(numverts, numtriangles, elements);
1618 c_rt_lighttris += numtriangles;
1619 GL_LockArrays(0, 0);
1621 memset(&m, 0, sizeof(m));
1622 m.pointer_vertex = vertex3f;
1623 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1625 m.pointer_texcoord3f[0] = vertex3f;
1626 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1628 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1629 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1632 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1633 GL_LockArrays(0, numverts);
1634 R_Mesh_Draw(numverts, numtriangles, elements);
1635 GL_LockArrays(0, 0);
1637 c_rt_lighttris += numtriangles;
1639 memset(&m, 0, sizeof(m));
1640 m.pointer_vertex = vertex3f;
1641 m.tex[0] = R_GetTexture(glosstexture);
1642 m.pointer_texcoord[0] = texcoord2f;
1645 m.texcubemap[1] = R_GetTexture(lightcubemap);
1647 m.pointer_texcoord3f[1] = vertex3f;
1648 m.texmatrix[1] = *matrix_modeltolight;
1650 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1651 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1655 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1657 // 2/0/0/2 3D combine blendsquare path
1658 memset(&m, 0, sizeof(m));
1659 m.pointer_vertex = vertex3f;
1660 m.tex[0] = R_GetTexture(bumptexture);
1661 m.pointer_texcoord[0] = texcoord2f;
1662 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1663 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1664 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1665 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1667 GL_ColorMask(0,0,0,1);
1668 // this squares the result
1669 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1670 GL_LockArrays(0, numverts);
1671 R_Mesh_Draw(numverts, numtriangles, elements);
1672 GL_LockArrays(0, 0);
1674 c_rt_lighttris += numtriangles;
1676 memset(&m, 0, sizeof(m));
1677 m.pointer_vertex = vertex3f;
1679 GL_LockArrays(0, numverts);
1680 // square alpha in framebuffer a few times to make it shiny
1681 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1682 // these comments are a test run through this math for intensity 0.5
1683 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1684 // 0.25 * 0.25 = 0.0625 (this is another pass)
1685 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1686 R_Mesh_Draw(numverts, numtriangles, elements);
1688 c_rt_lighttris += numtriangles;
1689 R_Mesh_Draw(numverts, numtriangles, elements);
1691 c_rt_lighttris += numtriangles;
1692 GL_LockArrays(0, 0);
1694 memset(&m, 0, sizeof(m));
1695 m.pointer_vertex = vertex3f;
1696 m.tex[0] = R_GetTexture(glosstexture);
1697 m.pointer_texcoord[0] = texcoord2f;
1698 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1700 m.pointer_texcoord3f[1] = vertex3f;
1701 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1703 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1704 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1709 // 2/0/0/2/2 2D combine blendsquare path
1710 memset(&m, 0, sizeof(m));
1711 m.pointer_vertex = vertex3f;
1712 m.tex[0] = R_GetTexture(bumptexture);
1713 m.pointer_texcoord[0] = texcoord2f;
1714 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1715 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1716 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1717 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1719 GL_ColorMask(0,0,0,1);
1720 // this squares the result
1721 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1722 GL_LockArrays(0, numverts);
1723 R_Mesh_Draw(numverts, numtriangles, elements);
1724 GL_LockArrays(0, 0);
1726 c_rt_lighttris += numtriangles;
1728 memset(&m, 0, sizeof(m));
1729 m.pointer_vertex = vertex3f;
1731 GL_LockArrays(0, numverts);
1732 // square alpha in framebuffer a few times to make it shiny
1733 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1734 // these comments are a test run through this math for intensity 0.5
1735 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1736 // 0.25 * 0.25 = 0.0625 (this is another pass)
1737 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1738 R_Mesh_Draw(numverts, numtriangles, elements);
1740 c_rt_lighttris += numtriangles;
1741 R_Mesh_Draw(numverts, numtriangles, elements);
1743 c_rt_lighttris += numtriangles;
1744 GL_LockArrays(0, 0);
1746 memset(&m, 0, sizeof(m));
1747 m.pointer_vertex = vertex3f;
1748 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1750 m.pointer_texcoord3f[0] = vertex3f;
1751 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1753 m.pointer_texcoord[0] = varray_texcoord2f[0];
1754 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1756 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1758 m.pointer_texcoord3f[1] = vertex3f;
1759 m.texmatrix[1] = *matrix_modeltoattenuationz;
1761 m.pointer_texcoord[1] = varray_texcoord2f[1];
1762 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1765 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1766 GL_LockArrays(0, numverts);
1767 R_Mesh_Draw(numverts, numtriangles, elements);
1768 GL_LockArrays(0, 0);
1770 c_rt_lighttris += numtriangles;
1772 memset(&m, 0, sizeof(m));
1773 m.pointer_vertex = vertex3f;
1774 m.tex[0] = R_GetTexture(glosstexture);
1775 m.pointer_texcoord[0] = texcoord2f;
1778 m.texcubemap[1] = R_GetTexture(lightcubemap);
1780 m.pointer_texcoord3f[1] = vertex3f;
1781 m.texmatrix[1] = *matrix_modeltolight;
1783 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1784 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1790 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1791 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1792 VectorScale(lightcolor, colorscale, color2);
1793 GL_LockArrays(0, numverts);
1794 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1796 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1797 R_Mesh_Draw(numverts, numtriangles, elements);
1799 c_rt_lighttris += numtriangles;
1801 GL_LockArrays(0, 0);
1806 if (lighting & LIGHTING_DIFFUSE)
1808 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1809 VectorScale(lightcolor, r_shadow_lightintensityscale.value, color2);
1810 memset(&m, 0, sizeof(m));
1811 m.pointer_vertex = vertex3f;
1812 m.pointer_color = varray_color4f;
1813 m.tex[0] = R_GetTexture(basetexture);
1814 m.pointer_texcoord[0] = texcoord2f;
1815 if (r_textureunits.integer >= 2)
1818 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1820 m.pointer_texcoord3f[1] = vertex3f;
1821 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1823 m.pointer_texcoord[1] = varray_texcoord2f[1];
1824 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1826 if (r_textureunits.integer >= 3)
1828 // Geforce3/Radeon class but not using dot3
1829 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1831 m.pointer_texcoord3f[2] = vertex3f;
1832 m.texmatrix[2] = *matrix_modeltoattenuationz;
1834 m.pointer_texcoord[2] = varray_texcoord2f[2];
1835 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationz);
1840 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1842 color[0] = bound(0, color2[0], 1);
1843 color[1] = bound(0, color2[1], 1);
1844 color[2] = bound(0, color2[2], 1);
1845 if (r_textureunits.integer >= 3)
1846 R_Shadow_VertexShading(numverts, vertex3f, normal3f, color, matrix_modeltolight);
1847 else if (r_textureunits.integer >= 2)
1848 R_Shadow_VertexShadingWithZAttenuation(numverts, vertex3f, normal3f, color, matrix_modeltolight);
1850 R_Shadow_VertexShadingWithXYZAttenuation(numverts, vertex3f, normal3f, color, matrix_modeltolight);
1851 GL_LockArrays(0, numverts);
1852 R_Mesh_Draw(numverts, numtriangles, elements);
1853 GL_LockArrays(0, 0);
1855 c_rt_lighttris += numtriangles;
1861 void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
1865 R_RTLight_Uncompile(rtlight);
1866 memset(rtlight, 0, sizeof(*rtlight));
1868 VectorCopy(light->origin, rtlight->shadoworigin);
1869 VectorCopy(light->color, rtlight->color);
1870 rtlight->radius = light->radius;
1871 //rtlight->cullradius = rtlight->radius;
1872 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
1873 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
1874 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
1875 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
1876 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
1877 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
1878 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
1879 rtlight->cubemapname[0] = 0;
1880 if (light->cubemapname[0])
1881 strcpy(rtlight->cubemapname, light->cubemapname);
1882 else if (light->cubemapnum > 0)
1883 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
1884 rtlight->shadow = light->shadow;
1885 rtlight->corona = light->corona;
1886 rtlight->style = light->style;
1887 rtlight->isstatic = isstatic;
1888 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
1889 // ConcatScale won't work here because this needs to scale rotate and
1890 // translate, not just rotate
1891 scale = 1.0f / rtlight->radius;
1892 for (k = 0;k < 3;k++)
1893 for (j = 0;j < 4;j++)
1894 rtlight->matrix_worldtolight.m[k][j] *= scale;
1895 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationxyz, &matrix_attenuationxyz, &rtlight->matrix_worldtolight);
1896 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationz, &matrix_attenuationz, &rtlight->matrix_worldtolight);
1898 rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
1899 rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
1900 VectorScale(rtlight->color, rtlight->radius * d_lightstylevalue[rtlight->style] * 0.125f, rtlight->lightmap_light);
1901 rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
1904 // compiles rtlight geometry
1905 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
1906 void R_RTLight_Compile(rtlight_t *rtlight)
1908 int shadowmeshes, shadowtris, lightmeshes, lighttris, numclusters, numsurfaces;
1909 entity_render_t *ent = &cl_entities[0].render;
1910 model_t *model = ent->model;
1912 // compile the light
1913 rtlight->compiled = true;
1914 rtlight->static_numclusters = 0;
1915 rtlight->static_numclusterpvsbytes = 0;
1916 rtlight->static_clusterlist = NULL;
1917 rtlight->static_clusterpvs = NULL;
1918 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
1919 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
1920 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
1921 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
1922 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
1923 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
1925 if (model && model->GetLightInfo)
1927 // this variable directs the DrawShadowVolume and DrawLight code to capture into the mesh chain instead of rendering
1928 r_shadow_compilingrtlight = rtlight;
1929 R_Shadow_EnlargeClusterBuffer(model->brush.num_pvsclusters);
1930 R_Shadow_EnlargeSurfaceBuffer(model->nummodelsurfaces);
1931 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);
1934 rtlight->static_numclusters = numclusters;
1935 rtlight->static_numclusterpvsbytes = (model->brush.num_pvsclusters + 7) >> 3;
1936 rtlight->static_clusterlist = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
1937 rtlight->static_clusterpvs = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusterpvsbytes);
1938 memcpy(rtlight->static_clusterlist, r_shadow_buffer_clusterlist, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
1939 memcpy(rtlight->static_clusterpvs, r_shadow_buffer_clusterpvs, rtlight->static_numclusterpvsbytes);
1941 if (model->DrawShadowVolume && rtlight->shadow)
1943 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
1944 model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
1945 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_shadow, false, false);
1947 if (model->DrawLight)
1949 rtlight->static_meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true);
1950 model->DrawLight(ent, rtlight->shadoworigin, vec3_origin, rtlight->radius, vec3_origin, &r_identitymatrix, &r_identitymatrix, &r_identitymatrix, NULL, numsurfaces, r_shadow_buffer_surfacelist);
1951 rtlight->static_meshchain_light = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_light, true, false);
1953 // switch back to rendering when DrawShadowVolume or DrawLight is called
1954 r_shadow_compilingrtlight = NULL;
1958 // use smallest available cullradius - box radius or light radius
1959 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
1960 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
1964 if (rtlight->static_meshchain_shadow)
1967 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
1970 shadowtris += mesh->numtriangles;
1976 if (rtlight->static_meshchain_light)
1979 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
1982 lighttris += mesh->numtriangles;
1986 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);
1989 void R_RTLight_Uncompile(rtlight_t *rtlight)
1991 if (rtlight->compiled)
1993 if (rtlight->static_meshchain_shadow)
1994 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
1995 rtlight->static_meshchain_shadow = NULL;
1996 if (rtlight->static_meshchain_light)
1997 Mod_ShadowMesh_Free(rtlight->static_meshchain_light);
1998 rtlight->static_meshchain_light = NULL;
1999 if (rtlight->static_clusterlist)
2000 Mem_Free(rtlight->static_clusterlist);
2001 rtlight->static_clusterlist = NULL;
2002 if (rtlight->static_clusterpvs)
2003 Mem_Free(rtlight->static_clusterpvs);
2004 rtlight->static_clusterpvs = NULL;
2005 rtlight->static_numclusters = 0;
2006 rtlight->static_numclusterpvsbytes = 0;
2007 rtlight->compiled = false;
2011 void R_Shadow_UncompileWorldLights(void)
2014 for (light = r_shadow_worldlightchain;light;light = light->next)
2015 R_RTLight_Uncompile(&light->rtlight);
2018 void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes)
2021 entity_render_t *ent;
2023 vec3_t relativelightorigin, relativeeyeorigin, lightcolor;
2024 rtexture_t *cubemaptexture;
2025 matrix4x4_t matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz;
2026 int numclusters, numsurfaces;
2027 int *clusterlist, *surfacelist;
2029 vec3_t cullmins, cullmaxs;
2033 // loading is done before visibility checks because loading should happen
2034 // all at once at the start of a level, not when it stalls gameplay.
2035 // (especially important to benchmarks)
2036 if (rtlight->isstatic && !rtlight->compiled && r_shadow_staticworldlights.integer)
2037 R_RTLight_Compile(rtlight);
2038 if (rtlight->cubemapname[0])
2039 cubemaptexture = R_Shadow_Cubemap(rtlight->cubemapname);
2041 cubemaptexture = NULL;
2043 cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2044 cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2045 cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2046 cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2047 cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2048 cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2049 if (d_lightstylevalue[rtlight->style] <= 0)
2056 if (rtlight->compiled && r_shadow_staticworldlights.integer)
2058 // compiled light, world available and can receive realtime lighting
2059 // retrieve cluster information
2060 numclusters = rtlight->static_numclusters;
2061 clusterlist = rtlight->static_clusterlist;
2062 clusterpvs = rtlight->static_clusterpvs;
2063 VectorCopy(rtlight->cullmins, cullmins);
2064 VectorCopy(rtlight->cullmaxs, cullmaxs);
2066 else if (cl.worldmodel && cl.worldmodel->GetLightInfo)
2068 // dynamic light, world available and can receive realtime lighting
2069 // if the light box is offscreen, skip it right away
2070 if (R_CullBox(cullmins, cullmaxs))
2072 // calculate lit surfaces and clusters
2073 R_Shadow_EnlargeClusterBuffer(cl.worldmodel->brush.num_pvsclusters);
2074 R_Shadow_EnlargeSurfaceBuffer(cl.worldmodel->nummodelsurfaces);
2075 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);
2076 clusterlist = r_shadow_buffer_clusterlist;
2077 clusterpvs = r_shadow_buffer_clusterpvs;
2078 surfacelist = r_shadow_buffer_surfacelist;
2080 // if the reduced cluster bounds are offscreen, skip it
2081 if (R_CullBox(cullmins, cullmaxs))
2083 // check if light is illuminating any visible clusters
2086 for (i = 0;i < numclusters;i++)
2087 if (CHECKPVSBIT(r_pvsbits, clusterlist[i]))
2089 if (i == numclusters)
2092 // set up a scissor rectangle for this light
2093 if (R_Shadow_ScissorForBBox(cullmins, cullmaxs))
2096 f = d_lightstylevalue[rtlight->style] * (1.0f / 256.0f);
2097 VectorScale(rtlight->color, f, lightcolor);
2099 if (rtlight->selected)
2101 f = 2 + sin(realtime * M_PI * 4.0);
2102 VectorScale(lightcolor, f, lightcolor);
2107 shadow = rtlight->shadow && (rtlight->isstatic ? r_shadow_realtime_world_shadows.integer : (r_shadow_realtime_world.integer ? r_shadow_realtime_world_dlightshadows.integer : r_shadow_realtime_dlight_shadows.integer));
2110 if (rtlight->shadow)
2112 if (rtlight->isstatic)
2113 shadow = r_shadow_realtime_world_shadows.integer;
2116 if (r_shadow_realtime_world.integer)
2117 shadow = r_shadow_realtime_world_dlightshadows.integer;
2119 shadow = r_shadow_realtime_dlight_shadows.integer;
2124 if (shadow && (gl_stencil || visiblevolumes))
2126 if (!visiblevolumes)
2127 R_Shadow_Stage_ShadowVolumes();
2128 ent = &cl_entities[0].render;
2129 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2131 memset(&m, 0, sizeof(m));
2132 R_Mesh_Matrix(&ent->matrix);
2133 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2135 m.pointer_vertex = mesh->vertex3f;
2137 GL_LockArrays(0, mesh->numverts);
2138 if (r_shadowstage == SHADOWSTAGE_STENCIL)
2140 // decrement stencil if frontface is behind depthbuffer
2141 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2142 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2143 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2144 c_rtcached_shadowmeshes++;
2145 c_rtcached_shadowtris += mesh->numtriangles;
2146 // increment stencil if backface is behind depthbuffer
2147 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2148 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2150 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2151 c_rtcached_shadowmeshes++;
2152 c_rtcached_shadowtris += mesh->numtriangles;
2153 GL_LockArrays(0, 0);
2158 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2159 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, numsurfaces, surfacelist);
2161 if (r_drawentities.integer)
2163 for (i = 0;i < r_refdef.numentities;i++)
2165 ent = r_refdef.entities[i];
2167 if (r_shadow_cull.integer)
2169 if (!BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs))
2171 if (cl.worldmodel != NULL && cl.worldmodel->brush.BoxTouchingPVS != NULL && !cl.worldmodel->brush.BoxTouchingPVS(cl.worldmodel, clusterpvs, ent->mins, ent->maxs))
2174 if (!(ent->flags & RENDER_SHADOW) || !ent->model || !ent->model->DrawShadowVolume)
2176 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2177 // light emitting entities should not cast their own shadow
2178 if (VectorLength2(relativelightorigin) < 0.1)
2180 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, ent->model->nummodelsurfaces, ent->model->surfacelist);
2185 if (!visiblevolumes)
2187 R_Shadow_Stage_Light(shadow && gl_stencil);
2189 ent = &cl_entities[0].render;
2190 if (ent->model && ent->model->DrawLight)
2192 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2193 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2194 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2195 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2196 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2197 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2199 R_Mesh_Matrix(&ent->matrix);
2200 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2201 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);
2204 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, numsurfaces, surfacelist);
2206 if (r_drawentities.integer)
2208 for (i = 0;i < r_refdef.numentities;i++)
2210 ent = r_refdef.entities[i];
2211 if (ent->visframe == r_framecount && BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs) && ent->model && ent->model->DrawLight && (ent->flags & RENDER_LIGHT))
2213 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2214 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2215 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2216 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2217 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2218 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, ent->model->nummodelsurfaces, ent->model->surfacelist);
2225 void R_ShadowVolumeLighting(int visiblevolumes)
2231 if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2232 R_Shadow_EditLights_Reload_f();
2236 memset(&m, 0, sizeof(m));
2239 GL_BlendFunc(GL_ONE, GL_ONE);
2240 GL_DepthMask(false);
2241 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
2242 qglDisable(GL_CULL_FACE);
2243 GL_Color(0.0, 0.0125, 0.1, 1);
2246 R_Shadow_Stage_Begin();
2247 if (r_shadow_realtime_world.integer)
2249 if (r_shadow_debuglight.integer >= 0)
2251 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2252 if (lnum == r_shadow_debuglight.integer)
2253 R_DrawRTLight(&light->rtlight, visiblevolumes);
2256 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2257 R_DrawRTLight(&light->rtlight, visiblevolumes);
2259 if (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer)
2260 for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
2261 R_DrawRTLight(&light->rtlight, visiblevolumes);
2265 qglEnable(GL_CULL_FACE);
2266 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
2269 R_Shadow_Stage_End();
2272 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2273 typedef struct suffixinfo_s
2276 qboolean flipx, flipy, flipdiagonal;
2279 static suffixinfo_t suffix[3][6] =
2282 {"px", false, false, false},
2283 {"nx", false, false, false},
2284 {"py", false, false, false},
2285 {"ny", false, false, false},
2286 {"pz", false, false, false},
2287 {"nz", false, false, false}
2290 {"posx", false, false, false},
2291 {"negx", false, false, false},
2292 {"posy", false, false, false},
2293 {"negy", false, false, false},
2294 {"posz", false, false, false},
2295 {"negz", false, false, false}
2298 {"rt", true, false, true},
2299 {"lf", false, true, true},
2300 {"ft", true, true, false},
2301 {"bk", false, false, false},
2302 {"up", true, false, true},
2303 {"dn", true, false, true}
2307 static int componentorder[4] = {0, 1, 2, 3};
2309 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2311 int i, j, cubemapsize;
2312 qbyte *cubemappixels, *image_rgba;
2313 rtexture_t *cubemaptexture;
2315 // must start 0 so the first loadimagepixels has no requested width/height
2317 cubemappixels = NULL;
2318 cubemaptexture = NULL;
2319 // keep trying different suffix groups (posx, px, rt) until one loads
2320 for (j = 0;j < 3 && !cubemappixels;j++)
2322 // load the 6 images in the suffix group
2323 for (i = 0;i < 6;i++)
2325 // generate an image name based on the base and and suffix
2326 snprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2328 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2330 // an image loaded, make sure width and height are equal
2331 if (image_width == image_height)
2333 // if this is the first image to load successfully, allocate the cubemap memory
2334 if (!cubemappixels && image_width >= 1)
2336 cubemapsize = image_width;
2337 // note this clears to black, so unavailable sides are black
2338 cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2340 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2342 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);
2345 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2347 Mem_Free(image_rgba);
2351 // if a cubemap loaded, upload it
2354 if (!r_shadow_filters_texturepool)
2355 r_shadow_filters_texturepool = R_AllocTexturePool();
2356 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
2357 Mem_Free(cubemappixels);
2361 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
2362 for (j = 0;j < 3;j++)
2363 for (i = 0;i < 6;i++)
2364 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2365 Con_Print(" and was unable to find any of them.\n");
2367 return cubemaptexture;
2370 rtexture_t *R_Shadow_Cubemap(const char *basename)
2373 for (i = 0;i < numcubemaps;i++)
2374 if (!strcasecmp(cubemaps[i].basename, basename))
2375 return cubemaps[i].texture;
2376 if (i >= MAX_CUBEMAPS)
2379 strcpy(cubemaps[i].basename, basename);
2380 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
2381 return cubemaps[i].texture;
2384 void R_Shadow_FreeCubemaps(void)
2387 R_FreeTexturePool(&r_shadow_filters_texturepool);
2390 void R_Shadow_NewWorldLight(vec3_t origin, vec3_t angles, vec3_t color, vec_t radius, vec_t corona, int style, int shadowenable, const char *cubemapname)
2394 if (radius < 15 || DotProduct(color, color) < 0.03)
2396 Con_Print("R_Shadow_NewWorldLight: refusing to create a light too small/dim\n");
2400 light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
2401 VectorCopy(origin, light->origin);
2402 VectorCopy(angles, light->angles);
2403 VectorCopy(color, light->color);
2404 light->radius = radius;
2405 light->style = style;
2406 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
2408 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
2411 light->shadow = shadowenable;
2412 light->corona = corona;
2413 if (cubemapname && cubemapname[0] && strlen(cubemapname) < sizeof(light->cubemapname))
2414 strcpy(light->cubemapname, cubemapname);
2415 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
2416 light->next = r_shadow_worldlightchain;
2417 r_shadow_worldlightchain = light;
2419 R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
2422 void R_Shadow_FreeWorldLight(dlight_t *light)
2424 dlight_t **lightpointer;
2425 R_RTLight_Uncompile(&light->rtlight);
2426 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
2427 if (*lightpointer != light)
2428 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
2429 *lightpointer = light->next;
2433 void R_Shadow_ClearWorldLights(void)
2435 while (r_shadow_worldlightchain)
2436 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
2437 r_shadow_selectedlight = NULL;
2438 R_Shadow_FreeCubemaps();
2441 void R_Shadow_SelectLight(dlight_t *light)
2443 if (r_shadow_selectedlight)
2444 r_shadow_selectedlight->selected = false;
2445 r_shadow_selectedlight = light;
2446 if (r_shadow_selectedlight)
2447 r_shadow_selectedlight->selected = true;
2450 void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
2452 float scale = r_editlights_cursorgrid.value * 0.5f;
2453 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);
2456 void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
2459 const dlight_t *light;
2462 if (light->selected)
2463 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
2466 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);
2469 void R_Shadow_DrawLightSprites(void)
2475 for (i = 0;i < 5;i++)
2477 lighttextures[i] = NULL;
2478 if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1))))
2479 lighttextures[i] = pic->tex;
2482 for (light = r_shadow_worldlightchain;light;light = light->next)
2483 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, ((int) light) % 5);
2484 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
2487 void R_Shadow_SelectLightInView(void)
2489 float bestrating, rating, temp[3];
2490 dlight_t *best, *light;
2493 for (light = r_shadow_worldlightchain;light;light = light->next)
2495 VectorSubtract(light->origin, r_vieworigin, temp);
2496 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
2499 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
2500 if (bestrating < rating && CL_TraceLine(light->origin, r_vieworigin, NULL, NULL, true, NULL, SUPERCONTENTS_SOLID) == 1.0f)
2502 bestrating = rating;
2507 R_Shadow_SelectLight(best);
2510 void R_Shadow_LoadWorldLights(void)
2512 int n, a, style, shadow;
2513 char name[MAX_QPATH], cubemapname[MAX_QPATH], *lightsstring, *s, *t;
2514 float origin[3], radius, color[3], angles[3], corona;
2515 if (cl.worldmodel == NULL)
2517 Con_Print("No map loaded.\n");
2520 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2521 strlcat (name, ".rtlights", sizeof (name));
2522 lightsstring = FS_LoadFile(name, tempmempool, false);
2532 for (;COM_Parse(t, true) && strcmp(
2533 if (COM_Parse(t, true))
2535 if (com_token[0] == '!')
2538 origin[0] = atof(com_token+1);
2541 origin[0] = atof(com_token);
2546 while (*s && *s != '\n')
2552 // check for modifier flags
2558 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]);
2560 VectorClear(angles);
2563 if (a < 9 || !strcmp(cubemapname, "\"\""))
2568 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);
2571 VectorScale(color, r_editlights_rtlightscolorscale.value, color);
2572 radius *= r_editlights_rtlightssizescale.value;
2573 R_Shadow_NewWorldLight(origin, angles, color, radius, corona, style, shadow, cubemapname);
2578 Con_Printf("invalid rtlights file \"%s\"\n", name);
2579 Mem_Free(lightsstring);
2583 void R_Shadow_SaveWorldLights(void)
2586 int bufchars, bufmaxchars;
2588 char name[MAX_QPATH];
2590 if (!r_shadow_worldlightchain)
2592 if (cl.worldmodel == NULL)
2594 Con_Print("No map loaded.\n");
2597 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2598 strlcat (name, ".rtlights", sizeof (name));
2599 bufchars = bufmaxchars = 0;
2601 for (light = r_shadow_worldlightchain;light;light = light->next)
2603 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]);
2604 if (bufchars + (int) strlen(line) > bufmaxchars)
2606 bufmaxchars = bufchars + strlen(line) + 2048;
2608 buf = Mem_Alloc(r_shadow_mempool, bufmaxchars);
2612 memcpy(buf, oldbuf, bufchars);
2618 memcpy(buf + bufchars, line, strlen(line));
2619 bufchars += strlen(line);
2623 FS_WriteFile(name, buf, bufchars);
2628 void R_Shadow_LoadLightsFile(void)
2631 char name[MAX_QPATH], *lightsstring, *s, *t;
2632 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
2633 if (cl.worldmodel == NULL)
2635 Con_Print("No map loaded.\n");
2638 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2639 strlcat (name, ".lights", sizeof (name));
2640 lightsstring = FS_LoadFile(name, tempmempool, false);
2648 while (*s && *s != '\n')
2653 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);
2657 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);
2660 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
2661 radius = bound(15, radius, 4096);
2662 VectorScale(color, (2.0f / (8388608.0f)), color);
2663 R_Shadow_NewWorldLight(origin, vec3_origin, color, radius, 0, style, true, NULL);
2668 Con_Printf("invalid lights file \"%s\"\n", name);
2669 Mem_Free(lightsstring);
2673 // tyrlite/hmap2 light types in the delay field
2674 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
2676 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
2678 int entnum, style, islight, skin, pflags, effects, type, n;
2679 char key[256], value[1024];
2680 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
2683 if (cl.worldmodel == NULL)
2685 Con_Print("No map loaded.\n");
2688 data = cl.worldmodel->brush.entities;
2691 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
2693 type = LIGHTTYPE_MINUSX;
2694 origin[0] = origin[1] = origin[2] = 0;
2695 originhack[0] = originhack[1] = originhack[2] = 0;
2696 angles[0] = angles[1] = angles[2] = 0;
2697 color[0] = color[1] = color[2] = 1;
2698 light[0] = light[1] = light[2] = 1;light[3] = 300;
2699 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
2709 if (!COM_ParseToken(&data, false))
2711 if (com_token[0] == '}')
2712 break; // end of entity
2713 if (com_token[0] == '_')
2714 strcpy(key, com_token + 1);
2716 strcpy(key, com_token);
2717 while (key[strlen(key)-1] == ' ') // remove trailing spaces
2718 key[strlen(key)-1] = 0;
2719 if (!COM_ParseToken(&data, false))
2721 strcpy(value, com_token);
2723 // now that we have the key pair worked out...
2724 if (!strcmp("light", key))
2726 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
2730 light[0] = vec[0] * (1.0f / 256.0f);
2731 light[1] = vec[0] * (1.0f / 256.0f);
2732 light[2] = vec[0] * (1.0f / 256.0f);
2738 light[0] = vec[0] * (1.0f / 255.0f);
2739 light[1] = vec[1] * (1.0f / 255.0f);
2740 light[2] = vec[2] * (1.0f / 255.0f);
2744 else if (!strcmp("delay", key))
2746 else if (!strcmp("origin", key))
2747 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
2748 else if (!strcmp("angle", key))
2749 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
2750 else if (!strcmp("angles", key))
2751 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
2752 else if (!strcmp("color", key))
2753 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
2754 else if (!strcmp("wait", key))
2755 fadescale = atof(value);
2756 else if (!strcmp("classname", key))
2758 if (!strncmp(value, "light", 5))
2761 if (!strcmp(value, "light_fluoro"))
2766 overridecolor[0] = 1;
2767 overridecolor[1] = 1;
2768 overridecolor[2] = 1;
2770 if (!strcmp(value, "light_fluorospark"))
2775 overridecolor[0] = 1;
2776 overridecolor[1] = 1;
2777 overridecolor[2] = 1;
2779 if (!strcmp(value, "light_globe"))
2784 overridecolor[0] = 1;
2785 overridecolor[1] = 0.8;
2786 overridecolor[2] = 0.4;
2788 if (!strcmp(value, "light_flame_large_yellow"))
2793 overridecolor[0] = 1;
2794 overridecolor[1] = 0.5;
2795 overridecolor[2] = 0.1;
2797 if (!strcmp(value, "light_flame_small_yellow"))
2802 overridecolor[0] = 1;
2803 overridecolor[1] = 0.5;
2804 overridecolor[2] = 0.1;
2806 if (!strcmp(value, "light_torch_small_white"))
2811 overridecolor[0] = 1;
2812 overridecolor[1] = 0.5;
2813 overridecolor[2] = 0.1;
2815 if (!strcmp(value, "light_torch_small_walltorch"))
2820 overridecolor[0] = 1;
2821 overridecolor[1] = 0.5;
2822 overridecolor[2] = 0.1;
2826 else if (!strcmp("style", key))
2827 style = atoi(value);
2828 else if (cl.worldmodel->type == mod_brushq3)
2830 if (!strcmp("scale", key))
2831 lightscale = atof(value);
2832 if (!strcmp("fade", key))
2833 fadescale = atof(value);
2835 else if (!strcmp("skin", key))
2836 skin = (int)atof(value);
2837 else if (!strcmp("pflags", key))
2838 pflags = (int)atof(value);
2839 else if (!strcmp("effects", key))
2840 effects = (int)atof(value);
2844 if (lightscale <= 0)
2848 if (color[0] == color[1] && color[0] == color[2])
2850 color[0] *= overridecolor[0];
2851 color[1] *= overridecolor[1];
2852 color[2] *= overridecolor[2];
2854 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
2855 color[0] = color[0] * light[0];
2856 color[1] = color[1] * light[1];
2857 color[2] = color[2] * light[2];
2860 case LIGHTTYPE_MINUSX:
2862 case LIGHTTYPE_RECIPX:
2864 VectorScale(color, (1.0f / 16.0f), color);
2866 case LIGHTTYPE_RECIPXX:
2868 VectorScale(color, (1.0f / 16.0f), color);
2871 case LIGHTTYPE_NONE:
2875 case LIGHTTYPE_MINUSXX:
2878 VectorAdd(origin, originhack, origin);
2880 R_Shadow_NewWorldLight(origin, angles, color, radius, (pflags & PFLAGS_CORONA) != 0, style, (pflags & PFLAGS_NOSHADOW) == 0, skin >= 16 ? va("cubemaps/%i", skin) : NULL);
2885 void R_Shadow_SetCursorLocationForView(void)
2887 vec_t dist, push, frac;
2888 vec3_t dest, endpos, normal;
2889 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
2890 frac = CL_TraceLine(r_vieworigin, dest, endpos, normal, true, NULL, SUPERCONTENTS_SOLID);
2893 dist = frac * r_editlights_cursordistance.value;
2894 push = r_editlights_cursorpushback.value;
2898 VectorMA(endpos, push, r_viewforward, endpos);
2899 VectorMA(endpos, r_editlights_cursorpushoff.value, normal, endpos);
2901 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2902 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2903 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2906 void R_Shadow_UpdateWorldLightSelection(void)
2908 if (r_editlights.integer)
2910 R_Shadow_SetCursorLocationForView();
2911 R_Shadow_SelectLightInView();
2912 R_Shadow_DrawLightSprites();
2915 R_Shadow_SelectLight(NULL);
2918 void R_Shadow_EditLights_Clear_f(void)
2920 R_Shadow_ClearWorldLights();
2923 void R_Shadow_EditLights_Reload_f(void)
2927 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
2928 R_Shadow_ClearWorldLights();
2929 R_Shadow_LoadWorldLights();
2930 if (r_shadow_worldlightchain == NULL)
2932 R_Shadow_LoadLightsFile();
2933 if (r_shadow_worldlightchain == NULL)
2934 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
2938 void R_Shadow_EditLights_Save_f(void)
2942 R_Shadow_SaveWorldLights();
2945 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
2947 R_Shadow_ClearWorldLights();
2948 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
2951 void R_Shadow_EditLights_ImportLightsFile_f(void)
2953 R_Shadow_ClearWorldLights();
2954 R_Shadow_LoadLightsFile();
2957 void R_Shadow_EditLights_Spawn_f(void)
2960 if (!r_editlights.integer)
2962 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
2965 if (Cmd_Argc() != 1)
2967 Con_Print("r_editlights_spawn does not take parameters\n");
2970 color[0] = color[1] = color[2] = 1;
2971 R_Shadow_NewWorldLight(r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL);
2974 void R_Shadow_EditLights_Edit_f(void)
2976 vec3_t origin, angles, color;
2977 vec_t radius, corona;
2979 char cubemapname[1024];
2980 if (!r_editlights.integer)
2982 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
2985 if (!r_shadow_selectedlight)
2987 Con_Print("No selected light.\n");
2990 VectorCopy(r_shadow_selectedlight->origin, origin);
2991 VectorCopy(r_shadow_selectedlight->angles, angles);
2992 VectorCopy(r_shadow_selectedlight->color, color);
2993 radius = r_shadow_selectedlight->radius;
2994 style = r_shadow_selectedlight->style;
2995 if (r_shadow_selectedlight->cubemapname)
2996 strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
2999 shadows = r_shadow_selectedlight->shadow;
3000 corona = r_shadow_selectedlight->corona;
3001 if (!strcmp(Cmd_Argv(1), "origin"))
3003 if (Cmd_Argc() != 5)
3005 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3008 origin[0] = atof(Cmd_Argv(2));
3009 origin[1] = atof(Cmd_Argv(3));
3010 origin[2] = atof(Cmd_Argv(4));
3012 else if (!strcmp(Cmd_Argv(1), "originx"))
3014 if (Cmd_Argc() != 3)
3016 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3019 origin[0] = atof(Cmd_Argv(2));
3021 else if (!strcmp(Cmd_Argv(1), "originy"))
3023 if (Cmd_Argc() != 3)
3025 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3028 origin[1] = atof(Cmd_Argv(2));
3030 else if (!strcmp(Cmd_Argv(1), "originz"))
3032 if (Cmd_Argc() != 3)
3034 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3037 origin[2] = atof(Cmd_Argv(2));
3039 else if (!strcmp(Cmd_Argv(1), "move"))
3041 if (Cmd_Argc() != 5)
3043 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3046 origin[0] += atof(Cmd_Argv(2));
3047 origin[1] += atof(Cmd_Argv(3));
3048 origin[2] += atof(Cmd_Argv(4));
3050 else if (!strcmp(Cmd_Argv(1), "movex"))
3052 if (Cmd_Argc() != 3)
3054 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3057 origin[0] += atof(Cmd_Argv(2));
3059 else if (!strcmp(Cmd_Argv(1), "movey"))
3061 if (Cmd_Argc() != 3)
3063 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3066 origin[1] += atof(Cmd_Argv(2));
3068 else if (!strcmp(Cmd_Argv(1), "movez"))
3070 if (Cmd_Argc() != 3)
3072 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3075 origin[2] += atof(Cmd_Argv(2));
3077 else if (!strcmp(Cmd_Argv(1), "angles"))
3079 if (Cmd_Argc() != 5)
3081 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3084 angles[0] = atof(Cmd_Argv(2));
3085 angles[1] = atof(Cmd_Argv(3));
3086 angles[2] = atof(Cmd_Argv(4));
3088 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3090 if (Cmd_Argc() != 3)
3092 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3095 angles[0] = atof(Cmd_Argv(2));
3097 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3099 if (Cmd_Argc() != 3)
3101 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3104 angles[1] = atof(Cmd_Argv(2));
3106 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3108 if (Cmd_Argc() != 3)
3110 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3113 angles[2] = atof(Cmd_Argv(2));
3115 else if (!strcmp(Cmd_Argv(1), "color"))
3117 if (Cmd_Argc() != 5)
3119 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3122 color[0] = atof(Cmd_Argv(2));
3123 color[1] = atof(Cmd_Argv(3));
3124 color[2] = atof(Cmd_Argv(4));
3126 else if (!strcmp(Cmd_Argv(1), "radius"))
3128 if (Cmd_Argc() != 3)
3130 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3133 radius = atof(Cmd_Argv(2));
3135 else if (!strcmp(Cmd_Argv(1), "style"))
3137 if (Cmd_Argc() != 3)
3139 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3142 style = atoi(Cmd_Argv(2));
3144 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3148 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3151 if (Cmd_Argc() == 3)
3152 strcpy(cubemapname, Cmd_Argv(2));
3156 else if (!strcmp(Cmd_Argv(1), "shadows"))
3158 if (Cmd_Argc() != 3)
3160 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3163 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3165 else if (!strcmp(Cmd_Argv(1), "corona"))
3167 if (Cmd_Argc() != 3)
3169 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3172 corona = atof(Cmd_Argv(2));
3176 Con_Print("usage: r_editlights_edit [property] [value]\n");
3177 Con_Print("Selected light's properties:\n");
3178 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3179 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3180 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3181 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3182 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3183 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3184 Con_Printf("Shadows: %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3185 Con_Printf("Cubemap: %s\n", r_shadow_selectedlight->cubemapname);
3188 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3189 r_shadow_selectedlight = NULL;
3190 R_Shadow_NewWorldLight(origin, angles, color, radius, corona, style, shadows, cubemapname);
3193 void R_Shadow_EditLights_EditAll_f(void)
3197 if (!r_editlights.integer)
3199 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
3203 for (light = r_shadow_worldlightchain;light;light = light->next)
3205 R_Shadow_SelectLight(light);
3206 R_Shadow_EditLights_Edit_f();
3210 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3214 if (!r_editlights.integer)
3218 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;
3219 if (r_shadow_selectedlight == NULL)
3221 sprintf(temp, "Light properties");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3222 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;
3223 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;
3224 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;
3225 sprintf(temp, "Radius %f", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3226 sprintf(temp, "Corona %f", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3227 sprintf(temp, "Style %i", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3228 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;
3229 sprintf(temp, "Cubemap %s", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3232 void R_Shadow_EditLights_ToggleShadow_f(void)
3234 if (!r_editlights.integer)
3236 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3239 if (!r_shadow_selectedlight)
3241 Con_Print("No selected light.\n");
3244 R_Shadow_NewWorldLight(r_shadow_selectedlight->origin, r_shadow_selectedlight->angles, r_shadow_selectedlight->color, r_shadow_selectedlight->radius, r_shadow_selectedlight->corona, r_shadow_selectedlight->style, !r_shadow_selectedlight->shadow, r_shadow_selectedlight->cubemapname);
3245 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3246 r_shadow_selectedlight = NULL;
3249 void R_Shadow_EditLights_ToggleCorona_f(void)
3251 if (!r_editlights.integer)
3253 Con_Print("Cannot spawn 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_NewWorldLight(r_shadow_selectedlight->origin, r_shadow_selectedlight->angles, r_shadow_selectedlight->color, r_shadow_selectedlight->radius, !r_shadow_selectedlight->corona, r_shadow_selectedlight->style, r_shadow_selectedlight->shadow, r_shadow_selectedlight->cubemapname);
3262 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3263 r_shadow_selectedlight = NULL;
3266 void R_Shadow_EditLights_Remove_f(void)
3268 if (!r_editlights.integer)
3270 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
3273 if (!r_shadow_selectedlight)
3275 Con_Print("No selected light.\n");
3278 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3279 r_shadow_selectedlight = NULL;
3282 void R_Shadow_EditLights_Help_f(void)
3285 "Documentation on r_editlights system:\n"
3287 "r_editlights : enable/disable editing mode\n"
3288 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
3289 "r_editlights_cursorpushback : push back cursor this far from surface\n"
3290 "r_editlights_cursorpushoff : push cursor off surface this far\n"
3291 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
3292 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
3293 "r_editlights_rtlightssizescale : imported rtlight size scaling\n"
3294 "r_editlights_rtlightscolorscale : imported rtlight color scaling\n"
3296 "r_editlights_help : this help\n"
3297 "r_editlights_clear : remove all lights\n"
3298 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
3299 "r_editlights_save : save to .rtlights file\n"
3300 "r_editlights_spawn : create a light with default settings\n"
3301 "r_editlights_edit command : edit selected light - more documentation below\n"
3302 "r_editlights_remove : remove selected light\n"
3303 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
3304 "r_editlights_importlightentitiesfrommap : reload light entities\n"
3305 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
3307 "origin x y z : set light location\n"
3308 "originx x: set x component of light location\n"
3309 "originy y: set y component of light location\n"
3310 "originz z: set z component of light location\n"
3311 "move x y z : adjust light location\n"
3312 "movex x: adjust x component of light location\n"
3313 "movey y: adjust y component of light location\n"
3314 "movez z: adjust z component of light location\n"
3315 "angles x y z : set light angles\n"
3316 "anglesx x: set x component of light angles\n"
3317 "anglesy y: set y component of light angles\n"
3318 "anglesz z: set z component of light angles\n"
3319 "color r g b : set color of light (can be brighter than 1 1 1)\n"
3320 "radius radius : set radius (size) of light\n"
3321 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
3322 "cubemap basename : set filter cubemap of light (not yet supported)\n"
3323 "shadows 1/0 : turn on/off shadows\n"
3324 "corona n : set corona intensity\n"
3325 "<nothing> : print light properties to console\n"
3329 void R_Shadow_EditLights_CopyInfo_f(void)
3331 if (!r_editlights.integer)
3333 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
3336 if (!r_shadow_selectedlight)
3338 Con_Print("No selected light.\n");
3341 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
3342 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
3343 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
3344 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
3345 if (r_shadow_selectedlight->cubemapname)
3346 strcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname);
3348 r_shadow_bufferlight.cubemapname[0] = 0;
3349 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
3350 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
3353 void R_Shadow_EditLights_PasteInfo_f(void)
3356 VectorCopy(r_shadow_selectedlight->origin, origin);
3357 if (!r_editlights.integer)
3359 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
3362 if (!r_shadow_selectedlight)
3364 Con_Print("No selected light.\n");
3367 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3368 r_shadow_selectedlight = NULL;
3369 R_Shadow_NewWorldLight(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);
3372 void R_Shadow_EditLights_Init(void)
3374 Cvar_RegisterVariable(&r_editlights);
3375 Cvar_RegisterVariable(&r_editlights_cursordistance);
3376 Cvar_RegisterVariable(&r_editlights_cursorpushback);
3377 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
3378 Cvar_RegisterVariable(&r_editlights_cursorgrid);
3379 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
3380 Cvar_RegisterVariable(&r_editlights_rtlightssizescale);
3381 Cvar_RegisterVariable(&r_editlights_rtlightscolorscale);
3382 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
3383 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
3384 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
3385 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
3386 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
3387 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
3388 Cmd_AddCommand("r_editlights_editall", R_Shadow_EditLights_EditAll_f);
3389 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
3390 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
3391 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
3392 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
3393 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);
3394 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f);
3395 Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f);