3 Terminology: Stencil Shadow Volume (sometimes called Stencil Shadows)
4 An extrusion of the lit faces, beginning at the original geometry and ending
5 further from the light source than the original geometry (presumably at least
6 as far as the light's radius, if the light has a radius at all), capped at
7 both front and back to avoid any problems (extrusion from dark faces also
8 works but has a different set of problems)
10 This is rendered using Carmack's Reverse technique, in which backfaces behind
11 zbuffer (zfail) increment the stencil, and frontfaces behind zbuffer (zfail)
12 decrement the stencil, the result is a stencil value of zero where shadows
13 did not intersect the visible geometry, suitable as a stencil mask for
14 rendering lighting everywhere but shadow.
16 In our case we use a biased stencil clear of 128 to avoid requiring the
17 stencil wrap extension (but probably should support it), and to address
18 Creative's patent on this sort of technology we also draw the frontfaces
19 first, and backfaces second (decrement, increment).
22 This algorithm may be covered by Creative's patent (US Patent #6384822)
23 on Carmack's Reverse paper (which I have not read), however that patent
24 seems to be about drawing a stencil shadow from a model in an otherwise
25 unshadowed scene, where as realtime lighting technology draws light where
30 Terminology: Stencil Light Volume (sometimes called Light Volumes)
31 Similar to a Stencil Shadow Volume, but inverted; rather than containing the
32 areas in shadow it contanis the areas in light, this can only be built
33 quickly for certain limited cases (such as portal visibility from a point),
34 but is quite useful for some effects (sunlight coming from sky polygons is
35 one possible example, translucent occluders is another example).
39 Terminology: Optimized Stencil Shadow Volume
40 A Stencil Shadow Volume that has been processed sufficiently to ensure it has
41 no duplicate coverage of areas (no need to shadow an area twice), often this
42 greatly improves performance but is an operation too costly to use on moving
43 lights (however completely optimal Stencil Light Volumes can be constructed
48 Terminology: Per Pixel Lighting (sometimes abbreviated PPL)
49 Per pixel evaluation of lighting equations, at a bare minimum this involves
50 DOT3 shading of diffuse lighting (per pixel dotproduct of negated incidence
51 vector and surface normal, using a texture of the surface bumps, called a
52 NormalMap) if supported by hardware; in our case there is support for cards
53 which are incapable of DOT3, the quality is quite poor however. Additionally
54 it is desirable to have specular evaluation per pixel, per vertex
55 normalization of specular halfangle vectors causes noticable distortion but
56 is unavoidable on hardware without GL_ARB_fragment_program.
60 Terminology: Normalization CubeMap
61 A cubemap containing normalized dot3-encoded (vectors of length 1 or less
62 encoded as RGB colors) for any possible direction, this technique allows per
63 pixel calculation of incidence vector for per pixel lighting purposes, which
64 would not otherwise be possible per pixel without GL_ARB_fragment_program.
68 Terminology: 2D Attenuation Texturing
69 A very crude approximation of light attenuation with distance which results
70 in cylindrical light shapes which fade vertically as a streak (some games
71 such as Doom3 allow this to be rotated to be less noticable in specific
72 cases), the technique is simply modulating lighting by two 2D textures (which
73 can be the same) on different axes of projection (XY and Z, typically), this
74 is the best technique available without 3D Attenuation Texturing or
75 GL_ARB_fragment_program technology.
79 Terminology: 3D Attenuation Texturing
80 A slightly crude approximation of light attenuation with distance, its flaws
81 are limited radius and resolution (performance tradeoffs).
85 Terminology: 3D Attenuation-Normalization Texturing
86 A 3D Attenuation Texture merged with a Normalization CubeMap, by making the
87 vectors shorter the lighting becomes darker, a very effective optimization of
88 diffuse lighting if 3D Attenuation Textures are already used.
92 Terminology: Light Cubemap Filtering
93 A technique for modeling non-uniform light distribution according to
94 direction, for example projecting a stained glass window image onto a wall,
95 this is done by texturing the lighting with a cubemap.
99 Terminology: Light Projection Filtering
100 A technique for modeling shadowing of light passing through translucent
101 surfaces, allowing stained glass windows and other effects to be done more
102 elegantly than possible with Light Cubemap Filtering by applying an occluder
103 texture to the lighting combined with a stencil light volume to limit the lit
104 area (this allows evaluating multiple translucent occluders in a scene).
108 Terminology: Doom3 Lighting
109 A combination of Stencil Shadow Volume, Per Pixel Lighting, Normalization
110 CubeMap, 2D Attenuation Texturing, and Light Filtering, as demonstrated by
111 the (currently upcoming) game Doom3.
114 #include "quakedef.h"
115 #include "r_shadow.h"
116 #include "cl_collision.h"
120 extern void R_Shadow_EditLights_Init(void);
122 #define SHADOWSTAGE_NONE 0
123 #define SHADOWSTAGE_STENCIL 1
124 #define SHADOWSTAGE_LIGHT 2
125 #define SHADOWSTAGE_STENCILTWOSIDE 3
127 int r_shadowstage = SHADOWSTAGE_NONE;
129 mempool_t *r_shadow_mempool;
131 int maxshadowelements;
145 int r_shadow_buffer_numclusterpvsbytes;
146 qbyte *r_shadow_buffer_clusterpvs;
147 int *r_shadow_buffer_clusterlist;
149 int r_shadow_buffer_numsurfacepvsbytes;
150 qbyte *r_shadow_buffer_surfacepvs;
151 int *r_shadow_buffer_surfacelist;
153 rtexturepool_t *r_shadow_texturepool;
154 rtexture_t *r_shadow_normalcubetexture;
155 rtexture_t *r_shadow_attenuation2dtexture;
156 rtexture_t *r_shadow_attenuation3dtexture;
157 rtexture_t *r_shadow_blankbumptexture;
158 rtexture_t *r_shadow_blankglosstexture;
159 rtexture_t *r_shadow_blankwhitetexture;
161 // lights are reloaded when this changes
162 char r_shadow_mapname[MAX_QPATH];
164 // used only for light filters (cubemaps)
165 rtexturepool_t *r_shadow_filters_texturepool;
167 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0"};
168 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4"};
169 cvar_t r_shadow_cull = {0, "r_shadow_cull", "1"};
170 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1"};
171 cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1"};
172 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.25"};
173 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1"};
174 cvar_t r_shadow_lightattenuationpower = {0, "r_shadow_lightattenuationpower", "0.5"};
175 cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1"};
176 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1"};
177 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1"};
178 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000"};
179 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1"};
180 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "0"};
181 cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0"};
182 cvar_t r_shadow_realtime_world_dlightshadows = {CVAR_SAVE, "r_shadow_realtime_world_dlightshadows", "1"};
183 cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0"};
184 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1"};
185 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1"};
186 cvar_t r_shadow_shadow_polygonfactor = {0, "r_shadow_shadow_polygonfactor", "0"};
187 cvar_t r_shadow_shadow_polygonoffset = {0, "r_shadow_shadow_polygonoffset", "1"};
188 cvar_t r_shadow_singlepassvolumegeneration = {0, "r_shadow_singlepassvolumegeneration", "1"};
189 cvar_t r_shadow_staticworldlights = {0, "r_shadow_staticworldlights", "1"};
190 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1"};
191 cvar_t r_shadow_visiblevolumes = {0, "r_shadow_visiblevolumes", "0"};
192 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1"};
193 cvar_t r_editlights = {0, "r_editlights", "0"};
194 cvar_t r_editlights_cursordistance = {0, "r_editlights_distance", "1024"};
195 cvar_t r_editlights_cursorpushback = {0, "r_editlights_pushback", "0"};
196 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_pushoff", "4"};
197 cvar_t r_editlights_cursorgrid = {0, "r_editlights_grid", "4"};
198 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "0.8"};
199 cvar_t r_editlights_rtlightssizescale = {CVAR_SAVE, "r_editlights_rtlightssizescale", "0.7"};
200 cvar_t r_editlights_rtlightscolorscale = {CVAR_SAVE, "r_editlights_rtlightscolorscale", "2"};
202 int c_rt_lights, c_rt_clears, c_rt_scissored;
203 int c_rt_shadowmeshes, c_rt_shadowtris, c_rt_lightmeshes, c_rt_lighttris;
204 int c_rtcached_shadowmeshes, c_rtcached_shadowtris;
206 float r_shadow_attenpower, r_shadow_attenscale;
208 rtlight_t *r_shadow_compilingrtlight;
209 dlight_t *r_shadow_worldlightchain;
210 dlight_t *r_shadow_selectedlight;
211 dlight_t r_shadow_bufferlight;
212 vec3_t r_editlights_cursorlocation;
214 rtexture_t *lighttextures[5];
216 extern int con_vislines;
218 typedef struct cubemapinfo_s
225 #define MAX_CUBEMAPS 256
226 static int numcubemaps;
227 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
229 void R_Shadow_UncompileWorldLights(void);
230 void R_Shadow_ClearWorldLights(void);
231 void R_Shadow_SaveWorldLights(void);
232 void R_Shadow_LoadWorldLights(void);
233 void R_Shadow_LoadLightsFile(void);
234 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
235 void R_Shadow_EditLights_Reload_f(void);
236 void R_Shadow_ValidateCvars(void);
237 static void R_Shadow_MakeTextures(void);
238 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light);
240 void r_shadow_start(void)
242 // allocate vertex processing arrays
244 r_shadow_normalcubetexture = NULL;
245 r_shadow_attenuation2dtexture = NULL;
246 r_shadow_attenuation3dtexture = NULL;
247 r_shadow_blankbumptexture = NULL;
248 r_shadow_blankglosstexture = NULL;
249 r_shadow_blankwhitetexture = NULL;
250 r_shadow_texturepool = NULL;
251 r_shadow_filters_texturepool = NULL;
252 R_Shadow_ValidateCvars();
253 R_Shadow_MakeTextures();
254 maxshadowelements = 0;
255 shadowelements = NULL;
263 shadowmarklist = NULL;
265 r_shadow_buffer_numclusterpvsbytes = 0;
266 r_shadow_buffer_clusterpvs = NULL;
267 r_shadow_buffer_clusterlist = NULL;
268 r_shadow_buffer_numsurfacepvsbytes = 0;
269 r_shadow_buffer_surfacepvs = NULL;
270 r_shadow_buffer_surfacelist = NULL;
273 void r_shadow_shutdown(void)
275 R_Shadow_UncompileWorldLights();
277 r_shadow_normalcubetexture = NULL;
278 r_shadow_attenuation2dtexture = NULL;
279 r_shadow_attenuation3dtexture = NULL;
280 r_shadow_blankbumptexture = NULL;
281 r_shadow_blankglosstexture = NULL;
282 r_shadow_blankwhitetexture = NULL;
283 R_FreeTexturePool(&r_shadow_texturepool);
284 R_FreeTexturePool(&r_shadow_filters_texturepool);
285 maxshadowelements = 0;
287 Mem_Free(shadowelements);
288 shadowelements = NULL;
291 Mem_Free(vertexupdate);
294 Mem_Free(vertexremap);
300 Mem_Free(shadowmark);
303 Mem_Free(shadowmarklist);
304 shadowmarklist = NULL;
306 r_shadow_buffer_numclusterpvsbytes = 0;
307 if (r_shadow_buffer_clusterpvs)
308 Mem_Free(r_shadow_buffer_clusterpvs);
309 r_shadow_buffer_clusterpvs = NULL;
310 if (r_shadow_buffer_clusterlist)
311 Mem_Free(r_shadow_buffer_clusterlist);
312 r_shadow_buffer_clusterlist = NULL;
313 r_shadow_buffer_numsurfacepvsbytes = 0;
314 if (r_shadow_buffer_surfacepvs)
315 Mem_Free(r_shadow_buffer_surfacepvs);
316 r_shadow_buffer_surfacepvs = NULL;
317 if (r_shadow_buffer_surfacelist)
318 Mem_Free(r_shadow_buffer_surfacelist);
319 r_shadow_buffer_surfacelist = NULL;
322 void r_shadow_newmap(void)
326 void R_Shadow_Help_f(void)
329 "Documentation on r_shadow system:\n"
331 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
332 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
333 "r_shadow_debuglight : render only this light number (-1 = all)\n"
334 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
335 "r_shadow_gloss2intensity : brightness of forced gloss\n"
336 "r_shadow_glossintensity : brightness of textured gloss\n"
337 "r_shadow_lightattenuationpower : used to generate attenuation texture\n"
338 "r_shadow_lightattenuationscale : used to generate attenuation texture\n"
339 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
340 "r_shadow_portallight : use portal visibility for static light precomputation\n"
341 "r_shadow_projectdistance : shadow volume projection distance\n"
342 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
343 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
344 "r_shadow_realtime_world : use high quality world lighting mode\n"
345 "r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n"
346 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
347 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
348 "r_shadow_scissor : use scissor optimization\n"
349 "r_shadow_shadow_polygonfactor : nudge shadow volumes closer/further\n"
350 "r_shadow_shadow_polygonoffset : nudge shadow volumes closer/further\n"
351 "r_shadow_singlepassvolumegeneration : selects shadow volume algorithm\n"
352 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
353 "r_shadow_visiblevolumes : useful for performance testing; bright = slow!\n"
355 "r_shadow_help : this help\n"
359 void R_Shadow_Init(void)
361 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
362 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
363 Cvar_RegisterVariable(&r_shadow_cull);
364 Cvar_RegisterVariable(&r_shadow_debuglight);
365 Cvar_RegisterVariable(&r_shadow_gloss);
366 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
367 Cvar_RegisterVariable(&r_shadow_glossintensity);
368 Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
369 Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
370 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
371 Cvar_RegisterVariable(&r_shadow_portallight);
372 Cvar_RegisterVariable(&r_shadow_projectdistance);
373 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
374 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
375 Cvar_RegisterVariable(&r_shadow_realtime_world);
376 Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows);
377 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
378 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
379 Cvar_RegisterVariable(&r_shadow_scissor);
380 Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor);
381 Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset);
382 Cvar_RegisterVariable(&r_shadow_singlepassvolumegeneration);
383 Cvar_RegisterVariable(&r_shadow_staticworldlights);
384 Cvar_RegisterVariable(&r_shadow_texture3d);
385 Cvar_RegisterVariable(&r_shadow_visiblevolumes);
386 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
387 if (gamemode == GAME_TENEBRAE)
389 Cvar_SetValue("r_shadow_gloss", 2);
390 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
392 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f);
393 R_Shadow_EditLights_Init();
394 r_shadow_mempool = Mem_AllocPool("R_Shadow", 0, NULL);
395 r_shadow_worldlightchain = NULL;
396 maxshadowelements = 0;
397 shadowelements = NULL;
405 shadowmarklist = NULL;
407 r_shadow_buffer_numclusterpvsbytes = 0;
408 r_shadow_buffer_clusterpvs = NULL;
409 r_shadow_buffer_clusterlist = NULL;
410 r_shadow_buffer_numsurfacepvsbytes = 0;
411 r_shadow_buffer_surfacepvs = NULL;
412 r_shadow_buffer_surfacelist = NULL;
413 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
416 matrix4x4_t matrix_attenuationxyz =
419 {0.5, 0.0, 0.0, 0.5},
420 {0.0, 0.5, 0.0, 0.5},
421 {0.0, 0.0, 0.5, 0.5},
426 matrix4x4_t matrix_attenuationz =
429 {0.0, 0.0, 0.5, 0.5},
430 {0.0, 0.0, 0.0, 0.5},
431 {0.0, 0.0, 0.0, 0.5},
436 int *R_Shadow_ResizeShadowElements(int numtris)
438 // make sure shadowelements is big enough for this volume
439 if (maxshadowelements < numtris * 24)
441 maxshadowelements = numtris * 24;
443 Mem_Free(shadowelements);
444 shadowelements = Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int));
446 return shadowelements;
449 void R_Shadow_EnlargeClusterBuffer(int numclusters)
451 int numclusterpvsbytes = (((numclusters + 7) >> 3) + 255) & ~255;
452 if (r_shadow_buffer_numclusterpvsbytes < numclusterpvsbytes)
454 if (r_shadow_buffer_clusterpvs)
455 Mem_Free(r_shadow_buffer_clusterpvs);
456 if (r_shadow_buffer_clusterlist)
457 Mem_Free(r_shadow_buffer_clusterlist);
458 r_shadow_buffer_numclusterpvsbytes = numclusterpvsbytes;
459 r_shadow_buffer_clusterpvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numclusterpvsbytes);
460 r_shadow_buffer_clusterlist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numclusterpvsbytes * 8 * sizeof(*r_shadow_buffer_clusterlist));
464 void R_Shadow_EnlargeSurfaceBuffer(int numsurfaces)
466 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
467 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
469 if (r_shadow_buffer_surfacepvs)
470 Mem_Free(r_shadow_buffer_surfacepvs);
471 if (r_shadow_buffer_surfacelist)
472 Mem_Free(r_shadow_buffer_surfacelist);
473 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
474 r_shadow_buffer_surfacepvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes);
475 r_shadow_buffer_surfacelist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
479 void R_Shadow_PrepareShadowMark(int numtris)
481 // make sure shadowmark is big enough for this volume
482 if (maxshadowmark < numtris)
484 maxshadowmark = numtris;
486 Mem_Free(shadowmark);
488 Mem_Free(shadowmarklist);
489 shadowmark = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmark));
490 shadowmarklist = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmarklist));
494 // if shadowmarkcount wrapped we clear the array and adjust accordingly
495 if (shadowmarkcount == 0)
498 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
503 int R_Shadow_ConstructShadowVolume(int innumvertices, int innumtris, const int *inelement3i, const int *inneighbor3i, const float *invertex3f, int *outnumvertices, int *outelement3i, float *outvertex3f, const float *projectorigin, float projectdistance, int numshadowmarktris, const int *shadowmarktris)
505 int i, j, tris = 0, vr[3], t, outvertices = 0;
510 if (maxvertexupdate < innumvertices)
512 maxvertexupdate = innumvertices;
514 Mem_Free(vertexupdate);
516 Mem_Free(vertexremap);
517 vertexupdate = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
518 vertexremap = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
522 if (vertexupdatenum == 0)
525 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
526 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
529 for (i = 0;i < numshadowmarktris;i++)
530 shadowmark[shadowmarktris[i]] = shadowmarkcount;
532 for (i = 0;i < numshadowmarktris;i++)
534 t = shadowmarktris[i];
535 e = inelement3i + t * 3;
536 // make sure the vertices are created
537 for (j = 0;j < 3;j++)
539 if (vertexupdate[e[j]] != vertexupdatenum)
541 vertexupdate[e[j]] = vertexupdatenum;
542 vertexremap[e[j]] = outvertices;
543 v = invertex3f + e[j] * 3;
544 // project one copy of the vertex to the sphere radius of the light
545 // (FIXME: would projecting it to the light box be better?)
546 VectorSubtract(v, projectorigin, temp);
547 f = projectdistance / VectorLength(temp);
548 VectorCopy(v, outvertex3f);
549 VectorMA(projectorigin, f, temp, (outvertex3f + 3));
556 for (i = 0;i < numshadowmarktris;i++)
558 t = shadowmarktris[i];
559 e = inelement3i + t * 3;
560 n = inneighbor3i + t * 3;
561 // output the front and back triangles
562 outelement3i[0] = vertexremap[e[0]];
563 outelement3i[1] = vertexremap[e[1]];
564 outelement3i[2] = vertexremap[e[2]];
565 outelement3i[3] = vertexremap[e[2]] + 1;
566 outelement3i[4] = vertexremap[e[1]] + 1;
567 outelement3i[5] = vertexremap[e[0]] + 1;
570 // output the sides (facing outward from this triangle)
571 if (shadowmark[n[0]] != shadowmarkcount)
573 vr[0] = vertexremap[e[0]];
574 vr[1] = vertexremap[e[1]];
575 outelement3i[0] = vr[1];
576 outelement3i[1] = vr[0];
577 outelement3i[2] = vr[0] + 1;
578 outelement3i[3] = vr[1];
579 outelement3i[4] = vr[0] + 1;
580 outelement3i[5] = vr[1] + 1;
584 if (shadowmark[n[1]] != shadowmarkcount)
586 vr[1] = vertexremap[e[1]];
587 vr[2] = vertexremap[e[2]];
588 outelement3i[0] = vr[2];
589 outelement3i[1] = vr[1];
590 outelement3i[2] = vr[1] + 1;
591 outelement3i[3] = vr[2];
592 outelement3i[4] = vr[1] + 1;
593 outelement3i[5] = vr[2] + 1;
597 if (shadowmark[n[2]] != shadowmarkcount)
599 vr[0] = vertexremap[e[0]];
600 vr[2] = vertexremap[e[2]];
601 outelement3i[0] = vr[0];
602 outelement3i[1] = vr[2];
603 outelement3i[2] = vr[2] + 1;
604 outelement3i[3] = vr[0];
605 outelement3i[4] = vr[2] + 1;
606 outelement3i[5] = vr[0] + 1;
612 *outnumvertices = outvertices;
616 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)
619 if (projectdistance < 0.1)
621 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
624 if (!numverts || !nummarktris)
626 // make sure shadowelements is big enough for this volume
627 if (maxshadowelements < nummarktris * 24)
628 R_Shadow_ResizeShadowElements((nummarktris + 256) * 24);
629 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, varray_vertex3f2, projectorigin, projectdistance, nummarktris, marktris);
630 R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements);
633 void R_Shadow_MarkVolumeFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const vec3_t projectorigin, vec3_t lightmins, vec3_t lightmaxs, vec3_t surfacemins, vec3_t surfacemaxs)
638 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
640 tend = firsttriangle + numtris;
641 if (surfacemins[0] >= lightmins[0] && surfacemaxs[0] <= lightmaxs[0]
642 && surfacemins[1] >= lightmins[1] && surfacemaxs[1] <= lightmaxs[1]
643 && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2])
645 // surface box entirely inside light box, no box cull
646 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
647 if (PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
648 shadowmarklist[numshadowmark++] = t;
652 // surface box not entirely inside light box, cull each triangle
653 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
655 v[0] = invertex3f + e[0] * 3;
656 v[1] = invertex3f + e[1] * 3;
657 v[2] = invertex3f + e[2] * 3;
658 if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
659 && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
660 && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
661 && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
662 && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
663 && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
664 && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
665 shadowmarklist[numshadowmark++] = t;
670 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
673 if (r_shadow_compilingrtlight)
675 // if we're compiling an rtlight, capture the mesh
676 Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
679 memset(&m, 0, sizeof(m));
680 m.pointer_vertex = vertex3f;
682 GL_LockArrays(0, numvertices);
683 if (r_shadowstage == SHADOWSTAGE_STENCIL)
685 // increment stencil if backface is behind depthbuffer
686 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
687 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
688 R_Mesh_Draw(numvertices, numtriangles, element3i);
690 c_rt_shadowtris += numtriangles;
691 // decrement stencil if frontface is behind depthbuffer
692 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
693 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
695 R_Mesh_Draw(numvertices, numtriangles, element3i);
697 c_rt_shadowtris += numtriangles;
701 static void R_Shadow_MakeTextures(void)
703 int x, y, z, d, side;
704 float v[3], s, t, intensity;
706 R_FreeTexturePool(&r_shadow_texturepool);
707 r_shadow_texturepool = R_AllocTexturePool();
708 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
709 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
711 #define ATTEN2DSIZE 64
712 #define ATTEN3DSIZE 32
713 data = Mem_Alloc(tempmempool, max(6*NORMSIZE*NORMSIZE*4, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4)));
718 r_shadow_blankbumptexture = R_LoadTexture2D(r_shadow_texturepool, "blankbump", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
723 r_shadow_blankglosstexture = R_LoadTexture2D(r_shadow_texturepool, "blankgloss", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
728 r_shadow_blankwhitetexture = R_LoadTexture2D(r_shadow_texturepool, "blankwhite", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
729 if (gl_texturecubemap)
731 for (side = 0;side < 6;side++)
733 for (y = 0;y < NORMSIZE;y++)
735 for (x = 0;x < NORMSIZE;x++)
737 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
738 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
772 intensity = 127.0f / sqrt(DotProduct(v, v));
773 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+0] = 128.0f + intensity * v[0];
774 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+1] = 128.0f + intensity * v[1];
775 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+2] = 128.0f + intensity * v[2];
776 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+3] = 255;
780 r_shadow_normalcubetexture = R_LoadTextureCubeMap(r_shadow_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
783 r_shadow_normalcubetexture = NULL;
784 for (y = 0;y < ATTEN2DSIZE;y++)
786 for (x = 0;x < ATTEN2DSIZE;x++)
788 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
789 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
791 intensity = 1.0f - sqrt(DotProduct(v, v));
793 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
794 d = bound(0, intensity, 255);
795 data[(y*ATTEN2DSIZE+x)*4+0] = d;
796 data[(y*ATTEN2DSIZE+x)*4+1] = d;
797 data[(y*ATTEN2DSIZE+x)*4+2] = d;
798 data[(y*ATTEN2DSIZE+x)*4+3] = d;
801 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
802 if (r_shadow_texture3d.integer)
804 for (z = 0;z < ATTEN3DSIZE;z++)
806 for (y = 0;y < ATTEN3DSIZE;y++)
808 for (x = 0;x < ATTEN3DSIZE;x++)
810 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
811 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
812 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
813 intensity = 1.0f - sqrt(DotProduct(v, v));
815 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
816 d = bound(0, intensity, 255);
817 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
818 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
819 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
820 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
824 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
829 void R_Shadow_ValidateCvars(void)
831 if (r_shadow_texture3d.integer && !gl_texture3d)
832 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
833 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
834 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
837 void R_Shadow_Stage_Begin(void)
841 R_Shadow_ValidateCvars();
843 if (!r_shadow_attenuation2dtexture
844 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
845 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
846 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
847 R_Shadow_MakeTextures();
849 memset(&m, 0, sizeof(m));
850 GL_BlendFunc(GL_ONE, GL_ZERO);
854 GL_Color(0, 0, 0, 1);
855 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
856 qglEnable(GL_CULL_FACE);
857 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
858 r_shadowstage = SHADOWSTAGE_NONE;
860 c_rt_lights = c_rt_clears = c_rt_scissored = 0;
861 c_rt_shadowmeshes = c_rt_shadowtris = c_rt_lightmeshes = c_rt_lighttris = 0;
862 c_rtcached_shadowmeshes = c_rtcached_shadowtris = 0;
865 void R_Shadow_Stage_ShadowVolumes(void)
868 memset(&m, 0, sizeof(m));
870 GL_Color(1, 1, 1, 1);
871 GL_ColorMask(0, 0, 0, 0);
872 GL_BlendFunc(GL_ONE, GL_ZERO);
875 qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
876 //if (r_shadow_shadow_polygonoffset.value != 0)
878 // qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
879 // qglEnable(GL_POLYGON_OFFSET_FILL);
882 // qglDisable(GL_POLYGON_OFFSET_FILL);
883 qglDepthFunc(GL_LESS);
884 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
885 qglEnable(GL_STENCIL_TEST);
886 qglStencilFunc(GL_ALWAYS, 128, ~0);
887 if (gl_ext_stenciltwoside.integer)
889 r_shadowstage = SHADOWSTAGE_STENCILTWOSIDE;
890 qglDisable(GL_CULL_FACE);
891 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
892 qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
894 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
895 qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
897 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
901 r_shadowstage = SHADOWSTAGE_STENCIL;
902 qglEnable(GL_CULL_FACE);
904 // this is changed by every shadow render so its value here is unimportant
905 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
907 GL_Clear(GL_STENCIL_BUFFER_BIT);
909 // LordHavoc note: many shadow volumes reside entirely inside the world
910 // (that is to say they are entirely bounded by their lit surfaces),
911 // which can be optimized by handling things as an inverted light volume,
912 // with the shadow boundaries of the world being simulated by an altered
913 // (129) bias to stencil clearing on such lights
914 // FIXME: generate inverted light volumes for use as shadow volumes and
915 // optimize for them as noted above
918 void R_Shadow_Stage_Light(int shadowtest)
921 memset(&m, 0, sizeof(m));
923 GL_BlendFunc(GL_ONE, GL_ONE);
926 qglPolygonOffset(0, 0);
927 //qglDisable(GL_POLYGON_OFFSET_FILL);
928 GL_Color(1, 1, 1, 1);
929 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
930 qglDepthFunc(GL_EQUAL);
931 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
932 qglEnable(GL_CULL_FACE);
934 qglEnable(GL_STENCIL_TEST);
936 qglDisable(GL_STENCIL_TEST);
937 if (gl_support_stenciltwoside)
938 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
940 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
941 // only draw light where this geometry was already rendered AND the
942 // stencil is 128 (values other than this mean shadow)
943 qglStencilFunc(GL_EQUAL, 128, ~0);
944 r_shadowstage = SHADOWSTAGE_LIGHT;
948 void R_Shadow_Stage_End(void)
951 memset(&m, 0, sizeof(m));
953 GL_BlendFunc(GL_ONE, GL_ZERO);
956 qglPolygonOffset(0, 0);
957 //qglDisable(GL_POLYGON_OFFSET_FILL);
958 GL_Color(1, 1, 1, 1);
959 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
960 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
961 qglDepthFunc(GL_LEQUAL);
962 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
963 qglDisable(GL_STENCIL_TEST);
964 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
965 if (gl_support_stenciltwoside)
966 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
968 qglStencilFunc(GL_ALWAYS, 128, ~0);
969 r_shadowstage = SHADOWSTAGE_NONE;
972 int R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
974 int i, ix1, iy1, ix2, iy2;
975 float x1, y1, x2, y2, x, y, f;
978 if (!r_shadow_scissor.integer)
980 // if view is inside the box, just say yes it's visible
981 if (BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
983 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
986 for (i = 0;i < 3;i++)
988 if (r_viewforward[i] >= 0)
999 f = DotProduct(r_viewforward, r_vieworigin) + 1;
1000 if (DotProduct(r_viewforward, v2) <= f)
1002 // entirely behind nearclip plane
1005 if (DotProduct(r_viewforward, v) >= f)
1007 // entirely infront of nearclip plane
1008 x1 = y1 = x2 = y2 = 0;
1009 for (i = 0;i < 8;i++)
1011 v[0] = (i & 1) ? mins[0] : maxs[0];
1012 v[1] = (i & 2) ? mins[1] : maxs[1];
1013 v[2] = (i & 4) ? mins[2] : maxs[2];
1015 GL_TransformToScreen(v, v2);
1016 //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]);
1035 // clipped by nearclip plane
1036 // this is nasty and crude...
1037 // create viewspace bbox
1038 for (i = 0;i < 8;i++)
1040 v[0] = ((i & 1) ? mins[0] : maxs[0]) - r_vieworigin[0];
1041 v[1] = ((i & 2) ? mins[1] : maxs[1]) - r_vieworigin[1];
1042 v[2] = ((i & 4) ? mins[2] : maxs[2]) - r_vieworigin[2];
1043 v2[0] = -DotProduct(v, r_viewleft);
1044 v2[1] = DotProduct(v, r_viewup);
1045 v2[2] = DotProduct(v, r_viewforward);
1048 if (smins[0] > v2[0]) smins[0] = v2[0];
1049 if (smaxs[0] < v2[0]) smaxs[0] = v2[0];
1050 if (smins[1] > v2[1]) smins[1] = v2[1];
1051 if (smaxs[1] < v2[1]) smaxs[1] = v2[1];
1052 if (smins[2] > v2[2]) smins[2] = v2[2];
1053 if (smaxs[2] < v2[2]) smaxs[2] = v2[2];
1057 smins[0] = smaxs[0] = v2[0];
1058 smins[1] = smaxs[1] = v2[1];
1059 smins[2] = smaxs[2] = v2[2];
1062 // now we have a bbox in viewspace
1063 // clip it to the view plane
1066 // return true if that culled the box
1067 if (smins[2] >= smaxs[2])
1069 // ok some of it is infront of the view, transform each corner back to
1070 // worldspace and then to screenspace and make screen rect
1071 // initialize these variables just to avoid compiler warnings
1072 x1 = y1 = x2 = y2 = 0;
1073 for (i = 0;i < 8;i++)
1075 v2[0] = (i & 1) ? smins[0] : smaxs[0];
1076 v2[1] = (i & 2) ? smins[1] : smaxs[1];
1077 v2[2] = (i & 4) ? smins[2] : smaxs[2];
1078 v[0] = v2[0] * -r_viewleft[0] + v2[1] * r_viewup[0] + v2[2] * r_viewforward[0] + r_vieworigin[0];
1079 v[1] = v2[0] * -r_viewleft[1] + v2[1] * r_viewup[1] + v2[2] * r_viewforward[1] + r_vieworigin[1];
1080 v[2] = v2[0] * -r_viewleft[2] + v2[1] * r_viewup[2] + v2[2] * r_viewforward[2] + r_vieworigin[2];
1082 GL_TransformToScreen(v, v2);
1083 //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]);
1100 // this code doesn't handle boxes with any points behind view properly
1101 x1 = 1000;x2 = -1000;
1102 y1 = 1000;y2 = -1000;
1103 for (i = 0;i < 8;i++)
1105 v[0] = (i & 1) ? mins[0] : maxs[0];
1106 v[1] = (i & 2) ? mins[1] : maxs[1];
1107 v[2] = (i & 4) ? mins[2] : maxs[2];
1109 GL_TransformToScreen(v, v2);
1110 //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]);
1128 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1129 if (ix1 < r_view_x) ix1 = r_view_x;
1130 if (iy1 < r_view_y) iy1 = r_view_y;
1131 if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
1132 if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
1133 if (ix2 <= ix1 || iy2 <= iy1)
1135 // set up the scissor rectangle
1136 GL_Scissor(ix1, vid.realheight - iy2, ix2 - ix1, iy2 - iy1);
1137 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1138 //qglEnable(GL_SCISSOR_TEST);
1143 static void R_Shadow_VertexShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1145 float *color4f = varray_color4f;
1146 float dist, dot, intensity, v[3], n[3];
1147 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1149 Matrix4x4_Transform(m, vertex3f, v);
1150 if ((dist = DotProduct(v, v)) < 1)
1152 Matrix4x4_Transform3x3(m, normal3f, n);
1153 if ((dot = DotProduct(n, v)) > 0)
1156 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1157 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1158 VectorScale(lightcolor, intensity, color4f);
1163 VectorClear(color4f);
1169 VectorClear(color4f);
1175 static void R_Shadow_VertexShadingWithZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1177 float *color4f = varray_color4f;
1178 float dist, dot, intensity, v[3], n[3];
1179 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1181 Matrix4x4_Transform(m, vertex3f, v);
1182 if ((dist = fabs(v[2])) < 1)
1184 Matrix4x4_Transform3x3(m, normal3f, n);
1185 if ((dot = DotProduct(n, v)) > 0)
1187 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1188 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1189 VectorScale(lightcolor, intensity, color4f);
1194 VectorClear(color4f);
1200 VectorClear(color4f);
1206 static void R_Shadow_VertexShading(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1208 float *color4f = varray_color4f;
1209 float dot, intensity, v[3], n[3];
1210 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1212 Matrix4x4_Transform(m, vertex3f, v);
1213 Matrix4x4_Transform3x3(m, normal3f, n);
1214 if ((dot = DotProduct(n, v)) > 0)
1216 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1217 VectorScale(lightcolor, intensity, color4f);
1222 VectorClear(color4f);
1228 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1229 #define USETEXMATRIX
1231 #ifndef USETEXMATRIX
1232 // this should be done in a texture matrix or vertex program when possible, but here's code to do it manually
1233 // if hardware texcoord manipulation is not available (or not suitable, this would really benefit from 3DNow! or SSE
1234 static void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1238 tc3f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1239 tc3f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1240 tc3f[2] = vertex3f[0] * matrix->m[2][0] + vertex3f[1] * matrix->m[2][1] + vertex3f[2] * matrix->m[2][2] + matrix->m[2][3];
1247 static void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1251 tc2f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1252 tc2f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1260 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)
1264 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1266 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1267 // the cubemap normalizes this for us
1268 out3f[0] = DotProduct(svector3f, lightdir);
1269 out3f[1] = DotProduct(tvector3f, lightdir);
1270 out3f[2] = DotProduct(normal3f, lightdir);
1274 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)
1277 float lightdir[3], eyedir[3], halfdir[3];
1278 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1280 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1281 VectorNormalizeFast(lightdir);
1282 VectorSubtract(vertex3f, relativeeyeorigin, eyedir);
1283 VectorNormalizeFast(eyedir);
1284 VectorAdd(lightdir, eyedir, halfdir);
1285 // the cubemap normalizes this for us
1286 out3f[0] = DotProduct(svector3f, halfdir);
1287 out3f[1] = DotProduct(tvector3f, halfdir);
1288 out3f[2] = DotProduct(normal3f, halfdir);
1292 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)
1295 float color[3], color2[3], colorscale;
1298 bumptexture = r_shadow_blankbumptexture;
1300 glosstexture = r_shadow_blankglosstexture;
1301 // FIXME: support EF_NODEPTHTEST
1302 GL_DepthMask(false);
1304 if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
1306 if (lighting & LIGHTING_DIFFUSE)
1309 colorscale = r_shadow_lightintensityscale.value;
1310 // colorscale accounts for how much we multiply the brightness
1313 // mult is how many times the final pass of the lighting will be
1314 // performed to get more brightness than otherwise possible.
1316 // Limit mult to 64 for sanity sake.
1317 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1319 // 3/2 3D combine path (Geforce3, Radeon 8500)
1320 memset(&m, 0, sizeof(m));
1321 m.pointer_vertex = vertex3f;
1322 m.tex[0] = R_GetTexture(bumptexture);
1323 m.texcombinergb[0] = GL_REPLACE;
1324 m.pointer_texcoord[0] = texcoord2f;
1325 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1326 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1327 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1328 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1329 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1331 m.pointer_texcoord3f[2] = vertex3f;
1332 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
1334 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1335 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1338 GL_ColorMask(0,0,0,1);
1339 GL_BlendFunc(GL_ONE, GL_ZERO);
1340 GL_LockArrays(0, numverts);
1341 R_Mesh_Draw(numverts, numtriangles, elements);
1342 GL_LockArrays(0, 0);
1344 c_rt_lighttris += numtriangles;
1346 memset(&m, 0, sizeof(m));
1347 m.pointer_vertex = vertex3f;
1348 m.tex[0] = R_GetTexture(basetexture);
1349 m.pointer_texcoord[0] = texcoord2f;
1352 m.texcubemap[1] = R_GetTexture(lightcubemap);
1354 m.pointer_texcoord3f[1] = vertex3f;
1355 m.texmatrix[1] = *matrix_modeltolight;
1357 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1358 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1362 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap)
1364 // 1/2/2 3D combine path (original Radeon)
1365 memset(&m, 0, sizeof(m));
1366 m.pointer_vertex = vertex3f;
1367 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1369 m.pointer_texcoord3f[0] = vertex3f;
1370 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1372 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1373 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1376 GL_ColorMask(0,0,0,1);
1377 GL_BlendFunc(GL_ONE, GL_ZERO);
1378 GL_LockArrays(0, numverts);
1379 R_Mesh_Draw(numverts, numtriangles, elements);
1380 GL_LockArrays(0, 0);
1382 c_rt_lighttris += numtriangles;
1384 memset(&m, 0, sizeof(m));
1385 m.pointer_vertex = vertex3f;
1386 m.tex[0] = R_GetTexture(bumptexture);
1387 m.texcombinergb[0] = GL_REPLACE;
1388 m.pointer_texcoord[0] = texcoord2f;
1389 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1390 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1391 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1392 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1394 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1395 GL_LockArrays(0, numverts);
1396 R_Mesh_Draw(numverts, numtriangles, elements);
1397 GL_LockArrays(0, 0);
1399 c_rt_lighttris += numtriangles;
1401 memset(&m, 0, sizeof(m));
1402 m.pointer_vertex = vertex3f;
1403 m.tex[0] = R_GetTexture(basetexture);
1404 m.pointer_texcoord[0] = texcoord2f;
1407 m.texcubemap[1] = R_GetTexture(lightcubemap);
1409 m.pointer_texcoord3f[1] = vertex3f;
1410 m.texmatrix[1] = *matrix_modeltolight;
1412 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1413 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1417 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap)
1419 // 2/2 3D combine path (original Radeon)
1420 memset(&m, 0, sizeof(m));
1421 m.pointer_vertex = vertex3f;
1422 m.tex[0] = R_GetTexture(bumptexture);
1423 m.texcombinergb[0] = GL_REPLACE;
1424 m.pointer_texcoord[0] = texcoord2f;
1425 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1426 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1427 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1428 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1430 GL_ColorMask(0,0,0,1);
1431 GL_BlendFunc(GL_ONE, GL_ZERO);
1432 GL_LockArrays(0, numverts);
1433 R_Mesh_Draw(numverts, numtriangles, elements);
1434 GL_LockArrays(0, 0);
1436 c_rt_lighttris += numtriangles;
1438 memset(&m, 0, sizeof(m));
1439 m.pointer_vertex = vertex3f;
1440 m.tex[0] = R_GetTexture(basetexture);
1441 m.pointer_texcoord[0] = texcoord2f;
1442 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1444 m.pointer_texcoord3f[1] = vertex3f;
1445 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1447 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1448 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1451 else if (r_textureunits.integer >= 4)
1453 // 4/2 2D combine path (Geforce3, Radeon 8500)
1454 memset(&m, 0, sizeof(m));
1455 m.pointer_vertex = vertex3f;
1456 m.tex[0] = R_GetTexture(bumptexture);
1457 m.texcombinergb[0] = GL_REPLACE;
1458 m.pointer_texcoord[0] = texcoord2f;
1459 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1460 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1461 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1462 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1463 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1465 m.pointer_texcoord3f[2] = vertex3f;
1466 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
1468 m.pointer_texcoord[2] = varray_texcoord2f[2];
1469 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1471 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1473 m.pointer_texcoord3f[3] = vertex3f;
1474 m.texmatrix[3] = *matrix_modeltoattenuationz;
1476 m.pointer_texcoord[3] = varray_texcoord2f[3];
1477 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[3], numverts, vertex3f, matrix_modeltoattenuationz);
1480 GL_ColorMask(0,0,0,1);
1481 GL_BlendFunc(GL_ONE, GL_ZERO);
1482 GL_LockArrays(0, numverts);
1483 R_Mesh_Draw(numverts, numtriangles, elements);
1484 GL_LockArrays(0, 0);
1486 c_rt_lighttris += numtriangles;
1488 memset(&m, 0, sizeof(m));
1489 m.pointer_vertex = vertex3f;
1490 m.tex[0] = R_GetTexture(basetexture);
1491 m.pointer_texcoord[0] = texcoord2f;
1494 m.texcubemap[1] = R_GetTexture(lightcubemap);
1496 m.pointer_texcoord3f[1] = vertex3f;
1497 m.texmatrix[1] = *matrix_modeltolight;
1499 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1500 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1506 // 2/2/2 2D combine path (any dot3 card)
1507 memset(&m, 0, sizeof(m));
1508 m.pointer_vertex = vertex3f;
1509 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1511 m.pointer_texcoord3f[0] = vertex3f;
1512 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1514 m.pointer_texcoord[0] = varray_texcoord2f[0];
1515 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1517 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1519 m.pointer_texcoord3f[1] = vertex3f;
1520 m.texmatrix[1] = *matrix_modeltoattenuationz;
1522 m.pointer_texcoord[1] = varray_texcoord2f[1];
1523 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1526 GL_ColorMask(0,0,0,1);
1527 GL_BlendFunc(GL_ONE, GL_ZERO);
1528 GL_LockArrays(0, numverts);
1529 R_Mesh_Draw(numverts, numtriangles, elements);
1530 GL_LockArrays(0, 0);
1532 c_rt_lighttris += numtriangles;
1534 memset(&m, 0, sizeof(m));
1535 m.pointer_vertex = vertex3f;
1536 m.tex[0] = R_GetTexture(bumptexture);
1537 m.texcombinergb[0] = GL_REPLACE;
1538 m.pointer_texcoord[0] = texcoord2f;
1539 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1540 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1541 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1542 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1544 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1545 GL_LockArrays(0, numverts);
1546 R_Mesh_Draw(numverts, numtriangles, elements);
1547 GL_LockArrays(0, 0);
1549 c_rt_lighttris += numtriangles;
1551 memset(&m, 0, sizeof(m));
1552 m.pointer_vertex = vertex3f;
1553 m.tex[0] = R_GetTexture(basetexture);
1554 m.pointer_texcoord[0] = texcoord2f;
1557 m.texcubemap[1] = R_GetTexture(lightcubemap);
1559 m.pointer_texcoord3f[1] = vertex3f;
1560 m.texmatrix[1] = *matrix_modeltolight;
1562 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1563 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1567 // this final code is shared
1569 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1570 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1571 VectorScale(lightcolor, colorscale, color2);
1572 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1574 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1575 GL_LockArrays(0, numverts);
1576 R_Mesh_Draw(numverts, numtriangles, elements);
1577 GL_LockArrays(0, 0);
1579 c_rt_lighttris += numtriangles;
1582 if ((lighting & LIGHTING_SPECULAR) && (r_shadow_gloss.integer >= 2 || (r_shadow_gloss.integer >= 1 && glosstexture != r_shadow_blankglosstexture)))
1584 // FIXME: detect blendsquare!
1585 //if (gl_support_blendsquare)
1587 colorscale = r_shadow_lightintensityscale.value * r_shadow_glossintensity.value;
1588 if (glosstexture == r_shadow_blankglosstexture)
1589 colorscale *= r_shadow_gloss2intensity.value;
1591 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1593 // 2/0/0/1/2 3D combine blendsquare path
1594 memset(&m, 0, sizeof(m));
1595 m.pointer_vertex = vertex3f;
1596 m.tex[0] = R_GetTexture(bumptexture);
1597 m.pointer_texcoord[0] = texcoord2f;
1598 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1599 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1600 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1601 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1603 GL_ColorMask(0,0,0,1);
1604 // this squares the result
1605 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1606 GL_LockArrays(0, numverts);
1607 R_Mesh_Draw(numverts, numtriangles, elements);
1608 GL_LockArrays(0, 0);
1610 c_rt_lighttris += numtriangles;
1612 memset(&m, 0, sizeof(m));
1613 m.pointer_vertex = vertex3f;
1615 GL_LockArrays(0, numverts);
1616 // square alpha in framebuffer a few times to make it shiny
1617 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1618 // these comments are a test run through this math for intensity 0.5
1619 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1620 // 0.25 * 0.25 = 0.0625 (this is another pass)
1621 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1622 R_Mesh_Draw(numverts, numtriangles, elements);
1624 c_rt_lighttris += numtriangles;
1625 R_Mesh_Draw(numverts, numtriangles, elements);
1627 c_rt_lighttris += numtriangles;
1628 GL_LockArrays(0, 0);
1630 memset(&m, 0, sizeof(m));
1631 m.pointer_vertex = vertex3f;
1632 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1634 m.pointer_texcoord3f[0] = vertex3f;
1635 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1637 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1638 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1641 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1642 GL_LockArrays(0, numverts);
1643 R_Mesh_Draw(numverts, numtriangles, elements);
1644 GL_LockArrays(0, 0);
1646 c_rt_lighttris += numtriangles;
1648 memset(&m, 0, sizeof(m));
1649 m.pointer_vertex = vertex3f;
1650 m.tex[0] = R_GetTexture(glosstexture);
1651 m.pointer_texcoord[0] = texcoord2f;
1654 m.texcubemap[1] = R_GetTexture(lightcubemap);
1656 m.pointer_texcoord3f[1] = vertex3f;
1657 m.texmatrix[1] = *matrix_modeltolight;
1659 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1660 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1664 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1666 // 2/0/0/2 3D combine blendsquare path
1667 memset(&m, 0, sizeof(m));
1668 m.pointer_vertex = vertex3f;
1669 m.tex[0] = R_GetTexture(bumptexture);
1670 m.pointer_texcoord[0] = texcoord2f;
1671 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1672 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1673 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1674 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1676 GL_ColorMask(0,0,0,1);
1677 // this squares the result
1678 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1679 GL_LockArrays(0, numverts);
1680 R_Mesh_Draw(numverts, numtriangles, elements);
1681 GL_LockArrays(0, 0);
1683 c_rt_lighttris += numtriangles;
1685 memset(&m, 0, sizeof(m));
1686 m.pointer_vertex = vertex3f;
1688 GL_LockArrays(0, numverts);
1689 // square alpha in framebuffer a few times to make it shiny
1690 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1691 // these comments are a test run through this math for intensity 0.5
1692 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1693 // 0.25 * 0.25 = 0.0625 (this is another pass)
1694 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1695 R_Mesh_Draw(numverts, numtriangles, elements);
1697 c_rt_lighttris += numtriangles;
1698 R_Mesh_Draw(numverts, numtriangles, elements);
1700 c_rt_lighttris += numtriangles;
1701 GL_LockArrays(0, 0);
1703 memset(&m, 0, sizeof(m));
1704 m.pointer_vertex = vertex3f;
1705 m.tex[0] = R_GetTexture(glosstexture);
1706 m.pointer_texcoord[0] = texcoord2f;
1707 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1709 m.pointer_texcoord3f[1] = vertex3f;
1710 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1712 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1713 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1718 // 2/0/0/2/2 2D combine blendsquare path
1719 memset(&m, 0, sizeof(m));
1720 m.pointer_vertex = vertex3f;
1721 m.tex[0] = R_GetTexture(bumptexture);
1722 m.pointer_texcoord[0] = texcoord2f;
1723 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1724 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1725 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1726 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1728 GL_ColorMask(0,0,0,1);
1729 // this squares the result
1730 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1731 GL_LockArrays(0, numverts);
1732 R_Mesh_Draw(numverts, numtriangles, elements);
1733 GL_LockArrays(0, 0);
1735 c_rt_lighttris += numtriangles;
1737 memset(&m, 0, sizeof(m));
1738 m.pointer_vertex = vertex3f;
1740 GL_LockArrays(0, numverts);
1741 // square alpha in framebuffer a few times to make it shiny
1742 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1743 // these comments are a test run through this math for intensity 0.5
1744 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1745 // 0.25 * 0.25 = 0.0625 (this is another pass)
1746 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1747 R_Mesh_Draw(numverts, numtriangles, elements);
1749 c_rt_lighttris += numtriangles;
1750 R_Mesh_Draw(numverts, numtriangles, elements);
1752 c_rt_lighttris += numtriangles;
1753 GL_LockArrays(0, 0);
1755 memset(&m, 0, sizeof(m));
1756 m.pointer_vertex = vertex3f;
1757 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1759 m.pointer_texcoord3f[0] = vertex3f;
1760 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1762 m.pointer_texcoord[0] = varray_texcoord2f[0];
1763 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1765 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1767 m.pointer_texcoord3f[1] = vertex3f;
1768 m.texmatrix[1] = *matrix_modeltoattenuationz;
1770 m.pointer_texcoord[1] = varray_texcoord2f[1];
1771 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1774 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1775 GL_LockArrays(0, numverts);
1776 R_Mesh_Draw(numverts, numtriangles, elements);
1777 GL_LockArrays(0, 0);
1779 c_rt_lighttris += numtriangles;
1781 memset(&m, 0, sizeof(m));
1782 m.pointer_vertex = vertex3f;
1783 m.tex[0] = R_GetTexture(glosstexture);
1784 m.pointer_texcoord[0] = texcoord2f;
1787 m.texcubemap[1] = R_GetTexture(lightcubemap);
1789 m.pointer_texcoord3f[1] = vertex3f;
1790 m.texmatrix[1] = *matrix_modeltolight;
1792 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1793 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1799 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1800 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1801 VectorScale(lightcolor, colorscale, color2);
1802 GL_LockArrays(0, numverts);
1803 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1805 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1806 R_Mesh_Draw(numverts, numtriangles, elements);
1808 c_rt_lighttris += numtriangles;
1810 GL_LockArrays(0, 0);
1815 if (lighting & LIGHTING_DIFFUSE)
1817 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1818 VectorScale(lightcolor, r_shadow_lightintensityscale.value, color2);
1819 memset(&m, 0, sizeof(m));
1820 m.pointer_vertex = vertex3f;
1821 m.pointer_color = varray_color4f;
1822 m.tex[0] = R_GetTexture(basetexture);
1823 m.pointer_texcoord[0] = texcoord2f;
1824 if (r_textureunits.integer >= 2)
1827 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1829 m.pointer_texcoord3f[1] = vertex3f;
1830 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1832 m.pointer_texcoord[1] = varray_texcoord2f[1];
1833 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1835 if (r_textureunits.integer >= 3)
1837 // Geforce3/Radeon class but not using dot3
1838 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1840 m.pointer_texcoord3f[2] = vertex3f;
1841 m.texmatrix[2] = *matrix_modeltoattenuationz;
1843 m.pointer_texcoord[2] = varray_texcoord2f[2];
1844 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationz);
1849 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1851 color[0] = bound(0, color2[0], 1);
1852 color[1] = bound(0, color2[1], 1);
1853 color[2] = bound(0, color2[2], 1);
1854 if (r_textureunits.integer >= 3)
1855 R_Shadow_VertexShading(numverts, vertex3f, normal3f, color, matrix_modeltolight);
1856 else if (r_textureunits.integer >= 2)
1857 R_Shadow_VertexShadingWithZAttenuation(numverts, vertex3f, normal3f, color, matrix_modeltolight);
1859 R_Shadow_VertexShadingWithXYZAttenuation(numverts, vertex3f, normal3f, color, matrix_modeltolight);
1860 GL_LockArrays(0, numverts);
1861 R_Mesh_Draw(numverts, numtriangles, elements);
1862 GL_LockArrays(0, 0);
1864 c_rt_lighttris += numtriangles;
1870 void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
1874 R_RTLight_Uncompile(rtlight);
1875 memset(rtlight, 0, sizeof(*rtlight));
1877 VectorCopy(light->origin, rtlight->shadoworigin);
1878 VectorCopy(light->color, rtlight->color);
1879 rtlight->radius = light->radius;
1880 //rtlight->cullradius = rtlight->radius;
1881 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
1882 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
1883 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
1884 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
1885 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
1886 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
1887 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
1888 rtlight->cubemapname[0] = 0;
1889 if (light->cubemapname[0])
1890 strcpy(rtlight->cubemapname, light->cubemapname);
1891 else if (light->cubemapnum > 0)
1892 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
1893 rtlight->shadow = light->shadow;
1894 rtlight->corona = light->corona;
1895 rtlight->style = light->style;
1896 rtlight->isstatic = isstatic;
1897 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
1898 // ConcatScale won't work here because this needs to scale rotate and
1899 // translate, not just rotate
1900 scale = 1.0f / rtlight->radius;
1901 for (k = 0;k < 3;k++)
1902 for (j = 0;j < 4;j++)
1903 rtlight->matrix_worldtolight.m[k][j] *= scale;
1904 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationxyz, &matrix_attenuationxyz, &rtlight->matrix_worldtolight);
1905 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationz, &matrix_attenuationz, &rtlight->matrix_worldtolight);
1907 rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
1908 rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
1909 VectorScale(rtlight->color, rtlight->radius * d_lightstylevalue[rtlight->style] * 0.125f, rtlight->lightmap_light);
1910 rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
1913 // compiles rtlight geometry
1914 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
1915 void R_RTLight_Compile(rtlight_t *rtlight)
1917 int shadowmeshes, shadowtris, lightmeshes, lighttris, numclusters, numsurfaces;
1918 entity_render_t *ent = &cl_entities[0].render;
1919 model_t *model = ent->model;
1921 // compile the light
1922 rtlight->compiled = true;
1923 rtlight->static_numclusters = 0;
1924 rtlight->static_numclusterpvsbytes = 0;
1925 rtlight->static_clusterlist = NULL;
1926 rtlight->static_clusterpvs = NULL;
1927 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
1928 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
1929 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
1930 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
1931 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
1932 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
1934 if (model && model->GetLightInfo)
1936 // this variable directs the DrawShadowVolume and DrawLight code to capture into the mesh chain instead of rendering
1937 r_shadow_compilingrtlight = rtlight;
1938 R_Shadow_EnlargeClusterBuffer(model->brush.num_pvsclusters);
1939 R_Shadow_EnlargeSurfaceBuffer(model->nummodelsurfaces);
1940 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);
1943 rtlight->static_numclusters = numclusters;
1944 rtlight->static_numclusterpvsbytes = (model->brush.num_pvsclusters + 7) >> 3;
1945 rtlight->static_clusterlist = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
1946 rtlight->static_clusterpvs = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusterpvsbytes);
1947 memcpy(rtlight->static_clusterlist, r_shadow_buffer_clusterlist, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
1948 memcpy(rtlight->static_clusterpvs, r_shadow_buffer_clusterpvs, rtlight->static_numclusterpvsbytes);
1950 if (model->DrawShadowVolume && rtlight->shadow)
1952 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
1953 model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
1954 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_shadow, false, false);
1956 if (model->DrawLight)
1958 rtlight->static_meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true);
1959 model->DrawLight(ent, rtlight->shadoworigin, vec3_origin, rtlight->radius, vec3_origin, &r_identitymatrix, &r_identitymatrix, &r_identitymatrix, NULL, numsurfaces, r_shadow_buffer_surfacelist);
1960 rtlight->static_meshchain_light = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_light, true, false);
1962 // switch back to rendering when DrawShadowVolume or DrawLight is called
1963 r_shadow_compilingrtlight = NULL;
1967 // use smallest available cullradius - box radius or light radius
1968 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
1969 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
1973 if (rtlight->static_meshchain_shadow)
1976 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
1979 shadowtris += mesh->numtriangles;
1985 if (rtlight->static_meshchain_light)
1988 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
1991 lighttris += mesh->numtriangles;
1995 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);
1998 void R_RTLight_Uncompile(rtlight_t *rtlight)
2000 if (rtlight->compiled)
2002 if (rtlight->static_meshchain_shadow)
2003 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2004 rtlight->static_meshchain_shadow = NULL;
2005 if (rtlight->static_meshchain_light)
2006 Mod_ShadowMesh_Free(rtlight->static_meshchain_light);
2007 rtlight->static_meshchain_light = NULL;
2008 if (rtlight->static_clusterlist)
2009 Mem_Free(rtlight->static_clusterlist);
2010 rtlight->static_clusterlist = NULL;
2011 if (rtlight->static_clusterpvs)
2012 Mem_Free(rtlight->static_clusterpvs);
2013 rtlight->static_clusterpvs = NULL;
2014 rtlight->static_numclusters = 0;
2015 rtlight->static_numclusterpvsbytes = 0;
2016 rtlight->compiled = false;
2020 void R_Shadow_UncompileWorldLights(void)
2023 for (light = r_shadow_worldlightchain;light;light = light->next)
2024 R_RTLight_Uncompile(&light->rtlight);
2027 void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes)
2030 entity_render_t *ent;
2032 vec3_t relativelightorigin, relativeeyeorigin, lightcolor, lightcolor2;
2033 rtexture_t *cubemaptexture;
2034 matrix4x4_t matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz;
2035 int numclusters, numsurfaces;
2036 int *clusterlist, *surfacelist;
2038 vec3_t cullmins, cullmaxs;
2042 // loading is done before visibility checks because loading should happen
2043 // all at once at the start of a level, not when it stalls gameplay.
2044 // (especially important to benchmarks)
2045 if (rtlight->isstatic && !rtlight->compiled && r_shadow_staticworldlights.integer)
2046 R_RTLight_Compile(rtlight);
2047 if (rtlight->cubemapname[0])
2048 cubemaptexture = R_Shadow_Cubemap(rtlight->cubemapname);
2050 cubemaptexture = NULL;
2052 cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2053 cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2054 cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2055 cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2056 cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2057 cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2058 if (d_lightstylevalue[rtlight->style] <= 0)
2065 if (rtlight->compiled && r_shadow_staticworldlights.integer)
2067 // compiled light, world available and can receive realtime lighting
2068 // retrieve cluster information
2069 numclusters = rtlight->static_numclusters;
2070 clusterlist = rtlight->static_clusterlist;
2071 clusterpvs = rtlight->static_clusterpvs;
2072 VectorCopy(rtlight->cullmins, cullmins);
2073 VectorCopy(rtlight->cullmaxs, cullmaxs);
2075 else if (cl.worldmodel && cl.worldmodel->GetLightInfo)
2077 // dynamic light, world available and can receive realtime lighting
2078 // if the light box is offscreen, skip it right away
2079 if (R_CullBox(cullmins, cullmaxs))
2081 // calculate lit surfaces and clusters
2082 R_Shadow_EnlargeClusterBuffer(cl.worldmodel->brush.num_pvsclusters);
2083 R_Shadow_EnlargeSurfaceBuffer(cl.worldmodel->nummodelsurfaces);
2084 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);
2085 clusterlist = r_shadow_buffer_clusterlist;
2086 clusterpvs = r_shadow_buffer_clusterpvs;
2087 surfacelist = r_shadow_buffer_surfacelist;
2089 // if the reduced cluster bounds are offscreen, skip it
2090 if (R_CullBox(cullmins, cullmaxs))
2092 // check if light is illuminating any visible clusters
2095 for (i = 0;i < numclusters;i++)
2096 if (CHECKPVSBIT(r_pvsbits, clusterlist[i]))
2098 if (i == numclusters)
2101 // set up a scissor rectangle for this light
2102 if (R_Shadow_ScissorForBBox(cullmins, cullmaxs))
2105 f = d_lightstylevalue[rtlight->style] * (1.0f / 256.0f);
2106 VectorScale(rtlight->color, f, lightcolor);
2108 if (rtlight->selected)
2110 f = 2 + sin(realtime * M_PI * 4.0);
2111 VectorScale(lightcolor, f, lightcolor);
2115 shadow = rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows);
2117 if (shadow && (gl_stencil || visiblevolumes))
2119 if (!visiblevolumes)
2120 R_Shadow_Stage_ShadowVolumes();
2121 ent = &cl_entities[0].render;
2122 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2124 memset(&m, 0, sizeof(m));
2125 R_Mesh_Matrix(&ent->matrix);
2126 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2128 m.pointer_vertex = mesh->vertex3f;
2130 GL_LockArrays(0, mesh->numverts);
2131 if (r_shadowstage == SHADOWSTAGE_STENCIL)
2133 // decrement stencil if frontface is behind depthbuffer
2134 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2135 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2136 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2137 c_rtcached_shadowmeshes++;
2138 c_rtcached_shadowtris += mesh->numtriangles;
2139 // increment stencil if backface is behind depthbuffer
2140 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2141 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2143 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2144 c_rtcached_shadowmeshes++;
2145 c_rtcached_shadowtris += mesh->numtriangles;
2146 GL_LockArrays(0, 0);
2149 else if (numsurfaces)
2151 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2152 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, numsurfaces, surfacelist);
2154 if (r_drawentities.integer)
2156 for (i = 0;i < r_refdef.numentities;i++)
2158 ent = r_refdef.entities[i];
2160 if (r_shadow_cull.integer)
2162 if (!BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs))
2164 if (cl.worldmodel != NULL && cl.worldmodel->brush.BoxTouchingPVS != NULL && !cl.worldmodel->brush.BoxTouchingPVS(cl.worldmodel, clusterpvs, ent->mins, ent->maxs))
2167 if (!(ent->flags & RENDER_SHADOW) || !ent->model || !ent->model->DrawShadowVolume)
2169 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2170 // light emitting entities should not cast their own shadow
2171 if (VectorLength2(relativelightorigin) < 0.1)
2173 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, ent->model->nummodelsurfaces, ent->model->surfacelist);
2178 if (!visiblevolumes)
2180 R_Shadow_Stage_Light(shadow && gl_stencil);
2182 ent = &cl_entities[0].render;
2183 if (ent->model && ent->model->DrawLight && (ent->flags & RENDER_LIGHT))
2185 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2186 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2187 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2188 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2189 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2190 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2192 R_Mesh_Matrix(&ent->matrix);
2193 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2194 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);
2197 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, numsurfaces, surfacelist);
2199 if (r_drawentities.integer)
2201 for (i = 0;i < r_refdef.numentities;i++)
2203 ent = r_refdef.entities[i];
2204 // can't draw transparent entity lighting here because
2205 // transparent meshes are deferred for later
2206 if (ent->visframe == r_framecount && BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs) && ent->model && ent->model->DrawLight && (ent->flags & (RENDER_LIGHT | RENDER_TRANSPARENT)) == RENDER_LIGHT)
2208 VectorScale(lightcolor, ent->alpha, lightcolor2);
2209 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2210 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2211 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2212 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2213 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2214 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor2, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, ent->model->nummodelsurfaces, ent->model->surfacelist);
2221 void R_ShadowVolumeLighting(int visiblevolumes)
2227 if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2228 R_Shadow_EditLights_Reload_f();
2232 memset(&m, 0, sizeof(m));
2235 GL_BlendFunc(GL_ONE, GL_ONE);
2236 GL_DepthMask(false);
2237 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
2238 qglDisable(GL_CULL_FACE);
2239 GL_Color(0.0, 0.0125, 0.1, 1);
2242 R_Shadow_Stage_Begin();
2245 if (r_shadow_debuglight.integer >= 0)
2247 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2248 if (lnum == r_shadow_debuglight.integer)
2249 R_DrawRTLight(&light->rtlight, visiblevolumes);
2252 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2253 R_DrawRTLight(&light->rtlight, visiblevolumes);
2256 for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
2257 R_DrawRTLight(&light->rtlight, visiblevolumes);
2261 qglEnable(GL_CULL_FACE);
2262 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
2265 R_Shadow_Stage_End();
2268 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2269 typedef struct suffixinfo_s
2272 qboolean flipx, flipy, flipdiagonal;
2275 static suffixinfo_t suffix[3][6] =
2278 {"px", false, false, false},
2279 {"nx", false, false, false},
2280 {"py", false, false, false},
2281 {"ny", false, false, false},
2282 {"pz", false, false, false},
2283 {"nz", false, false, false}
2286 {"posx", false, false, false},
2287 {"negx", false, false, false},
2288 {"posy", false, false, false},
2289 {"negy", false, false, false},
2290 {"posz", false, false, false},
2291 {"negz", false, false, false}
2294 {"rt", true, false, true},
2295 {"lf", false, true, true},
2296 {"ft", true, true, false},
2297 {"bk", false, false, false},
2298 {"up", true, false, true},
2299 {"dn", true, false, true}
2303 static int componentorder[4] = {0, 1, 2, 3};
2305 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2307 int i, j, cubemapsize;
2308 qbyte *cubemappixels, *image_rgba;
2309 rtexture_t *cubemaptexture;
2311 // must start 0 so the first loadimagepixels has no requested width/height
2313 cubemappixels = NULL;
2314 cubemaptexture = NULL;
2315 // keep trying different suffix groups (posx, px, rt) until one loads
2316 for (j = 0;j < 3 && !cubemappixels;j++)
2318 // load the 6 images in the suffix group
2319 for (i = 0;i < 6;i++)
2321 // generate an image name based on the base and and suffix
2322 snprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2324 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2326 // an image loaded, make sure width and height are equal
2327 if (image_width == image_height)
2329 // if this is the first image to load successfully, allocate the cubemap memory
2330 if (!cubemappixels && image_width >= 1)
2332 cubemapsize = image_width;
2333 // note this clears to black, so unavailable sides are black
2334 cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2336 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2338 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);
2341 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2343 Mem_Free(image_rgba);
2347 // if a cubemap loaded, upload it
2350 if (!r_shadow_filters_texturepool)
2351 r_shadow_filters_texturepool = R_AllocTexturePool();
2352 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
2353 Mem_Free(cubemappixels);
2357 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
2358 for (j = 0;j < 3;j++)
2359 for (i = 0;i < 6;i++)
2360 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2361 Con_Print(" and was unable to find any of them.\n");
2363 return cubemaptexture;
2366 rtexture_t *R_Shadow_Cubemap(const char *basename)
2369 for (i = 0;i < numcubemaps;i++)
2370 if (!strcasecmp(cubemaps[i].basename, basename))
2371 return cubemaps[i].texture;
2372 if (i >= MAX_CUBEMAPS)
2375 strcpy(cubemaps[i].basename, basename);
2376 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
2377 return cubemaps[i].texture;
2380 void R_Shadow_FreeCubemaps(void)
2383 R_FreeTexturePool(&r_shadow_filters_texturepool);
2386 dlight_t *R_Shadow_NewWorldLight(void)
2389 light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
2390 light->next = r_shadow_worldlightchain;
2391 r_shadow_worldlightchain = light;
2395 void R_Shadow_UpdateWorldLight(dlight_t *light, vec3_t origin, vec3_t angles, vec3_t color, vec_t radius, vec_t corona, int style, int shadowenable, const char *cubemapname)
2397 VectorCopy(origin, light->origin);
2398 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
2399 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
2400 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
2401 light->color[0] = max(color[0], 0);
2402 light->color[1] = max(color[1], 0);
2403 light->color[2] = max(color[2], 0);
2404 light->radius = max(radius, 0);
2405 light->style = style;
2406 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
2408 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
2411 light->shadow = shadowenable;
2412 light->corona = corona;
2415 strlcpy(light->cubemapname, cubemapname, strlen(light->cubemapname));
2416 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
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 (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
2482 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, i % 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_UpdateWorldLight(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 if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
2603 sprintf(line, "%s%f %f %f %f %f %f %f %d \"%s\" %f %f %f %f\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius / r_editlights_rtlightssizescale.value, light->color[0] / r_editlights_rtlightscolorscale.value, light->color[1] / r_editlights_rtlightscolorscale.value, light->color[2] / r_editlights_rtlightscolorscale.value, light->style, light->cubemapname, light->corona, light->angles[0], light->angles[1], light->angles[2]);
2605 sprintf(line, "%s%f %f %f %f %f %f %f %d\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);
2606 if (bufchars + (int) strlen(line) > bufmaxchars)
2608 bufmaxchars = bufchars + strlen(line) + 2048;
2610 buf = Mem_Alloc(r_shadow_mempool, bufmaxchars);
2614 memcpy(buf, oldbuf, bufchars);
2620 memcpy(buf + bufchars, line, strlen(line));
2621 bufchars += strlen(line);
2625 FS_WriteFile(name, buf, bufchars);
2630 void R_Shadow_LoadLightsFile(void)
2633 char name[MAX_QPATH], *lightsstring, *s, *t;
2634 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
2635 if (cl.worldmodel == NULL)
2637 Con_Print("No map loaded.\n");
2640 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2641 strlcat (name, ".lights", sizeof (name));
2642 lightsstring = FS_LoadFile(name, tempmempool, false);
2650 while (*s && *s != '\n')
2655 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);
2659 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);
2662 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
2663 radius = bound(15, radius, 4096);
2664 VectorScale(color, (2.0f / (8388608.0f)), color);
2665 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL);
2670 Con_Printf("invalid lights file \"%s\"\n", name);
2671 Mem_Free(lightsstring);
2675 // tyrlite/hmap2 light types in the delay field
2676 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
2678 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
2680 int entnum, style, islight, skin, pflags, effects, type, n;
2683 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
2684 char key[256], value[1024];
2686 if (cl.worldmodel == NULL)
2688 Con_Print("No map loaded.\n");
2691 // try to load a .ent file first
2692 FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
2693 strlcat (key, ".ent", sizeof (key));
2694 data = entfiledata = FS_LoadFile(key, tempmempool, true);
2695 // and if that is not found, fall back to the bsp file entity string
2697 data = cl.worldmodel->brush.entities;
2700 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
2702 type = LIGHTTYPE_MINUSX;
2703 origin[0] = origin[1] = origin[2] = 0;
2704 originhack[0] = originhack[1] = originhack[2] = 0;
2705 angles[0] = angles[1] = angles[2] = 0;
2706 color[0] = color[1] = color[2] = 1;
2707 light[0] = light[1] = light[2] = 1;light[3] = 300;
2708 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
2718 if (!COM_ParseToken(&data, false))
2720 if (com_token[0] == '}')
2721 break; // end of entity
2722 if (com_token[0] == '_')
2723 strcpy(key, com_token + 1);
2725 strcpy(key, com_token);
2726 while (key[strlen(key)-1] == ' ') // remove trailing spaces
2727 key[strlen(key)-1] = 0;
2728 if (!COM_ParseToken(&data, false))
2730 strcpy(value, com_token);
2732 // now that we have the key pair worked out...
2733 if (!strcmp("light", key))
2735 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
2739 light[0] = vec[0] * (1.0f / 256.0f);
2740 light[1] = vec[0] * (1.0f / 256.0f);
2741 light[2] = vec[0] * (1.0f / 256.0f);
2747 light[0] = vec[0] * (1.0f / 255.0f);
2748 light[1] = vec[1] * (1.0f / 255.0f);
2749 light[2] = vec[2] * (1.0f / 255.0f);
2753 else if (!strcmp("delay", key))
2755 else if (!strcmp("origin", key))
2756 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
2757 else if (!strcmp("angle", key))
2758 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
2759 else if (!strcmp("angles", key))
2760 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
2761 else if (!strcmp("color", key))
2762 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
2763 else if (!strcmp("wait", key))
2764 fadescale = atof(value);
2765 else if (!strcmp("classname", key))
2767 if (!strncmp(value, "light", 5))
2770 if (!strcmp(value, "light_fluoro"))
2775 overridecolor[0] = 1;
2776 overridecolor[1] = 1;
2777 overridecolor[2] = 1;
2779 if (!strcmp(value, "light_fluorospark"))
2784 overridecolor[0] = 1;
2785 overridecolor[1] = 1;
2786 overridecolor[2] = 1;
2788 if (!strcmp(value, "light_globe"))
2793 overridecolor[0] = 1;
2794 overridecolor[1] = 0.8;
2795 overridecolor[2] = 0.4;
2797 if (!strcmp(value, "light_flame_large_yellow"))
2802 overridecolor[0] = 1;
2803 overridecolor[1] = 0.5;
2804 overridecolor[2] = 0.1;
2806 if (!strcmp(value, "light_flame_small_yellow"))
2811 overridecolor[0] = 1;
2812 overridecolor[1] = 0.5;
2813 overridecolor[2] = 0.1;
2815 if (!strcmp(value, "light_torch_small_white"))
2820 overridecolor[0] = 1;
2821 overridecolor[1] = 0.5;
2822 overridecolor[2] = 0.1;
2824 if (!strcmp(value, "light_torch_small_walltorch"))
2829 overridecolor[0] = 1;
2830 overridecolor[1] = 0.5;
2831 overridecolor[2] = 0.1;
2835 else if (!strcmp("style", key))
2836 style = atoi(value);
2837 else if (cl.worldmodel->type == mod_brushq3)
2839 if (!strcmp("scale", key))
2840 lightscale = atof(value);
2841 if (!strcmp("fade", key))
2842 fadescale = atof(value);
2844 else if (!strcmp("skin", key))
2845 skin = (int)atof(value);
2846 else if (!strcmp("pflags", key))
2847 pflags = (int)atof(value);
2848 else if (!strcmp("effects", key))
2849 effects = (int)atof(value);
2853 if (lightscale <= 0)
2857 if (color[0] == color[1] && color[0] == color[2])
2859 color[0] *= overridecolor[0];
2860 color[1] *= overridecolor[1];
2861 color[2] *= overridecolor[2];
2863 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
2864 color[0] = color[0] * light[0];
2865 color[1] = color[1] * light[1];
2866 color[2] = color[2] * light[2];
2869 case LIGHTTYPE_MINUSX:
2871 case LIGHTTYPE_RECIPX:
2873 VectorScale(color, (1.0f / 16.0f), color);
2875 case LIGHTTYPE_RECIPXX:
2877 VectorScale(color, (1.0f / 16.0f), color);
2880 case LIGHTTYPE_NONE:
2884 case LIGHTTYPE_MINUSXX:
2887 VectorAdd(origin, originhack, origin);
2889 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, (pflags & PFLAGS_CORONA) != 0, style, (pflags & PFLAGS_NOSHADOW) == 0, skin >= 16 ? va("cubemaps/%i", skin) : NULL);
2892 Mem_Free(entfiledata);
2896 void R_Shadow_SetCursorLocationForView(void)
2898 vec_t dist, push, frac;
2899 vec3_t dest, endpos, normal;
2900 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
2901 frac = CL_TraceLine(r_vieworigin, dest, endpos, normal, true, NULL, SUPERCONTENTS_SOLID);
2904 dist = frac * r_editlights_cursordistance.value;
2905 push = r_editlights_cursorpushback.value;
2909 VectorMA(endpos, push, r_viewforward, endpos);
2910 VectorMA(endpos, r_editlights_cursorpushoff.value, normal, endpos);
2912 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2913 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2914 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2917 void R_Shadow_UpdateWorldLightSelection(void)
2919 if (r_editlights.integer)
2921 R_Shadow_SetCursorLocationForView();
2922 R_Shadow_SelectLightInView();
2923 R_Shadow_DrawLightSprites();
2926 R_Shadow_SelectLight(NULL);
2929 void R_Shadow_EditLights_Clear_f(void)
2931 R_Shadow_ClearWorldLights();
2934 void R_Shadow_EditLights_Reload_f(void)
2938 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
2939 R_Shadow_ClearWorldLights();
2940 R_Shadow_LoadWorldLights();
2941 if (r_shadow_worldlightchain == NULL)
2943 R_Shadow_LoadLightsFile();
2944 if (r_shadow_worldlightchain == NULL)
2945 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
2949 void R_Shadow_EditLights_Save_f(void)
2953 R_Shadow_SaveWorldLights();
2956 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
2958 R_Shadow_ClearWorldLights();
2959 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
2962 void R_Shadow_EditLights_ImportLightsFile_f(void)
2964 R_Shadow_ClearWorldLights();
2965 R_Shadow_LoadLightsFile();
2968 void R_Shadow_EditLights_Spawn_f(void)
2971 if (!r_editlights.integer)
2973 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
2976 if (Cmd_Argc() != 1)
2978 Con_Print("r_editlights_spawn does not take parameters\n");
2981 color[0] = color[1] = color[2] = 1;
2982 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL);
2985 void R_Shadow_EditLights_Edit_f(void)
2987 vec3_t origin, angles, color;
2988 vec_t radius, corona;
2990 char cubemapname[1024];
2991 if (!r_editlights.integer)
2993 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
2996 if (!r_shadow_selectedlight)
2998 Con_Print("No selected light.\n");
3001 VectorCopy(r_shadow_selectedlight->origin, origin);
3002 VectorCopy(r_shadow_selectedlight->angles, angles);
3003 VectorCopy(r_shadow_selectedlight->color, color);
3004 radius = r_shadow_selectedlight->radius;
3005 style = r_shadow_selectedlight->style;
3006 if (r_shadow_selectedlight->cubemapname)
3007 strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
3010 shadows = r_shadow_selectedlight->shadow;
3011 corona = r_shadow_selectedlight->corona;
3012 if (!strcmp(Cmd_Argv(1), "origin"))
3014 if (Cmd_Argc() != 5)
3016 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3019 origin[0] = atof(Cmd_Argv(2));
3020 origin[1] = atof(Cmd_Argv(3));
3021 origin[2] = atof(Cmd_Argv(4));
3023 else if (!strcmp(Cmd_Argv(1), "originx"))
3025 if (Cmd_Argc() != 3)
3027 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3030 origin[0] = atof(Cmd_Argv(2));
3032 else if (!strcmp(Cmd_Argv(1), "originy"))
3034 if (Cmd_Argc() != 3)
3036 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3039 origin[1] = atof(Cmd_Argv(2));
3041 else if (!strcmp(Cmd_Argv(1), "originz"))
3043 if (Cmd_Argc() != 3)
3045 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3048 origin[2] = atof(Cmd_Argv(2));
3050 else if (!strcmp(Cmd_Argv(1), "move"))
3052 if (Cmd_Argc() != 5)
3054 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3057 origin[0] += atof(Cmd_Argv(2));
3058 origin[1] += atof(Cmd_Argv(3));
3059 origin[2] += atof(Cmd_Argv(4));
3061 else if (!strcmp(Cmd_Argv(1), "movex"))
3063 if (Cmd_Argc() != 3)
3065 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3068 origin[0] += atof(Cmd_Argv(2));
3070 else if (!strcmp(Cmd_Argv(1), "movey"))
3072 if (Cmd_Argc() != 3)
3074 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3077 origin[1] += atof(Cmd_Argv(2));
3079 else if (!strcmp(Cmd_Argv(1), "movez"))
3081 if (Cmd_Argc() != 3)
3083 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3086 origin[2] += atof(Cmd_Argv(2));
3088 else if (!strcmp(Cmd_Argv(1), "angles"))
3090 if (Cmd_Argc() != 5)
3092 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3095 angles[0] = atof(Cmd_Argv(2));
3096 angles[1] = atof(Cmd_Argv(3));
3097 angles[2] = atof(Cmd_Argv(4));
3099 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3101 if (Cmd_Argc() != 3)
3103 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3106 angles[0] = atof(Cmd_Argv(2));
3108 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3110 if (Cmd_Argc() != 3)
3112 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3115 angles[1] = atof(Cmd_Argv(2));
3117 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3119 if (Cmd_Argc() != 3)
3121 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3124 angles[2] = atof(Cmd_Argv(2));
3126 else if (!strcmp(Cmd_Argv(1), "color"))
3128 if (Cmd_Argc() != 5)
3130 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3133 color[0] = atof(Cmd_Argv(2));
3134 color[1] = atof(Cmd_Argv(3));
3135 color[2] = atof(Cmd_Argv(4));
3137 else if (!strcmp(Cmd_Argv(1), "radius"))
3139 if (Cmd_Argc() != 3)
3141 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3144 radius = atof(Cmd_Argv(2));
3146 else if (!strcmp(Cmd_Argv(1), "style"))
3148 if (Cmd_Argc() != 3)
3150 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3153 style = atoi(Cmd_Argv(2));
3155 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3159 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3162 if (Cmd_Argc() == 3)
3163 strcpy(cubemapname, Cmd_Argv(2));
3167 else if (!strcmp(Cmd_Argv(1), "shadows"))
3169 if (Cmd_Argc() != 3)
3171 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3174 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3176 else if (!strcmp(Cmd_Argv(1), "corona"))
3178 if (Cmd_Argc() != 3)
3180 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3183 corona = atof(Cmd_Argv(2));
3187 Con_Print("usage: r_editlights_edit [property] [value]\n");
3188 Con_Print("Selected light's properties:\n");
3189 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3190 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3191 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3192 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3193 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3194 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3195 Con_Printf("Shadows: %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3196 Con_Printf("Cubemap: %s\n", r_shadow_selectedlight->cubemapname);
3199 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname);
3202 void R_Shadow_EditLights_EditAll_f(void)
3206 if (!r_editlights.integer)
3208 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
3212 for (light = r_shadow_worldlightchain;light;light = light->next)
3214 R_Shadow_SelectLight(light);
3215 R_Shadow_EditLights_Edit_f();
3219 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3221 int lightnumber, lightcount;
3225 if (!r_editlights.integer)
3231 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
3232 if (light == r_shadow_selectedlight)
3233 lightnumber = lightcount;
3234 sprintf(temp, "Cursor %f %f %f Total Lights %i", r_editlights_cursorlocation[0], r_editlights_cursorlocation[1], r_editlights_cursorlocation[2], lightcount);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3235 if (r_shadow_selectedlight == NULL)
3237 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3238 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;
3239 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;
3240 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;
3241 sprintf(temp, "Radius %f", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3242 sprintf(temp, "Corona %f", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3243 sprintf(temp, "Style %i", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3244 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;
3245 sprintf(temp, "Cubemap %s", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3248 void R_Shadow_EditLights_ToggleShadow_f(void)
3250 if (!r_editlights.integer)
3252 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3255 if (!r_shadow_selectedlight)
3257 Con_Print("No selected light.\n");
3260 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, r_shadow_selectedlight->origin, r_shadow_selectedlight->angles, r_shadow_selectedlight->color, r_shadow_selectedlight->radius, r_shadow_selectedlight->corona, r_shadow_selectedlight->style, !r_shadow_selectedlight->shadow, r_shadow_selectedlight->cubemapname);
3263 void R_Shadow_EditLights_ToggleCorona_f(void)
3265 if (!r_editlights.integer)
3267 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3270 if (!r_shadow_selectedlight)
3272 Con_Print("No selected light.\n");
3275 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, r_shadow_selectedlight->origin, r_shadow_selectedlight->angles, r_shadow_selectedlight->color, r_shadow_selectedlight->radius, !r_shadow_selectedlight->corona, r_shadow_selectedlight->style, r_shadow_selectedlight->shadow, r_shadow_selectedlight->cubemapname);
3278 void R_Shadow_EditLights_Remove_f(void)
3280 if (!r_editlights.integer)
3282 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
3285 if (!r_shadow_selectedlight)
3287 Con_Print("No selected light.\n");
3290 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3291 r_shadow_selectedlight = NULL;
3294 void R_Shadow_EditLights_Help_f(void)
3297 "Documentation on r_editlights system:\n"
3299 "r_editlights : enable/disable editing mode\n"
3300 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
3301 "r_editlights_cursorpushback : push back cursor this far from surface\n"
3302 "r_editlights_cursorpushoff : push cursor off surface this far\n"
3303 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
3304 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
3305 "r_editlights_rtlightssizescale : imported rtlight size scaling\n"
3306 "r_editlights_rtlightscolorscale : imported rtlight color scaling\n"
3308 "r_editlights_help : this help\n"
3309 "r_editlights_clear : remove all lights\n"
3310 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
3311 "r_editlights_save : save to .rtlights file\n"
3312 "r_editlights_spawn : create a light with default settings\n"
3313 "r_editlights_edit command : edit selected light - more documentation below\n"
3314 "r_editlights_remove : remove selected light\n"
3315 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
3316 "r_editlights_importlightentitiesfrommap : reload light entities\n"
3317 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
3319 "origin x y z : set light location\n"
3320 "originx x: set x component of light location\n"
3321 "originy y: set y component of light location\n"
3322 "originz z: set z component of light location\n"
3323 "move x y z : adjust light location\n"
3324 "movex x: adjust x component of light location\n"
3325 "movey y: adjust y component of light location\n"
3326 "movez z: adjust z component of light location\n"
3327 "angles x y z : set light angles\n"
3328 "anglesx x: set x component of light angles\n"
3329 "anglesy y: set y component of light angles\n"
3330 "anglesz z: set z component of light angles\n"
3331 "color r g b : set color of light (can be brighter than 1 1 1)\n"
3332 "radius radius : set radius (size) of light\n"
3333 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
3334 "cubemap basename : set filter cubemap of light (not yet supported)\n"
3335 "shadows 1/0 : turn on/off shadows\n"
3336 "corona n : set corona intensity\n"
3337 "<nothing> : print light properties to console\n"
3341 void R_Shadow_EditLights_CopyInfo_f(void)
3343 if (!r_editlights.integer)
3345 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
3348 if (!r_shadow_selectedlight)
3350 Con_Print("No selected light.\n");
3353 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
3354 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
3355 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
3356 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
3357 if (r_shadow_selectedlight->cubemapname)
3358 strcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname);
3360 r_shadow_bufferlight.cubemapname[0] = 0;
3361 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
3362 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
3365 void R_Shadow_EditLights_PasteInfo_f(void)
3367 if (!r_editlights.integer)
3369 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
3372 if (!r_shadow_selectedlight)
3374 Con_Print("No selected light.\n");
3377 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, r_shadow_selectedlight->origin, r_shadow_bufferlight.angles, r_shadow_bufferlight.color, r_shadow_bufferlight.radius, r_shadow_bufferlight.corona, r_shadow_bufferlight.style, r_shadow_bufferlight.shadow, r_shadow_bufferlight.cubemapname);
3380 void R_Shadow_EditLights_Init(void)
3382 Cvar_RegisterVariable(&r_editlights);
3383 Cvar_RegisterVariable(&r_editlights_cursordistance);
3384 Cvar_RegisterVariable(&r_editlights_cursorpushback);
3385 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
3386 Cvar_RegisterVariable(&r_editlights_cursorgrid);
3387 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
3388 Cvar_RegisterVariable(&r_editlights_rtlightssizescale);
3389 Cvar_RegisterVariable(&r_editlights_rtlightscolorscale);
3390 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
3391 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
3392 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
3393 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
3394 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
3395 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
3396 Cmd_AddCommand("r_editlights_editall", R_Shadow_EditLights_EditAll_f);
3397 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
3398 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
3399 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
3400 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
3401 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);
3402 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f);
3403 Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f);