3 Terminology: Stencil Shadow Volume (sometimes called Stencil Shadows)
4 An extrusion of the lit faces, beginning at the original geometry and ending
5 further from the light source than the original geometry (presumably at least
6 as far as the light's radius, if the light has a radius at all), capped at
7 both front and back to avoid any problems (extrusion from dark faces also
8 works but has a different set of problems)
10 This is rendered using Carmack's Reverse technique, in which backfaces behind
11 zbuffer (zfail) increment the stencil, and frontfaces behind zbuffer (zfail)
12 decrement the stencil, the result is a stencil value of zero where shadows
13 did not intersect the visible geometry, suitable as a stencil mask for
14 rendering lighting everywhere but shadow.
16 In our case we use a biased stencil clear of 128 to avoid requiring the
17 stencil wrap extension (but probably should support it), and to address
18 Creative's patent on this sort of technology we also draw the frontfaces
19 first, and backfaces second (decrement, increment).
22 This algorithm may be covered by Creative's patent (US Patent #6384822)
23 on Carmack's Reverse paper (which I have not read), however that patent
24 seems to be about drawing a stencil shadow from a model in an otherwise
25 unshadowed scene, where as realtime lighting technology draws light where
30 Terminology: Stencil Light Volume (sometimes called Light Volumes)
31 Similar to a Stencil Shadow Volume, but inverted; rather than containing the
32 areas in shadow it contanis the areas in light, this can only be built
33 quickly for certain limited cases (such as portal visibility from a point),
34 but is quite useful for some effects (sunlight coming from sky polygons is
35 one possible example, translucent occluders is another example).
39 Terminology: Optimized Stencil Shadow Volume
40 A Stencil Shadow Volume that has been processed sufficiently to ensure it has
41 no duplicate coverage of areas (no need to shadow an area twice), often this
42 greatly improves performance but is an operation too costly to use on moving
43 lights (however completely optimal Stencil Light Volumes can be constructed
48 Terminology: Per Pixel Lighting (sometimes abbreviated PPL)
49 Per pixel evaluation of lighting equations, at a bare minimum this involves
50 DOT3 shading of diffuse lighting (per pixel dotproduct of negated incidence
51 vector and surface normal, using a texture of the surface bumps, called a
52 NormalMap) if supported by hardware; in our case there is support for cards
53 which are incapable of DOT3, the quality is quite poor however. Additionally
54 it is desirable to have specular evaluation per pixel, per vertex
55 normalization of specular halfangle vectors causes noticable distortion but
56 is unavoidable on hardware without GL_ARB_fragment_program.
60 Terminology: Normalization CubeMap
61 A cubemap containing normalized dot3-encoded (vectors of length 1 or less
62 encoded as RGB colors) for any possible direction, this technique allows per
63 pixel calculation of incidence vector for per pixel lighting purposes, which
64 would not otherwise be possible per pixel without GL_ARB_fragment_program.
68 Terminology: 2D Attenuation Texturing
69 A very crude approximation of light attenuation with distance which results
70 in cylindrical light shapes which fade vertically as a streak (some games
71 such as Doom3 allow this to be rotated to be less noticable in specific
72 cases), the technique is simply modulating lighting by two 2D textures (which
73 can be the same) on different axes of projection (XY and Z, typically), this
74 is the best technique available without 3D Attenuation Texturing or
75 GL_ARB_fragment_program technology.
79 Terminology: 3D Attenuation Texturing
80 A slightly crude approximation of light attenuation with distance, its flaws
81 are limited radius and resolution (performance tradeoffs).
85 Terminology: 3D Attenuation-Normalization Texturing
86 A 3D Attenuation Texture merged with a Normalization CubeMap, by making the
87 vectors shorter the lighting becomes darker, a very effective optimization of
88 diffuse lighting if 3D Attenuation Textures are already used.
92 Terminology: Light Cubemap Filtering
93 A technique for modeling non-uniform light distribution according to
94 direction, for example projecting a stained glass window image onto a wall,
95 this is done by texturing the lighting with a cubemap.
99 Terminology: Light Projection Filtering
100 A technique for modeling shadowing of light passing through translucent
101 surfaces, allowing stained glass windows and other effects to be done more
102 elegantly than possible with Light Cubemap Filtering by applying an occluder
103 texture to the lighting combined with a stencil light volume to limit the lit
104 area (this allows evaluating multiple translucent occluders in a scene).
108 Terminology: Doom3 Lighting
109 A combination of Stencil Shadow Volume, Per Pixel Lighting, Normalization
110 CubeMap, 2D Attenuation Texturing, and Light Filtering, as demonstrated by
111 the (currently upcoming) game Doom3.
114 #include "quakedef.h"
115 #include "r_shadow.h"
116 #include "cl_collision.h"
120 extern void R_Shadow_EditLights_Init(void);
122 #define SHADOWSTAGE_NONE 0
123 #define SHADOWSTAGE_STENCIL 1
124 #define SHADOWSTAGE_LIGHT 2
125 #define SHADOWSTAGE_STENCILTWOSIDE 3
127 int r_shadowstage = SHADOWSTAGE_NONE;
129 mempool_t *r_shadow_mempool;
131 int maxshadowelements;
145 int r_shadow_buffer_numclusterpvsbytes;
146 qbyte *r_shadow_buffer_clusterpvs;
147 int *r_shadow_buffer_clusterlist;
149 int r_shadow_buffer_numsurfacepvsbytes;
150 qbyte *r_shadow_buffer_surfacepvs;
151 int *r_shadow_buffer_surfacelist;
153 rtexturepool_t *r_shadow_texturepool;
154 rtexture_t *r_shadow_normalcubetexture;
155 rtexture_t *r_shadow_attenuation2dtexture;
156 rtexture_t *r_shadow_attenuation3dtexture;
157 rtexture_t *r_shadow_blankbumptexture;
158 rtexture_t *r_shadow_blankglosstexture;
159 rtexture_t *r_shadow_blankwhitetexture;
161 // lights are reloaded when this changes
162 char r_shadow_mapname[MAX_QPATH];
164 // used only for light filters (cubemaps)
165 rtexturepool_t *r_shadow_filters_texturepool;
167 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0"};
168 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4"};
169 cvar_t r_shadow_cull = {0, "r_shadow_cull", "1"};
170 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1"};
171 cvar_t r_shadow_gloss = {0, "r_shadow_gloss", "1"};
172 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.25"};
173 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1"};
174 cvar_t r_shadow_lightattenuationpower = {0, "r_shadow_lightattenuationpower", "0.5"};
175 cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1"};
176 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1"};
177 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1"};
178 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000"};
179 cvar_t r_shadow_realtime_dlight = {0, "r_shadow_realtime_dlight", "1"};
180 cvar_t r_shadow_realtime_dlight_shadows = {0, "r_shadow_realtime_dlight_shadows", "0"};
181 cvar_t r_shadow_realtime_world = {0, "r_shadow_realtime_world", "0"};
182 cvar_t r_shadow_realtime_world_dlightshadows = {0, "r_shadow_realtime_world_dlightshadows", "1"};
183 cvar_t r_shadow_realtime_world_lightmaps = {0, "r_shadow_realtime_world_lightmaps", "0"};
184 cvar_t r_shadow_realtime_world_shadows = {0, "r_shadow_realtime_world_shadows", "1"};
185 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1"};
186 cvar_t r_shadow_shadow_polygonfactor = {0, "r_shadow_shadow_polygonfactor", "0"};
187 cvar_t r_shadow_shadow_polygonoffset = {0, "r_shadow_shadow_polygonoffset", "1"};
188 cvar_t r_shadow_singlepassvolumegeneration = {0, "r_shadow_singlepassvolumegeneration", "1"};
189 cvar_t r_shadow_staticworldlights = {0, "r_shadow_staticworldlights", "1"};
190 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1"};
191 cvar_t r_shadow_visiblevolumes = {0, "r_shadow_visiblevolumes", "0"};
192 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1"};
193 cvar_t r_editlights = {0, "r_editlights", "0"};
194 cvar_t r_editlights_cursordistance = {0, "r_editlights_distance", "1024"};
195 cvar_t r_editlights_cursorpushback = {0, "r_editlights_pushback", "0"};
196 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_pushoff", "4"};
197 cvar_t r_editlights_cursorgrid = {0, "r_editlights_grid", "4"};
198 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "0.8"};
199 cvar_t r_editlights_rtlightssizescale = {CVAR_SAVE, "r_editlights_rtlightssizescale", "0.7"};
200 cvar_t r_editlights_rtlightscolorscale = {CVAR_SAVE, "r_editlights_rtlightscolorscale", "2"};
202 int c_rt_lights, c_rt_clears, c_rt_scissored;
203 int c_rt_shadowmeshes, c_rt_shadowtris, c_rt_lightmeshes, c_rt_lighttris;
204 int c_rtcached_shadowmeshes, c_rtcached_shadowtris;
206 float r_shadow_attenpower, r_shadow_attenscale;
208 rtlight_t *r_shadow_compilingrtlight;
209 dlight_t *r_shadow_worldlightchain;
210 dlight_t *r_shadow_selectedlight;
211 vec3_t r_editlights_cursorlocation;
213 rtexture_t *lighttextures[5];
215 extern int con_vislines;
217 typedef struct cubemapinfo_s
224 #define MAX_CUBEMAPS 256
225 static int numcubemaps;
226 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
228 void R_Shadow_UncompileWorldLights(void);
229 void R_Shadow_ClearWorldLights(void);
230 void R_Shadow_SaveWorldLights(void);
231 void R_Shadow_LoadWorldLights(void);
232 void R_Shadow_LoadLightsFile(void);
233 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
234 void R_Shadow_EditLights_Reload_f(void);
235 void R_Shadow_ValidateCvars(void);
236 static void R_Shadow_MakeTextures(void);
237 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light);
239 void r_shadow_start(void)
241 // allocate vertex processing arrays
243 r_shadow_normalcubetexture = NULL;
244 r_shadow_attenuation2dtexture = NULL;
245 r_shadow_attenuation3dtexture = NULL;
246 r_shadow_blankbumptexture = NULL;
247 r_shadow_blankglosstexture = NULL;
248 r_shadow_blankwhitetexture = NULL;
249 r_shadow_texturepool = NULL;
250 r_shadow_filters_texturepool = NULL;
251 R_Shadow_ValidateCvars();
252 R_Shadow_MakeTextures();
253 maxshadowelements = 0;
254 shadowelements = NULL;
262 shadowmarklist = NULL;
264 r_shadow_buffer_numclusterpvsbytes = 0;
265 r_shadow_buffer_clusterpvs = NULL;
266 r_shadow_buffer_clusterlist = NULL;
267 r_shadow_buffer_numsurfacepvsbytes = 0;
268 r_shadow_buffer_surfacepvs = NULL;
269 r_shadow_buffer_surfacelist = NULL;
272 void r_shadow_shutdown(void)
274 R_Shadow_UncompileWorldLights();
276 r_shadow_normalcubetexture = NULL;
277 r_shadow_attenuation2dtexture = NULL;
278 r_shadow_attenuation3dtexture = NULL;
279 r_shadow_blankbumptexture = NULL;
280 r_shadow_blankglosstexture = NULL;
281 r_shadow_blankwhitetexture = NULL;
282 R_FreeTexturePool(&r_shadow_texturepool);
283 R_FreeTexturePool(&r_shadow_filters_texturepool);
284 maxshadowelements = 0;
286 Mem_Free(shadowelements);
287 shadowelements = NULL;
290 Mem_Free(vertexupdate);
293 Mem_Free(vertexremap);
299 Mem_Free(shadowmark);
302 Mem_Free(shadowmarklist);
303 shadowmarklist = NULL;
305 r_shadow_buffer_numclusterpvsbytes = 0;
306 if (r_shadow_buffer_clusterpvs)
307 Mem_Free(r_shadow_buffer_clusterpvs);
308 r_shadow_buffer_clusterpvs = NULL;
309 if (r_shadow_buffer_clusterlist)
310 Mem_Free(r_shadow_buffer_clusterlist);
311 r_shadow_buffer_clusterlist = NULL;
312 r_shadow_buffer_numsurfacepvsbytes = 0;
313 if (r_shadow_buffer_surfacepvs)
314 Mem_Free(r_shadow_buffer_surfacepvs);
315 r_shadow_buffer_surfacepvs = NULL;
316 if (r_shadow_buffer_surfacelist)
317 Mem_Free(r_shadow_buffer_surfacelist);
318 r_shadow_buffer_surfacelist = NULL;
321 void r_shadow_newmap(void)
325 void R_Shadow_Help_f(void)
328 "Documentation on r_shadow system:\n"
330 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
331 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
332 "r_shadow_debuglight : render only this light number (-1 = all)\n"
333 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
334 "r_shadow_gloss2intensity : brightness of forced gloss\n"
335 "r_shadow_glossintensity : brightness of textured gloss\n"
336 "r_shadow_lightattenuationpower : used to generate attenuation texture\n"
337 "r_shadow_lightattenuationscale : used to generate attenuation texture\n"
338 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
339 "r_shadow_portallight : use portal visibility for static light precomputation\n"
340 "r_shadow_projectdistance : shadow volume projection distance\n"
341 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
342 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
343 "r_shadow_realtime_world : use high quality world lighting mode\n"
344 "r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n"
345 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
346 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
347 "r_shadow_scissor : use scissor optimization\n"
348 "r_shadow_shadow_polygonfactor : nudge shadow volumes closer/further\n"
349 "r_shadow_shadow_polygonoffset : nudge shadow volumes closer/further\n"
350 "r_shadow_singlepassvolumegeneration : selects shadow volume algorithm\n"
351 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
352 "r_shadow_visiblevolumes : useful for performance testing; bright = slow!\n"
354 "r_shadow_help : this help\n"
358 void R_Shadow_Init(void)
360 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
361 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
362 Cvar_RegisterVariable(&r_shadow_cull);
363 Cvar_RegisterVariable(&r_shadow_debuglight);
364 Cvar_RegisterVariable(&r_shadow_gloss);
365 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
366 Cvar_RegisterVariable(&r_shadow_glossintensity);
367 Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
368 Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
369 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
370 Cvar_RegisterVariable(&r_shadow_portallight);
371 Cvar_RegisterVariable(&r_shadow_projectdistance);
372 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
373 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
374 Cvar_RegisterVariable(&r_shadow_realtime_world);
375 Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows);
376 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
377 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
378 Cvar_RegisterVariable(&r_shadow_scissor);
379 Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor);
380 Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset);
381 Cvar_RegisterVariable(&r_shadow_singlepassvolumegeneration);
382 Cvar_RegisterVariable(&r_shadow_staticworldlights);
383 Cvar_RegisterVariable(&r_shadow_texture3d);
384 Cvar_RegisterVariable(&r_shadow_visiblevolumes);
385 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
386 if (gamemode == GAME_TENEBRAE)
388 Cvar_SetValue("r_shadow_gloss", 2);
389 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
391 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f);
392 R_Shadow_EditLights_Init();
393 r_shadow_mempool = Mem_AllocPool("R_Shadow", 0, NULL);
394 r_shadow_worldlightchain = NULL;
395 maxshadowelements = 0;
396 shadowelements = NULL;
404 shadowmarklist = NULL;
406 r_shadow_buffer_numclusterpvsbytes = 0;
407 r_shadow_buffer_clusterpvs = NULL;
408 r_shadow_buffer_clusterlist = NULL;
409 r_shadow_buffer_numsurfacepvsbytes = 0;
410 r_shadow_buffer_surfacepvs = NULL;
411 r_shadow_buffer_surfacelist = NULL;
412 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
415 matrix4x4_t matrix_attenuationxyz =
418 {0.5, 0.0, 0.0, 0.5},
419 {0.0, 0.5, 0.0, 0.5},
420 {0.0, 0.0, 0.5, 0.5},
425 matrix4x4_t matrix_attenuationz =
428 {0.0, 0.0, 0.5, 0.5},
429 {0.0, 0.0, 0.0, 0.5},
430 {0.0, 0.0, 0.0, 0.5},
435 int *R_Shadow_ResizeShadowElements(int numtris)
437 // make sure shadowelements is big enough for this volume
438 if (maxshadowelements < numtris * 24)
440 maxshadowelements = numtris * 24;
442 Mem_Free(shadowelements);
443 shadowelements = Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int));
445 return shadowelements;
448 void R_Shadow_EnlargeClusterBuffer(int numclusters)
450 int numclusterpvsbytes = (((numclusters + 7) >> 3) + 255) & ~255;
451 if (r_shadow_buffer_numclusterpvsbytes < numclusterpvsbytes)
453 if (r_shadow_buffer_clusterpvs)
454 Mem_Free(r_shadow_buffer_clusterpvs);
455 if (r_shadow_buffer_clusterlist)
456 Mem_Free(r_shadow_buffer_clusterlist);
457 r_shadow_buffer_numclusterpvsbytes = numclusterpvsbytes;
458 r_shadow_buffer_clusterpvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numclusterpvsbytes);
459 r_shadow_buffer_clusterlist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numclusterpvsbytes * 8 * sizeof(*r_shadow_buffer_clusterlist));
463 void R_Shadow_EnlargeSurfaceBuffer(int numsurfaces)
465 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
466 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
468 if (r_shadow_buffer_surfacepvs)
469 Mem_Free(r_shadow_buffer_surfacepvs);
470 if (r_shadow_buffer_surfacelist)
471 Mem_Free(r_shadow_buffer_surfacelist);
472 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
473 r_shadow_buffer_surfacepvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes);
474 r_shadow_buffer_surfacelist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
478 void R_Shadow_PrepareShadowMark(int numtris)
480 // make sure shadowmark is big enough for this volume
481 if (maxshadowmark < numtris)
483 maxshadowmark = numtris;
485 Mem_Free(shadowmark);
487 Mem_Free(shadowmarklist);
488 shadowmark = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmark));
489 shadowmarklist = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmarklist));
493 // if shadowmarkcount wrapped we clear the array and adjust accordingly
494 if (shadowmarkcount == 0)
497 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
502 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)
504 int i, j, tris = 0, vr[3], t, outvertices = 0;
508 if (maxvertexupdate < innumvertices)
510 maxvertexupdate = innumvertices;
512 Mem_Free(vertexupdate);
514 Mem_Free(vertexremap);
515 vertexupdate = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
516 vertexremap = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
520 if (vertexupdatenum == 0)
523 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
524 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
527 for (i = 0;i < numshadowmarktris;i++)
529 t = shadowmarktris[i];
530 shadowmark[t] = shadowmarkcount;
531 e = inelement3i + t * 3;
532 // make sure the vertices are created
533 for (j = 0;j < 3;j++)
535 if (vertexupdate[e[j]] != vertexupdatenum)
537 vertexupdate[e[j]] = vertexupdatenum;
538 vertexremap[e[j]] = outvertices;
539 VectorSubtract(invertex3f + e[j] * 3, projectorigin, temp);
540 f = projectdistance / VectorLength(temp);
541 VectorCopy(invertex3f + e[j] * 3, outvertex3f);
542 VectorMA(projectorigin, f, temp, (outvertex3f + 3));
547 // output the front and back triangles
548 outelement3i[0] = vertexremap[e[0]];
549 outelement3i[1] = vertexremap[e[1]];
550 outelement3i[2] = vertexremap[e[2]];
551 outelement3i[3] = vertexremap[e[2]] + 1;
552 outelement3i[4] = vertexremap[e[1]] + 1;
553 outelement3i[5] = vertexremap[e[0]] + 1;
558 for (i = 0;i < numshadowmarktris;i++)
560 t = shadowmarktris[i];
561 e = inelement3i + t * 3;
562 n = inneighbor3i + t * 3;
563 // output the sides (facing outward from this triangle)
564 if (shadowmark[n[0]] != shadowmarkcount)
566 vr[0] = vertexremap[e[0]];
567 vr[1] = vertexremap[e[1]];
568 outelement3i[0] = vr[1];
569 outelement3i[1] = vr[0];
570 outelement3i[2] = vr[0] + 1;
571 outelement3i[3] = vr[1];
572 outelement3i[4] = vr[0] + 1;
573 outelement3i[5] = vr[1] + 1;
577 if (shadowmark[n[1]] != shadowmarkcount)
579 vr[1] = vertexremap[e[1]];
580 vr[2] = vertexremap[e[2]];
581 outelement3i[0] = vr[2];
582 outelement3i[1] = vr[1];
583 outelement3i[2] = vr[1] + 1;
584 outelement3i[3] = vr[2];
585 outelement3i[4] = vr[1] + 1;
586 outelement3i[5] = vr[2] + 1;
590 if (shadowmark[n[2]] != shadowmarkcount)
592 vr[0] = vertexremap[e[0]];
593 vr[2] = vertexremap[e[2]];
594 outelement3i[0] = vr[0];
595 outelement3i[1] = vr[2];
596 outelement3i[2] = vr[2] + 1;
597 outelement3i[3] = vr[0];
598 outelement3i[4] = vr[2] + 1;
599 outelement3i[5] = vr[0] + 1;
605 *outnumvertices = outvertices;
609 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)
612 if (projectdistance < 0.1)
614 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
617 if (!numverts || !nummarktris)
619 // make sure shadowelements is big enough for this volume
620 if (maxshadowelements < nummarktris * 24)
621 R_Shadow_ResizeShadowElements((nummarktris + 256) * 24);
622 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, varray_vertex3f2, projectorigin, projectdistance, nummarktris, marktris);
623 R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements);
626 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)
631 // check which triangles are facing the , and then output
632 // triangle elements and vertices... by clever use of elements we
633 // can construct the whole shadow from the unprojected vertices and
634 // the projected vertices
636 // identify lit faces within the bounding box
637 R_Shadow_PrepareShadowMark(numtris);
638 for (i = 0;i < numtris;i++)
640 v[0] = invertex3f + elements[i*3+0] * 3;
641 v[1] = invertex3f + elements[i*3+1] * 3;
642 v[2] = invertex3f + elements[i*3+2] * 3;
643 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])))
644 shadowmarklist[numshadowmark++] = i;
646 R_Shadow_VolumeFromList(numverts, numtris, invertex3f, elements, neighbors, projectorigin, projectdistance, numshadowmark, shadowmarklist);
649 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)
652 mins[0] = projectorigin[0] - radius;
653 mins[1] = projectorigin[1] - radius;
654 mins[2] = projectorigin[2] - radius;
655 maxs[0] = projectorigin[0] + radius;
656 maxs[1] = projectorigin[1] + radius;
657 maxs[2] = projectorigin[2] + radius;
658 R_Shadow_VolumeFromBox(numverts, numtris, invertex3f, elements, neighbors, projectorigin, projectdistance, mins, maxs);
661 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
664 if (r_shadow_compilingrtlight)
666 // if we're compiling an rtlight, capture the mesh
667 Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
670 memset(&m, 0, sizeof(m));
671 m.pointer_vertex = vertex3f;
673 GL_LockArrays(0, numvertices);
674 if (r_shadowstage == SHADOWSTAGE_STENCIL)
676 // increment stencil if backface is behind depthbuffer
677 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
678 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
679 R_Mesh_Draw(numvertices, numtriangles, element3i);
681 c_rt_shadowtris += numtriangles;
682 // decrement stencil if frontface is behind depthbuffer
683 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
684 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
686 R_Mesh_Draw(numvertices, numtriangles, element3i);
688 c_rt_shadowtris += numtriangles;
692 static void R_Shadow_MakeTextures(void)
694 int x, y, z, d, side;
695 float v[3], s, t, intensity;
697 R_FreeTexturePool(&r_shadow_texturepool);
698 r_shadow_texturepool = R_AllocTexturePool();
699 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
700 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
702 #define ATTEN2DSIZE 64
703 #define ATTEN3DSIZE 32
704 data = Mem_Alloc(tempmempool, max(6*NORMSIZE*NORMSIZE*4, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4)));
709 r_shadow_blankbumptexture = R_LoadTexture2D(r_shadow_texturepool, "blankbump", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
714 r_shadow_blankglosstexture = R_LoadTexture2D(r_shadow_texturepool, "blankgloss", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
719 r_shadow_blankwhitetexture = R_LoadTexture2D(r_shadow_texturepool, "blankwhite", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
720 if (gl_texturecubemap)
722 for (side = 0;side < 6;side++)
724 for (y = 0;y < NORMSIZE;y++)
726 for (x = 0;x < NORMSIZE;x++)
728 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
729 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
763 intensity = 127.0f / sqrt(DotProduct(v, v));
764 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+0] = 128.0f + intensity * v[0];
765 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+1] = 128.0f + intensity * v[1];
766 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+2] = 128.0f + intensity * v[2];
767 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+3] = 255;
771 r_shadow_normalcubetexture = R_LoadTextureCubeMap(r_shadow_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
774 r_shadow_normalcubetexture = NULL;
775 for (y = 0;y < ATTEN2DSIZE;y++)
777 for (x = 0;x < ATTEN2DSIZE;x++)
779 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
780 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
782 intensity = 1.0f - sqrt(DotProduct(v, v));
784 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
785 d = bound(0, intensity, 255);
786 data[(y*ATTEN2DSIZE+x)*4+0] = d;
787 data[(y*ATTEN2DSIZE+x)*4+1] = d;
788 data[(y*ATTEN2DSIZE+x)*4+2] = d;
789 data[(y*ATTEN2DSIZE+x)*4+3] = d;
792 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
793 if (r_shadow_texture3d.integer)
795 for (z = 0;z < ATTEN3DSIZE;z++)
797 for (y = 0;y < ATTEN3DSIZE;y++)
799 for (x = 0;x < ATTEN3DSIZE;x++)
801 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
802 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
803 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
804 intensity = 1.0f - sqrt(DotProduct(v, v));
806 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
807 d = bound(0, intensity, 255);
808 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
809 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
810 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
811 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
815 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
820 void R_Shadow_ValidateCvars(void)
822 if (r_shadow_texture3d.integer && !gl_texture3d)
823 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
824 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
825 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
828 void R_Shadow_Stage_Begin(void)
832 R_Shadow_ValidateCvars();
834 if (!r_shadow_attenuation2dtexture
835 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
836 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
837 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
838 R_Shadow_MakeTextures();
840 memset(&m, 0, sizeof(m));
841 GL_BlendFunc(GL_ONE, GL_ZERO);
845 GL_Color(0, 0, 0, 1);
846 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
847 qglEnable(GL_CULL_FACE);
848 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
849 r_shadowstage = SHADOWSTAGE_NONE;
851 c_rt_lights = c_rt_clears = c_rt_scissored = 0;
852 c_rt_shadowmeshes = c_rt_shadowtris = c_rt_lightmeshes = c_rt_lighttris = 0;
853 c_rtcached_shadowmeshes = c_rtcached_shadowtris = 0;
856 void R_Shadow_Stage_ShadowVolumes(void)
859 memset(&m, 0, sizeof(m));
861 GL_Color(1, 1, 1, 1);
862 GL_ColorMask(0, 0, 0, 0);
863 GL_BlendFunc(GL_ONE, GL_ZERO);
866 qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
867 //if (r_shadow_shadow_polygonoffset.value != 0)
869 // qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
870 // qglEnable(GL_POLYGON_OFFSET_FILL);
873 // qglDisable(GL_POLYGON_OFFSET_FILL);
874 qglDepthFunc(GL_LESS);
875 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
876 qglEnable(GL_STENCIL_TEST);
877 qglStencilFunc(GL_ALWAYS, 128, ~0);
878 if (gl_ext_stenciltwoside.integer)
880 r_shadowstage = SHADOWSTAGE_STENCILTWOSIDE;
881 qglDisable(GL_CULL_FACE);
882 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
883 qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
885 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
886 qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
888 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
892 r_shadowstage = SHADOWSTAGE_STENCIL;
893 qglEnable(GL_CULL_FACE);
895 // this is changed by every shadow render so its value here is unimportant
896 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
898 GL_Clear(GL_STENCIL_BUFFER_BIT);
900 // LordHavoc note: many shadow volumes reside entirely inside the world
901 // (that is to say they are entirely bounded by their lit surfaces),
902 // which can be optimized by handling things as an inverted light volume,
903 // with the shadow boundaries of the world being simulated by an altered
904 // (129) bias to stencil clearing on such lights
905 // FIXME: generate inverted light volumes for use as shadow volumes and
906 // optimize for them as noted above
909 void R_Shadow_Stage_Light(int shadowtest)
912 memset(&m, 0, sizeof(m));
914 GL_BlendFunc(GL_ONE, GL_ONE);
917 qglPolygonOffset(0, 0);
918 //qglDisable(GL_POLYGON_OFFSET_FILL);
919 GL_Color(1, 1, 1, 1);
920 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
921 qglDepthFunc(GL_EQUAL);
922 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
923 qglEnable(GL_CULL_FACE);
925 qglEnable(GL_STENCIL_TEST);
927 qglDisable(GL_STENCIL_TEST);
928 if (gl_support_stenciltwoside)
929 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
931 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
932 // only draw light where this geometry was already rendered AND the
933 // stencil is 128 (values other than this mean shadow)
934 qglStencilFunc(GL_EQUAL, 128, ~0);
935 r_shadowstage = SHADOWSTAGE_LIGHT;
939 void R_Shadow_Stage_End(void)
942 memset(&m, 0, sizeof(m));
944 GL_BlendFunc(GL_ONE, GL_ZERO);
947 qglPolygonOffset(0, 0);
948 //qglDisable(GL_POLYGON_OFFSET_FILL);
949 GL_Color(1, 1, 1, 1);
950 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
951 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
952 qglDepthFunc(GL_LEQUAL);
953 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
954 qglDisable(GL_STENCIL_TEST);
955 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
956 if (gl_support_stenciltwoside)
957 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
959 qglStencilFunc(GL_ALWAYS, 128, ~0);
960 r_shadowstage = SHADOWSTAGE_NONE;
963 int R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
965 int i, ix1, iy1, ix2, iy2;
966 float x1, y1, x2, y2, x, y, f;
969 if (!r_shadow_scissor.integer)
971 // if view is inside the box, just say yes it's visible
972 if (BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
974 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
977 for (i = 0;i < 3;i++)
979 if (r_viewforward[i] >= 0)
990 f = DotProduct(r_viewforward, r_vieworigin) + 1;
991 if (DotProduct(r_viewforward, v2) <= f)
993 // entirely behind nearclip plane
996 if (DotProduct(r_viewforward, v) >= f)
998 // entirely infront of nearclip plane
999 x1 = y1 = x2 = y2 = 0;
1000 for (i = 0;i < 8;i++)
1002 v[0] = (i & 1) ? mins[0] : maxs[0];
1003 v[1] = (i & 2) ? mins[1] : maxs[1];
1004 v[2] = (i & 4) ? mins[2] : maxs[2];
1006 GL_TransformToScreen(v, v2);
1007 //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]);
1026 // clipped by nearclip plane
1027 // this is nasty and crude...
1028 // create viewspace bbox
1029 for (i = 0;i < 8;i++)
1031 v[0] = ((i & 1) ? mins[0] : maxs[0]) - r_vieworigin[0];
1032 v[1] = ((i & 2) ? mins[1] : maxs[1]) - r_vieworigin[1];
1033 v[2] = ((i & 4) ? mins[2] : maxs[2]) - r_vieworigin[2];
1034 v2[0] = -DotProduct(v, r_viewleft);
1035 v2[1] = DotProduct(v, r_viewup);
1036 v2[2] = DotProduct(v, r_viewforward);
1039 if (smins[0] > v2[0]) smins[0] = v2[0];
1040 if (smaxs[0] < v2[0]) smaxs[0] = v2[0];
1041 if (smins[1] > v2[1]) smins[1] = v2[1];
1042 if (smaxs[1] < v2[1]) smaxs[1] = v2[1];
1043 if (smins[2] > v2[2]) smins[2] = v2[2];
1044 if (smaxs[2] < v2[2]) smaxs[2] = v2[2];
1048 smins[0] = smaxs[0] = v2[0];
1049 smins[1] = smaxs[1] = v2[1];
1050 smins[2] = smaxs[2] = v2[2];
1053 // now we have a bbox in viewspace
1054 // clip it to the view plane
1057 // return true if that culled the box
1058 if (smins[2] >= smaxs[2])
1060 // ok some of it is infront of the view, transform each corner back to
1061 // worldspace and then to screenspace and make screen rect
1062 // initialize these variables just to avoid compiler warnings
1063 x1 = y1 = x2 = y2 = 0;
1064 for (i = 0;i < 8;i++)
1066 v2[0] = (i & 1) ? smins[0] : smaxs[0];
1067 v2[1] = (i & 2) ? smins[1] : smaxs[1];
1068 v2[2] = (i & 4) ? smins[2] : smaxs[2];
1069 v[0] = v2[0] * -r_viewleft[0] + v2[1] * r_viewup[0] + v2[2] * r_viewforward[0] + r_vieworigin[0];
1070 v[1] = v2[0] * -r_viewleft[1] + v2[1] * r_viewup[1] + v2[2] * r_viewforward[1] + r_vieworigin[1];
1071 v[2] = v2[0] * -r_viewleft[2] + v2[1] * r_viewup[2] + v2[2] * r_viewforward[2] + r_vieworigin[2];
1073 GL_TransformToScreen(v, v2);
1074 //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]);
1091 // this code doesn't handle boxes with any points behind view properly
1092 x1 = 1000;x2 = -1000;
1093 y1 = 1000;y2 = -1000;
1094 for (i = 0;i < 8;i++)
1096 v[0] = (i & 1) ? mins[0] : maxs[0];
1097 v[1] = (i & 2) ? mins[1] : maxs[1];
1098 v[2] = (i & 4) ? mins[2] : maxs[2];
1100 GL_TransformToScreen(v, v2);
1101 //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]);
1119 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1120 if (ix1 < r_view_x) ix1 = r_view_x;
1121 if (iy1 < r_view_y) iy1 = r_view_y;
1122 if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
1123 if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
1124 if (ix2 <= ix1 || iy2 <= iy1)
1126 // set up the scissor rectangle
1127 GL_Scissor(ix1, vid.realheight - iy2, ix2 - ix1, iy2 - iy1);
1128 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1129 //qglEnable(GL_SCISSOR_TEST);
1134 static void R_Shadow_VertexShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1136 float *color4f = varray_color4f;
1137 float dist, dot, intensity, v[3], n[3];
1138 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1140 Matrix4x4_Transform(m, vertex3f, v);
1141 if ((dist = DotProduct(v, v)) < 1)
1143 Matrix4x4_Transform3x3(m, normal3f, n);
1144 if ((dot = DotProduct(n, v)) > 0)
1147 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1148 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1149 VectorScale(lightcolor, intensity, color4f);
1154 VectorClear(color4f);
1160 VectorClear(color4f);
1166 static void R_Shadow_VertexShadingWithZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1168 float *color4f = varray_color4f;
1169 float dist, dot, intensity, v[3], n[3];
1170 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1172 Matrix4x4_Transform(m, vertex3f, v);
1173 if ((dist = fabs(v[2])) < 1)
1175 Matrix4x4_Transform3x3(m, normal3f, n);
1176 if ((dot = DotProduct(n, v)) > 0)
1178 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1179 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1180 VectorScale(lightcolor, intensity, color4f);
1185 VectorClear(color4f);
1191 VectorClear(color4f);
1197 static void R_Shadow_VertexShading(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1199 float *color4f = varray_color4f;
1200 float dot, intensity, v[3], n[3];
1201 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1203 Matrix4x4_Transform(m, vertex3f, v);
1204 Matrix4x4_Transform3x3(m, normal3f, n);
1205 if ((dot = DotProduct(n, v)) > 0)
1207 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1208 VectorScale(lightcolor, intensity, color4f);
1213 VectorClear(color4f);
1219 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1220 #define USETEXMATRIX
1222 #ifndef USETEXMATRIX
1223 // this should be done in a texture matrix or vertex program when possible, but here's code to do it manually
1224 // if hardware texcoord manipulation is not available (or not suitable, this would really benefit from 3DNow! or SSE
1225 static void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1229 tc3f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1230 tc3f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1231 tc3f[2] = vertex3f[0] * matrix->m[2][0] + vertex3f[1] * matrix->m[2][1] + vertex3f[2] * matrix->m[2][2] + matrix->m[2][3];
1238 static void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1242 tc2f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1243 tc2f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1251 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)
1255 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1257 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1258 // the cubemap normalizes this for us
1259 out3f[0] = DotProduct(svector3f, lightdir);
1260 out3f[1] = DotProduct(tvector3f, lightdir);
1261 out3f[2] = DotProduct(normal3f, lightdir);
1265 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)
1268 float lightdir[3], eyedir[3], halfdir[3];
1269 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1271 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1272 VectorNormalizeFast(lightdir);
1273 VectorSubtract(vertex3f, relativeeyeorigin, eyedir);
1274 VectorNormalizeFast(eyedir);
1275 VectorAdd(lightdir, eyedir, halfdir);
1276 // the cubemap normalizes this for us
1277 out3f[0] = DotProduct(svector3f, halfdir);
1278 out3f[1] = DotProduct(tvector3f, halfdir);
1279 out3f[2] = DotProduct(normal3f, halfdir);
1283 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)
1286 float color[3], color2[3], colorscale;
1289 bumptexture = r_shadow_blankbumptexture;
1291 glosstexture = r_shadow_blankglosstexture;
1292 GL_DepthMask(false);
1294 if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
1296 if (lighting & LIGHTING_DIFFUSE)
1299 colorscale = r_shadow_lightintensityscale.value;
1300 // colorscale accounts for how much we multiply the brightness
1303 // mult is how many times the final pass of the lighting will be
1304 // performed to get more brightness than otherwise possible.
1306 // Limit mult to 64 for sanity sake.
1307 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1309 // 3/2 3D combine path (Geforce3, Radeon 8500)
1310 memset(&m, 0, sizeof(m));
1311 m.pointer_vertex = vertex3f;
1312 m.tex[0] = R_GetTexture(bumptexture);
1313 m.texcombinergb[0] = GL_REPLACE;
1314 m.pointer_texcoord[0] = texcoord2f;
1315 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1316 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1317 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1318 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1319 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1321 m.pointer_texcoord3f[2] = vertex3f;
1322 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
1324 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1325 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1328 GL_ColorMask(0,0,0,1);
1329 GL_BlendFunc(GL_ONE, GL_ZERO);
1330 GL_LockArrays(0, numverts);
1331 R_Mesh_Draw(numverts, numtriangles, elements);
1332 GL_LockArrays(0, 0);
1334 c_rt_lighttris += numtriangles;
1336 memset(&m, 0, sizeof(m));
1337 m.pointer_vertex = vertex3f;
1338 m.tex[0] = R_GetTexture(basetexture);
1339 m.pointer_texcoord[0] = texcoord2f;
1342 m.texcubemap[1] = R_GetTexture(lightcubemap);
1344 m.pointer_texcoord3f[1] = vertex3f;
1345 m.texmatrix[1] = *matrix_modeltolight;
1347 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1348 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1352 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap)
1354 // 1/2/2 3D combine path (original Radeon)
1355 memset(&m, 0, sizeof(m));
1356 m.pointer_vertex = vertex3f;
1357 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1359 m.pointer_texcoord3f[0] = vertex3f;
1360 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1362 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1363 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1366 GL_ColorMask(0,0,0,1);
1367 GL_BlendFunc(GL_ONE, GL_ZERO);
1368 GL_LockArrays(0, numverts);
1369 R_Mesh_Draw(numverts, numtriangles, elements);
1370 GL_LockArrays(0, 0);
1372 c_rt_lighttris += numtriangles;
1374 memset(&m, 0, sizeof(m));
1375 m.pointer_vertex = vertex3f;
1376 m.tex[0] = R_GetTexture(bumptexture);
1377 m.texcombinergb[0] = GL_REPLACE;
1378 m.pointer_texcoord[0] = texcoord2f;
1379 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1380 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1381 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1382 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1384 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1385 GL_LockArrays(0, numverts);
1386 R_Mesh_Draw(numverts, numtriangles, elements);
1387 GL_LockArrays(0, 0);
1389 c_rt_lighttris += numtriangles;
1391 memset(&m, 0, sizeof(m));
1392 m.pointer_vertex = vertex3f;
1393 m.tex[0] = R_GetTexture(basetexture);
1394 m.pointer_texcoord[0] = texcoord2f;
1397 m.texcubemap[1] = R_GetTexture(lightcubemap);
1399 m.pointer_texcoord3f[1] = vertex3f;
1400 m.texmatrix[1] = *matrix_modeltolight;
1402 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1403 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1407 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap)
1409 // 2/2 3D combine path (original Radeon)
1410 memset(&m, 0, sizeof(m));
1411 m.pointer_vertex = vertex3f;
1412 m.tex[0] = R_GetTexture(bumptexture);
1413 m.texcombinergb[0] = GL_REPLACE;
1414 m.pointer_texcoord[0] = texcoord2f;
1415 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1416 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1417 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1418 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1420 GL_ColorMask(0,0,0,1);
1421 GL_BlendFunc(GL_ONE, GL_ZERO);
1422 GL_LockArrays(0, numverts);
1423 R_Mesh_Draw(numverts, numtriangles, elements);
1424 GL_LockArrays(0, 0);
1426 c_rt_lighttris += numtriangles;
1428 memset(&m, 0, sizeof(m));
1429 m.pointer_vertex = vertex3f;
1430 m.tex[0] = R_GetTexture(basetexture);
1431 m.pointer_texcoord[0] = texcoord2f;
1432 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1434 m.pointer_texcoord3f[1] = vertex3f;
1435 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1437 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1438 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1441 else if (r_textureunits.integer >= 4)
1443 // 4/2 2D combine path (Geforce3, Radeon 8500)
1444 memset(&m, 0, sizeof(m));
1445 m.pointer_vertex = vertex3f;
1446 m.tex[0] = R_GetTexture(bumptexture);
1447 m.texcombinergb[0] = GL_REPLACE;
1448 m.pointer_texcoord[0] = texcoord2f;
1449 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1450 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1451 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1452 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1453 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1455 m.pointer_texcoord3f[2] = vertex3f;
1456 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
1458 m.pointer_texcoord[2] = varray_texcoord2f[2];
1459 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1461 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1463 m.pointer_texcoord3f[3] = vertex3f;
1464 m.texmatrix[3] = *matrix_modeltoattenuationz;
1466 m.pointer_texcoord[3] = varray_texcoord2f[3];
1467 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[3], numverts, vertex3f, matrix_modeltoattenuationz);
1470 GL_ColorMask(0,0,0,1);
1471 GL_BlendFunc(GL_ONE, GL_ZERO);
1472 GL_LockArrays(0, numverts);
1473 R_Mesh_Draw(numverts, numtriangles, elements);
1474 GL_LockArrays(0, 0);
1476 c_rt_lighttris += numtriangles;
1478 memset(&m, 0, sizeof(m));
1479 m.pointer_vertex = vertex3f;
1480 m.tex[0] = R_GetTexture(basetexture);
1481 m.pointer_texcoord[0] = texcoord2f;
1484 m.texcubemap[1] = R_GetTexture(lightcubemap);
1486 m.pointer_texcoord3f[1] = vertex3f;
1487 m.texmatrix[1] = *matrix_modeltolight;
1489 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1490 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1496 // 2/2/2 2D combine path (any dot3 card)
1497 memset(&m, 0, sizeof(m));
1498 m.pointer_vertex = vertex3f;
1499 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1501 m.pointer_texcoord3f[0] = vertex3f;
1502 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1504 m.pointer_texcoord[0] = varray_texcoord2f[0];
1505 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1507 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1509 m.pointer_texcoord3f[1] = vertex3f;
1510 m.texmatrix[1] = *matrix_modeltoattenuationz;
1512 m.pointer_texcoord[1] = varray_texcoord2f[1];
1513 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1516 GL_ColorMask(0,0,0,1);
1517 GL_BlendFunc(GL_ONE, GL_ZERO);
1518 GL_LockArrays(0, numverts);
1519 R_Mesh_Draw(numverts, numtriangles, elements);
1520 GL_LockArrays(0, 0);
1522 c_rt_lighttris += numtriangles;
1524 memset(&m, 0, sizeof(m));
1525 m.pointer_vertex = vertex3f;
1526 m.tex[0] = R_GetTexture(bumptexture);
1527 m.texcombinergb[0] = GL_REPLACE;
1528 m.pointer_texcoord[0] = texcoord2f;
1529 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1530 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1531 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1532 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1534 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1535 GL_LockArrays(0, numverts);
1536 R_Mesh_Draw(numverts, numtriangles, elements);
1537 GL_LockArrays(0, 0);
1539 c_rt_lighttris += numtriangles;
1541 memset(&m, 0, sizeof(m));
1542 m.pointer_vertex = vertex3f;
1543 m.tex[0] = R_GetTexture(basetexture);
1544 m.pointer_texcoord[0] = texcoord2f;
1547 m.texcubemap[1] = R_GetTexture(lightcubemap);
1549 m.pointer_texcoord3f[1] = vertex3f;
1550 m.texmatrix[1] = *matrix_modeltolight;
1552 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1553 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1557 // this final code is shared
1559 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1560 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1561 VectorScale(lightcolor, colorscale, color2);
1562 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1564 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1565 GL_LockArrays(0, numverts);
1566 R_Mesh_Draw(numverts, numtriangles, elements);
1567 GL_LockArrays(0, 0);
1569 c_rt_lighttris += numtriangles;
1572 if ((lighting & LIGHTING_SPECULAR) && (r_shadow_gloss.integer >= 2 || (r_shadow_gloss.integer >= 1 && glosstexture != r_shadow_blankglosstexture)))
1574 // FIXME: detect blendsquare!
1575 //if (gl_support_blendsquare)
1577 colorscale = r_shadow_lightintensityscale.value * r_shadow_glossintensity.value;
1578 if (glosstexture == r_shadow_blankglosstexture)
1579 colorscale *= r_shadow_gloss2intensity.value;
1581 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1583 // 2/0/0/1/2 3D combine blendsquare path
1584 memset(&m, 0, sizeof(m));
1585 m.pointer_vertex = vertex3f;
1586 m.tex[0] = R_GetTexture(bumptexture);
1587 m.pointer_texcoord[0] = texcoord2f;
1588 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1589 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1590 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1591 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1593 GL_ColorMask(0,0,0,1);
1594 // this squares the result
1595 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1596 GL_LockArrays(0, numverts);
1597 R_Mesh_Draw(numverts, numtriangles, elements);
1598 GL_LockArrays(0, 0);
1600 c_rt_lighttris += numtriangles;
1602 memset(&m, 0, sizeof(m));
1603 m.pointer_vertex = vertex3f;
1605 GL_LockArrays(0, numverts);
1606 // square alpha in framebuffer a few times to make it shiny
1607 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1608 // these comments are a test run through this math for intensity 0.5
1609 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1610 // 0.25 * 0.25 = 0.0625 (this is another pass)
1611 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1612 R_Mesh_Draw(numverts, numtriangles, elements);
1614 c_rt_lighttris += numtriangles;
1615 R_Mesh_Draw(numverts, numtriangles, elements);
1617 c_rt_lighttris += numtriangles;
1618 GL_LockArrays(0, 0);
1620 memset(&m, 0, sizeof(m));
1621 m.pointer_vertex = vertex3f;
1622 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1624 m.pointer_texcoord3f[0] = vertex3f;
1625 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1627 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1628 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1631 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1632 GL_LockArrays(0, numverts);
1633 R_Mesh_Draw(numverts, numtriangles, elements);
1634 GL_LockArrays(0, 0);
1636 c_rt_lighttris += numtriangles;
1638 memset(&m, 0, sizeof(m));
1639 m.pointer_vertex = vertex3f;
1640 m.tex[0] = R_GetTexture(glosstexture);
1641 m.pointer_texcoord[0] = texcoord2f;
1644 m.texcubemap[1] = R_GetTexture(lightcubemap);
1646 m.pointer_texcoord3f[1] = vertex3f;
1647 m.texmatrix[1] = *matrix_modeltolight;
1649 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1650 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1654 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1656 // 2/0/0/2 3D combine blendsquare path
1657 memset(&m, 0, sizeof(m));
1658 m.pointer_vertex = vertex3f;
1659 m.tex[0] = R_GetTexture(bumptexture);
1660 m.pointer_texcoord[0] = texcoord2f;
1661 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1662 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1663 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1664 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1666 GL_ColorMask(0,0,0,1);
1667 // this squares the result
1668 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1669 GL_LockArrays(0, numverts);
1670 R_Mesh_Draw(numverts, numtriangles, elements);
1671 GL_LockArrays(0, 0);
1673 c_rt_lighttris += numtriangles;
1675 memset(&m, 0, sizeof(m));
1676 m.pointer_vertex = vertex3f;
1678 GL_LockArrays(0, numverts);
1679 // square alpha in framebuffer a few times to make it shiny
1680 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1681 // these comments are a test run through this math for intensity 0.5
1682 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1683 // 0.25 * 0.25 = 0.0625 (this is another pass)
1684 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1685 R_Mesh_Draw(numverts, numtriangles, elements);
1687 c_rt_lighttris += numtriangles;
1688 R_Mesh_Draw(numverts, numtriangles, elements);
1690 c_rt_lighttris += numtriangles;
1691 GL_LockArrays(0, 0);
1693 memset(&m, 0, sizeof(m));
1694 m.pointer_vertex = vertex3f;
1695 m.tex[0] = R_GetTexture(glosstexture);
1696 m.pointer_texcoord[0] = texcoord2f;
1697 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1699 m.pointer_texcoord3f[1] = vertex3f;
1700 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1702 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1703 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1708 // 2/0/0/2/2 2D combine blendsquare path
1709 memset(&m, 0, sizeof(m));
1710 m.pointer_vertex = vertex3f;
1711 m.tex[0] = R_GetTexture(bumptexture);
1712 m.pointer_texcoord[0] = texcoord2f;
1713 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1714 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1715 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1716 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1718 GL_ColorMask(0,0,0,1);
1719 // this squares the result
1720 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1721 GL_LockArrays(0, numverts);
1722 R_Mesh_Draw(numverts, numtriangles, elements);
1723 GL_LockArrays(0, 0);
1725 c_rt_lighttris += numtriangles;
1727 memset(&m, 0, sizeof(m));
1728 m.pointer_vertex = vertex3f;
1730 GL_LockArrays(0, numverts);
1731 // square alpha in framebuffer a few times to make it shiny
1732 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1733 // these comments are a test run through this math for intensity 0.5
1734 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1735 // 0.25 * 0.25 = 0.0625 (this is another pass)
1736 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1737 R_Mesh_Draw(numverts, numtriangles, elements);
1739 c_rt_lighttris += numtriangles;
1740 R_Mesh_Draw(numverts, numtriangles, elements);
1742 c_rt_lighttris += numtriangles;
1743 GL_LockArrays(0, 0);
1745 memset(&m, 0, sizeof(m));
1746 m.pointer_vertex = vertex3f;
1747 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1749 m.pointer_texcoord3f[0] = vertex3f;
1750 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1752 m.pointer_texcoord[0] = varray_texcoord2f[0];
1753 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1755 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1757 m.pointer_texcoord3f[1] = vertex3f;
1758 m.texmatrix[1] = *matrix_modeltoattenuationz;
1760 m.pointer_texcoord[1] = varray_texcoord2f[1];
1761 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1764 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1765 GL_LockArrays(0, numverts);
1766 R_Mesh_Draw(numverts, numtriangles, elements);
1767 GL_LockArrays(0, 0);
1769 c_rt_lighttris += numtriangles;
1771 memset(&m, 0, sizeof(m));
1772 m.pointer_vertex = vertex3f;
1773 m.tex[0] = R_GetTexture(glosstexture);
1774 m.pointer_texcoord[0] = texcoord2f;
1777 m.texcubemap[1] = R_GetTexture(lightcubemap);
1779 m.pointer_texcoord3f[1] = vertex3f;
1780 m.texmatrix[1] = *matrix_modeltolight;
1782 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1783 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1789 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1790 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1791 VectorScale(lightcolor, colorscale, color2);
1792 GL_LockArrays(0, numverts);
1793 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1795 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1796 R_Mesh_Draw(numverts, numtriangles, elements);
1798 c_rt_lighttris += numtriangles;
1800 GL_LockArrays(0, 0);
1805 if (lighting & LIGHTING_DIFFUSE)
1807 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1808 VectorScale(lightcolor, r_shadow_lightintensityscale.value, color2);
1809 memset(&m, 0, sizeof(m));
1810 m.pointer_vertex = vertex3f;
1811 m.pointer_color = varray_color4f;
1812 m.tex[0] = R_GetTexture(basetexture);
1813 m.pointer_texcoord[0] = texcoord2f;
1814 if (r_textureunits.integer >= 2)
1817 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1819 m.pointer_texcoord3f[1] = vertex3f;
1820 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1822 m.pointer_texcoord[1] = varray_texcoord2f[1];
1823 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1825 if (r_textureunits.integer >= 3)
1827 // Geforce3/Radeon class but not using dot3
1828 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1830 m.pointer_texcoord3f[2] = vertex3f;
1831 m.texmatrix[2] = *matrix_modeltoattenuationz;
1833 m.pointer_texcoord[2] = varray_texcoord2f[2];
1834 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationz);
1839 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1841 color[0] = bound(0, color2[0], 1);
1842 color[1] = bound(0, color2[1], 1);
1843 color[2] = bound(0, color2[2], 1);
1844 if (r_textureunits.integer >= 3)
1845 R_Shadow_VertexShading(numverts, vertex3f, normal3f, color, matrix_modeltolight);
1846 else if (r_textureunits.integer >= 2)
1847 R_Shadow_VertexShadingWithZAttenuation(numverts, vertex3f, normal3f, color, matrix_modeltolight);
1849 R_Shadow_VertexShadingWithXYZAttenuation(numverts, vertex3f, normal3f, color, matrix_modeltolight);
1850 GL_LockArrays(0, numverts);
1851 R_Mesh_Draw(numverts, numtriangles, elements);
1852 GL_LockArrays(0, 0);
1854 c_rt_lighttris += numtriangles;
1860 void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
1864 R_RTLight_Uncompile(rtlight);
1865 memset(rtlight, 0, sizeof(*rtlight));
1867 VectorCopy(light->origin, rtlight->shadoworigin);
1868 VectorCopy(light->color, rtlight->color);
1869 rtlight->radius = light->radius;
1870 //rtlight->cullradius = rtlight->radius;
1871 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
1872 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
1873 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
1874 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
1875 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
1876 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
1877 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
1878 rtlight->cubemapname[0] = 0;
1879 if (light->cubemapname[0])
1880 strcpy(rtlight->cubemapname, light->cubemapname);
1881 else if (light->cubemapnum > 0)
1882 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
1883 rtlight->shadow = light->shadow;
1884 rtlight->corona = light->corona;
1885 rtlight->style = light->style;
1886 rtlight->isstatic = isstatic;
1887 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
1888 // ConcatScale won't work here because this needs to scale rotate and
1889 // translate, not just rotate
1890 scale = 1.0f / rtlight->radius;
1891 for (k = 0;k < 3;k++)
1892 for (j = 0;j < 4;j++)
1893 rtlight->matrix_worldtolight.m[k][j] *= scale;
1894 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationxyz, &matrix_attenuationxyz, &rtlight->matrix_worldtolight);
1895 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationz, &matrix_attenuationz, &rtlight->matrix_worldtolight);
1897 rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
1898 rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
1899 VectorScale(rtlight->color, rtlight->radius * d_lightstylevalue[rtlight->style] * 0.125f, rtlight->lightmap_light);
1900 rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
1903 // compiles rtlight geometry
1904 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
1905 void R_RTLight_Compile(rtlight_t *rtlight)
1907 int shadowmeshes, shadowtris, lightmeshes, lighttris, numclusters, numsurfaces;
1908 entity_render_t *ent = &cl_entities[0].render;
1909 model_t *model = ent->model;
1911 // compile the light
1912 rtlight->compiled = true;
1913 rtlight->static_numclusters = 0;
1914 rtlight->static_numclusterpvsbytes = 0;
1915 rtlight->static_clusterlist = NULL;
1916 rtlight->static_clusterpvs = NULL;
1917 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
1918 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
1919 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
1920 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
1921 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
1922 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
1924 if (model && model->GetLightInfo)
1926 // this variable directs the DrawShadowVolume and DrawLight code to capture into the mesh chain instead of rendering
1927 r_shadow_compilingrtlight = rtlight;
1928 R_Shadow_EnlargeClusterBuffer(model->brush.num_pvsclusters);
1929 R_Shadow_EnlargeSurfaceBuffer(model->nummodelsurfaces);
1930 model->GetLightInfo(ent, rtlight->shadoworigin, rtlight->radius, rtlight->cullmins, rtlight->cullmaxs, r_shadow_buffer_clusterlist, r_shadow_buffer_clusterpvs, &numclusters, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces);
1933 rtlight->static_numclusters = numclusters;
1934 rtlight->static_numclusterpvsbytes = (model->brush.num_pvsclusters + 7) >> 3;
1935 rtlight->static_clusterlist = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
1936 rtlight->static_clusterpvs = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusterpvsbytes);
1937 memcpy(rtlight->static_clusterlist, r_shadow_buffer_clusterlist, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
1938 memcpy(rtlight->static_clusterpvs, r_shadow_buffer_clusterpvs, rtlight->static_numclusterpvsbytes);
1940 if (model->DrawShadowVolume && rtlight->shadow)
1942 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
1943 model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
1944 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_shadow, false, false);
1946 if (model->DrawLight)
1948 rtlight->static_meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true);
1949 model->DrawLight(ent, rtlight->shadoworigin, vec3_origin, rtlight->radius, vec3_origin, &r_identitymatrix, &r_identitymatrix, &r_identitymatrix, NULL, numsurfaces, r_shadow_buffer_surfacelist);
1950 rtlight->static_meshchain_light = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_light, true, false);
1952 // switch back to rendering when DrawShadowVolume or DrawLight is called
1953 r_shadow_compilingrtlight = NULL;
1957 // use smallest available cullradius - box radius or light radius
1958 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
1959 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
1963 if (rtlight->static_meshchain_shadow)
1966 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
1969 shadowtris += mesh->numtriangles;
1975 if (rtlight->static_meshchain_light)
1978 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
1981 lighttris += mesh->numtriangles;
1985 Con_DPrintf("static light built: %f %f %f : %f %f %f box, %i shadow volume triangles (in %i meshes), %i light triangles (in %i meshes)\n", rtlight->cullmins[0], rtlight->cullmins[1], rtlight->cullmins[2], rtlight->cullmaxs[0], rtlight->cullmaxs[1], rtlight->cullmaxs[2], shadowtris, shadowmeshes, lighttris, lightmeshes);
1988 void R_RTLight_Uncompile(rtlight_t *rtlight)
1990 if (rtlight->compiled)
1992 if (rtlight->static_meshchain_shadow)
1993 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
1994 rtlight->static_meshchain_shadow = NULL;
1995 if (rtlight->static_meshchain_light)
1996 Mod_ShadowMesh_Free(rtlight->static_meshchain_light);
1997 rtlight->static_meshchain_light = NULL;
1998 if (rtlight->static_clusterlist)
1999 Mem_Free(rtlight->static_clusterlist);
2000 rtlight->static_clusterlist = NULL;
2001 if (rtlight->static_clusterpvs)
2002 Mem_Free(rtlight->static_clusterpvs);
2003 rtlight->static_clusterpvs = NULL;
2004 rtlight->static_numclusters = 0;
2005 rtlight->static_numclusterpvsbytes = 0;
2006 rtlight->compiled = false;
2010 void R_Shadow_UncompileWorldLights(void)
2013 for (light = r_shadow_worldlightchain;light;light = light->next)
2014 R_RTLight_Uncompile(&light->rtlight);
2017 void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes)
2020 entity_render_t *ent;
2022 vec3_t relativelightorigin, relativeeyeorigin, lightcolor;
2023 rtexture_t *cubemaptexture;
2024 matrix4x4_t matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz;
2025 int numclusters, numsurfaces;
2026 int *clusterlist, *surfacelist;
2028 vec3_t cullmins, cullmaxs;
2032 // loading is done before visibility checks because loading should happen
2033 // all at once at the start of a level, not when it stalls gameplay.
2034 // (especially important to benchmarks)
2035 if (rtlight->isstatic && !rtlight->compiled && r_shadow_staticworldlights.integer)
2036 R_RTLight_Compile(rtlight);
2037 if (rtlight->cubemapname[0])
2038 cubemaptexture = R_Shadow_Cubemap(rtlight->cubemapname);
2040 cubemaptexture = NULL;
2042 cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2043 cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2044 cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2045 cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2046 cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2047 cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2048 if (d_lightstylevalue[rtlight->style] <= 0)
2055 if (rtlight->compiled && r_shadow_staticworldlights.integer)
2057 // compiled light, world available and can receive realtime lighting
2058 // retrieve cluster information
2059 numclusters = rtlight->static_numclusters;
2060 clusterlist = rtlight->static_clusterlist;
2061 clusterpvs = rtlight->static_clusterpvs;
2062 VectorCopy(rtlight->cullmins, cullmins);
2063 VectorCopy(rtlight->cullmaxs, cullmaxs);
2065 else if (cl.worldmodel && cl.worldmodel->GetLightInfo)
2067 // dynamic light, world available and can receive realtime lighting
2068 // if the light box is offscreen, skip it right away
2069 if (R_CullBox(cullmins, cullmaxs))
2071 // calculate lit surfaces and clusters
2072 R_Shadow_EnlargeClusterBuffer(cl.worldmodel->brush.num_pvsclusters);
2073 R_Shadow_EnlargeSurfaceBuffer(cl.worldmodel->nummodelsurfaces);
2074 cl.worldmodel->GetLightInfo(&cl_entities[0].render, rtlight->shadoworigin, rtlight->radius, cullmins, cullmaxs, r_shadow_buffer_clusterlist, r_shadow_buffer_clusterpvs, &numclusters, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces);
2075 clusterlist = r_shadow_buffer_clusterlist;
2076 clusterpvs = r_shadow_buffer_clusterpvs;
2077 surfacelist = r_shadow_buffer_surfacelist;
2079 // if the reduced cluster bounds are offscreen, skip it
2080 if (R_CullBox(cullmins, cullmaxs))
2082 // check if light is illuminating any visible clusters
2085 for (i = 0;i < numclusters;i++)
2086 if (CHECKPVSBIT(r_pvsbits, clusterlist[i]))
2088 if (i == numclusters)
2091 // set up a scissor rectangle for this light
2092 if (R_Shadow_ScissorForBBox(cullmins, cullmaxs))
2095 f = d_lightstylevalue[rtlight->style] * (1.0f / 256.0f);
2096 VectorScale(rtlight->color, f, lightcolor);
2098 if (rtlight->selected)
2100 f = 2 + sin(realtime * M_PI * 4.0);
2101 VectorScale(lightcolor, f, lightcolor);
2106 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));
2109 if (rtlight->shadow)
2111 if (rtlight->isstatic)
2112 shadow = r_shadow_realtime_world_shadows.integer;
2115 if (r_shadow_realtime_world.integer)
2116 shadow = r_shadow_realtime_world_dlightshadows.integer;
2118 shadow = r_shadow_realtime_dlight_shadows.integer;
2123 if (shadow && (gl_stencil || visiblevolumes))
2125 if (!visiblevolumes)
2126 R_Shadow_Stage_ShadowVolumes();
2127 ent = &cl_entities[0].render;
2128 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2130 memset(&m, 0, sizeof(m));
2131 R_Mesh_Matrix(&ent->matrix);
2132 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2134 m.pointer_vertex = mesh->vertex3f;
2136 GL_LockArrays(0, mesh->numverts);
2137 if (r_shadowstage == SHADOWSTAGE_STENCIL)
2139 // decrement stencil if frontface is behind depthbuffer
2140 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2141 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2142 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2143 c_rtcached_shadowmeshes++;
2144 c_rtcached_shadowtris += mesh->numtriangles;
2145 // increment stencil if backface is behind depthbuffer
2146 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2147 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2149 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2150 c_rtcached_shadowmeshes++;
2151 c_rtcached_shadowtris += mesh->numtriangles;
2152 GL_LockArrays(0, 0);
2157 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2158 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, numsurfaces, surfacelist);
2160 if (r_drawentities.integer)
2162 for (i = 0;i < r_refdef.numentities;i++)
2164 ent = r_refdef.entities[i];
2166 if (r_shadow_cull.integer)
2168 if (!BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs))
2170 if (cl.worldmodel != NULL && cl.worldmodel->brush.BoxTouchingPVS != NULL && !cl.worldmodel->brush.BoxTouchingPVS(cl.worldmodel, clusterpvs, ent->mins, ent->maxs))
2173 if (!(ent->flags & RENDER_SHADOW) || !ent->model || !ent->model->DrawShadowVolume)
2175 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2176 // light emitting entities should not cast their own shadow
2177 if (VectorLength2(relativelightorigin) < 0.1)
2179 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, ent->model->nummodelsurfaces, ent->model->surfacelist);
2184 if (!visiblevolumes)
2186 R_Shadow_Stage_Light(shadow && gl_stencil);
2188 ent = &cl_entities[0].render;
2189 if (ent->model && ent->model->DrawLight)
2191 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2192 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2193 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2194 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2195 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2196 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2198 R_Mesh_Matrix(&ent->matrix);
2199 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2200 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);
2203 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, numsurfaces, surfacelist);
2205 if (r_drawentities.integer)
2207 for (i = 0;i < r_refdef.numentities;i++)
2209 ent = r_refdef.entities[i];
2210 if (ent->visframe == r_framecount && BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs) && ent->model && ent->model->DrawLight && (ent->flags & RENDER_LIGHT))
2212 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2213 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2214 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2215 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2216 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2217 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, ent->model->nummodelsurfaces, ent->model->surfacelist);
2224 void R_ShadowVolumeLighting(int visiblevolumes)
2230 if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2231 R_Shadow_EditLights_Reload_f();
2235 memset(&m, 0, sizeof(m));
2238 GL_BlendFunc(GL_ONE, GL_ONE);
2239 GL_DepthMask(false);
2240 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
2241 qglDisable(GL_CULL_FACE);
2242 GL_Color(0.0, 0.0125, 0.1, 1);
2245 R_Shadow_Stage_Begin();
2246 if (r_shadow_realtime_world.integer)
2248 if (r_shadow_debuglight.integer >= 0)
2250 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2251 if (lnum == r_shadow_debuglight.integer)
2252 R_DrawRTLight(&light->rtlight, visiblevolumes);
2255 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2256 R_DrawRTLight(&light->rtlight, visiblevolumes);
2258 if (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer)
2259 for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
2260 R_DrawRTLight(&light->rtlight, visiblevolumes);
2264 qglEnable(GL_CULL_FACE);
2265 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
2268 R_Shadow_Stage_End();
2271 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2272 typedef struct suffixinfo_s
2275 qboolean flipx, flipy, flipdiagonal;
2278 static suffixinfo_t suffix[3][6] =
2281 {"px", false, false, false},
2282 {"nx", false, false, false},
2283 {"py", false, false, false},
2284 {"ny", false, false, false},
2285 {"pz", false, false, false},
2286 {"nz", false, false, false}
2289 {"posx", false, false, false},
2290 {"negx", false, false, false},
2291 {"posy", false, false, false},
2292 {"negy", false, false, false},
2293 {"posz", false, false, false},
2294 {"negz", false, false, false}
2297 {"rt", true, false, true},
2298 {"lf", false, true, true},
2299 {"ft", true, true, false},
2300 {"bk", false, false, false},
2301 {"up", true, false, true},
2302 {"dn", true, false, true}
2306 static int componentorder[4] = {0, 1, 2, 3};
2308 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2310 int i, j, cubemapsize;
2311 qbyte *cubemappixels, *image_rgba;
2312 rtexture_t *cubemaptexture;
2314 // must start 0 so the first loadimagepixels has no requested width/height
2316 cubemappixels = NULL;
2317 cubemaptexture = NULL;
2318 // keep trying different suffix groups (posx, px, rt) until one loads
2319 for (j = 0;j < 3 && !cubemappixels;j++)
2321 // load the 6 images in the suffix group
2322 for (i = 0;i < 6;i++)
2324 // generate an image name based on the base and and suffix
2325 snprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2327 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2329 // an image loaded, make sure width and height are equal
2330 if (image_width == image_height)
2332 // if this is the first image to load successfully, allocate the cubemap memory
2333 if (!cubemappixels && image_width >= 1)
2335 cubemapsize = image_width;
2336 // note this clears to black, so unavailable sides are black
2337 cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2339 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2341 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);
2344 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2346 Mem_Free(image_rgba);
2350 // if a cubemap loaded, upload it
2353 if (!r_shadow_filters_texturepool)
2354 r_shadow_filters_texturepool = R_AllocTexturePool();
2355 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
2356 Mem_Free(cubemappixels);
2360 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
2361 for (j = 0;j < 3;j++)
2362 for (i = 0;i < 6;i++)
2363 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2364 Con_Print(" and was unable to find any of them.\n");
2366 return cubemaptexture;
2369 rtexture_t *R_Shadow_Cubemap(const char *basename)
2372 for (i = 0;i < numcubemaps;i++)
2373 if (!strcasecmp(cubemaps[i].basename, basename))
2374 return cubemaps[i].texture;
2375 if (i >= MAX_CUBEMAPS)
2378 strcpy(cubemaps[i].basename, basename);
2379 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
2380 return cubemaps[i].texture;
2383 void R_Shadow_FreeCubemaps(void)
2386 R_FreeTexturePool(&r_shadow_filters_texturepool);
2389 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)
2393 if (radius < 15 || DotProduct(color, color) < 0.03)
2395 Con_Print("R_Shadow_NewWorldLight: refusing to create a light too small/dim\n");
2399 light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
2400 VectorCopy(origin, light->origin);
2401 VectorCopy(angles, light->angles);
2402 VectorCopy(color, light->color);
2403 light->radius = radius;
2404 light->style = style;
2405 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
2407 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
2410 light->shadow = shadowenable;
2411 light->corona = corona;
2412 if (cubemapname && cubemapname[0] && strlen(cubemapname) < sizeof(light->cubemapname))
2413 strcpy(light->cubemapname, cubemapname);
2414 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
2415 light->next = r_shadow_worldlightchain;
2416 r_shadow_worldlightchain = light;
2418 R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
2421 void R_Shadow_FreeWorldLight(dlight_t *light)
2423 dlight_t **lightpointer;
2424 R_RTLight_Uncompile(&light->rtlight);
2425 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
2426 if (*lightpointer != light)
2427 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
2428 *lightpointer = light->next;
2432 void R_Shadow_ClearWorldLights(void)
2434 while (r_shadow_worldlightchain)
2435 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
2436 r_shadow_selectedlight = NULL;
2437 R_Shadow_FreeCubemaps();
2440 void R_Shadow_SelectLight(dlight_t *light)
2442 if (r_shadow_selectedlight)
2443 r_shadow_selectedlight->selected = false;
2444 r_shadow_selectedlight = light;
2445 if (r_shadow_selectedlight)
2446 r_shadow_selectedlight->selected = true;
2449 void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
2451 float scale = r_editlights_cursorgrid.value * 0.5f;
2452 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);
2455 void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
2458 const dlight_t *light;
2461 if (light->selected)
2462 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
2465 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);
2468 void R_Shadow_DrawLightSprites(void)
2474 for (i = 0;i < 5;i++)
2476 lighttextures[i] = NULL;
2477 if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1))))
2478 lighttextures[i] = pic->tex;
2481 for (light = r_shadow_worldlightchain;light;light = light->next)
2482 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, ((int) light) % 5);
2483 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
2486 void R_Shadow_SelectLightInView(void)
2488 float bestrating, rating, temp[3];
2489 dlight_t *best, *light;
2492 for (light = r_shadow_worldlightchain;light;light = light->next)
2494 VectorSubtract(light->origin, r_vieworigin, temp);
2495 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
2498 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
2499 if (bestrating < rating && CL_TraceLine(light->origin, r_vieworigin, NULL, NULL, true, NULL, SUPERCONTENTS_SOLID) == 1.0f)
2501 bestrating = rating;
2506 R_Shadow_SelectLight(best);
2509 void R_Shadow_LoadWorldLights(void)
2511 int n, a, style, shadow;
2512 char name[MAX_QPATH], cubemapname[MAX_QPATH], *lightsstring, *s, *t;
2513 float origin[3], radius, color[3], angles[3], corona;
2514 if (cl.worldmodel == NULL)
2516 Con_Print("No map loaded.\n");
2519 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2520 strlcat (name, ".rtlights", sizeof (name));
2521 lightsstring = FS_LoadFile(name, tempmempool, false);
2531 for (;COM_Parse(t, true) && strcmp(
2532 if (COM_Parse(t, true))
2534 if (com_token[0] == '!')
2537 origin[0] = atof(com_token+1);
2540 origin[0] = atof(com_token);
2545 while (*s && *s != '\n')
2551 // check for modifier flags
2557 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]);
2559 VectorClear(angles);
2562 if (a < 9 || !strcmp(cubemapname, "\"\""))
2567 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);
2570 VectorScale(color, r_editlights_rtlightscolorscale.value, color);
2571 radius *= r_editlights_rtlightssizescale.value;
2572 R_Shadow_NewWorldLight(origin, angles, color, radius, corona, style, shadow, cubemapname);
2577 Con_Printf("invalid rtlights file \"%s\"\n", name);
2578 Mem_Free(lightsstring);
2582 void R_Shadow_SaveWorldLights(void)
2585 int bufchars, bufmaxchars;
2587 char name[MAX_QPATH];
2589 if (!r_shadow_worldlightchain)
2591 if (cl.worldmodel == NULL)
2593 Con_Print("No map loaded.\n");
2596 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2597 strlcat (name, ".rtlights", sizeof (name));
2598 bufchars = bufmaxchars = 0;
2600 for (light = r_shadow_worldlightchain;light;light = light->next)
2602 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]);
2603 if (bufchars + (int) strlen(line) > bufmaxchars)
2605 bufmaxchars = bufchars + strlen(line) + 2048;
2607 buf = Mem_Alloc(r_shadow_mempool, bufmaxchars);
2611 memcpy(buf, oldbuf, bufchars);
2617 memcpy(buf + bufchars, line, strlen(line));
2618 bufchars += strlen(line);
2622 FS_WriteFile(name, buf, bufchars);
2627 void R_Shadow_LoadLightsFile(void)
2630 char name[MAX_QPATH], *lightsstring, *s, *t;
2631 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
2632 if (cl.worldmodel == NULL)
2634 Con_Print("No map loaded.\n");
2637 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2638 strlcat (name, ".lights", sizeof (name));
2639 lightsstring = FS_LoadFile(name, tempmempool, false);
2647 while (*s && *s != '\n')
2652 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);
2656 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);
2659 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
2660 radius = bound(15, radius, 4096);
2661 VectorScale(color, (2.0f / (8388608.0f)), color);
2662 R_Shadow_NewWorldLight(origin, vec3_origin, color, radius, 0, style, true, NULL);
2667 Con_Printf("invalid lights file \"%s\"\n", name);
2668 Mem_Free(lightsstring);
2672 // tyrlite/hmap2 light types in the delay field
2673 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
2675 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
2677 int entnum, style, islight, skin, pflags, effects, type, n;
2678 char key[256], value[1024];
2679 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
2682 if (cl.worldmodel == NULL)
2684 Con_Print("No map loaded.\n");
2687 data = cl.worldmodel->brush.entities;
2690 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
2692 type = LIGHTTYPE_MINUSX;
2693 origin[0] = origin[1] = origin[2] = 0;
2694 originhack[0] = originhack[1] = originhack[2] = 0;
2695 angles[0] = angles[1] = angles[2] = 0;
2696 color[0] = color[1] = color[2] = 1;
2697 light[0] = light[1] = light[2] = 1;light[3] = 300;
2698 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
2708 if (!COM_ParseToken(&data, false))
2710 if (com_token[0] == '}')
2711 break; // end of entity
2712 if (com_token[0] == '_')
2713 strcpy(key, com_token + 1);
2715 strcpy(key, com_token);
2716 while (key[strlen(key)-1] == ' ') // remove trailing spaces
2717 key[strlen(key)-1] = 0;
2718 if (!COM_ParseToken(&data, false))
2720 strcpy(value, com_token);
2722 // now that we have the key pair worked out...
2723 if (!strcmp("light", key))
2725 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
2729 light[0] = vec[0] * (1.0f / 256.0f);
2730 light[1] = vec[0] * (1.0f / 256.0f);
2731 light[2] = vec[0] * (1.0f / 256.0f);
2737 light[0] = vec[0] * (1.0f / 255.0f);
2738 light[1] = vec[1] * (1.0f / 255.0f);
2739 light[2] = vec[2] * (1.0f / 255.0f);
2743 else if (!strcmp("delay", key))
2745 else if (!strcmp("origin", key))
2746 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
2747 else if (!strcmp("angle", key))
2748 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
2749 else if (!strcmp("angles", key))
2750 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
2751 else if (!strcmp("color", key))
2752 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
2753 else if (!strcmp("wait", key))
2754 fadescale = atof(value);
2755 else if (!strcmp("classname", key))
2757 if (!strncmp(value, "light", 5))
2760 if (!strcmp(value, "light_fluoro"))
2765 overridecolor[0] = 1;
2766 overridecolor[1] = 1;
2767 overridecolor[2] = 1;
2769 if (!strcmp(value, "light_fluorospark"))
2774 overridecolor[0] = 1;
2775 overridecolor[1] = 1;
2776 overridecolor[2] = 1;
2778 if (!strcmp(value, "light_globe"))
2783 overridecolor[0] = 1;
2784 overridecolor[1] = 0.8;
2785 overridecolor[2] = 0.4;
2787 if (!strcmp(value, "light_flame_large_yellow"))
2792 overridecolor[0] = 1;
2793 overridecolor[1] = 0.5;
2794 overridecolor[2] = 0.1;
2796 if (!strcmp(value, "light_flame_small_yellow"))
2801 overridecolor[0] = 1;
2802 overridecolor[1] = 0.5;
2803 overridecolor[2] = 0.1;
2805 if (!strcmp(value, "light_torch_small_white"))
2810 overridecolor[0] = 1;
2811 overridecolor[1] = 0.5;
2812 overridecolor[2] = 0.1;
2814 if (!strcmp(value, "light_torch_small_walltorch"))
2819 overridecolor[0] = 1;
2820 overridecolor[1] = 0.5;
2821 overridecolor[2] = 0.1;
2825 else if (!strcmp("style", key))
2826 style = atoi(value);
2827 else if (cl.worldmodel->type == mod_brushq3)
2829 if (!strcmp("scale", key))
2830 lightscale = atof(value);
2831 if (!strcmp("fade", key))
2832 fadescale = atof(value);
2834 else if (!strcmp("skin", key))
2835 skin = (int)atof(value);
2836 else if (!strcmp("pflags", key))
2837 pflags = (int)atof(value);
2838 else if (!strcmp("effects", key))
2839 effects = (int)atof(value);
2843 if (lightscale <= 0)
2847 if (color[0] == color[1] && color[0] == color[2])
2849 color[0] *= overridecolor[0];
2850 color[1] *= overridecolor[1];
2851 color[2] *= overridecolor[2];
2853 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
2854 color[0] = color[0] * light[0];
2855 color[1] = color[1] * light[1];
2856 color[2] = color[2] * light[2];
2859 case LIGHTTYPE_MINUSX:
2861 case LIGHTTYPE_RECIPX:
2863 VectorScale(color, (1.0f / 16.0f), color);
2865 case LIGHTTYPE_RECIPXX:
2867 VectorScale(color, (1.0f / 16.0f), color);
2870 case LIGHTTYPE_NONE:
2874 case LIGHTTYPE_MINUSXX:
2877 VectorAdd(origin, originhack, origin);
2879 R_Shadow_NewWorldLight(origin, angles, color, radius, (pflags & PFLAGS_CORONA) != 0, style, (pflags & PFLAGS_NOSHADOW) == 0, skin >= 16 ? va("cubemaps/%i", skin) : NULL);
2884 void R_Shadow_SetCursorLocationForView(void)
2886 vec_t dist, push, frac;
2887 vec3_t dest, endpos, normal;
2888 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
2889 frac = CL_TraceLine(r_vieworigin, dest, endpos, normal, true, NULL, SUPERCONTENTS_SOLID);
2892 dist = frac * r_editlights_cursordistance.value;
2893 push = r_editlights_cursorpushback.value;
2897 VectorMA(endpos, push, r_viewforward, endpos);
2898 VectorMA(endpos, r_editlights_cursorpushoff.value, normal, endpos);
2900 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2901 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2902 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2905 void R_Shadow_UpdateWorldLightSelection(void)
2907 if (r_editlights.integer)
2909 R_Shadow_SetCursorLocationForView();
2910 R_Shadow_SelectLightInView();
2911 R_Shadow_DrawLightSprites();
2914 R_Shadow_SelectLight(NULL);
2917 void R_Shadow_EditLights_Clear_f(void)
2919 R_Shadow_ClearWorldLights();
2922 void R_Shadow_EditLights_Reload_f(void)
2926 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
2927 R_Shadow_ClearWorldLights();
2928 R_Shadow_LoadWorldLights();
2929 if (r_shadow_worldlightchain == NULL)
2931 R_Shadow_LoadLightsFile();
2932 if (r_shadow_worldlightchain == NULL)
2933 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
2937 void R_Shadow_EditLights_Save_f(void)
2941 R_Shadow_SaveWorldLights();
2944 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
2946 R_Shadow_ClearWorldLights();
2947 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
2950 void R_Shadow_EditLights_ImportLightsFile_f(void)
2952 R_Shadow_ClearWorldLights();
2953 R_Shadow_LoadLightsFile();
2956 void R_Shadow_EditLights_Spawn_f(void)
2959 if (!r_editlights.integer)
2961 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
2964 if (Cmd_Argc() != 1)
2966 Con_Print("r_editlights_spawn does not take parameters\n");
2969 color[0] = color[1] = color[2] = 1;
2970 R_Shadow_NewWorldLight(r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL);
2973 void R_Shadow_EditLights_Edit_f(void)
2975 vec3_t origin, angles, color;
2976 vec_t radius, corona;
2978 char cubemapname[1024];
2979 if (!r_editlights.integer)
2981 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
2984 if (!r_shadow_selectedlight)
2986 Con_Print("No selected light.\n");
2989 VectorCopy(r_shadow_selectedlight->origin, origin);
2990 VectorCopy(r_shadow_selectedlight->angles, angles);
2991 VectorCopy(r_shadow_selectedlight->color, color);
2992 radius = r_shadow_selectedlight->radius;
2993 style = r_shadow_selectedlight->style;
2994 if (r_shadow_selectedlight->cubemapname)
2995 strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
2998 shadows = r_shadow_selectedlight->shadow;
2999 corona = r_shadow_selectedlight->corona;
3000 if (!strcmp(Cmd_Argv(1), "origin"))
3002 if (Cmd_Argc() != 5)
3004 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3007 origin[0] = atof(Cmd_Argv(2));
3008 origin[1] = atof(Cmd_Argv(3));
3009 origin[2] = atof(Cmd_Argv(4));
3011 else if (!strcmp(Cmd_Argv(1), "originx"))
3013 if (Cmd_Argc() != 3)
3015 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3018 origin[0] = atof(Cmd_Argv(2));
3020 else if (!strcmp(Cmd_Argv(1), "originy"))
3022 if (Cmd_Argc() != 3)
3024 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3027 origin[1] = atof(Cmd_Argv(2));
3029 else if (!strcmp(Cmd_Argv(1), "originz"))
3031 if (Cmd_Argc() != 3)
3033 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3036 origin[2] = atof(Cmd_Argv(2));
3038 else if (!strcmp(Cmd_Argv(1), "move"))
3040 if (Cmd_Argc() != 5)
3042 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3045 origin[0] += atof(Cmd_Argv(2));
3046 origin[1] += atof(Cmd_Argv(3));
3047 origin[2] += atof(Cmd_Argv(4));
3049 else if (!strcmp(Cmd_Argv(1), "movex"))
3051 if (Cmd_Argc() != 3)
3053 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3056 origin[0] += atof(Cmd_Argv(2));
3058 else if (!strcmp(Cmd_Argv(1), "movey"))
3060 if (Cmd_Argc() != 3)
3062 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3065 origin[1] += atof(Cmd_Argv(2));
3067 else if (!strcmp(Cmd_Argv(1), "movez"))
3069 if (Cmd_Argc() != 3)
3071 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3074 origin[2] += atof(Cmd_Argv(2));
3076 else if (!strcmp(Cmd_Argv(1), "angles"))
3078 if (Cmd_Argc() != 5)
3080 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3083 angles[0] = atof(Cmd_Argv(2));
3084 angles[1] = atof(Cmd_Argv(3));
3085 angles[2] = atof(Cmd_Argv(4));
3087 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3089 if (Cmd_Argc() != 3)
3091 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3094 angles[0] = atof(Cmd_Argv(2));
3096 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3098 if (Cmd_Argc() != 3)
3100 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3103 angles[1] = atof(Cmd_Argv(2));
3105 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3107 if (Cmd_Argc() != 3)
3109 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3112 angles[2] = atof(Cmd_Argv(2));
3114 else if (!strcmp(Cmd_Argv(1), "color"))
3116 if (Cmd_Argc() != 5)
3118 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3121 color[0] = atof(Cmd_Argv(2));
3122 color[1] = atof(Cmd_Argv(3));
3123 color[2] = atof(Cmd_Argv(4));
3125 else if (!strcmp(Cmd_Argv(1), "radius"))
3127 if (Cmd_Argc() != 3)
3129 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3132 radius = atof(Cmd_Argv(2));
3134 else if (!strcmp(Cmd_Argv(1), "style"))
3136 if (Cmd_Argc() != 3)
3138 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3141 style = atoi(Cmd_Argv(2));
3143 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3147 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3150 if (Cmd_Argc() == 3)
3151 strcpy(cubemapname, Cmd_Argv(2));
3155 else if (!strcmp(Cmd_Argv(1), "shadows"))
3157 if (Cmd_Argc() != 3)
3159 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3162 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3164 else if (!strcmp(Cmd_Argv(1), "corona"))
3166 if (Cmd_Argc() != 3)
3168 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3171 corona = atof(Cmd_Argv(2));
3175 Con_Print("usage: r_editlights_edit [property] [value]\n");
3176 Con_Print("Selected light's properties:\n");
3177 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3178 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3179 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3180 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3181 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3182 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3183 Con_Printf("Shadows: %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3184 Con_Printf("Cubemap: %s\n", r_shadow_selectedlight->cubemapname);
3187 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3188 r_shadow_selectedlight = NULL;
3189 R_Shadow_NewWorldLight(origin, angles, color, radius, corona, style, shadows, cubemapname);
3192 void R_Shadow_EditLights_EditAll_f(void)
3196 for (light = r_shadow_worldlightchain;light;light = light->next)
3198 R_Shadow_SelectLight(light);
3199 R_Shadow_EditLights_Edit_f();
3203 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3207 if (!r_editlights.integer)
3211 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;
3212 if (r_shadow_selectedlight == NULL)
3214 sprintf(temp, "Light properties");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3215 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;
3216 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;
3217 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;
3218 sprintf(temp, "Radius %f", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3219 sprintf(temp, "Corona %f", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3220 sprintf(temp, "Style %i", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3221 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;
3222 sprintf(temp, "Cubemap %s", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3225 void R_Shadow_EditLights_ToggleShadow_f(void)
3227 if (!r_editlights.integer)
3229 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3232 if (!r_shadow_selectedlight)
3234 Con_Print("No selected light.\n");
3237 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);
3238 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3239 r_shadow_selectedlight = NULL;
3242 void R_Shadow_EditLights_ToggleCorona_f(void)
3244 if (!r_editlights.integer)
3246 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3249 if (!r_shadow_selectedlight)
3251 Con_Print("No selected light.\n");
3254 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);
3255 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3256 r_shadow_selectedlight = NULL;
3259 void R_Shadow_EditLights_Remove_f(void)
3261 if (!r_editlights.integer)
3263 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
3266 if (!r_shadow_selectedlight)
3268 Con_Print("No selected light.\n");
3271 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3272 r_shadow_selectedlight = NULL;
3275 void R_Shadow_EditLights_Help_f(void)
3278 "Documentation on r_editlights system:\n"
3280 "r_editlights : enable/disable editing mode\n"
3281 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
3282 "r_editlights_cursorpushback : push back cursor this far from surface\n"
3283 "r_editlights_cursorpushoff : push cursor off surface this far\n"
3284 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
3285 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
3286 "r_editlights_rtlightssizescale : imported rtlight size scaling\n"
3287 "r_editlights_rtlightscolorscale : imported rtlight color scaling\n"
3289 "r_editlights_help : this help\n"
3290 "r_editlights_clear : remove all lights\n"
3291 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
3292 "r_editlights_save : save to .rtlights file\n"
3293 "r_editlights_spawn : create a light with default settings\n"
3294 "r_editlights_edit command : edit selected light - more documentation below\n"
3295 "r_editlights_remove : remove selected light\n"
3296 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
3297 "r_editlights_importlightentitiesfrommap : reload light entities\n"
3298 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
3300 "origin x y z : set light location\n"
3301 "originx x: set x component of light location\n"
3302 "originy y: set y component of light location\n"
3303 "originz z: set z component of light location\n"
3304 "move x y z : adjust light location\n"
3305 "movex x: adjust x component of light location\n"
3306 "movey y: adjust y component of light location\n"
3307 "movez z: adjust z component of light location\n"
3308 "angles x y z : set light angles\n"
3309 "anglesx x: set x component of light angles\n"
3310 "anglesy y: set y component of light angles\n"
3311 "anglesz z: set z component of light angles\n"
3312 "color r g b : set color of light (can be brighter than 1 1 1)\n"
3313 "radius radius : set radius (size) of light\n"
3314 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
3315 "cubemap basename : set filter cubemap of light (not yet supported)\n"
3316 "shadows 1/0 : turn on/off shadows\n"
3317 "corona n : set corona intensity\n"
3318 "<nothing> : print light properties to console\n"
3322 void R_Shadow_EditLights_Init(void)
3324 Cvar_RegisterVariable(&r_editlights);
3325 Cvar_RegisterVariable(&r_editlights_cursordistance);
3326 Cvar_RegisterVariable(&r_editlights_cursorpushback);
3327 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
3328 Cvar_RegisterVariable(&r_editlights_cursorgrid);
3329 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
3330 Cvar_RegisterVariable(&r_editlights_rtlightssizescale);
3331 Cvar_RegisterVariable(&r_editlights_rtlightscolorscale);
3332 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
3333 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
3334 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
3335 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
3336 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
3337 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
3338 Cmd_AddCommand("r_editlights_editall", R_Shadow_EditLights_EditAll_f);
3339 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
3340 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
3341 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
3342 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
3343 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);