3 Terminology: Stencil Shadow Volume (sometimes called Stencil Shadows)
4 An extrusion of the lit faces, beginning at the original geometry and ending
5 further from the light source than the original geometry (presumably at least
6 as far as the light's radius, if the light has a radius at all), capped at
7 both front and back to avoid any problems (extrusion from dark faces also
8 works but has a different set of problems)
10 This is rendered using Carmack's Reverse technique, in which backfaces behind
11 zbuffer (zfail) increment the stencil, and frontfaces behind zbuffer (zfail)
12 decrement the stencil, the result is a stencil value of zero where shadows
13 did not intersect the visible geometry, suitable as a stencil mask for
14 rendering lighting everywhere but shadow.
16 In our case we use a biased stencil clear of 128 to avoid requiring the
17 stencil wrap extension (but probably should support it), and to address
18 Creative's patent on this sort of technology we also draw the frontfaces
19 first, and backfaces second (decrement, increment).
22 This algorithm may be covered by Creative's patent (US Patent #6384822)
23 on Carmack's Reverse paper (which I have not read), however that patent
24 seems to be about drawing a stencil shadow from a model in an otherwise
25 unshadowed scene, where as realtime lighting technology draws light where
30 Terminology: Stencil Light Volume (sometimes called Light Volumes)
31 Similar to a Stencil Shadow Volume, but inverted; rather than containing the
32 areas in shadow it contanis the areas in light, this can only be built
33 quickly for certain limited cases (such as portal visibility from a point),
34 but is quite useful for some effects (sunlight coming from sky polygons is
35 one possible example, translucent occluders is another example).
39 Terminology: Optimized Stencil Shadow Volume
40 A Stencil Shadow Volume that has been processed sufficiently to ensure it has
41 no duplicate coverage of areas (no need to shadow an area twice), often this
42 greatly improves performance but is an operation too costly to use on moving
43 lights (however completely optimal Stencil Light Volumes can be constructed
48 Terminology: Per Pixel Lighting (sometimes abbreviated PPL)
49 Per pixel evaluation of lighting equations, at a bare minimum this involves
50 DOT3 shading of diffuse lighting (per pixel dotproduct of negated incidence
51 vector and surface normal, using a texture of the surface bumps, called a
52 NormalMap) if supported by hardware; in our case there is support for cards
53 which are incapable of DOT3, the quality is quite poor however. Additionally
54 it is desirable to have specular evaluation per pixel, per vertex
55 normalization of specular halfangle vectors causes noticable distortion but
56 is unavoidable on hardware without GL_ARB_fragment_program.
60 Terminology: Normalization CubeMap
61 A cubemap containing normalized dot3-encoded (vectors of length 1 or less
62 encoded as RGB colors) for any possible direction, this technique allows per
63 pixel calculation of incidence vector for per pixel lighting purposes, which
64 would not otherwise be possible per pixel without GL_ARB_fragment_program.
68 Terminology: 2D Attenuation Texturing
69 A very crude approximation of light attenuation with distance which results
70 in cylindrical light shapes which fade vertically as a streak (some games
71 such as Doom3 allow this to be rotated to be less noticable in specific
72 cases), the technique is simply modulating lighting by two 2D textures (which
73 can be the same) on different axes of projection (XY and Z, typically), this
74 is the best technique available without 3D Attenuation Texturing or
75 GL_ARB_fragment_program technology.
79 Terminology: 3D Attenuation Texturing
80 A slightly crude approximation of light attenuation with distance, its flaws
81 are limited radius and resolution (performance tradeoffs).
85 Terminology: 3D Attenuation-Normalization Texturing
86 A 3D Attenuation Texture merged with a Normalization CubeMap, by making the
87 vectors shorter the lighting becomes darker, a very effective optimization of
88 diffuse lighting if 3D Attenuation Textures are already used.
92 Terminology: Light Cubemap Filtering
93 A technique for modeling non-uniform light distribution according to
94 direction, for example projecting a stained glass window image onto a wall,
95 this is done by texturing the lighting with a cubemap.
99 Terminology: Light Projection Filtering
100 A technique for modeling shadowing of light passing through translucent
101 surfaces, allowing stained glass windows and other effects to be done more
102 elegantly than possible with Light Cubemap Filtering by applying an occluder
103 texture to the lighting combined with a stencil light volume to limit the lit
104 area (this allows evaluating multiple translucent occluders in a scene).
108 Terminology: Doom3 Lighting
109 A combination of Stencil Shadow Volume, Per Pixel Lighting, Normalization
110 CubeMap, 2D Attenuation Texturing, and Light Filtering, as demonstrated by
111 the (currently upcoming) game Doom3.
114 #include "quakedef.h"
115 #include "r_shadow.h"
116 #include "cl_collision.h"
120 extern void R_Shadow_EditLights_Init(void);
122 #define SHADOWSTAGE_NONE 0
123 #define SHADOWSTAGE_STENCIL 1
124 #define SHADOWSTAGE_LIGHT 2
125 #define SHADOWSTAGE_STENCILTWOSIDE 3
127 int r_shadowstage = SHADOWSTAGE_NONE;
129 mempool_t *r_shadow_mempool;
131 int maxshadowelements;
145 int r_shadow_buffer_numclusterpvsbytes;
146 qbyte *r_shadow_buffer_clusterpvs;
147 int *r_shadow_buffer_clusterlist;
149 int r_shadow_buffer_numsurfacepvsbytes;
150 qbyte *r_shadow_buffer_surfacepvs;
151 int *r_shadow_buffer_surfacelist;
153 rtexturepool_t *r_shadow_texturepool;
154 rtexture_t *r_shadow_normalcubetexture;
155 rtexture_t *r_shadow_attenuation2dtexture;
156 rtexture_t *r_shadow_attenuation3dtexture;
157 rtexture_t *r_shadow_blankbumptexture;
158 rtexture_t *r_shadow_blankglosstexture;
159 rtexture_t *r_shadow_blankwhitetexture;
161 // lights are reloaded when this changes
162 char r_shadow_mapname[MAX_QPATH];
164 // used only for light filters (cubemaps)
165 rtexturepool_t *r_shadow_filters_texturepool;
167 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0"};
168 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4"};
169 cvar_t r_shadow_cull = {0, "r_shadow_cull", "1"};
170 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1"};
171 cvar_t r_shadow_gloss = {0, "r_shadow_gloss", "1"};
172 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.25"};
173 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1"};
174 cvar_t r_shadow_lightattenuationpower = {0, "r_shadow_lightattenuationpower", "0.5"};
175 cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1"};
176 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1"};
177 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1"};
178 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000"};
179 cvar_t r_shadow_realtime_dlight = {0, "r_shadow_realtime_dlight", "1"};
180 cvar_t r_shadow_realtime_dlight_shadows = {0, "r_shadow_realtime_dlight_shadows", "0"};
181 cvar_t r_shadow_realtime_world = {0, "r_shadow_realtime_world", "0"};
182 cvar_t r_shadow_realtime_world_dlightshadows = {0, "r_shadow_realtime_world_dlightshadows", "1"};
183 cvar_t r_shadow_realtime_world_lightmaps = {0, "r_shadow_realtime_world_lightmaps", "0"};
184 cvar_t r_shadow_realtime_world_shadows = {0, "r_shadow_realtime_world_shadows", "1"};
185 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1"};
186 cvar_t r_shadow_shadow_polygonfactor = {0, "r_shadow_shadow_polygonfactor", "0"};
187 cvar_t r_shadow_shadow_polygonoffset = {0, "r_shadow_shadow_polygonoffset", "1"};
188 cvar_t r_shadow_singlepassvolumegeneration = {0, "r_shadow_singlepassvolumegeneration", "1"};
189 cvar_t r_shadow_staticworldlights = {0, "r_shadow_staticworldlights", "1"};
190 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1"};
191 cvar_t r_shadow_visiblevolumes = {0, "r_shadow_visiblevolumes", "0"};
192 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1"};
193 cvar_t r_editlights = {0, "r_editlights", "0"};
194 cvar_t r_editlights_cursordistance = {0, "r_editlights_distance", "1024"};
195 cvar_t r_editlights_cursorpushback = {0, "r_editlights_pushback", "0"};
196 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_pushoff", "4"};
197 cvar_t r_editlights_cursorgrid = {0, "r_editlights_grid", "4"};
198 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "0.8"};
199 cvar_t r_editlights_rtlightssizescale = {CVAR_SAVE, "r_editlights_rtlightssizescale", "0.7"};
200 cvar_t r_editlights_rtlightscolorscale = {CVAR_SAVE, "r_editlights_rtlightscolorscale", "2"};
202 int c_rt_lights, c_rt_clears, c_rt_scissored;
203 int c_rt_shadowmeshes, c_rt_shadowtris, c_rt_lightmeshes, c_rt_lighttris;
204 int c_rtcached_shadowmeshes, c_rtcached_shadowtris;
206 float r_shadow_attenpower, r_shadow_attenscale;
208 float varray_vertex3f2[65536*3];
210 rtlight_t *r_shadow_compilingrtlight;
211 dlight_t *r_shadow_worldlightchain;
212 dlight_t *r_shadow_selectedlight;
213 vec3_t r_editlights_cursorlocation;
215 rtexture_t *lighttextures[5];
217 extern int con_vislines;
219 typedef struct cubemapinfo_s
226 #define MAX_CUBEMAPS 256
227 static int numcubemaps;
228 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
230 void R_Shadow_UncompileWorldLights(void);
231 void R_Shadow_ClearWorldLights(void);
232 void R_Shadow_SaveWorldLights(void);
233 void R_Shadow_LoadWorldLights(void);
234 void R_Shadow_LoadLightsFile(void);
235 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
236 void R_Shadow_EditLights_Reload_f(void);
237 void R_Shadow_ValidateCvars(void);
238 static void R_Shadow_MakeTextures(void);
239 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light);
241 void r_shadow_start(void)
243 // allocate vertex processing arrays
245 r_shadow_normalcubetexture = NULL;
246 r_shadow_attenuation2dtexture = NULL;
247 r_shadow_attenuation3dtexture = NULL;
248 r_shadow_blankbumptexture = NULL;
249 r_shadow_blankglosstexture = NULL;
250 r_shadow_blankwhitetexture = NULL;
251 r_shadow_texturepool = NULL;
252 r_shadow_filters_texturepool = NULL;
253 R_Shadow_ValidateCvars();
254 R_Shadow_MakeTextures();
255 maxshadowelements = 0;
256 shadowelements = NULL;
264 shadowmarklist = NULL;
266 r_shadow_buffer_numclusterpvsbytes = 0;
267 r_shadow_buffer_clusterpvs = NULL;
268 r_shadow_buffer_clusterlist = NULL;
269 r_shadow_buffer_numsurfacepvsbytes = 0;
270 r_shadow_buffer_surfacepvs = NULL;
271 r_shadow_buffer_surfacelist = NULL;
274 void r_shadow_shutdown(void)
276 R_Shadow_UncompileWorldLights();
278 r_shadow_normalcubetexture = NULL;
279 r_shadow_attenuation2dtexture = NULL;
280 r_shadow_attenuation3dtexture = NULL;
281 r_shadow_blankbumptexture = NULL;
282 r_shadow_blankglosstexture = NULL;
283 r_shadow_blankwhitetexture = NULL;
284 R_FreeTexturePool(&r_shadow_texturepool);
285 R_FreeTexturePool(&r_shadow_filters_texturepool);
286 maxshadowelements = 0;
288 Mem_Free(shadowelements);
289 shadowelements = NULL;
292 Mem_Free(vertexupdate);
295 Mem_Free(vertexremap);
301 Mem_Free(shadowmark);
304 Mem_Free(shadowmarklist);
305 shadowmarklist = NULL;
307 r_shadow_buffer_numclusterpvsbytes = 0;
308 if (r_shadow_buffer_clusterpvs)
309 Mem_Free(r_shadow_buffer_clusterpvs);
310 r_shadow_buffer_clusterpvs = NULL;
311 if (r_shadow_buffer_clusterlist)
312 Mem_Free(r_shadow_buffer_clusterlist);
313 r_shadow_buffer_clusterlist = NULL;
314 r_shadow_buffer_numsurfacepvsbytes = 0;
315 if (r_shadow_buffer_surfacepvs)
316 Mem_Free(r_shadow_buffer_surfacepvs);
317 r_shadow_buffer_surfacepvs = NULL;
318 if (r_shadow_buffer_surfacelist)
319 Mem_Free(r_shadow_buffer_surfacelist);
320 r_shadow_buffer_surfacelist = NULL;
323 void r_shadow_newmap(void)
327 void R_Shadow_Help_f(void)
330 "Documentation on r_shadow system:\n"
332 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
333 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
334 "r_shadow_debuglight : render only this light number (-1 = all)\n"
335 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
336 "r_shadow_gloss2intensity : brightness of forced gloss\n"
337 "r_shadow_glossintensity : brightness of textured gloss\n"
338 "r_shadow_lightattenuationpower : used to generate attenuation texture\n"
339 "r_shadow_lightattenuationscale : used to generate attenuation texture\n"
340 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
341 "r_shadow_portallight : use portal visibility for static light precomputation\n"
342 "r_shadow_projectdistance : shadow volume projection distance\n"
343 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
344 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
345 "r_shadow_realtime_world : use high quality world lighting mode\n"
346 "r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n"
347 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
348 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
349 "r_shadow_scissor : use scissor optimization\n"
350 "r_shadow_shadow_polygonfactor : nudge shadow volumes closer/further\n"
351 "r_shadow_shadow_polygonoffset : nudge shadow volumes closer/further\n"
352 "r_shadow_singlepassvolumegeneration : selects shadow volume algorithm\n"
353 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
354 "r_shadow_visiblevolumes : useful for performance testing; bright = slow!\n"
356 "r_shadow_help : this help\n"
360 void R_Shadow_Init(void)
362 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
363 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
364 Cvar_RegisterVariable(&r_shadow_cull);
365 Cvar_RegisterVariable(&r_shadow_debuglight);
366 Cvar_RegisterVariable(&r_shadow_gloss);
367 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
368 Cvar_RegisterVariable(&r_shadow_glossintensity);
369 Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
370 Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
371 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
372 Cvar_RegisterVariable(&r_shadow_portallight);
373 Cvar_RegisterVariable(&r_shadow_projectdistance);
374 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
375 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
376 Cvar_RegisterVariable(&r_shadow_realtime_world);
377 Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows);
378 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
379 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
380 Cvar_RegisterVariable(&r_shadow_scissor);
381 Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor);
382 Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset);
383 Cvar_RegisterVariable(&r_shadow_singlepassvolumegeneration);
384 Cvar_RegisterVariable(&r_shadow_staticworldlights);
385 Cvar_RegisterVariable(&r_shadow_texture3d);
386 Cvar_RegisterVariable(&r_shadow_visiblevolumes);
387 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
388 if (gamemode == GAME_TENEBRAE)
390 Cvar_SetValue("r_shadow_gloss", 2);
391 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
393 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f);
394 R_Shadow_EditLights_Init();
395 r_shadow_mempool = Mem_AllocPool("R_Shadow", 0, NULL);
396 r_shadow_worldlightchain = NULL;
397 maxshadowelements = 0;
398 shadowelements = NULL;
406 shadowmarklist = NULL;
408 r_shadow_buffer_numclusterpvsbytes = 0;
409 r_shadow_buffer_clusterpvs = NULL;
410 r_shadow_buffer_clusterlist = NULL;
411 r_shadow_buffer_numsurfacepvsbytes = 0;
412 r_shadow_buffer_surfacepvs = NULL;
413 r_shadow_buffer_surfacelist = NULL;
414 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
417 matrix4x4_t matrix_attenuationxyz =
420 {0.5, 0.0, 0.0, 0.5},
421 {0.0, 0.5, 0.0, 0.5},
422 {0.0, 0.0, 0.5, 0.5},
427 matrix4x4_t matrix_attenuationz =
430 {0.0, 0.0, 0.5, 0.5},
431 {0.0, 0.0, 0.0, 0.5},
432 {0.0, 0.0, 0.0, 0.5},
437 int *R_Shadow_ResizeShadowElements(int numtris)
439 // make sure shadowelements is big enough for this volume
440 if (maxshadowelements < numtris * 24)
442 maxshadowelements = numtris * 24;
444 Mem_Free(shadowelements);
445 shadowelements = Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int));
447 return shadowelements;
450 void R_Shadow_EnlargeClusterBuffer(int numclusters)
452 int numclusterpvsbytes = (((numclusters + 7) >> 3) + 255) & ~255;
453 if (r_shadow_buffer_numclusterpvsbytes < numclusterpvsbytes)
455 if (r_shadow_buffer_clusterpvs)
456 Mem_Free(r_shadow_buffer_clusterpvs);
457 if (r_shadow_buffer_clusterlist)
458 Mem_Free(r_shadow_buffer_clusterlist);
459 r_shadow_buffer_numclusterpvsbytes = numclusterpvsbytes;
460 r_shadow_buffer_clusterpvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numclusterpvsbytes);
461 r_shadow_buffer_clusterlist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numclusterpvsbytes * 8 * sizeof(*r_shadow_buffer_clusterlist));
465 void R_Shadow_EnlargeSurfaceBuffer(int numsurfaces)
467 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
468 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
470 if (r_shadow_buffer_surfacepvs)
471 Mem_Free(r_shadow_buffer_surfacepvs);
472 if (r_shadow_buffer_surfacelist)
473 Mem_Free(r_shadow_buffer_surfacelist);
474 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
475 r_shadow_buffer_surfacepvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes);
476 r_shadow_buffer_surfacelist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
480 void R_Shadow_PrepareShadowMark(int numtris)
482 // make sure shadowmark is big enough for this volume
483 if (maxshadowmark < numtris)
485 maxshadowmark = numtris;
487 Mem_Free(shadowmark);
489 Mem_Free(shadowmarklist);
490 shadowmark = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmark));
491 shadowmarklist = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmarklist));
495 // if shadowmarkcount wrapped we clear the array and adjust accordingly
496 if (shadowmarkcount == 0)
499 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
504 int R_Shadow_ConstructShadowVolume(int innumvertices, int innumtris, const int *inelement3i, const int *inneighbor3i, const float *invertex3f, int *outnumvertices, int *outelement3i, float *outvertex3f, const float *projectorigin, float projectdistance, int numshadowmarktris, const int *shadowmarktris)
506 int i, j, tris = 0, vr[3], t, outvertices = 0;
510 if (maxvertexupdate < innumvertices)
512 maxvertexupdate = innumvertices;
514 Mem_Free(vertexupdate);
516 Mem_Free(vertexremap);
517 vertexupdate = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
518 vertexremap = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
522 if (vertexupdatenum == 0)
525 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
526 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
529 for (i = 0;i < numshadowmarktris;i++)
531 t = shadowmarktris[i];
532 shadowmark[t] = shadowmarkcount;
533 e = inelement3i + t * 3;
534 // make sure the vertices are created
535 for (j = 0;j < 3;j++)
537 if (vertexupdate[e[j]] != vertexupdatenum)
539 vertexupdate[e[j]] = vertexupdatenum;
540 vertexremap[e[j]] = outvertices;
541 VectorSubtract(invertex3f + e[j] * 3, projectorigin, temp);
542 f = projectdistance / VectorLength(temp);
543 VectorCopy(invertex3f + e[j] * 3, outvertex3f);
544 VectorMA(projectorigin, f, temp, (outvertex3f + 3));
549 // output the front and back triangles
550 outelement3i[0] = vertexremap[e[0]];
551 outelement3i[1] = vertexremap[e[1]];
552 outelement3i[2] = vertexremap[e[2]];
553 outelement3i[3] = vertexremap[e[2]] + 1;
554 outelement3i[4] = vertexremap[e[1]] + 1;
555 outelement3i[5] = vertexremap[e[0]] + 1;
560 for (i = 0;i < numshadowmarktris;i++)
562 t = shadowmarktris[i];
563 e = inelement3i + t * 3;
564 n = inneighbor3i + t * 3;
565 // output the sides (facing outward from this triangle)
566 if (shadowmark[n[0]] != shadowmarkcount)
568 vr[0] = vertexremap[e[0]];
569 vr[1] = vertexremap[e[1]];
570 outelement3i[0] = vr[1];
571 outelement3i[1] = vr[0];
572 outelement3i[2] = vr[0] + 1;
573 outelement3i[3] = vr[1];
574 outelement3i[4] = vr[0] + 1;
575 outelement3i[5] = vr[1] + 1;
579 if (shadowmark[n[1]] != shadowmarkcount)
581 vr[1] = vertexremap[e[1]];
582 vr[2] = vertexremap[e[2]];
583 outelement3i[0] = vr[2];
584 outelement3i[1] = vr[1];
585 outelement3i[2] = vr[1] + 1;
586 outelement3i[3] = vr[2];
587 outelement3i[4] = vr[1] + 1;
588 outelement3i[5] = vr[2] + 1;
592 if (shadowmark[n[2]] != shadowmarkcount)
594 vr[0] = vertexremap[e[0]];
595 vr[2] = vertexremap[e[2]];
596 outelement3i[0] = vr[0];
597 outelement3i[1] = vr[2];
598 outelement3i[2] = vr[2] + 1;
599 outelement3i[3] = vr[0];
600 outelement3i[4] = vr[2] + 1;
601 outelement3i[5] = vr[0] + 1;
607 *outnumvertices = outvertices;
611 void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, float projectdistance, int nummarktris, const int *marktris)
614 if (projectdistance < 0.1)
616 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
619 if (!numverts || !nummarktris)
621 // make sure shadowelements is big enough for this volume
622 if (maxshadowelements < nummarktris * 24)
623 R_Shadow_ResizeShadowElements((nummarktris + 256) * 24);
624 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, varray_vertex3f2, projectorigin, projectdistance, nummarktris, marktris);
625 R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements);
628 void R_Shadow_VolumeFromBox(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, float projectdistance, const vec3_t mins, const vec3_t maxs)
633 // check which triangles are facing the , and then output
634 // triangle elements and vertices... by clever use of elements we
635 // can construct the whole shadow from the unprojected vertices and
636 // the projected vertices
638 // identify lit faces within the bounding box
639 R_Shadow_PrepareShadowMark(numtris);
640 for (i = 0;i < numtris;i++)
642 v[0] = invertex3f + elements[i*3+0] * 3;
643 v[1] = invertex3f + elements[i*3+1] * 3;
644 v[2] = invertex3f + elements[i*3+2] * 3;
645 if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]) && maxs[0] > min(v[0][0], min(v[1][0], v[2][0])) && mins[0] < max(v[0][0], max(v[1][0], v[2][0])) && maxs[1] > min(v[0][1], min(v[1][1], v[2][1])) && mins[1] < max(v[0][1], max(v[1][1], v[2][1])) && maxs[2] > min(v[0][2], min(v[1][2], v[2][2])) && mins[2] < max(v[0][2], max(v[1][2], v[2][2])))
646 shadowmarklist[numshadowmark++] = i;
648 R_Shadow_VolumeFromList(numverts, numtris, invertex3f, elements, neighbors, projectorigin, projectdistance, numshadowmark, shadowmarklist);
651 void R_Shadow_VolumeFromSphere(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, float projectdistance, float radius)
654 mins[0] = projectorigin[0] - radius;
655 mins[1] = projectorigin[1] - radius;
656 mins[2] = projectorigin[2] - radius;
657 maxs[0] = projectorigin[0] + radius;
658 maxs[1] = projectorigin[1] + radius;
659 maxs[2] = projectorigin[2] + radius;
660 R_Shadow_VolumeFromBox(numverts, numtris, invertex3f, elements, neighbors, projectorigin, projectdistance, mins, maxs);
663 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
666 if (r_shadow_compilingrtlight)
668 // if we're compiling an rtlight, capture the mesh
669 Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
672 memset(&m, 0, sizeof(m));
673 m.pointer_vertex = vertex3f;
675 GL_LockArrays(0, numvertices);
676 if (r_shadowstage == SHADOWSTAGE_STENCIL)
678 // increment stencil if backface is behind depthbuffer
679 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
680 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
681 R_Mesh_Draw(numvertices, numtriangles, element3i);
683 c_rt_shadowtris += numtriangles;
684 // decrement stencil if frontface is behind depthbuffer
685 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
686 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
688 R_Mesh_Draw(numvertices, numtriangles, element3i);
690 c_rt_shadowtris += numtriangles;
694 static void R_Shadow_MakeTextures(void)
696 int x, y, z, d, side;
697 float v[3], s, t, intensity;
699 R_FreeTexturePool(&r_shadow_texturepool);
700 r_shadow_texturepool = R_AllocTexturePool();
701 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
702 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
704 #define ATTEN2DSIZE 64
705 #define ATTEN3DSIZE 32
706 data = Mem_Alloc(tempmempool, max(6*NORMSIZE*NORMSIZE*4, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4)));
711 r_shadow_blankbumptexture = R_LoadTexture2D(r_shadow_texturepool, "blankbump", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
716 r_shadow_blankglosstexture = R_LoadTexture2D(r_shadow_texturepool, "blankgloss", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
721 r_shadow_blankwhitetexture = R_LoadTexture2D(r_shadow_texturepool, "blankwhite", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
722 if (gl_texturecubemap)
724 for (side = 0;side < 6;side++)
726 for (y = 0;y < NORMSIZE;y++)
728 for (x = 0;x < NORMSIZE;x++)
730 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
731 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
765 intensity = 127.0f / sqrt(DotProduct(v, v));
766 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+0] = 128.0f + intensity * v[0];
767 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+1] = 128.0f + intensity * v[1];
768 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+2] = 128.0f + intensity * v[2];
769 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+3] = 255;
773 r_shadow_normalcubetexture = R_LoadTextureCubeMap(r_shadow_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
776 r_shadow_normalcubetexture = NULL;
777 for (y = 0;y < ATTEN2DSIZE;y++)
779 for (x = 0;x < ATTEN2DSIZE;x++)
781 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
782 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
784 intensity = 1.0f - sqrt(DotProduct(v, v));
786 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
787 d = bound(0, intensity, 255);
788 data[(y*ATTEN2DSIZE+x)*4+0] = d;
789 data[(y*ATTEN2DSIZE+x)*4+1] = d;
790 data[(y*ATTEN2DSIZE+x)*4+2] = d;
791 data[(y*ATTEN2DSIZE+x)*4+3] = d;
794 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
795 if (r_shadow_texture3d.integer)
797 for (z = 0;z < ATTEN3DSIZE;z++)
799 for (y = 0;y < ATTEN3DSIZE;y++)
801 for (x = 0;x < ATTEN3DSIZE;x++)
803 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
804 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
805 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
806 intensity = 1.0f - sqrt(DotProduct(v, v));
808 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
809 d = bound(0, intensity, 255);
810 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
811 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
812 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
813 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
817 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
822 void R_Shadow_ValidateCvars(void)
824 if (r_shadow_texture3d.integer && !gl_texture3d)
825 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
826 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
827 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
830 void R_Shadow_Stage_Begin(void)
834 R_Shadow_ValidateCvars();
836 if (!r_shadow_attenuation2dtexture
837 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
838 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
839 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
840 R_Shadow_MakeTextures();
842 memset(&m, 0, sizeof(m));
843 GL_BlendFunc(GL_ONE, GL_ZERO);
847 GL_Color(0, 0, 0, 1);
848 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
849 qglEnable(GL_CULL_FACE);
850 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
851 r_shadowstage = SHADOWSTAGE_NONE;
853 c_rt_lights = c_rt_clears = c_rt_scissored = 0;
854 c_rt_shadowmeshes = c_rt_shadowtris = c_rt_lightmeshes = c_rt_lighttris = 0;
855 c_rtcached_shadowmeshes = c_rtcached_shadowtris = 0;
858 void R_Shadow_Stage_ShadowVolumes(void)
861 memset(&m, 0, sizeof(m));
863 GL_Color(1, 1, 1, 1);
864 GL_ColorMask(0, 0, 0, 0);
865 GL_BlendFunc(GL_ONE, GL_ZERO);
868 qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
869 //if (r_shadow_shadow_polygonoffset.value != 0)
871 // qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
872 // qglEnable(GL_POLYGON_OFFSET_FILL);
875 // qglDisable(GL_POLYGON_OFFSET_FILL);
876 qglDepthFunc(GL_LESS);
877 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
878 qglEnable(GL_STENCIL_TEST);
879 qglStencilFunc(GL_ALWAYS, 128, ~0);
880 if (gl_ext_stenciltwoside.integer)
882 r_shadowstage = SHADOWSTAGE_STENCILTWOSIDE;
883 qglDisable(GL_CULL_FACE);
884 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
885 qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
887 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
888 qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
890 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
894 r_shadowstage = SHADOWSTAGE_STENCIL;
895 qglEnable(GL_CULL_FACE);
897 // this is changed by every shadow render so its value here is unimportant
898 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
900 GL_Clear(GL_STENCIL_BUFFER_BIT);
902 // LordHavoc note: many shadow volumes reside entirely inside the world
903 // (that is to say they are entirely bounded by their lit surfaces),
904 // which can be optimized by handling things as an inverted light volume,
905 // with the shadow boundaries of the world being simulated by an altered
906 // (129) bias to stencil clearing on such lights
907 // FIXME: generate inverted light volumes for use as shadow volumes and
908 // optimize for them as noted above
911 void R_Shadow_Stage_Light(int shadowtest)
914 memset(&m, 0, sizeof(m));
916 GL_BlendFunc(GL_ONE, GL_ONE);
919 qglPolygonOffset(0, 0);
920 //qglDisable(GL_POLYGON_OFFSET_FILL);
921 GL_Color(1, 1, 1, 1);
922 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
923 qglDepthFunc(GL_EQUAL);
924 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
925 qglEnable(GL_CULL_FACE);
927 qglEnable(GL_STENCIL_TEST);
929 qglDisable(GL_STENCIL_TEST);
930 if (gl_support_stenciltwoside)
931 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
933 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
934 // only draw light where this geometry was already rendered AND the
935 // stencil is 128 (values other than this mean shadow)
936 qglStencilFunc(GL_EQUAL, 128, ~0);
937 r_shadowstage = SHADOWSTAGE_LIGHT;
941 void R_Shadow_Stage_End(void)
944 memset(&m, 0, sizeof(m));
946 GL_BlendFunc(GL_ONE, GL_ZERO);
949 qglPolygonOffset(0, 0);
950 //qglDisable(GL_POLYGON_OFFSET_FILL);
951 GL_Color(1, 1, 1, 1);
952 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
953 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
954 qglDepthFunc(GL_LEQUAL);
955 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
956 qglDisable(GL_STENCIL_TEST);
957 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
958 if (gl_support_stenciltwoside)
959 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
961 qglStencilFunc(GL_ALWAYS, 128, ~0);
962 r_shadowstage = SHADOWSTAGE_NONE;
965 int R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
967 int i, ix1, iy1, ix2, iy2;
968 float x1, y1, x2, y2, x, y, f;
971 if (!r_shadow_scissor.integer)
973 // if view is inside the box, just say yes it's visible
974 if (BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
976 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
979 for (i = 0;i < 3;i++)
981 if (r_viewforward[i] >= 0)
992 f = DotProduct(r_viewforward, r_vieworigin) + 1;
993 if (DotProduct(r_viewforward, v2) <= f)
995 // entirely behind nearclip plane
998 if (DotProduct(r_viewforward, v) >= f)
1000 // entirely infront of nearclip plane
1001 x1 = y1 = x2 = y2 = 0;
1002 for (i = 0;i < 8;i++)
1004 v[0] = (i & 1) ? mins[0] : maxs[0];
1005 v[1] = (i & 2) ? mins[1] : maxs[1];
1006 v[2] = (i & 4) ? mins[2] : maxs[2];
1008 GL_TransformToScreen(v, v2);
1009 //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]);
1028 // clipped by nearclip plane
1029 // this is nasty and crude...
1030 // create viewspace bbox
1031 for (i = 0;i < 8;i++)
1033 v[0] = ((i & 1) ? mins[0] : maxs[0]) - r_vieworigin[0];
1034 v[1] = ((i & 2) ? mins[1] : maxs[1]) - r_vieworigin[1];
1035 v[2] = ((i & 4) ? mins[2] : maxs[2]) - r_vieworigin[2];
1036 v2[0] = -DotProduct(v, r_viewleft);
1037 v2[1] = DotProduct(v, r_viewup);
1038 v2[2] = DotProduct(v, r_viewforward);
1041 if (smins[0] > v2[0]) smins[0] = v2[0];
1042 if (smaxs[0] < v2[0]) smaxs[0] = v2[0];
1043 if (smins[1] > v2[1]) smins[1] = v2[1];
1044 if (smaxs[1] < v2[1]) smaxs[1] = v2[1];
1045 if (smins[2] > v2[2]) smins[2] = v2[2];
1046 if (smaxs[2] < v2[2]) smaxs[2] = v2[2];
1050 smins[0] = smaxs[0] = v2[0];
1051 smins[1] = smaxs[1] = v2[1];
1052 smins[2] = smaxs[2] = v2[2];
1055 // now we have a bbox in viewspace
1056 // clip it to the view plane
1059 // return true if that culled the box
1060 if (smins[2] >= smaxs[2])
1062 // ok some of it is infront of the view, transform each corner back to
1063 // worldspace and then to screenspace and make screen rect
1064 // initialize these variables just to avoid compiler warnings
1065 x1 = y1 = x2 = y2 = 0;
1066 for (i = 0;i < 8;i++)
1068 v2[0] = (i & 1) ? smins[0] : smaxs[0];
1069 v2[1] = (i & 2) ? smins[1] : smaxs[1];
1070 v2[2] = (i & 4) ? smins[2] : smaxs[2];
1071 v[0] = v2[0] * -r_viewleft[0] + v2[1] * r_viewup[0] + v2[2] * r_viewforward[0] + r_vieworigin[0];
1072 v[1] = v2[0] * -r_viewleft[1] + v2[1] * r_viewup[1] + v2[2] * r_viewforward[1] + r_vieworigin[1];
1073 v[2] = v2[0] * -r_viewleft[2] + v2[1] * r_viewup[2] + v2[2] * r_viewforward[2] + r_vieworigin[2];
1075 GL_TransformToScreen(v, v2);
1076 //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]);
1093 // this code doesn't handle boxes with any points behind view properly
1094 x1 = 1000;x2 = -1000;
1095 y1 = 1000;y2 = -1000;
1096 for (i = 0;i < 8;i++)
1098 v[0] = (i & 1) ? mins[0] : maxs[0];
1099 v[1] = (i & 2) ? mins[1] : maxs[1];
1100 v[2] = (i & 4) ? mins[2] : maxs[2];
1102 GL_TransformToScreen(v, v2);
1103 //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]);
1121 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1122 if (ix1 < r_view_x) ix1 = r_view_x;
1123 if (iy1 < r_view_y) iy1 = r_view_y;
1124 if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
1125 if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
1126 if (ix2 <= ix1 || iy2 <= iy1)
1128 // set up the scissor rectangle
1129 GL_Scissor(ix1, vid.realheight - iy2, ix2 - ix1, iy2 - iy1);
1130 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1131 //qglEnable(GL_SCISSOR_TEST);
1136 static void R_Shadow_VertexShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1138 float *color4f = varray_color4f;
1139 float dist, dot, intensity, v[3], n[3];
1140 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1142 Matrix4x4_Transform(m, vertex3f, v);
1143 if ((dist = DotProduct(v, v)) < 1)
1145 Matrix4x4_Transform3x3(m, normal3f, n);
1146 if ((dot = DotProduct(n, v)) > 0)
1149 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1150 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1151 VectorScale(lightcolor, intensity, color4f);
1156 VectorClear(color4f);
1162 VectorClear(color4f);
1168 static void R_Shadow_VertexShadingWithZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1170 float *color4f = varray_color4f;
1171 float dist, dot, intensity, v[3], n[3];
1172 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1174 Matrix4x4_Transform(m, vertex3f, v);
1175 if ((dist = fabs(v[2])) < 1)
1177 Matrix4x4_Transform3x3(m, normal3f, n);
1178 if ((dot = DotProduct(n, v)) > 0)
1180 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1181 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1182 VectorScale(lightcolor, intensity, color4f);
1187 VectorClear(color4f);
1193 VectorClear(color4f);
1199 static void R_Shadow_VertexShading(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1201 float *color4f = varray_color4f;
1202 float dot, intensity, v[3], n[3];
1203 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1205 Matrix4x4_Transform(m, vertex3f, v);
1206 Matrix4x4_Transform3x3(m, normal3f, n);
1207 if ((dot = DotProduct(n, v)) > 0)
1209 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1210 VectorScale(lightcolor, intensity, color4f);
1215 VectorClear(color4f);
1221 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1222 #define USETEXMATRIX
1224 #ifndef USETEXMATRIX
1225 // this should be done in a texture matrix or vertex program when possible, but here's code to do it manually
1226 // if hardware texcoord manipulation is not available (or not suitable, this would really benefit from 3DNow! or SSE
1227 static void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1231 tc3f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1232 tc3f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1233 tc3f[2] = vertex3f[0] * matrix->m[2][0] + vertex3f[1] * matrix->m[2][1] + vertex3f[2] * matrix->m[2][2] + matrix->m[2][3];
1240 static void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1244 tc2f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1245 tc2f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1253 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)
1257 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1259 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1260 // the cubemap normalizes this for us
1261 out3f[0] = DotProduct(svector3f, lightdir);
1262 out3f[1] = DotProduct(tvector3f, lightdir);
1263 out3f[2] = DotProduct(normal3f, lightdir);
1267 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)
1270 float lightdir[3], eyedir[3], halfdir[3];
1271 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1273 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1274 VectorNormalizeFast(lightdir);
1275 VectorSubtract(vertex3f, relativeeyeorigin, eyedir);
1276 VectorNormalizeFast(eyedir);
1277 VectorAdd(lightdir, eyedir, halfdir);
1278 // the cubemap normalizes this for us
1279 out3f[0] = DotProduct(svector3f, halfdir);
1280 out3f[1] = DotProduct(tvector3f, halfdir);
1281 out3f[2] = DotProduct(normal3f, halfdir);
1285 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)
1288 float color[3], color2[3], colorscale;
1291 bumptexture = r_shadow_blankbumptexture;
1293 glosstexture = r_shadow_blankglosstexture;
1294 GL_DepthMask(false);
1296 if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
1298 if (lighting & LIGHTING_DIFFUSE)
1301 colorscale = r_shadow_lightintensityscale.value;
1302 // colorscale accounts for how much we multiply the brightness
1305 // mult is how many times the final pass of the lighting will be
1306 // performed to get more brightness than otherwise possible.
1308 // Limit mult to 64 for sanity sake.
1309 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1311 // 3/2 3D combine path (Geforce3, Radeon 8500)
1312 memset(&m, 0, sizeof(m));
1313 m.pointer_vertex = vertex3f;
1314 m.tex[0] = R_GetTexture(bumptexture);
1315 m.texcombinergb[0] = GL_REPLACE;
1316 m.pointer_texcoord[0] = texcoord2f;
1317 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1318 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1319 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1320 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1321 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1323 m.pointer_texcoord3f[2] = vertex3f;
1324 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
1326 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1327 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1330 GL_ColorMask(0,0,0,1);
1331 GL_BlendFunc(GL_ONE, GL_ZERO);
1332 GL_LockArrays(0, numverts);
1333 R_Mesh_Draw(numverts, numtriangles, elements);
1334 GL_LockArrays(0, 0);
1336 c_rt_lighttris += numtriangles;
1338 memset(&m, 0, sizeof(m));
1339 m.pointer_vertex = vertex3f;
1340 m.tex[0] = R_GetTexture(basetexture);
1341 m.pointer_texcoord[0] = texcoord2f;
1344 m.texcubemap[1] = R_GetTexture(lightcubemap);
1346 m.pointer_texcoord3f[1] = vertex3f;
1347 m.texmatrix[1] = *matrix_modeltolight;
1349 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1350 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1354 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap)
1356 // 1/2/2 3D combine path (original Radeon)
1357 memset(&m, 0, sizeof(m));
1358 m.pointer_vertex = vertex3f;
1359 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1361 m.pointer_texcoord3f[0] = vertex3f;
1362 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1364 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1365 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1368 GL_ColorMask(0,0,0,1);
1369 GL_BlendFunc(GL_ONE, GL_ZERO);
1370 GL_LockArrays(0, numverts);
1371 R_Mesh_Draw(numverts, numtriangles, elements);
1372 GL_LockArrays(0, 0);
1374 c_rt_lighttris += numtriangles;
1376 memset(&m, 0, sizeof(m));
1377 m.pointer_vertex = vertex3f;
1378 m.tex[0] = R_GetTexture(bumptexture);
1379 m.texcombinergb[0] = GL_REPLACE;
1380 m.pointer_texcoord[0] = texcoord2f;
1381 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1382 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1383 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1384 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1386 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1387 GL_LockArrays(0, numverts);
1388 R_Mesh_Draw(numverts, numtriangles, elements);
1389 GL_LockArrays(0, 0);
1391 c_rt_lighttris += numtriangles;
1393 memset(&m, 0, sizeof(m));
1394 m.pointer_vertex = vertex3f;
1395 m.tex[0] = R_GetTexture(basetexture);
1396 m.pointer_texcoord[0] = texcoord2f;
1399 m.texcubemap[1] = R_GetTexture(lightcubemap);
1401 m.pointer_texcoord3f[1] = vertex3f;
1402 m.texmatrix[1] = *matrix_modeltolight;
1404 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1405 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1409 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap)
1411 // 2/2 3D combine path (original Radeon)
1412 memset(&m, 0, sizeof(m));
1413 m.pointer_vertex = vertex3f;
1414 m.tex[0] = R_GetTexture(bumptexture);
1415 m.texcombinergb[0] = GL_REPLACE;
1416 m.pointer_texcoord[0] = texcoord2f;
1417 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1418 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1419 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1420 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1422 GL_ColorMask(0,0,0,1);
1423 GL_BlendFunc(GL_ONE, GL_ZERO);
1424 GL_LockArrays(0, numverts);
1425 R_Mesh_Draw(numverts, numtriangles, elements);
1426 GL_LockArrays(0, 0);
1428 c_rt_lighttris += numtriangles;
1430 memset(&m, 0, sizeof(m));
1431 m.pointer_vertex = vertex3f;
1432 m.tex[0] = R_GetTexture(basetexture);
1433 m.pointer_texcoord[0] = texcoord2f;
1434 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1436 m.pointer_texcoord3f[1] = vertex3f;
1437 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1439 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1440 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1443 else if (r_textureunits.integer >= 4)
1445 // 4/2 2D combine path (Geforce3, Radeon 8500)
1446 memset(&m, 0, sizeof(m));
1447 m.pointer_vertex = vertex3f;
1448 m.tex[0] = R_GetTexture(bumptexture);
1449 m.texcombinergb[0] = GL_REPLACE;
1450 m.pointer_texcoord[0] = texcoord2f;
1451 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1452 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1453 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1454 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1455 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1457 m.pointer_texcoord3f[2] = vertex3f;
1458 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
1460 m.pointer_texcoord[2] = varray_texcoord2f[2];
1461 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1463 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1465 m.pointer_texcoord3f[3] = vertex3f;
1466 m.texmatrix[3] = *matrix_modeltoattenuationz;
1468 m.pointer_texcoord[3] = varray_texcoord2f[3];
1469 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[3], numverts, vertex3f, matrix_modeltoattenuationz);
1472 GL_ColorMask(0,0,0,1);
1473 GL_BlendFunc(GL_ONE, GL_ZERO);
1474 GL_LockArrays(0, numverts);
1475 R_Mesh_Draw(numverts, numtriangles, elements);
1476 GL_LockArrays(0, 0);
1478 c_rt_lighttris += numtriangles;
1480 memset(&m, 0, sizeof(m));
1481 m.pointer_vertex = vertex3f;
1482 m.tex[0] = R_GetTexture(basetexture);
1483 m.pointer_texcoord[0] = texcoord2f;
1486 m.texcubemap[1] = R_GetTexture(lightcubemap);
1488 m.pointer_texcoord3f[1] = vertex3f;
1489 m.texmatrix[1] = *matrix_modeltolight;
1491 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1492 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1498 // 2/2/2 2D combine path (any dot3 card)
1499 memset(&m, 0, sizeof(m));
1500 m.pointer_vertex = vertex3f;
1501 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1503 m.pointer_texcoord3f[0] = vertex3f;
1504 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1506 m.pointer_texcoord[0] = varray_texcoord2f[0];
1507 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1509 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1511 m.pointer_texcoord3f[1] = vertex3f;
1512 m.texmatrix[1] = *matrix_modeltoattenuationz;
1514 m.pointer_texcoord[1] = varray_texcoord2f[1];
1515 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1518 GL_ColorMask(0,0,0,1);
1519 GL_BlendFunc(GL_ONE, GL_ZERO);
1520 GL_LockArrays(0, numverts);
1521 R_Mesh_Draw(numverts, numtriangles, elements);
1522 GL_LockArrays(0, 0);
1524 c_rt_lighttris += numtriangles;
1526 memset(&m, 0, sizeof(m));
1527 m.pointer_vertex = vertex3f;
1528 m.tex[0] = R_GetTexture(bumptexture);
1529 m.texcombinergb[0] = GL_REPLACE;
1530 m.pointer_texcoord[0] = texcoord2f;
1531 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1532 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1533 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1534 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1536 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1537 GL_LockArrays(0, numverts);
1538 R_Mesh_Draw(numverts, numtriangles, elements);
1539 GL_LockArrays(0, 0);
1541 c_rt_lighttris += numtriangles;
1543 memset(&m, 0, sizeof(m));
1544 m.pointer_vertex = vertex3f;
1545 m.tex[0] = R_GetTexture(basetexture);
1546 m.pointer_texcoord[0] = texcoord2f;
1549 m.texcubemap[1] = R_GetTexture(lightcubemap);
1551 m.pointer_texcoord3f[1] = vertex3f;
1552 m.texmatrix[1] = *matrix_modeltolight;
1554 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1555 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1559 // this final code is shared
1561 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1562 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1563 VectorScale(lightcolor, colorscale, color2);
1564 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1566 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1567 GL_LockArrays(0, numverts);
1568 R_Mesh_Draw(numverts, numtriangles, elements);
1569 GL_LockArrays(0, 0);
1571 c_rt_lighttris += numtriangles;
1574 if ((lighting & LIGHTING_SPECULAR) && (r_shadow_gloss.integer >= 2 || (r_shadow_gloss.integer >= 1 && glosstexture != r_shadow_blankglosstexture)))
1576 // FIXME: detect blendsquare!
1577 //if (gl_support_blendsquare)
1579 colorscale = r_shadow_lightintensityscale.value * r_shadow_glossintensity.value;
1580 if (glosstexture == r_shadow_blankglosstexture)
1581 colorscale *= r_shadow_gloss2intensity.value;
1583 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1585 // 2/0/0/1/2 3D combine blendsquare path
1586 memset(&m, 0, sizeof(m));
1587 m.pointer_vertex = vertex3f;
1588 m.tex[0] = R_GetTexture(bumptexture);
1589 m.pointer_texcoord[0] = texcoord2f;
1590 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1591 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1592 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1593 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1595 GL_ColorMask(0,0,0,1);
1596 // this squares the result
1597 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1598 GL_LockArrays(0, numverts);
1599 R_Mesh_Draw(numverts, numtriangles, elements);
1600 GL_LockArrays(0, 0);
1602 c_rt_lighttris += numtriangles;
1604 memset(&m, 0, sizeof(m));
1605 m.pointer_vertex = vertex3f;
1607 GL_LockArrays(0, numverts);
1608 // square alpha in framebuffer a few times to make it shiny
1609 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1610 // these comments are a test run through this math for intensity 0.5
1611 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1612 // 0.25 * 0.25 = 0.0625 (this is another pass)
1613 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1614 R_Mesh_Draw(numverts, numtriangles, elements);
1616 c_rt_lighttris += numtriangles;
1617 R_Mesh_Draw(numverts, numtriangles, elements);
1619 c_rt_lighttris += numtriangles;
1620 GL_LockArrays(0, 0);
1622 memset(&m, 0, sizeof(m));
1623 m.pointer_vertex = vertex3f;
1624 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1626 m.pointer_texcoord3f[0] = vertex3f;
1627 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1629 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1630 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1633 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1634 GL_LockArrays(0, numverts);
1635 R_Mesh_Draw(numverts, numtriangles, elements);
1636 GL_LockArrays(0, 0);
1638 c_rt_lighttris += numtriangles;
1640 memset(&m, 0, sizeof(m));
1641 m.pointer_vertex = vertex3f;
1642 m.tex[0] = R_GetTexture(glosstexture);
1643 m.pointer_texcoord[0] = texcoord2f;
1646 m.texcubemap[1] = R_GetTexture(lightcubemap);
1648 m.pointer_texcoord3f[1] = vertex3f;
1649 m.texmatrix[1] = *matrix_modeltolight;
1651 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1652 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1656 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1658 // 2/0/0/2 3D combine blendsquare path
1659 memset(&m, 0, sizeof(m));
1660 m.pointer_vertex = vertex3f;
1661 m.tex[0] = R_GetTexture(bumptexture);
1662 m.pointer_texcoord[0] = texcoord2f;
1663 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1664 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1665 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1666 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1668 GL_ColorMask(0,0,0,1);
1669 // this squares the result
1670 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1671 GL_LockArrays(0, numverts);
1672 R_Mesh_Draw(numverts, numtriangles, elements);
1673 GL_LockArrays(0, 0);
1675 c_rt_lighttris += numtriangles;
1677 memset(&m, 0, sizeof(m));
1678 m.pointer_vertex = vertex3f;
1680 GL_LockArrays(0, numverts);
1681 // square alpha in framebuffer a few times to make it shiny
1682 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1683 // these comments are a test run through this math for intensity 0.5
1684 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1685 // 0.25 * 0.25 = 0.0625 (this is another pass)
1686 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1687 R_Mesh_Draw(numverts, numtriangles, elements);
1689 c_rt_lighttris += numtriangles;
1690 R_Mesh_Draw(numverts, numtriangles, elements);
1692 c_rt_lighttris += numtriangles;
1693 GL_LockArrays(0, 0);
1695 memset(&m, 0, sizeof(m));
1696 m.pointer_vertex = vertex3f;
1697 m.tex[0] = R_GetTexture(glosstexture);
1698 m.pointer_texcoord[0] = texcoord2f;
1699 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1701 m.pointer_texcoord3f[1] = vertex3f;
1702 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1704 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1705 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1710 // 2/0/0/2/2 2D combine blendsquare path
1711 memset(&m, 0, sizeof(m));
1712 m.pointer_vertex = vertex3f;
1713 m.tex[0] = R_GetTexture(bumptexture);
1714 m.pointer_texcoord[0] = texcoord2f;
1715 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1716 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1717 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1718 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1720 GL_ColorMask(0,0,0,1);
1721 // this squares the result
1722 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1723 GL_LockArrays(0, numverts);
1724 R_Mesh_Draw(numverts, numtriangles, elements);
1725 GL_LockArrays(0, 0);
1727 c_rt_lighttris += numtriangles;
1729 memset(&m, 0, sizeof(m));
1730 m.pointer_vertex = vertex3f;
1732 GL_LockArrays(0, numverts);
1733 // square alpha in framebuffer a few times to make it shiny
1734 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1735 // these comments are a test run through this math for intensity 0.5
1736 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1737 // 0.25 * 0.25 = 0.0625 (this is another pass)
1738 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1739 R_Mesh_Draw(numverts, numtriangles, elements);
1741 c_rt_lighttris += numtriangles;
1742 R_Mesh_Draw(numverts, numtriangles, elements);
1744 c_rt_lighttris += numtriangles;
1745 GL_LockArrays(0, 0);
1747 memset(&m, 0, sizeof(m));
1748 m.pointer_vertex = vertex3f;
1749 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1751 m.pointer_texcoord3f[0] = vertex3f;
1752 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1754 m.pointer_texcoord[0] = varray_texcoord2f[0];
1755 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1757 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1759 m.pointer_texcoord3f[1] = vertex3f;
1760 m.texmatrix[1] = *matrix_modeltoattenuationz;
1762 m.pointer_texcoord[1] = varray_texcoord2f[1];
1763 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1766 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1767 GL_LockArrays(0, numverts);
1768 R_Mesh_Draw(numverts, numtriangles, elements);
1769 GL_LockArrays(0, 0);
1771 c_rt_lighttris += numtriangles;
1773 memset(&m, 0, sizeof(m));
1774 m.pointer_vertex = vertex3f;
1775 m.tex[0] = R_GetTexture(glosstexture);
1776 m.pointer_texcoord[0] = texcoord2f;
1779 m.texcubemap[1] = R_GetTexture(lightcubemap);
1781 m.pointer_texcoord3f[1] = vertex3f;
1782 m.texmatrix[1] = *matrix_modeltolight;
1784 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1785 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1791 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1792 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1793 VectorScale(lightcolor, colorscale, color2);
1794 GL_LockArrays(0, numverts);
1795 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1797 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1798 R_Mesh_Draw(numverts, numtriangles, elements);
1800 c_rt_lighttris += numtriangles;
1802 GL_LockArrays(0, 0);
1807 if (lighting & LIGHTING_DIFFUSE)
1809 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1810 VectorScale(lightcolor, r_shadow_lightintensityscale.value, color2);
1811 memset(&m, 0, sizeof(m));
1812 m.pointer_vertex = vertex3f;
1813 m.pointer_color = varray_color4f;
1814 m.tex[0] = R_GetTexture(basetexture);
1815 m.pointer_texcoord[0] = texcoord2f;
1816 if (r_textureunits.integer >= 2)
1819 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1821 m.pointer_texcoord3f[1] = vertex3f;
1822 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1824 m.pointer_texcoord[1] = varray_texcoord2f[1];
1825 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1827 if (r_textureunits.integer >= 3)
1829 // Geforce3/Radeon class but not using dot3
1830 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1832 m.pointer_texcoord3f[2] = vertex3f;
1833 m.texmatrix[2] = *matrix_modeltoattenuationz;
1835 m.pointer_texcoord[2] = varray_texcoord2f[2];
1836 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationz);
1841 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1843 color[0] = bound(0, color2[0], 1);
1844 color[1] = bound(0, color2[1], 1);
1845 color[2] = bound(0, color2[2], 1);
1846 if (r_textureunits.integer >= 3)
1847 R_Shadow_VertexShading(numverts, vertex3f, normal3f, color, matrix_modeltolight);
1848 else if (r_textureunits.integer >= 2)
1849 R_Shadow_VertexShadingWithZAttenuation(numverts, vertex3f, normal3f, color, matrix_modeltolight);
1851 R_Shadow_VertexShadingWithXYZAttenuation(numverts, vertex3f, normal3f, color, matrix_modeltolight);
1852 GL_LockArrays(0, numverts);
1853 R_Mesh_Draw(numverts, numtriangles, elements);
1854 GL_LockArrays(0, 0);
1856 c_rt_lighttris += numtriangles;
1862 void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
1866 R_RTLight_Uncompile(rtlight);
1867 memset(rtlight, 0, sizeof(*rtlight));
1869 VectorCopy(light->origin, rtlight->shadoworigin);
1870 VectorCopy(light->color, rtlight->color);
1871 rtlight->radius = light->radius;
1872 //rtlight->cullradius = rtlight->radius;
1873 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
1874 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
1875 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
1876 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
1877 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
1878 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
1879 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
1880 rtlight->cubemapname[0] = 0;
1881 if (light->cubemapname[0])
1882 strcpy(rtlight->cubemapname, light->cubemapname);
1883 else if (light->cubemapnum > 0)
1884 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
1885 rtlight->shadow = light->shadow;
1886 rtlight->corona = light->corona;
1887 rtlight->style = light->style;
1888 rtlight->isstatic = isstatic;
1889 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
1890 // ConcatScale won't work here because this needs to scale rotate and
1891 // translate, not just rotate
1892 scale = 1.0f / rtlight->radius;
1893 for (k = 0;k < 3;k++)
1894 for (j = 0;j < 4;j++)
1895 rtlight->matrix_worldtolight.m[k][j] *= scale;
1896 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationxyz, &matrix_attenuationxyz, &rtlight->matrix_worldtolight);
1897 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationz, &matrix_attenuationz, &rtlight->matrix_worldtolight);
1899 rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
1900 rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
1901 VectorScale(rtlight->color, rtlight->radius * d_lightstylevalue[rtlight->style] * 0.125f, rtlight->lightmap_light);
1902 rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
1905 // compiles rtlight geometry
1906 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
1907 void R_RTLight_Compile(rtlight_t *rtlight)
1909 int shadowmeshes, shadowtris, lightmeshes, lighttris, numclusters, numsurfaces;
1910 entity_render_t *ent = &cl_entities[0].render;
1911 model_t *model = ent->model;
1913 // compile the light
1914 rtlight->compiled = true;
1915 rtlight->static_numclusters = 0;
1916 rtlight->static_numclusterpvsbytes = 0;
1917 rtlight->static_clusterlist = NULL;
1918 rtlight->static_clusterpvs = NULL;
1919 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
1920 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
1921 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
1922 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
1923 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
1924 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
1926 if (model && model->GetLightInfo)
1928 // this variable directs the DrawShadowVolume and DrawLight code to capture into the mesh chain instead of rendering
1929 r_shadow_compilingrtlight = rtlight;
1930 R_Shadow_EnlargeClusterBuffer(model->brush.num_pvsclusters);
1931 R_Shadow_EnlargeSurfaceBuffer(model->nummodelsurfaces);
1932 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);
1935 rtlight->static_numclusters = numclusters;
1936 rtlight->static_numclusterpvsbytes = (model->brush.num_pvsclusters + 7) >> 3;
1937 rtlight->static_clusterlist = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
1938 rtlight->static_clusterpvs = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusterpvsbytes);
1939 memcpy(rtlight->static_clusterlist, r_shadow_buffer_clusterlist, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
1940 memcpy(rtlight->static_clusterpvs, r_shadow_buffer_clusterpvs, rtlight->static_numclusterpvsbytes);
1942 if (model->DrawShadowVolume && rtlight->shadow)
1944 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
1945 model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
1946 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_shadow, false, false);
1948 if (model->DrawLight)
1950 rtlight->static_meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true);
1951 model->DrawLight(ent, rtlight->shadoworigin, vec3_origin, rtlight->radius, vec3_origin, &r_identitymatrix, &r_identitymatrix, &r_identitymatrix, NULL, numsurfaces, r_shadow_buffer_surfacelist);
1952 rtlight->static_meshchain_light = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_light, true, false);
1954 // switch back to rendering when DrawShadowVolume or DrawLight is called
1955 r_shadow_compilingrtlight = NULL;
1959 // use smallest available cullradius - box radius or light radius
1960 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
1961 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
1965 if (rtlight->static_meshchain_shadow)
1968 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
1971 shadowtris += mesh->numtriangles;
1977 if (rtlight->static_meshchain_light)
1980 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
1983 lighttris += mesh->numtriangles;
1987 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);
1990 void R_RTLight_Uncompile(rtlight_t *rtlight)
1992 if (rtlight->compiled)
1994 if (rtlight->static_meshchain_shadow)
1995 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
1996 rtlight->static_meshchain_shadow = NULL;
1997 if (rtlight->static_meshchain_light)
1998 Mod_ShadowMesh_Free(rtlight->static_meshchain_light);
1999 rtlight->static_meshchain_light = NULL;
2000 if (rtlight->static_clusterlist)
2001 Mem_Free(rtlight->static_clusterlist);
2002 rtlight->static_clusterlist = NULL;
2003 if (rtlight->static_clusterpvs)
2004 Mem_Free(rtlight->static_clusterpvs);
2005 rtlight->static_clusterpvs = NULL;
2006 rtlight->static_numclusters = 0;
2007 rtlight->static_numclusterpvsbytes = 0;
2008 rtlight->compiled = false;
2012 void R_Shadow_UncompileWorldLights(void)
2015 for (light = r_shadow_worldlightchain;light;light = light->next)
2016 R_RTLight_Uncompile(&light->rtlight);
2019 void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes)
2022 entity_render_t *ent;
2024 vec3_t relativelightorigin, relativeeyeorigin, lightcolor;
2025 rtexture_t *cubemaptexture;
2026 matrix4x4_t matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz;
2027 int numclusters, numsurfaces;
2028 int *clusterlist, *surfacelist;
2030 vec3_t cullmins, cullmaxs;
2034 // loading is done before visibility checks because loading should happen
2035 // all at once at the start of a level, not when it stalls gameplay.
2036 // (especially important to benchmarks)
2037 if (rtlight->isstatic && !rtlight->compiled && r_shadow_staticworldlights.integer)
2038 R_RTLight_Compile(rtlight);
2039 if (rtlight->cubemapname[0])
2040 cubemaptexture = R_Shadow_Cubemap(rtlight->cubemapname);
2042 cubemaptexture = NULL;
2044 cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2045 cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2046 cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2047 cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2048 cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2049 cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2050 if (d_lightstylevalue[rtlight->style] <= 0)
2057 if (rtlight->compiled && r_shadow_staticworldlights.integer)
2059 // compiled light, world available and can receive realtime lighting
2060 // retrieve cluster information
2061 numclusters = rtlight->static_numclusters;
2062 clusterlist = rtlight->static_clusterlist;
2063 clusterpvs = rtlight->static_clusterpvs;
2064 VectorCopy(rtlight->cullmins, cullmins);
2065 VectorCopy(rtlight->cullmaxs, cullmaxs);
2067 else if (cl.worldmodel && cl.worldmodel->GetLightInfo)
2069 // dynamic light, world available and can receive realtime lighting
2070 // if the light box is offscreen, skip it right away
2071 if (R_CullBox(cullmins, cullmaxs))
2073 // calculate lit surfaces and clusters
2074 R_Shadow_EnlargeClusterBuffer(cl.worldmodel->brush.num_pvsclusters);
2075 R_Shadow_EnlargeSurfaceBuffer(cl.worldmodel->nummodelsurfaces);
2076 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);
2077 clusterlist = r_shadow_buffer_clusterlist;
2078 clusterpvs = r_shadow_buffer_clusterpvs;
2079 surfacelist = r_shadow_buffer_surfacelist;
2081 // if the reduced cluster bounds are offscreen, skip it
2082 if (R_CullBox(cullmins, cullmaxs))
2084 // check if light is illuminating any visible clusters
2087 for (i = 0;i < numclusters;i++)
2088 if (CHECKPVSBIT(r_pvsbits, clusterlist[i]))
2090 if (i == numclusters)
2093 // set up a scissor rectangle for this light
2094 if (R_Shadow_ScissorForBBox(cullmins, cullmaxs))
2097 f = d_lightstylevalue[rtlight->style] * (1.0f / 256.0f);
2098 VectorScale(rtlight->color, f, lightcolor);
2100 if (rtlight->selected)
2102 f = 2 + sin(realtime * M_PI * 4.0);
2103 VectorScale(lightcolor, f, lightcolor);
2108 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));
2111 if (rtlight->shadow)
2113 if (rtlight->isstatic)
2114 shadow = r_shadow_realtime_world_shadows.integer;
2117 if (r_shadow_realtime_world.integer)
2118 shadow = r_shadow_realtime_world_dlightshadows.integer;
2120 shadow = r_shadow_realtime_dlight_shadows.integer;
2125 if (shadow && (gl_stencil || visiblevolumes))
2127 if (!visiblevolumes)
2128 R_Shadow_Stage_ShadowVolumes();
2129 ent = &cl_entities[0].render;
2130 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2132 memset(&m, 0, sizeof(m));
2133 R_Mesh_Matrix(&ent->matrix);
2134 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2136 m.pointer_vertex = mesh->vertex3f;
2138 GL_LockArrays(0, mesh->numverts);
2139 if (r_shadowstage == SHADOWSTAGE_STENCIL)
2141 // decrement stencil if frontface is behind depthbuffer
2142 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2143 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2144 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2145 c_rtcached_shadowmeshes++;
2146 c_rtcached_shadowtris += mesh->numtriangles;
2147 // increment stencil if backface is behind depthbuffer
2148 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2149 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2151 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2152 c_rtcached_shadowmeshes++;
2153 c_rtcached_shadowtris += mesh->numtriangles;
2154 GL_LockArrays(0, 0);
2159 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2160 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, numsurfaces, surfacelist);
2162 if (r_drawentities.integer)
2164 for (i = 0;i < r_refdef.numentities;i++)
2166 ent = r_refdef.entities[i];
2168 if (r_shadow_cull.integer)
2170 if (!BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs))
2172 if (cl.worldmodel != NULL && cl.worldmodel->brush.BoxTouchingPVS != NULL && !cl.worldmodel->brush.BoxTouchingPVS(cl.worldmodel, clusterpvs, ent->mins, ent->maxs))
2175 if (!(ent->flags & RENDER_SHADOW) || !ent->model || !ent->model->DrawShadowVolume)
2177 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2178 // light emitting entities should not cast their own shadow
2179 if (VectorLength2(relativelightorigin) < 0.1)
2181 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, ent->model->nummodelsurfaces, ent->model->surfacelist);
2186 if (!visiblevolumes)
2188 R_Shadow_Stage_Light(shadow && gl_stencil);
2190 ent = &cl_entities[0].render;
2191 if (ent->model && ent->model->DrawLight)
2193 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2194 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2195 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2196 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2197 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2198 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2200 R_Mesh_Matrix(&ent->matrix);
2201 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2202 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);
2205 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, numsurfaces, surfacelist);
2207 if (r_drawentities.integer)
2209 for (i = 0;i < r_refdef.numentities;i++)
2211 ent = r_refdef.entities[i];
2212 if (ent->visframe == r_framecount && BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs) && ent->model && ent->model->DrawLight && (ent->flags & RENDER_LIGHT))
2214 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2215 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2216 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2217 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2218 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2219 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, ent->model->nummodelsurfaces, ent->model->surfacelist);
2226 void R_ShadowVolumeLighting(int visiblevolumes)
2232 if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2233 R_Shadow_EditLights_Reload_f();
2237 memset(&m, 0, sizeof(m));
2240 GL_BlendFunc(GL_ONE, GL_ONE);
2241 GL_DepthMask(false);
2242 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
2243 qglDisable(GL_CULL_FACE);
2244 GL_Color(0.0, 0.0125, 0.1, 1);
2247 R_Shadow_Stage_Begin();
2248 if (r_shadow_realtime_world.integer)
2250 if (r_shadow_debuglight.integer >= 0)
2252 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2253 if (lnum == r_shadow_debuglight.integer)
2254 R_DrawRTLight(&light->rtlight, visiblevolumes);
2257 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2258 R_DrawRTLight(&light->rtlight, visiblevolumes);
2260 if (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer)
2261 for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
2262 R_DrawRTLight(&light->rtlight, visiblevolumes);
2266 qglEnable(GL_CULL_FACE);
2267 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
2270 R_Shadow_Stage_End();
2273 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2274 typedef struct suffixinfo_s
2277 qboolean flipx, flipy, flipdiagonal;
2280 static suffixinfo_t suffix[3][6] =
2283 {"px", false, false, false},
2284 {"nx", false, false, false},
2285 {"py", false, false, false},
2286 {"ny", false, false, false},
2287 {"pz", false, false, false},
2288 {"nz", false, false, false}
2291 {"posx", false, false, false},
2292 {"negx", false, false, false},
2293 {"posy", false, false, false},
2294 {"negy", false, false, false},
2295 {"posz", false, false, false},
2296 {"negz", false, false, false}
2299 {"rt", true, false, true},
2300 {"lf", false, true, true},
2301 {"ft", true, true, false},
2302 {"bk", false, false, false},
2303 {"up", true, false, true},
2304 {"dn", true, false, true}
2308 static int componentorder[4] = {0, 1, 2, 3};
2310 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2312 int i, j, cubemapsize;
2313 qbyte *cubemappixels, *image_rgba;
2314 rtexture_t *cubemaptexture;
2316 // must start 0 so the first loadimagepixels has no requested width/height
2318 cubemappixels = NULL;
2319 cubemaptexture = NULL;
2320 // keep trying different suffix groups (posx, px, rt) until one loads
2321 for (j = 0;j < 3 && !cubemappixels;j++)
2323 // load the 6 images in the suffix group
2324 for (i = 0;i < 6;i++)
2326 // generate an image name based on the base and and suffix
2327 snprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2329 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2331 // an image loaded, make sure width and height are equal
2332 if (image_width == image_height)
2334 // if this is the first image to load successfully, allocate the cubemap memory
2335 if (!cubemappixels && image_width >= 1)
2337 cubemapsize = image_width;
2338 // note this clears to black, so unavailable sides are black
2339 cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2341 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2343 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);
2346 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2348 Mem_Free(image_rgba);
2352 // if a cubemap loaded, upload it
2355 if (!r_shadow_filters_texturepool)
2356 r_shadow_filters_texturepool = R_AllocTexturePool();
2357 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
2358 Mem_Free(cubemappixels);
2362 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
2363 for (j = 0;j < 3;j++)
2364 for (i = 0;i < 6;i++)
2365 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2366 Con_Print(" and was unable to find any of them.\n");
2368 return cubemaptexture;
2371 rtexture_t *R_Shadow_Cubemap(const char *basename)
2374 for (i = 0;i < numcubemaps;i++)
2375 if (!strcasecmp(cubemaps[i].basename, basename))
2376 return cubemaps[i].texture;
2377 if (i >= MAX_CUBEMAPS)
2380 strcpy(cubemaps[i].basename, basename);
2381 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
2382 return cubemaps[i].texture;
2385 void R_Shadow_FreeCubemaps(void)
2388 R_FreeTexturePool(&r_shadow_filters_texturepool);
2391 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)
2395 if (radius < 15 || DotProduct(color, color) < 0.03)
2397 Con_Print("R_Shadow_NewWorldLight: refusing to create a light too small/dim\n");
2401 light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
2402 VectorCopy(origin, light->origin);
2403 VectorCopy(angles, light->angles);
2404 VectorCopy(color, light->color);
2405 light->radius = radius;
2406 light->style = style;
2407 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
2409 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
2412 light->shadow = shadowenable;
2413 light->corona = corona;
2414 if (cubemapname && cubemapname[0] && strlen(cubemapname) < sizeof(light->cubemapname))
2415 strcpy(light->cubemapname, cubemapname);
2416 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
2417 light->next = r_shadow_worldlightchain;
2418 r_shadow_worldlightchain = light;
2420 R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
2423 void R_Shadow_FreeWorldLight(dlight_t *light)
2425 dlight_t **lightpointer;
2426 R_RTLight_Uncompile(&light->rtlight);
2427 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
2428 if (*lightpointer != light)
2429 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
2430 *lightpointer = light->next;
2434 void R_Shadow_ClearWorldLights(void)
2436 while (r_shadow_worldlightchain)
2437 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
2438 r_shadow_selectedlight = NULL;
2439 R_Shadow_FreeCubemaps();
2442 void R_Shadow_SelectLight(dlight_t *light)
2444 if (r_shadow_selectedlight)
2445 r_shadow_selectedlight->selected = false;
2446 r_shadow_selectedlight = light;
2447 if (r_shadow_selectedlight)
2448 r_shadow_selectedlight->selected = true;
2451 void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
2453 float scale = r_editlights_cursorgrid.value * 0.5f;
2454 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);
2457 void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
2460 const dlight_t *light;
2463 if (light->selected)
2464 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
2467 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);
2470 void R_Shadow_DrawLightSprites(void)
2476 for (i = 0;i < 5;i++)
2478 lighttextures[i] = NULL;
2479 if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1))))
2480 lighttextures[i] = pic->tex;
2483 for (light = r_shadow_worldlightchain;light;light = light->next)
2484 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, ((int) light) % 5);
2485 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
2488 void R_Shadow_SelectLightInView(void)
2490 float bestrating, rating, temp[3];
2491 dlight_t *best, *light;
2494 for (light = r_shadow_worldlightchain;light;light = light->next)
2496 VectorSubtract(light->origin, r_vieworigin, temp);
2497 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
2500 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
2501 if (bestrating < rating && CL_TraceLine(light->origin, r_vieworigin, NULL, NULL, true, NULL, SUPERCONTENTS_SOLID) == 1.0f)
2503 bestrating = rating;
2508 R_Shadow_SelectLight(best);
2511 void R_Shadow_LoadWorldLights(void)
2513 int n, a, style, shadow;
2514 char name[MAX_QPATH], cubemapname[MAX_QPATH], *lightsstring, *s, *t;
2515 float origin[3], radius, color[3], angles[3], corona;
2516 if (cl.worldmodel == NULL)
2518 Con_Print("No map loaded.\n");
2521 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2522 strlcat (name, ".rtlights", sizeof (name));
2523 lightsstring = FS_LoadFile(name, tempmempool, false);
2533 for (;COM_Parse(t, true) && strcmp(
2534 if (COM_Parse(t, true))
2536 if (com_token[0] == '!')
2539 origin[0] = atof(com_token+1);
2542 origin[0] = atof(com_token);
2547 while (*s && *s != '\n')
2553 // check for modifier flags
2559 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]);
2561 VectorClear(angles);
2564 if (a < 9 || !strcmp(cubemapname, "\"\""))
2569 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);
2572 VectorScale(color, r_editlights_rtlightscolorscale.value, color);
2573 radius *= r_editlights_rtlightssizescale.value;
2574 R_Shadow_NewWorldLight(origin, angles, color, radius, corona, style, shadow, cubemapname);
2579 Con_Printf("invalid rtlights file \"%s\"\n", name);
2580 Mem_Free(lightsstring);
2584 void R_Shadow_SaveWorldLights(void)
2587 int bufchars, bufmaxchars;
2589 char name[MAX_QPATH];
2591 if (!r_shadow_worldlightchain)
2593 if (cl.worldmodel == NULL)
2595 Con_Print("No map loaded.\n");
2598 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2599 strlcat (name, ".rtlights", sizeof (name));
2600 bufchars = bufmaxchars = 0;
2602 for (light = r_shadow_worldlightchain;light;light = light->next)
2604 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]);
2605 if (bufchars + (int) strlen(line) > bufmaxchars)
2607 bufmaxchars = bufchars + strlen(line) + 2048;
2609 buf = Mem_Alloc(r_shadow_mempool, bufmaxchars);
2613 memcpy(buf, oldbuf, bufchars);
2619 memcpy(buf + bufchars, line, strlen(line));
2620 bufchars += strlen(line);
2624 FS_WriteFile(name, buf, bufchars);
2629 void R_Shadow_LoadLightsFile(void)
2632 char name[MAX_QPATH], *lightsstring, *s, *t;
2633 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
2634 if (cl.worldmodel == NULL)
2636 Con_Print("No map loaded.\n");
2639 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2640 strlcat (name, ".lights", sizeof (name));
2641 lightsstring = FS_LoadFile(name, tempmempool, false);
2649 while (*s && *s != '\n')
2654 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);
2658 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);
2661 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
2662 radius = bound(15, radius, 4096);
2663 VectorScale(color, (2.0f / (8388608.0f)), color);
2664 R_Shadow_NewWorldLight(origin, vec3_origin, color, radius, 0, style, true, NULL);
2669 Con_Printf("invalid lights file \"%s\"\n", name);
2670 Mem_Free(lightsstring);
2674 // tyrlite/hmap2 light types in the delay field
2675 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
2677 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
2679 int entnum, style, islight, skin, pflags, effects, type, n;
2680 char key[256], value[1024];
2681 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
2684 if (cl.worldmodel == NULL)
2686 Con_Print("No map loaded.\n");
2689 data = cl.worldmodel->brush.entities;
2692 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
2694 type = LIGHTTYPE_MINUSX;
2695 origin[0] = origin[1] = origin[2] = 0;
2696 originhack[0] = originhack[1] = originhack[2] = 0;
2697 angles[0] = angles[1] = angles[2] = 0;
2698 color[0] = color[1] = color[2] = 1;
2699 light[0] = light[1] = light[2] = 1;light[3] = 300;
2700 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
2710 if (!COM_ParseToken(&data, false))
2712 if (com_token[0] == '}')
2713 break; // end of entity
2714 if (com_token[0] == '_')
2715 strcpy(key, com_token + 1);
2717 strcpy(key, com_token);
2718 while (key[strlen(key)-1] == ' ') // remove trailing spaces
2719 key[strlen(key)-1] = 0;
2720 if (!COM_ParseToken(&data, false))
2722 strcpy(value, com_token);
2724 // now that we have the key pair worked out...
2725 if (!strcmp("light", key))
2727 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
2731 light[0] = vec[0] * (1.0f / 256.0f);
2732 light[1] = vec[0] * (1.0f / 256.0f);
2733 light[2] = vec[0] * (1.0f / 256.0f);
2739 light[0] = vec[0] * (1.0f / 255.0f);
2740 light[1] = vec[1] * (1.0f / 255.0f);
2741 light[2] = vec[2] * (1.0f / 255.0f);
2745 else if (!strcmp("delay", key))
2747 else if (!strcmp("origin", key))
2748 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
2749 else if (!strcmp("angle", key))
2750 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
2751 else if (!strcmp("angles", key))
2752 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
2753 else if (!strcmp("color", key))
2754 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
2755 else if (!strcmp("wait", key))
2756 fadescale = atof(value);
2757 else if (!strcmp("classname", key))
2759 if (!strncmp(value, "light", 5))
2762 if (!strcmp(value, "light_fluoro"))
2767 overridecolor[0] = 1;
2768 overridecolor[1] = 1;
2769 overridecolor[2] = 1;
2771 if (!strcmp(value, "light_fluorospark"))
2776 overridecolor[0] = 1;
2777 overridecolor[1] = 1;
2778 overridecolor[2] = 1;
2780 if (!strcmp(value, "light_globe"))
2785 overridecolor[0] = 1;
2786 overridecolor[1] = 0.8;
2787 overridecolor[2] = 0.4;
2789 if (!strcmp(value, "light_flame_large_yellow"))
2794 overridecolor[0] = 1;
2795 overridecolor[1] = 0.5;
2796 overridecolor[2] = 0.1;
2798 if (!strcmp(value, "light_flame_small_yellow"))
2803 overridecolor[0] = 1;
2804 overridecolor[1] = 0.5;
2805 overridecolor[2] = 0.1;
2807 if (!strcmp(value, "light_torch_small_white"))
2812 overridecolor[0] = 1;
2813 overridecolor[1] = 0.5;
2814 overridecolor[2] = 0.1;
2816 if (!strcmp(value, "light_torch_small_walltorch"))
2821 overridecolor[0] = 1;
2822 overridecolor[1] = 0.5;
2823 overridecolor[2] = 0.1;
2827 else if (!strcmp("style", key))
2828 style = atoi(value);
2829 else if (cl.worldmodel->type == mod_brushq3)
2831 if (!strcmp("scale", key))
2832 lightscale = atof(value);
2833 if (!strcmp("fade", key))
2834 fadescale = atof(value);
2836 else if (!strcmp("skin", key))
2837 skin = (int)atof(value);
2838 else if (!strcmp("pflags", key))
2839 pflags = (int)atof(value);
2840 else if (!strcmp("effects", key))
2841 effects = (int)atof(value);
2845 if (lightscale <= 0)
2849 if (color[0] == color[1] && color[0] == color[2])
2851 color[0] *= overridecolor[0];
2852 color[1] *= overridecolor[1];
2853 color[2] *= overridecolor[2];
2855 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
2856 color[0] = color[0] * light[0];
2857 color[1] = color[1] * light[1];
2858 color[2] = color[2] * light[2];
2861 case LIGHTTYPE_MINUSX:
2863 case LIGHTTYPE_RECIPX:
2865 VectorScale(color, (1.0f / 16.0f), color);
2867 case LIGHTTYPE_RECIPXX:
2869 VectorScale(color, (1.0f / 16.0f), color);
2872 case LIGHTTYPE_NONE:
2876 case LIGHTTYPE_MINUSXX:
2879 VectorAdd(origin, originhack, origin);
2881 R_Shadow_NewWorldLight(origin, angles, color, radius, (pflags & PFLAGS_CORONA) != 0, style, (pflags & PFLAGS_NOSHADOW) == 0, skin >= 16 ? va("cubemaps/%i", skin) : NULL);
2886 void R_Shadow_SetCursorLocationForView(void)
2888 vec_t dist, push, frac;
2889 vec3_t dest, endpos, normal;
2890 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
2891 frac = CL_TraceLine(r_vieworigin, dest, endpos, normal, true, NULL, SUPERCONTENTS_SOLID);
2894 dist = frac * r_editlights_cursordistance.value;
2895 push = r_editlights_cursorpushback.value;
2899 VectorMA(endpos, push, r_viewforward, endpos);
2900 VectorMA(endpos, r_editlights_cursorpushoff.value, normal, endpos);
2902 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2903 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2904 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2907 void R_Shadow_UpdateWorldLightSelection(void)
2909 if (r_editlights.integer)
2911 R_Shadow_SetCursorLocationForView();
2912 R_Shadow_SelectLightInView();
2913 R_Shadow_DrawLightSprites();
2916 R_Shadow_SelectLight(NULL);
2919 void R_Shadow_EditLights_Clear_f(void)
2921 R_Shadow_ClearWorldLights();
2924 void R_Shadow_EditLights_Reload_f(void)
2928 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
2929 R_Shadow_ClearWorldLights();
2930 R_Shadow_LoadWorldLights();
2931 if (r_shadow_worldlightchain == NULL)
2933 R_Shadow_LoadLightsFile();
2934 if (r_shadow_worldlightchain == NULL)
2935 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
2939 void R_Shadow_EditLights_Save_f(void)
2943 R_Shadow_SaveWorldLights();
2946 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
2948 R_Shadow_ClearWorldLights();
2949 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
2952 void R_Shadow_EditLights_ImportLightsFile_f(void)
2954 R_Shadow_ClearWorldLights();
2955 R_Shadow_LoadLightsFile();
2958 void R_Shadow_EditLights_Spawn_f(void)
2961 if (!r_editlights.integer)
2963 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
2966 if (Cmd_Argc() != 1)
2968 Con_Print("r_editlights_spawn does not take parameters\n");
2971 color[0] = color[1] = color[2] = 1;
2972 R_Shadow_NewWorldLight(r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL);
2975 void R_Shadow_EditLights_Edit_f(void)
2977 vec3_t origin, angles, color;
2978 vec_t radius, corona;
2980 char cubemapname[1024];
2981 if (!r_editlights.integer)
2983 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
2986 if (!r_shadow_selectedlight)
2988 Con_Print("No selected light.\n");
2991 VectorCopy(r_shadow_selectedlight->origin, origin);
2992 VectorCopy(r_shadow_selectedlight->angles, angles);
2993 VectorCopy(r_shadow_selectedlight->color, color);
2994 radius = r_shadow_selectedlight->radius;
2995 style = r_shadow_selectedlight->style;
2996 if (r_shadow_selectedlight->cubemapname)
2997 strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
3000 shadows = r_shadow_selectedlight->shadow;
3001 corona = r_shadow_selectedlight->corona;
3002 if (!strcmp(Cmd_Argv(1), "origin"))
3004 if (Cmd_Argc() != 5)
3006 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3009 origin[0] = atof(Cmd_Argv(2));
3010 origin[1] = atof(Cmd_Argv(3));
3011 origin[2] = atof(Cmd_Argv(4));
3013 else if (!strcmp(Cmd_Argv(1), "originx"))
3015 if (Cmd_Argc() != 3)
3017 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3020 origin[0] = atof(Cmd_Argv(2));
3022 else if (!strcmp(Cmd_Argv(1), "originy"))
3024 if (Cmd_Argc() != 3)
3026 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3029 origin[1] = atof(Cmd_Argv(2));
3031 else if (!strcmp(Cmd_Argv(1), "originz"))
3033 if (Cmd_Argc() != 3)
3035 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3038 origin[2] = atof(Cmd_Argv(2));
3040 else if (!strcmp(Cmd_Argv(1), "move"))
3042 if (Cmd_Argc() != 5)
3044 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3047 origin[0] += atof(Cmd_Argv(2));
3048 origin[1] += atof(Cmd_Argv(3));
3049 origin[2] += atof(Cmd_Argv(4));
3051 else if (!strcmp(Cmd_Argv(1), "movex"))
3053 if (Cmd_Argc() != 3)
3055 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3058 origin[0] += atof(Cmd_Argv(2));
3060 else if (!strcmp(Cmd_Argv(1), "movey"))
3062 if (Cmd_Argc() != 3)
3064 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3067 origin[1] += atof(Cmd_Argv(2));
3069 else if (!strcmp(Cmd_Argv(1), "movez"))
3071 if (Cmd_Argc() != 3)
3073 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3076 origin[2] += atof(Cmd_Argv(2));
3078 else if (!strcmp(Cmd_Argv(1), "angles"))
3080 if (Cmd_Argc() != 5)
3082 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3085 angles[0] = atof(Cmd_Argv(2));
3086 angles[1] = atof(Cmd_Argv(3));
3087 angles[2] = atof(Cmd_Argv(4));
3089 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3091 if (Cmd_Argc() != 3)
3093 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3096 angles[0] = atof(Cmd_Argv(2));
3098 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3100 if (Cmd_Argc() != 3)
3102 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3105 angles[1] = atof(Cmd_Argv(2));
3107 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3109 if (Cmd_Argc() != 3)
3111 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3114 angles[2] = atof(Cmd_Argv(2));
3116 else if (!strcmp(Cmd_Argv(1), "color"))
3118 if (Cmd_Argc() != 5)
3120 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3123 color[0] = atof(Cmd_Argv(2));
3124 color[1] = atof(Cmd_Argv(3));
3125 color[2] = atof(Cmd_Argv(4));
3127 else if (!strcmp(Cmd_Argv(1), "radius"))
3129 if (Cmd_Argc() != 3)
3131 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3134 radius = atof(Cmd_Argv(2));
3136 else if (!strcmp(Cmd_Argv(1), "style"))
3138 if (Cmd_Argc() != 3)
3140 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3143 style = atoi(Cmd_Argv(2));
3145 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3149 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3152 if (Cmd_Argc() == 3)
3153 strcpy(cubemapname, Cmd_Argv(2));
3157 else if (!strcmp(Cmd_Argv(1), "shadows"))
3159 if (Cmd_Argc() != 3)
3161 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3164 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3166 else if (!strcmp(Cmd_Argv(1), "corona"))
3168 if (Cmd_Argc() != 3)
3170 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3173 corona = atof(Cmd_Argv(2));
3177 Con_Print("usage: r_editlights_edit [property] [value]\n");
3178 Con_Print("Selected light's properties:\n");
3179 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3180 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3181 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3182 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3183 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3184 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3185 Con_Printf("Shadows: %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3186 Con_Printf("Cubemap: %s\n", r_shadow_selectedlight->cubemapname);
3189 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3190 r_shadow_selectedlight = NULL;
3191 R_Shadow_NewWorldLight(origin, angles, color, radius, corona, style, shadows, cubemapname);
3194 void R_Shadow_EditLights_EditAll_f(void)
3198 for (light = r_shadow_worldlightchain;light;light = light->next)
3200 R_Shadow_SelectLight(light);
3201 R_Shadow_EditLights_Edit_f();
3205 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3209 if (!r_editlights.integer)
3213 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;
3214 if (r_shadow_selectedlight == NULL)
3216 sprintf(temp, "Light properties");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3217 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;
3218 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;
3219 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;
3220 sprintf(temp, "Radius %f", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3221 sprintf(temp, "Corona %f", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3222 sprintf(temp, "Style %i", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3223 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;
3224 sprintf(temp, "Cubemap %s", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3227 void R_Shadow_EditLights_ToggleShadow_f(void)
3229 if (!r_editlights.integer)
3231 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3234 if (!r_shadow_selectedlight)
3236 Con_Print("No selected light.\n");
3239 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);
3240 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3241 r_shadow_selectedlight = NULL;
3244 void R_Shadow_EditLights_ToggleCorona_f(void)
3246 if (!r_editlights.integer)
3248 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3251 if (!r_shadow_selectedlight)
3253 Con_Print("No selected light.\n");
3256 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);
3257 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3258 r_shadow_selectedlight = NULL;
3261 void R_Shadow_EditLights_Remove_f(void)
3263 if (!r_editlights.integer)
3265 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
3268 if (!r_shadow_selectedlight)
3270 Con_Print("No selected light.\n");
3273 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3274 r_shadow_selectedlight = NULL;
3277 void R_Shadow_EditLights_Help_f(void)
3280 "Documentation on r_editlights system:\n"
3282 "r_editlights : enable/disable editing mode\n"
3283 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
3284 "r_editlights_cursorpushback : push back cursor this far from surface\n"
3285 "r_editlights_cursorpushoff : push cursor off surface this far\n"
3286 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
3287 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
3288 "r_editlights_rtlightssizescale : imported rtlight size scaling\n"
3289 "r_editlights_rtlightscolorscale : imported rtlight color scaling\n"
3291 "r_editlights_help : this help\n"
3292 "r_editlights_clear : remove all lights\n"
3293 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
3294 "r_editlights_save : save to .rtlights file\n"
3295 "r_editlights_spawn : create a light with default settings\n"
3296 "r_editlights_edit command : edit selected light - more documentation below\n"
3297 "r_editlights_remove : remove selected light\n"
3298 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
3299 "r_editlights_importlightentitiesfrommap : reload light entities\n"
3300 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
3302 "origin x y z : set light location\n"
3303 "originx x: set x component of light location\n"
3304 "originy y: set y component of light location\n"
3305 "originz z: set z component of light location\n"
3306 "move x y z : adjust light location\n"
3307 "movex x: adjust x component of light location\n"
3308 "movey y: adjust y component of light location\n"
3309 "movez z: adjust z component of light location\n"
3310 "angles x y z : set light angles\n"
3311 "anglesx x: set x component of light angles\n"
3312 "anglesy y: set y component of light angles\n"
3313 "anglesz z: set z component of light angles\n"
3314 "color r g b : set color of light (can be brighter than 1 1 1)\n"
3315 "radius radius : set radius (size) of light\n"
3316 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
3317 "cubemap basename : set filter cubemap of light (not yet supported)\n"
3318 "shadows 1/0 : turn on/off shadows\n"
3319 "corona n : set corona intensity\n"
3320 "<nothing> : print light properties to console\n"
3324 void R_Shadow_EditLights_Init(void)
3326 Cvar_RegisterVariable(&r_editlights);
3327 Cvar_RegisterVariable(&r_editlights_cursordistance);
3328 Cvar_RegisterVariable(&r_editlights_cursorpushback);
3329 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
3330 Cvar_RegisterVariable(&r_editlights_cursorgrid);
3331 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
3332 Cvar_RegisterVariable(&r_editlights_rtlightssizescale);
3333 Cvar_RegisterVariable(&r_editlights_rtlightscolorscale);
3334 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
3335 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
3336 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
3337 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
3338 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
3339 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
3340 Cmd_AddCommand("r_editlights_editall", R_Shadow_EditLights_EditAll_f);
3341 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
3342 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
3343 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
3344 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
3345 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);