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, 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;
545 outvertex3f[0] = v[0];
546 outvertex3f[1] = v[1];
547 outvertex3f[2] = v[2];
548 outvertex3f[3] = v[0] + 1000000 * (v[0] - projectorigin[0]);
549 outvertex3f[4] = v[1] + 1000000 * (v[1] - projectorigin[1]);
550 outvertex3f[5] = v[2] + 1000000 * (v[2] - projectorigin[2]);
552 VectorSubtract(v, projectorigin, temp);
553 f = projectdistance / VectorLength(temp);
554 VectorCopy(v, outvertex3f);
555 VectorMA(projectorigin, f, temp, (outvertex3f + 3));
563 for (i = 0;i < numshadowmarktris;i++)
565 t = shadowmarktris[i];
566 e = inelement3i + t * 3;
567 n = inneighbor3i + t * 3;
568 // output the front and back triangles
569 outelement3i[0] = vertexremap[e[0]];
570 outelement3i[1] = vertexremap[e[1]];
571 outelement3i[2] = vertexremap[e[2]];
572 outelement3i[3] = vertexremap[e[2]] + 1;
573 outelement3i[4] = vertexremap[e[1]] + 1;
574 outelement3i[5] = vertexremap[e[0]] + 1;
577 // output the sides (facing outward from this triangle)
578 if (shadowmark[n[0]] != shadowmarkcount)
580 vr[0] = vertexremap[e[0]];
581 vr[1] = vertexremap[e[1]];
582 outelement3i[0] = vr[1];
583 outelement3i[1] = vr[0];
584 outelement3i[2] = vr[0] + 1;
585 outelement3i[3] = vr[1];
586 outelement3i[4] = vr[0] + 1;
587 outelement3i[5] = vr[1] + 1;
591 if (shadowmark[n[1]] != shadowmarkcount)
593 vr[1] = vertexremap[e[1]];
594 vr[2] = vertexremap[e[2]];
595 outelement3i[0] = vr[2];
596 outelement3i[1] = vr[1];
597 outelement3i[2] = vr[1] + 1;
598 outelement3i[3] = vr[2];
599 outelement3i[4] = vr[1] + 1;
600 outelement3i[5] = vr[2] + 1;
604 if (shadowmark[n[2]] != shadowmarkcount)
606 vr[0] = vertexremap[e[0]];
607 vr[2] = vertexremap[e[2]];
608 outelement3i[0] = vr[0];
609 outelement3i[1] = vr[2];
610 outelement3i[2] = vr[2] + 1;
611 outelement3i[3] = vr[0];
612 outelement3i[4] = vr[2] + 1;
613 outelement3i[5] = vr[0] + 1;
619 *outnumvertices = outvertices;
623 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)
626 if (projectdistance < 0.1)
628 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
631 if (!numverts || !nummarktris)
633 // make sure shadowelements is big enough for this volume
634 if (maxshadowelements < nummarktris * 24)
635 R_Shadow_ResizeShadowElements((nummarktris + 256) * 24);
636 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, varray_vertex3f2, projectorigin, projectdistance, nummarktris, marktris);
637 R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements);
640 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)
645 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
647 tend = firsttriangle + numtris;
648 if (surfacemins[0] >= lightmins[0] && surfacemaxs[0] <= lightmaxs[0]
649 && surfacemins[1] >= lightmins[1] && surfacemaxs[1] <= lightmaxs[1]
650 && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2])
652 // surface box entirely inside light box, no box cull
653 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
654 if (PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
655 shadowmarklist[numshadowmark++] = t;
659 // surface box not entirely inside light box, cull each triangle
660 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
662 v[0] = invertex3f + e[0] * 3;
663 v[1] = invertex3f + e[1] * 3;
664 v[2] = invertex3f + e[2] * 3;
665 if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
666 && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
667 && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
668 && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
669 && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
670 && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
671 && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
672 shadowmarklist[numshadowmark++] = t;
677 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
680 if (r_shadow_compilingrtlight)
682 // if we're compiling an rtlight, capture the mesh
683 Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
686 memset(&m, 0, sizeof(m));
687 m.pointer_vertex = vertex3f;
689 GL_LockArrays(0, numvertices);
690 if (r_shadowstage == SHADOWSTAGE_STENCIL)
692 // increment stencil if backface is behind depthbuffer
693 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
694 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
695 R_Mesh_Draw(numvertices, numtriangles, element3i);
697 c_rt_shadowtris += numtriangles;
698 // decrement stencil if frontface is behind depthbuffer
699 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
700 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
702 R_Mesh_Draw(numvertices, numtriangles, element3i);
704 c_rt_shadowtris += numtriangles;
708 static void R_Shadow_MakeTextures(void)
710 int x, y, z, d, side;
711 float v[3], s, t, intensity;
713 R_FreeTexturePool(&r_shadow_texturepool);
714 r_shadow_texturepool = R_AllocTexturePool();
715 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
716 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
718 #define ATTEN2DSIZE 64
719 #define ATTEN3DSIZE 32
720 data = Mem_Alloc(tempmempool, max(6*NORMSIZE*NORMSIZE*4, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4)));
725 r_shadow_blankbumptexture = R_LoadTexture2D(r_shadow_texturepool, "blankbump", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
730 r_shadow_blankglosstexture = R_LoadTexture2D(r_shadow_texturepool, "blankgloss", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
735 r_shadow_blankwhitetexture = R_LoadTexture2D(r_shadow_texturepool, "blankwhite", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
736 if (gl_texturecubemap)
738 for (side = 0;side < 6;side++)
740 for (y = 0;y < NORMSIZE;y++)
742 for (x = 0;x < NORMSIZE;x++)
744 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
745 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
779 intensity = 127.0f / sqrt(DotProduct(v, v));
780 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+0] = 128.0f + intensity * v[0];
781 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+1] = 128.0f + intensity * v[1];
782 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+2] = 128.0f + intensity * v[2];
783 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+3] = 255;
787 r_shadow_normalcubetexture = R_LoadTextureCubeMap(r_shadow_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
790 r_shadow_normalcubetexture = NULL;
791 for (y = 0;y < ATTEN2DSIZE;y++)
793 for (x = 0;x < ATTEN2DSIZE;x++)
795 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
796 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
798 intensity = 1.0f - sqrt(DotProduct(v, v));
800 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
801 d = bound(0, intensity, 255);
802 data[(y*ATTEN2DSIZE+x)*4+0] = d;
803 data[(y*ATTEN2DSIZE+x)*4+1] = d;
804 data[(y*ATTEN2DSIZE+x)*4+2] = d;
805 data[(y*ATTEN2DSIZE+x)*4+3] = d;
808 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
809 if (r_shadow_texture3d.integer)
811 for (z = 0;z < ATTEN3DSIZE;z++)
813 for (y = 0;y < ATTEN3DSIZE;y++)
815 for (x = 0;x < ATTEN3DSIZE;x++)
817 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
818 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
819 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
820 intensity = 1.0f - sqrt(DotProduct(v, v));
822 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
823 d = bound(0, intensity, 255);
824 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
825 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
826 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
827 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
831 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
836 void R_Shadow_ValidateCvars(void)
838 if (r_shadow_texture3d.integer && !gl_texture3d)
839 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
840 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
841 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
844 void R_Shadow_Stage_Begin(void)
848 R_Shadow_ValidateCvars();
850 if (!r_shadow_attenuation2dtexture
851 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
852 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
853 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
854 R_Shadow_MakeTextures();
856 memset(&m, 0, sizeof(m));
857 GL_BlendFunc(GL_ONE, GL_ZERO);
861 GL_Color(0, 0, 0, 1);
862 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
863 qglEnable(GL_CULL_FACE);
864 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
865 r_shadowstage = SHADOWSTAGE_NONE;
867 c_rt_lights = c_rt_clears = c_rt_scissored = 0;
868 c_rt_shadowmeshes = c_rt_shadowtris = c_rt_lightmeshes = c_rt_lighttris = 0;
869 c_rtcached_shadowmeshes = c_rtcached_shadowtris = 0;
872 void R_Shadow_Stage_ShadowVolumes(void)
875 memset(&m, 0, sizeof(m));
877 GL_Color(1, 1, 1, 1);
878 GL_ColorMask(0, 0, 0, 0);
879 GL_BlendFunc(GL_ONE, GL_ZERO);
882 qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
883 //if (r_shadow_shadow_polygonoffset.value != 0)
885 // qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
886 // qglEnable(GL_POLYGON_OFFSET_FILL);
889 // qglDisable(GL_POLYGON_OFFSET_FILL);
890 qglDepthFunc(GL_LESS);
891 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
892 qglEnable(GL_STENCIL_TEST);
893 qglStencilFunc(GL_ALWAYS, 128, ~0);
894 if (gl_ext_stenciltwoside.integer)
896 r_shadowstage = SHADOWSTAGE_STENCILTWOSIDE;
897 qglDisable(GL_CULL_FACE);
898 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
899 qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
901 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
902 qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
904 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
908 r_shadowstage = SHADOWSTAGE_STENCIL;
909 qglEnable(GL_CULL_FACE);
911 // this is changed by every shadow render so its value here is unimportant
912 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
914 GL_Clear(GL_STENCIL_BUFFER_BIT);
916 // LordHavoc note: many shadow volumes reside entirely inside the world
917 // (that is to say they are entirely bounded by their lit surfaces),
918 // which can be optimized by handling things as an inverted light volume,
919 // with the shadow boundaries of the world being simulated by an altered
920 // (129) bias to stencil clearing on such lights
921 // FIXME: generate inverted light volumes for use as shadow volumes and
922 // optimize for them as noted above
925 void R_Shadow_Stage_Light(int shadowtest)
928 memset(&m, 0, sizeof(m));
930 GL_BlendFunc(GL_ONE, GL_ONE);
933 qglPolygonOffset(0, 0);
934 //qglDisable(GL_POLYGON_OFFSET_FILL);
935 GL_Color(1, 1, 1, 1);
936 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
937 qglDepthFunc(GL_EQUAL);
938 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
939 qglEnable(GL_CULL_FACE);
941 qglEnable(GL_STENCIL_TEST);
943 qglDisable(GL_STENCIL_TEST);
944 if (gl_support_stenciltwoside)
945 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
947 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
948 // only draw light where this geometry was already rendered AND the
949 // stencil is 128 (values other than this mean shadow)
950 qglStencilFunc(GL_EQUAL, 128, ~0);
951 r_shadowstage = SHADOWSTAGE_LIGHT;
955 void R_Shadow_Stage_End(void)
958 memset(&m, 0, sizeof(m));
960 GL_BlendFunc(GL_ONE, GL_ZERO);
963 qglPolygonOffset(0, 0);
964 //qglDisable(GL_POLYGON_OFFSET_FILL);
965 GL_Color(1, 1, 1, 1);
966 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
967 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
968 qglDepthFunc(GL_LEQUAL);
969 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
970 qglDisable(GL_STENCIL_TEST);
971 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
972 if (gl_support_stenciltwoside)
973 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
975 qglStencilFunc(GL_ALWAYS, 128, ~0);
976 r_shadowstage = SHADOWSTAGE_NONE;
979 int R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
981 int i, ix1, iy1, ix2, iy2;
982 float x1, y1, x2, y2, x, y, f;
985 if (!r_shadow_scissor.integer)
987 // if view is inside the box, just say yes it's visible
988 if (BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
990 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
993 for (i = 0;i < 3;i++)
995 if (r_viewforward[i] >= 0)
1006 f = DotProduct(r_viewforward, r_vieworigin) + 1;
1007 if (DotProduct(r_viewforward, v2) <= f)
1009 // entirely behind nearclip plane
1012 if (DotProduct(r_viewforward, v) >= f)
1014 // entirely infront of nearclip plane
1015 x1 = y1 = x2 = y2 = 0;
1016 for (i = 0;i < 8;i++)
1018 v[0] = (i & 1) ? mins[0] : maxs[0];
1019 v[1] = (i & 2) ? mins[1] : maxs[1];
1020 v[2] = (i & 4) ? mins[2] : maxs[2];
1022 GL_TransformToScreen(v, v2);
1023 //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]);
1042 // clipped by nearclip plane
1043 // this is nasty and crude...
1044 // create viewspace bbox
1045 for (i = 0;i < 8;i++)
1047 v[0] = ((i & 1) ? mins[0] : maxs[0]) - r_vieworigin[0];
1048 v[1] = ((i & 2) ? mins[1] : maxs[1]) - r_vieworigin[1];
1049 v[2] = ((i & 4) ? mins[2] : maxs[2]) - r_vieworigin[2];
1050 v2[0] = -DotProduct(v, r_viewleft);
1051 v2[1] = DotProduct(v, r_viewup);
1052 v2[2] = DotProduct(v, r_viewforward);
1055 if (smins[0] > v2[0]) smins[0] = v2[0];
1056 if (smaxs[0] < v2[0]) smaxs[0] = v2[0];
1057 if (smins[1] > v2[1]) smins[1] = v2[1];
1058 if (smaxs[1] < v2[1]) smaxs[1] = v2[1];
1059 if (smins[2] > v2[2]) smins[2] = v2[2];
1060 if (smaxs[2] < v2[2]) smaxs[2] = v2[2];
1064 smins[0] = smaxs[0] = v2[0];
1065 smins[1] = smaxs[1] = v2[1];
1066 smins[2] = smaxs[2] = v2[2];
1069 // now we have a bbox in viewspace
1070 // clip it to the view plane
1073 // return true if that culled the box
1074 if (smins[2] >= smaxs[2])
1076 // ok some of it is infront of the view, transform each corner back to
1077 // worldspace and then to screenspace and make screen rect
1078 // initialize these variables just to avoid compiler warnings
1079 x1 = y1 = x2 = y2 = 0;
1080 for (i = 0;i < 8;i++)
1082 v2[0] = (i & 1) ? smins[0] : smaxs[0];
1083 v2[1] = (i & 2) ? smins[1] : smaxs[1];
1084 v2[2] = (i & 4) ? smins[2] : smaxs[2];
1085 v[0] = v2[0] * -r_viewleft[0] + v2[1] * r_viewup[0] + v2[2] * r_viewforward[0] + r_vieworigin[0];
1086 v[1] = v2[0] * -r_viewleft[1] + v2[1] * r_viewup[1] + v2[2] * r_viewforward[1] + r_vieworigin[1];
1087 v[2] = v2[0] * -r_viewleft[2] + v2[1] * r_viewup[2] + v2[2] * r_viewforward[2] + r_vieworigin[2];
1089 GL_TransformToScreen(v, v2);
1090 //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]);
1107 // this code doesn't handle boxes with any points behind view properly
1108 x1 = 1000;x2 = -1000;
1109 y1 = 1000;y2 = -1000;
1110 for (i = 0;i < 8;i++)
1112 v[0] = (i & 1) ? mins[0] : maxs[0];
1113 v[1] = (i & 2) ? mins[1] : maxs[1];
1114 v[2] = (i & 4) ? mins[2] : maxs[2];
1116 GL_TransformToScreen(v, v2);
1117 //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]);
1135 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1136 if (ix1 < r_view_x) ix1 = r_view_x;
1137 if (iy1 < r_view_y) iy1 = r_view_y;
1138 if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
1139 if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
1140 if (ix2 <= ix1 || iy2 <= iy1)
1142 // set up the scissor rectangle
1143 GL_Scissor(ix1, vid.realheight - iy2, ix2 - ix1, iy2 - iy1);
1144 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1145 //qglEnable(GL_SCISSOR_TEST);
1150 static void R_Shadow_VertexShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1152 float *color4f = varray_color4f;
1153 float dist, dot, intensity, v[3], n[3];
1154 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1156 Matrix4x4_Transform(m, vertex3f, v);
1157 if ((dist = DotProduct(v, v)) < 1)
1159 Matrix4x4_Transform3x3(m, normal3f, n);
1160 if ((dot = DotProduct(n, v)) > 0)
1163 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1164 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1165 VectorScale(lightcolor, intensity, color4f);
1170 VectorClear(color4f);
1176 VectorClear(color4f);
1182 static void R_Shadow_VertexShadingWithZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1184 float *color4f = varray_color4f;
1185 float dist, dot, intensity, v[3], n[3];
1186 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1188 Matrix4x4_Transform(m, vertex3f, v);
1189 if ((dist = fabs(v[2])) < 1)
1191 Matrix4x4_Transform3x3(m, normal3f, n);
1192 if ((dot = DotProduct(n, v)) > 0)
1194 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1195 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1196 VectorScale(lightcolor, intensity, color4f);
1201 VectorClear(color4f);
1207 VectorClear(color4f);
1213 static void R_Shadow_VertexShading(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1215 float *color4f = varray_color4f;
1216 float dot, intensity, v[3], n[3];
1217 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1219 Matrix4x4_Transform(m, vertex3f, v);
1220 Matrix4x4_Transform3x3(m, normal3f, n);
1221 if ((dot = DotProduct(n, v)) > 0)
1223 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1224 VectorScale(lightcolor, intensity, color4f);
1229 VectorClear(color4f);
1235 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1236 #define USETEXMATRIX
1238 #ifndef USETEXMATRIX
1239 // this should be done in a texture matrix or vertex program when possible, but here's code to do it manually
1240 // if hardware texcoord manipulation is not available (or not suitable, this would really benefit from 3DNow! or SSE
1241 static void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1245 tc3f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1246 tc3f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1247 tc3f[2] = vertex3f[0] * matrix->m[2][0] + vertex3f[1] * matrix->m[2][1] + vertex3f[2] * matrix->m[2][2] + matrix->m[2][3];
1254 static void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1258 tc2f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1259 tc2f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1267 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)
1271 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1273 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1274 // the cubemap normalizes this for us
1275 out3f[0] = DotProduct(svector3f, lightdir);
1276 out3f[1] = DotProduct(tvector3f, lightdir);
1277 out3f[2] = DotProduct(normal3f, lightdir);
1281 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)
1284 float lightdir[3], eyedir[3], halfdir[3];
1285 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1287 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1288 VectorNormalizeFast(lightdir);
1289 VectorSubtract(vertex3f, relativeeyeorigin, eyedir);
1290 VectorNormalizeFast(eyedir);
1291 VectorAdd(lightdir, eyedir, halfdir);
1292 // the cubemap normalizes this for us
1293 out3f[0] = DotProduct(svector3f, halfdir);
1294 out3f[1] = DotProduct(tvector3f, halfdir);
1295 out3f[2] = DotProduct(normal3f, halfdir);
1299 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)
1302 float color[3], color2[3], colorscale;
1305 bumptexture = r_shadow_blankbumptexture;
1307 glosstexture = r_shadow_blankglosstexture;
1308 // FIXME: support EF_NODEPTHTEST
1309 GL_DepthMask(false);
1311 if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
1313 if (lighting & LIGHTING_DIFFUSE)
1316 colorscale = r_shadow_lightintensityscale.value;
1317 // colorscale accounts for how much we multiply the brightness
1320 // mult is how many times the final pass of the lighting will be
1321 // performed to get more brightness than otherwise possible.
1323 // Limit mult to 64 for sanity sake.
1324 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1326 // 3/2 3D combine path (Geforce3, Radeon 8500)
1327 memset(&m, 0, sizeof(m));
1328 m.pointer_vertex = vertex3f;
1329 m.tex[0] = R_GetTexture(bumptexture);
1330 m.texcombinergb[0] = GL_REPLACE;
1331 m.pointer_texcoord[0] = texcoord2f;
1332 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1333 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1334 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1335 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1336 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1338 m.pointer_texcoord3f[2] = vertex3f;
1339 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
1341 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1342 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1345 GL_ColorMask(0,0,0,1);
1346 GL_BlendFunc(GL_ONE, GL_ZERO);
1347 GL_LockArrays(0, numverts);
1348 R_Mesh_Draw(numverts, numtriangles, elements);
1349 GL_LockArrays(0, 0);
1351 c_rt_lighttris += numtriangles;
1353 memset(&m, 0, sizeof(m));
1354 m.pointer_vertex = vertex3f;
1355 m.tex[0] = R_GetTexture(basetexture);
1356 m.pointer_texcoord[0] = texcoord2f;
1359 m.texcubemap[1] = R_GetTexture(lightcubemap);
1361 m.pointer_texcoord3f[1] = vertex3f;
1362 m.texmatrix[1] = *matrix_modeltolight;
1364 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1365 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1369 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap)
1371 // 1/2/2 3D combine path (original Radeon)
1372 memset(&m, 0, sizeof(m));
1373 m.pointer_vertex = vertex3f;
1374 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1376 m.pointer_texcoord3f[0] = vertex3f;
1377 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1379 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1380 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1383 GL_ColorMask(0,0,0,1);
1384 GL_BlendFunc(GL_ONE, GL_ZERO);
1385 GL_LockArrays(0, numverts);
1386 R_Mesh_Draw(numverts, numtriangles, elements);
1387 GL_LockArrays(0, 0);
1389 c_rt_lighttris += numtriangles;
1391 memset(&m, 0, sizeof(m));
1392 m.pointer_vertex = vertex3f;
1393 m.tex[0] = R_GetTexture(bumptexture);
1394 m.texcombinergb[0] = GL_REPLACE;
1395 m.pointer_texcoord[0] = texcoord2f;
1396 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1397 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1398 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1399 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1401 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1402 GL_LockArrays(0, numverts);
1403 R_Mesh_Draw(numverts, numtriangles, elements);
1404 GL_LockArrays(0, 0);
1406 c_rt_lighttris += numtriangles;
1408 memset(&m, 0, sizeof(m));
1409 m.pointer_vertex = vertex3f;
1410 m.tex[0] = R_GetTexture(basetexture);
1411 m.pointer_texcoord[0] = texcoord2f;
1414 m.texcubemap[1] = R_GetTexture(lightcubemap);
1416 m.pointer_texcoord3f[1] = vertex3f;
1417 m.texmatrix[1] = *matrix_modeltolight;
1419 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1420 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1424 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap)
1426 // 2/2 3D combine path (original Radeon)
1427 memset(&m, 0, sizeof(m));
1428 m.pointer_vertex = vertex3f;
1429 m.tex[0] = R_GetTexture(bumptexture);
1430 m.texcombinergb[0] = GL_REPLACE;
1431 m.pointer_texcoord[0] = texcoord2f;
1432 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1433 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1434 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1435 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1437 GL_ColorMask(0,0,0,1);
1438 GL_BlendFunc(GL_ONE, GL_ZERO);
1439 GL_LockArrays(0, numverts);
1440 R_Mesh_Draw(numverts, numtriangles, elements);
1441 GL_LockArrays(0, 0);
1443 c_rt_lighttris += numtriangles;
1445 memset(&m, 0, sizeof(m));
1446 m.pointer_vertex = vertex3f;
1447 m.tex[0] = R_GetTexture(basetexture);
1448 m.pointer_texcoord[0] = texcoord2f;
1449 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1451 m.pointer_texcoord3f[1] = vertex3f;
1452 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1454 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1455 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1458 else if (r_textureunits.integer >= 4)
1460 // 4/2 2D combine path (Geforce3, Radeon 8500)
1461 memset(&m, 0, sizeof(m));
1462 m.pointer_vertex = vertex3f;
1463 m.tex[0] = R_GetTexture(bumptexture);
1464 m.texcombinergb[0] = GL_REPLACE;
1465 m.pointer_texcoord[0] = texcoord2f;
1466 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1467 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1468 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1469 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1470 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1472 m.pointer_texcoord3f[2] = vertex3f;
1473 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
1475 m.pointer_texcoord[2] = varray_texcoord2f[2];
1476 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1478 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1480 m.pointer_texcoord3f[3] = vertex3f;
1481 m.texmatrix[3] = *matrix_modeltoattenuationz;
1483 m.pointer_texcoord[3] = varray_texcoord2f[3];
1484 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[3], numverts, vertex3f, matrix_modeltoattenuationz);
1487 GL_ColorMask(0,0,0,1);
1488 GL_BlendFunc(GL_ONE, GL_ZERO);
1489 GL_LockArrays(0, numverts);
1490 R_Mesh_Draw(numverts, numtriangles, elements);
1491 GL_LockArrays(0, 0);
1493 c_rt_lighttris += numtriangles;
1495 memset(&m, 0, sizeof(m));
1496 m.pointer_vertex = vertex3f;
1497 m.tex[0] = R_GetTexture(basetexture);
1498 m.pointer_texcoord[0] = texcoord2f;
1501 m.texcubemap[1] = R_GetTexture(lightcubemap);
1503 m.pointer_texcoord3f[1] = vertex3f;
1504 m.texmatrix[1] = *matrix_modeltolight;
1506 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1507 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1513 // 2/2/2 2D combine path (any dot3 card)
1514 memset(&m, 0, sizeof(m));
1515 m.pointer_vertex = vertex3f;
1516 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1518 m.pointer_texcoord3f[0] = vertex3f;
1519 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1521 m.pointer_texcoord[0] = varray_texcoord2f[0];
1522 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1524 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1526 m.pointer_texcoord3f[1] = vertex3f;
1527 m.texmatrix[1] = *matrix_modeltoattenuationz;
1529 m.pointer_texcoord[1] = varray_texcoord2f[1];
1530 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1533 GL_ColorMask(0,0,0,1);
1534 GL_BlendFunc(GL_ONE, GL_ZERO);
1535 GL_LockArrays(0, numverts);
1536 R_Mesh_Draw(numverts, numtriangles, elements);
1537 GL_LockArrays(0, 0);
1539 c_rt_lighttris += numtriangles;
1541 memset(&m, 0, sizeof(m));
1542 m.pointer_vertex = vertex3f;
1543 m.tex[0] = R_GetTexture(bumptexture);
1544 m.texcombinergb[0] = GL_REPLACE;
1545 m.pointer_texcoord[0] = texcoord2f;
1546 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1547 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1548 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1549 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1551 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1552 GL_LockArrays(0, numverts);
1553 R_Mesh_Draw(numverts, numtriangles, elements);
1554 GL_LockArrays(0, 0);
1556 c_rt_lighttris += numtriangles;
1558 memset(&m, 0, sizeof(m));
1559 m.pointer_vertex = vertex3f;
1560 m.tex[0] = R_GetTexture(basetexture);
1561 m.pointer_texcoord[0] = texcoord2f;
1564 m.texcubemap[1] = R_GetTexture(lightcubemap);
1566 m.pointer_texcoord3f[1] = vertex3f;
1567 m.texmatrix[1] = *matrix_modeltolight;
1569 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1570 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1574 // this final code is shared
1576 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1577 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1578 VectorScale(lightcolor, colorscale, color2);
1579 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1581 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1582 GL_LockArrays(0, numverts);
1583 R_Mesh_Draw(numverts, numtriangles, elements);
1584 GL_LockArrays(0, 0);
1586 c_rt_lighttris += numtriangles;
1589 if ((lighting & LIGHTING_SPECULAR) && (r_shadow_gloss.integer >= 2 || (r_shadow_gloss.integer >= 1 && glosstexture != r_shadow_blankglosstexture)))
1591 // FIXME: detect blendsquare!
1592 //if (gl_support_blendsquare)
1594 colorscale = r_shadow_lightintensityscale.value * r_shadow_glossintensity.value;
1595 if (glosstexture == r_shadow_blankglosstexture)
1596 colorscale *= r_shadow_gloss2intensity.value;
1598 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1600 // 2/0/0/1/2 3D combine blendsquare path
1601 memset(&m, 0, sizeof(m));
1602 m.pointer_vertex = vertex3f;
1603 m.tex[0] = R_GetTexture(bumptexture);
1604 m.pointer_texcoord[0] = texcoord2f;
1605 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1606 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1607 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1608 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1610 GL_ColorMask(0,0,0,1);
1611 // this squares the result
1612 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1613 GL_LockArrays(0, numverts);
1614 R_Mesh_Draw(numverts, numtriangles, elements);
1615 GL_LockArrays(0, 0);
1617 c_rt_lighttris += numtriangles;
1619 memset(&m, 0, sizeof(m));
1620 m.pointer_vertex = vertex3f;
1622 GL_LockArrays(0, numverts);
1623 // square alpha in framebuffer a few times to make it shiny
1624 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1625 // these comments are a test run through this math for intensity 0.5
1626 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1627 // 0.25 * 0.25 = 0.0625 (this is another pass)
1628 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1629 R_Mesh_Draw(numverts, numtriangles, elements);
1631 c_rt_lighttris += numtriangles;
1632 R_Mesh_Draw(numverts, numtriangles, elements);
1634 c_rt_lighttris += numtriangles;
1635 GL_LockArrays(0, 0);
1637 memset(&m, 0, sizeof(m));
1638 m.pointer_vertex = vertex3f;
1639 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1641 m.pointer_texcoord3f[0] = vertex3f;
1642 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1644 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1645 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1648 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1649 GL_LockArrays(0, numverts);
1650 R_Mesh_Draw(numverts, numtriangles, elements);
1651 GL_LockArrays(0, 0);
1653 c_rt_lighttris += numtriangles;
1655 memset(&m, 0, sizeof(m));
1656 m.pointer_vertex = vertex3f;
1657 m.tex[0] = R_GetTexture(glosstexture);
1658 m.pointer_texcoord[0] = texcoord2f;
1661 m.texcubemap[1] = R_GetTexture(lightcubemap);
1663 m.pointer_texcoord3f[1] = vertex3f;
1664 m.texmatrix[1] = *matrix_modeltolight;
1666 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1667 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1671 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1673 // 2/0/0/2 3D combine blendsquare path
1674 memset(&m, 0, sizeof(m));
1675 m.pointer_vertex = vertex3f;
1676 m.tex[0] = R_GetTexture(bumptexture);
1677 m.pointer_texcoord[0] = texcoord2f;
1678 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1679 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1680 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1681 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1683 GL_ColorMask(0,0,0,1);
1684 // this squares the result
1685 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1686 GL_LockArrays(0, numverts);
1687 R_Mesh_Draw(numverts, numtriangles, elements);
1688 GL_LockArrays(0, 0);
1690 c_rt_lighttris += numtriangles;
1692 memset(&m, 0, sizeof(m));
1693 m.pointer_vertex = vertex3f;
1695 GL_LockArrays(0, numverts);
1696 // square alpha in framebuffer a few times to make it shiny
1697 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1698 // these comments are a test run through this math for intensity 0.5
1699 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1700 // 0.25 * 0.25 = 0.0625 (this is another pass)
1701 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1702 R_Mesh_Draw(numverts, numtriangles, elements);
1704 c_rt_lighttris += numtriangles;
1705 R_Mesh_Draw(numverts, numtriangles, elements);
1707 c_rt_lighttris += numtriangles;
1708 GL_LockArrays(0, 0);
1710 memset(&m, 0, sizeof(m));
1711 m.pointer_vertex = vertex3f;
1712 m.tex[0] = R_GetTexture(glosstexture);
1713 m.pointer_texcoord[0] = texcoord2f;
1714 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1716 m.pointer_texcoord3f[1] = vertex3f;
1717 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1719 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1720 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1725 // 2/0/0/2/2 2D combine blendsquare path
1726 memset(&m, 0, sizeof(m));
1727 m.pointer_vertex = vertex3f;
1728 m.tex[0] = R_GetTexture(bumptexture);
1729 m.pointer_texcoord[0] = texcoord2f;
1730 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1731 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1732 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1733 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1735 GL_ColorMask(0,0,0,1);
1736 // this squares the result
1737 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1738 GL_LockArrays(0, numverts);
1739 R_Mesh_Draw(numverts, numtriangles, elements);
1740 GL_LockArrays(0, 0);
1742 c_rt_lighttris += numtriangles;
1744 memset(&m, 0, sizeof(m));
1745 m.pointer_vertex = vertex3f;
1747 GL_LockArrays(0, numverts);
1748 // square alpha in framebuffer a few times to make it shiny
1749 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1750 // these comments are a test run through this math for intensity 0.5
1751 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1752 // 0.25 * 0.25 = 0.0625 (this is another pass)
1753 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1754 R_Mesh_Draw(numverts, numtriangles, elements);
1756 c_rt_lighttris += numtriangles;
1757 R_Mesh_Draw(numverts, numtriangles, elements);
1759 c_rt_lighttris += numtriangles;
1760 GL_LockArrays(0, 0);
1762 memset(&m, 0, sizeof(m));
1763 m.pointer_vertex = vertex3f;
1764 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1766 m.pointer_texcoord3f[0] = vertex3f;
1767 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1769 m.pointer_texcoord[0] = varray_texcoord2f[0];
1770 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1772 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1774 m.pointer_texcoord3f[1] = vertex3f;
1775 m.texmatrix[1] = *matrix_modeltoattenuationz;
1777 m.pointer_texcoord[1] = varray_texcoord2f[1];
1778 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1781 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1782 GL_LockArrays(0, numverts);
1783 R_Mesh_Draw(numverts, numtriangles, elements);
1784 GL_LockArrays(0, 0);
1786 c_rt_lighttris += numtriangles;
1788 memset(&m, 0, sizeof(m));
1789 m.pointer_vertex = vertex3f;
1790 m.tex[0] = R_GetTexture(glosstexture);
1791 m.pointer_texcoord[0] = texcoord2f;
1794 m.texcubemap[1] = R_GetTexture(lightcubemap);
1796 m.pointer_texcoord3f[1] = vertex3f;
1797 m.texmatrix[1] = *matrix_modeltolight;
1799 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1800 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1806 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1807 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1808 VectorScale(lightcolor, colorscale, color2);
1809 GL_LockArrays(0, numverts);
1810 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1812 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1813 R_Mesh_Draw(numverts, numtriangles, elements);
1815 c_rt_lighttris += numtriangles;
1817 GL_LockArrays(0, 0);
1822 if (lighting & LIGHTING_DIFFUSE)
1824 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1825 VectorScale(lightcolor, r_shadow_lightintensityscale.value, color2);
1826 memset(&m, 0, sizeof(m));
1827 m.pointer_vertex = vertex3f;
1828 m.pointer_color = varray_color4f;
1829 m.tex[0] = R_GetTexture(basetexture);
1830 m.pointer_texcoord[0] = texcoord2f;
1831 if (r_textureunits.integer >= 2)
1834 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1836 m.pointer_texcoord3f[1] = vertex3f;
1837 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1839 m.pointer_texcoord[1] = varray_texcoord2f[1];
1840 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1842 if (r_textureunits.integer >= 3)
1844 // Geforce3/Radeon class but not using dot3
1845 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1847 m.pointer_texcoord3f[2] = vertex3f;
1848 m.texmatrix[2] = *matrix_modeltoattenuationz;
1850 m.pointer_texcoord[2] = varray_texcoord2f[2];
1851 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationz);
1856 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1858 color[0] = bound(0, color2[0], 1);
1859 color[1] = bound(0, color2[1], 1);
1860 color[2] = bound(0, color2[2], 1);
1861 if (r_textureunits.integer >= 3)
1862 R_Shadow_VertexShading(numverts, vertex3f, normal3f, color, matrix_modeltolight);
1863 else if (r_textureunits.integer >= 2)
1864 R_Shadow_VertexShadingWithZAttenuation(numverts, vertex3f, normal3f, color, matrix_modeltolight);
1866 R_Shadow_VertexShadingWithXYZAttenuation(numverts, vertex3f, normal3f, color, matrix_modeltolight);
1867 GL_LockArrays(0, numverts);
1868 R_Mesh_Draw(numverts, numtriangles, elements);
1869 GL_LockArrays(0, 0);
1871 c_rt_lighttris += numtriangles;
1877 void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
1881 R_RTLight_Uncompile(rtlight);
1882 memset(rtlight, 0, sizeof(*rtlight));
1884 VectorCopy(light->origin, rtlight->shadoworigin);
1885 VectorCopy(light->color, rtlight->color);
1886 rtlight->radius = light->radius;
1887 //rtlight->cullradius = rtlight->radius;
1888 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
1889 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
1890 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
1891 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
1892 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
1893 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
1894 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
1895 rtlight->cubemapname[0] = 0;
1896 if (light->cubemapname[0])
1897 strcpy(rtlight->cubemapname, light->cubemapname);
1898 else if (light->cubemapnum > 0)
1899 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
1900 rtlight->shadow = light->shadow;
1901 rtlight->corona = light->corona;
1902 rtlight->style = light->style;
1903 rtlight->isstatic = isstatic;
1904 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
1905 // ConcatScale won't work here because this needs to scale rotate and
1906 // translate, not just rotate
1907 scale = 1.0f / rtlight->radius;
1908 for (k = 0;k < 3;k++)
1909 for (j = 0;j < 4;j++)
1910 rtlight->matrix_worldtolight.m[k][j] *= scale;
1911 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationxyz, &matrix_attenuationxyz, &rtlight->matrix_worldtolight);
1912 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationz, &matrix_attenuationz, &rtlight->matrix_worldtolight);
1914 rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
1915 rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
1916 VectorScale(rtlight->color, rtlight->radius * d_lightstylevalue[rtlight->style] * 0.125f, rtlight->lightmap_light);
1917 rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
1920 // compiles rtlight geometry
1921 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
1922 void R_RTLight_Compile(rtlight_t *rtlight)
1924 int shadowmeshes, shadowtris, lightmeshes, lighttris, numclusters, numsurfaces;
1925 entity_render_t *ent = &cl_entities[0].render;
1926 model_t *model = ent->model;
1928 // compile the light
1929 rtlight->compiled = true;
1930 rtlight->static_numclusters = 0;
1931 rtlight->static_numclusterpvsbytes = 0;
1932 rtlight->static_clusterlist = NULL;
1933 rtlight->static_clusterpvs = NULL;
1934 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
1935 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
1936 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
1937 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
1938 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
1939 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
1941 if (model && model->GetLightInfo)
1943 // this variable directs the DrawShadowVolume and DrawLight code to capture into the mesh chain instead of rendering
1944 r_shadow_compilingrtlight = rtlight;
1945 R_Shadow_EnlargeClusterBuffer(model->brush.num_pvsclusters);
1946 R_Shadow_EnlargeSurfaceBuffer(model->nummodelsurfaces);
1947 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);
1950 rtlight->static_numclusters = numclusters;
1951 rtlight->static_numclusterpvsbytes = (model->brush.num_pvsclusters + 7) >> 3;
1952 rtlight->static_clusterlist = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
1953 rtlight->static_clusterpvs = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusterpvsbytes);
1954 memcpy(rtlight->static_clusterlist, r_shadow_buffer_clusterlist, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
1955 memcpy(rtlight->static_clusterpvs, r_shadow_buffer_clusterpvs, rtlight->static_numclusterpvsbytes);
1957 if (model->DrawShadowVolume && rtlight->shadow)
1959 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
1960 model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
1961 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_shadow, false, false);
1963 if (model->DrawLight)
1965 rtlight->static_meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true);
1966 model->DrawLight(ent, rtlight->shadoworigin, vec3_origin, rtlight->radius, vec3_origin, &r_identitymatrix, &r_identitymatrix, &r_identitymatrix, NULL, numsurfaces, r_shadow_buffer_surfacelist);
1967 rtlight->static_meshchain_light = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_light, true, false);
1969 // switch back to rendering when DrawShadowVolume or DrawLight is called
1970 r_shadow_compilingrtlight = NULL;
1974 // use smallest available cullradius - box radius or light radius
1975 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
1976 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
1980 if (rtlight->static_meshchain_shadow)
1983 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
1986 shadowtris += mesh->numtriangles;
1992 if (rtlight->static_meshchain_light)
1995 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
1998 lighttris += mesh->numtriangles;
2002 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);
2005 void R_RTLight_Uncompile(rtlight_t *rtlight)
2007 if (rtlight->compiled)
2009 if (rtlight->static_meshchain_shadow)
2010 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2011 rtlight->static_meshchain_shadow = NULL;
2012 if (rtlight->static_meshchain_light)
2013 Mod_ShadowMesh_Free(rtlight->static_meshchain_light);
2014 rtlight->static_meshchain_light = NULL;
2015 if (rtlight->static_clusterlist)
2016 Mem_Free(rtlight->static_clusterlist);
2017 rtlight->static_clusterlist = NULL;
2018 if (rtlight->static_clusterpvs)
2019 Mem_Free(rtlight->static_clusterpvs);
2020 rtlight->static_clusterpvs = NULL;
2021 rtlight->static_numclusters = 0;
2022 rtlight->static_numclusterpvsbytes = 0;
2023 rtlight->compiled = false;
2027 void R_Shadow_UncompileWorldLights(void)
2030 for (light = r_shadow_worldlightchain;light;light = light->next)
2031 R_RTLight_Uncompile(&light->rtlight);
2034 void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes)
2037 entity_render_t *ent;
2039 vec3_t relativelightorigin, relativeeyeorigin, lightcolor, lightcolor2;
2040 rtexture_t *cubemaptexture;
2041 matrix4x4_t matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz;
2042 int numclusters, numsurfaces;
2043 int *clusterlist, *surfacelist;
2045 vec3_t cullmins, cullmaxs;
2049 // loading is done before visibility checks because loading should happen
2050 // all at once at the start of a level, not when it stalls gameplay.
2051 // (especially important to benchmarks)
2052 if (rtlight->isstatic && !rtlight->compiled && r_shadow_staticworldlights.integer)
2053 R_RTLight_Compile(rtlight);
2054 if (rtlight->cubemapname[0])
2055 cubemaptexture = R_Shadow_Cubemap(rtlight->cubemapname);
2057 cubemaptexture = NULL;
2059 cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2060 cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2061 cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2062 cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2063 cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2064 cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2065 if (d_lightstylevalue[rtlight->style] <= 0)
2072 if (rtlight->compiled && r_shadow_staticworldlights.integer)
2074 // compiled light, world available and can receive realtime lighting
2075 // retrieve cluster information
2076 numclusters = rtlight->static_numclusters;
2077 clusterlist = rtlight->static_clusterlist;
2078 clusterpvs = rtlight->static_clusterpvs;
2079 VectorCopy(rtlight->cullmins, cullmins);
2080 VectorCopy(rtlight->cullmaxs, cullmaxs);
2082 else if (cl.worldmodel && cl.worldmodel->GetLightInfo)
2084 // dynamic light, world available and can receive realtime lighting
2085 // if the light box is offscreen, skip it right away
2086 if (R_CullBox(cullmins, cullmaxs))
2088 // calculate lit surfaces and clusters
2089 R_Shadow_EnlargeClusterBuffer(cl.worldmodel->brush.num_pvsclusters);
2090 R_Shadow_EnlargeSurfaceBuffer(cl.worldmodel->nummodelsurfaces);
2091 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);
2092 clusterlist = r_shadow_buffer_clusterlist;
2093 clusterpvs = r_shadow_buffer_clusterpvs;
2094 surfacelist = r_shadow_buffer_surfacelist;
2096 // if the reduced cluster bounds are offscreen, skip it
2097 if (R_CullBox(cullmins, cullmaxs))
2099 // check if light is illuminating any visible clusters
2102 for (i = 0;i < numclusters;i++)
2103 if (CHECKPVSBIT(r_pvsbits, clusterlist[i]))
2105 if (i == numclusters)
2108 // set up a scissor rectangle for this light
2109 if (R_Shadow_ScissorForBBox(cullmins, cullmaxs))
2112 f = d_lightstylevalue[rtlight->style] * (1.0f / 256.0f);
2113 VectorScale(rtlight->color, f, lightcolor);
2115 if (rtlight->selected)
2117 f = 2 + sin(realtime * M_PI * 4.0);
2118 VectorScale(lightcolor, f, lightcolor);
2122 shadow = rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows);
2124 if (shadow && (gl_stencil || visiblevolumes))
2126 if (!visiblevolumes)
2127 R_Shadow_Stage_ShadowVolumes();
2128 ent = &cl_entities[0].render;
2129 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2131 memset(&m, 0, sizeof(m));
2132 R_Mesh_Matrix(&ent->matrix);
2133 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2135 m.pointer_vertex = mesh->vertex3f;
2137 GL_LockArrays(0, mesh->numverts);
2138 if (r_shadowstage == SHADOWSTAGE_STENCIL)
2140 // decrement stencil if frontface is behind depthbuffer
2141 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2142 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2143 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2144 c_rtcached_shadowmeshes++;
2145 c_rtcached_shadowtris += mesh->numtriangles;
2146 // increment stencil if backface is behind depthbuffer
2147 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2148 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2150 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2151 c_rtcached_shadowmeshes++;
2152 c_rtcached_shadowtris += mesh->numtriangles;
2153 GL_LockArrays(0, 0);
2158 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2159 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, numsurfaces, surfacelist);
2161 if (r_drawentities.integer)
2163 for (i = 0;i < r_refdef.numentities;i++)
2165 ent = r_refdef.entities[i];
2167 if (r_shadow_cull.integer)
2169 if (!BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs))
2171 if (cl.worldmodel != NULL && cl.worldmodel->brush.BoxTouchingPVS != NULL && !cl.worldmodel->brush.BoxTouchingPVS(cl.worldmodel, clusterpvs, ent->mins, ent->maxs))
2174 if (!(ent->flags & RENDER_SHADOW) || !ent->model || !ent->model->DrawShadowVolume)
2176 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2177 // light emitting entities should not cast their own shadow
2178 if (VectorLength2(relativelightorigin) < 0.1)
2180 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, ent->model->nummodelsurfaces, ent->model->surfacelist);
2185 if (!visiblevolumes)
2187 R_Shadow_Stage_Light(shadow && gl_stencil);
2189 ent = &cl_entities[0].render;
2190 if (ent->model && ent->model->DrawLight && (ent->flags & RENDER_LIGHT))
2192 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2193 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2194 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2195 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2196 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2197 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2199 R_Mesh_Matrix(&ent->matrix);
2200 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2201 R_Shadow_RenderLighting(mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->vertex3f, mesh->svector3f, mesh->tvector3f, mesh->normal3f, mesh->texcoord2f, relativelightorigin, relativeeyeorigin, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, mesh->map_diffuse, mesh->map_normal, mesh->map_specular, cubemaptexture, LIGHTING_DIFFUSE | LIGHTING_SPECULAR);
2204 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, numsurfaces, surfacelist);
2206 if (r_drawentities.integer)
2208 for (i = 0;i < r_refdef.numentities;i++)
2210 ent = r_refdef.entities[i];
2211 // can't draw transparent entity lighting here because
2212 // transparent meshes are deferred for later
2213 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)
2215 VectorScale(lightcolor, ent->alpha, lightcolor2);
2216 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2217 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2218 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2219 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2220 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2221 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor2, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, ent->model->nummodelsurfaces, ent->model->surfacelist);
2228 void R_ShadowVolumeLighting(int visiblevolumes)
2234 if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2235 R_Shadow_EditLights_Reload_f();
2239 memset(&m, 0, sizeof(m));
2242 GL_BlendFunc(GL_ONE, GL_ONE);
2243 GL_DepthMask(false);
2244 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
2245 qglDisable(GL_CULL_FACE);
2246 GL_Color(0.0, 0.0125, 0.1, 1);
2249 R_Shadow_Stage_Begin();
2252 if (r_shadow_debuglight.integer >= 0)
2254 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2255 if (lnum == r_shadow_debuglight.integer)
2256 R_DrawRTLight(&light->rtlight, visiblevolumes);
2259 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2260 R_DrawRTLight(&light->rtlight, visiblevolumes);
2263 for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
2264 R_DrawRTLight(&light->rtlight, visiblevolumes);
2268 qglEnable(GL_CULL_FACE);
2269 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
2272 R_Shadow_Stage_End();
2275 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2276 typedef struct suffixinfo_s
2279 qboolean flipx, flipy, flipdiagonal;
2282 static suffixinfo_t suffix[3][6] =
2285 {"px", false, false, false},
2286 {"nx", false, false, false},
2287 {"py", false, false, false},
2288 {"ny", false, false, false},
2289 {"pz", false, false, false},
2290 {"nz", false, false, false}
2293 {"posx", false, false, false},
2294 {"negx", false, false, false},
2295 {"posy", false, false, false},
2296 {"negy", false, false, false},
2297 {"posz", false, false, false},
2298 {"negz", false, false, false}
2301 {"rt", true, false, true},
2302 {"lf", false, true, true},
2303 {"ft", true, true, false},
2304 {"bk", false, false, false},
2305 {"up", true, false, true},
2306 {"dn", true, false, true}
2310 static int componentorder[4] = {0, 1, 2, 3};
2312 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2314 int i, j, cubemapsize;
2315 qbyte *cubemappixels, *image_rgba;
2316 rtexture_t *cubemaptexture;
2318 // must start 0 so the first loadimagepixels has no requested width/height
2320 cubemappixels = NULL;
2321 cubemaptexture = NULL;
2322 // keep trying different suffix groups (posx, px, rt) until one loads
2323 for (j = 0;j < 3 && !cubemappixels;j++)
2325 // load the 6 images in the suffix group
2326 for (i = 0;i < 6;i++)
2328 // generate an image name based on the base and and suffix
2329 snprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2331 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2333 // an image loaded, make sure width and height are equal
2334 if (image_width == image_height)
2336 // if this is the first image to load successfully, allocate the cubemap memory
2337 if (!cubemappixels && image_width >= 1)
2339 cubemapsize = image_width;
2340 // note this clears to black, so unavailable sides are black
2341 cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2343 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2345 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);
2348 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2350 Mem_Free(image_rgba);
2354 // if a cubemap loaded, upload it
2357 if (!r_shadow_filters_texturepool)
2358 r_shadow_filters_texturepool = R_AllocTexturePool();
2359 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
2360 Mem_Free(cubemappixels);
2364 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
2365 for (j = 0;j < 3;j++)
2366 for (i = 0;i < 6;i++)
2367 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2368 Con_Print(" and was unable to find any of them.\n");
2370 return cubemaptexture;
2373 rtexture_t *R_Shadow_Cubemap(const char *basename)
2376 for (i = 0;i < numcubemaps;i++)
2377 if (!strcasecmp(cubemaps[i].basename, basename))
2378 return cubemaps[i].texture;
2379 if (i >= MAX_CUBEMAPS)
2382 strcpy(cubemaps[i].basename, basename);
2383 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
2384 return cubemaps[i].texture;
2387 void R_Shadow_FreeCubemaps(void)
2390 R_FreeTexturePool(&r_shadow_filters_texturepool);
2393 dlight_t *R_Shadow_NewWorldLight(void)
2396 light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
2397 light->next = r_shadow_worldlightchain;
2398 r_shadow_worldlightchain = light;
2402 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)
2404 VectorCopy(origin, light->origin);
2405 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
2406 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
2407 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
2408 light->color[0] = max(color[0], 0);
2409 light->color[1] = max(color[1], 0);
2410 light->color[2] = max(color[2], 0);
2411 light->radius = max(radius, 0);
2412 light->style = style;
2413 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
2415 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
2418 light->shadow = shadowenable;
2419 light->corona = corona;
2422 strlcpy(light->cubemapname, cubemapname, strlen(light->cubemapname));
2423 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
2425 R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
2428 void R_Shadow_FreeWorldLight(dlight_t *light)
2430 dlight_t **lightpointer;
2431 R_RTLight_Uncompile(&light->rtlight);
2432 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
2433 if (*lightpointer != light)
2434 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
2435 *lightpointer = light->next;
2439 void R_Shadow_ClearWorldLights(void)
2441 while (r_shadow_worldlightchain)
2442 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
2443 r_shadow_selectedlight = NULL;
2444 R_Shadow_FreeCubemaps();
2447 void R_Shadow_SelectLight(dlight_t *light)
2449 if (r_shadow_selectedlight)
2450 r_shadow_selectedlight->selected = false;
2451 r_shadow_selectedlight = light;
2452 if (r_shadow_selectedlight)
2453 r_shadow_selectedlight->selected = true;
2456 void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
2458 float scale = r_editlights_cursorgrid.value * 0.5f;
2459 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);
2462 void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
2465 const dlight_t *light;
2468 if (light->selected)
2469 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
2472 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);
2475 void R_Shadow_DrawLightSprites(void)
2481 for (i = 0;i < 5;i++)
2483 lighttextures[i] = NULL;
2484 if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1))))
2485 lighttextures[i] = pic->tex;
2488 for (light = r_shadow_worldlightchain;light;light = light->next)
2489 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, ((int) light) % 5);
2490 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
2493 void R_Shadow_SelectLightInView(void)
2495 float bestrating, rating, temp[3];
2496 dlight_t *best, *light;
2499 for (light = r_shadow_worldlightchain;light;light = light->next)
2501 VectorSubtract(light->origin, r_vieworigin, temp);
2502 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
2505 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
2506 if (bestrating < rating && CL_TraceLine(light->origin, r_vieworigin, NULL, NULL, true, NULL, SUPERCONTENTS_SOLID) == 1.0f)
2508 bestrating = rating;
2513 R_Shadow_SelectLight(best);
2516 void R_Shadow_LoadWorldLights(void)
2518 int n, a, style, shadow;
2519 char name[MAX_QPATH], cubemapname[MAX_QPATH], *lightsstring, *s, *t;
2520 float origin[3], radius, color[3], angles[3], corona;
2521 if (cl.worldmodel == NULL)
2523 Con_Print("No map loaded.\n");
2526 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2527 strlcat (name, ".rtlights", sizeof (name));
2528 lightsstring = FS_LoadFile(name, tempmempool, false);
2538 for (;COM_Parse(t, true) && strcmp(
2539 if (COM_Parse(t, true))
2541 if (com_token[0] == '!')
2544 origin[0] = atof(com_token+1);
2547 origin[0] = atof(com_token);
2552 while (*s && *s != '\n')
2558 // check for modifier flags
2564 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]);
2566 VectorClear(angles);
2569 if (a < 9 || !strcmp(cubemapname, "\"\""))
2574 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);
2577 VectorScale(color, r_editlights_rtlightscolorscale.value, color);
2578 radius *= r_editlights_rtlightssizescale.value;
2579 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname);
2584 Con_Printf("invalid rtlights file \"%s\"\n", name);
2585 Mem_Free(lightsstring);
2589 void R_Shadow_SaveWorldLights(void)
2592 int bufchars, bufmaxchars;
2594 char name[MAX_QPATH];
2596 if (!r_shadow_worldlightchain)
2598 if (cl.worldmodel == NULL)
2600 Con_Print("No map loaded.\n");
2603 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2604 strlcat (name, ".rtlights", sizeof (name));
2605 bufchars = bufmaxchars = 0;
2607 for (light = r_shadow_worldlightchain;light;light = light->next)
2609 sprintf(line, "%s%f %f %f %f %f %f %f %d %s %f %f %f %f\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius / r_editlights_rtlightssizescale.value, light->color[0] / r_editlights_rtlightscolorscale.value, light->color[1] / r_editlights_rtlightscolorscale.value, light->color[2] / r_editlights_rtlightscolorscale.value, light->style, light->cubemapname[0] ? light->cubemapname : "\"\"", light->corona, light->angles[0], light->angles[1], light->angles[2]);
2610 if (bufchars + (int) strlen(line) > bufmaxchars)
2612 bufmaxchars = bufchars + strlen(line) + 2048;
2614 buf = Mem_Alloc(r_shadow_mempool, bufmaxchars);
2618 memcpy(buf, oldbuf, bufchars);
2624 memcpy(buf + bufchars, line, strlen(line));
2625 bufchars += strlen(line);
2629 FS_WriteFile(name, buf, bufchars);
2634 void R_Shadow_LoadLightsFile(void)
2637 char name[MAX_QPATH], *lightsstring, *s, *t;
2638 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
2639 if (cl.worldmodel == NULL)
2641 Con_Print("No map loaded.\n");
2644 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2645 strlcat (name, ".lights", sizeof (name));
2646 lightsstring = FS_LoadFile(name, tempmempool, false);
2654 while (*s && *s != '\n')
2659 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);
2663 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);
2666 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
2667 radius = bound(15, radius, 4096);
2668 VectorScale(color, (2.0f / (8388608.0f)), color);
2669 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL);
2674 Con_Printf("invalid lights file \"%s\"\n", name);
2675 Mem_Free(lightsstring);
2679 // tyrlite/hmap2 light types in the delay field
2680 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
2682 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
2684 int entnum, style, islight, skin, pflags, effects, type, n;
2685 char key[256], value[1024];
2686 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
2689 if (cl.worldmodel == NULL)
2691 Con_Print("No map loaded.\n");
2694 data = cl.worldmodel->brush.entities;
2697 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
2699 type = LIGHTTYPE_MINUSX;
2700 origin[0] = origin[1] = origin[2] = 0;
2701 originhack[0] = originhack[1] = originhack[2] = 0;
2702 angles[0] = angles[1] = angles[2] = 0;
2703 color[0] = color[1] = color[2] = 1;
2704 light[0] = light[1] = light[2] = 1;light[3] = 300;
2705 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
2715 if (!COM_ParseToken(&data, false))
2717 if (com_token[0] == '}')
2718 break; // end of entity
2719 if (com_token[0] == '_')
2720 strcpy(key, com_token + 1);
2722 strcpy(key, com_token);
2723 while (key[strlen(key)-1] == ' ') // remove trailing spaces
2724 key[strlen(key)-1] = 0;
2725 if (!COM_ParseToken(&data, false))
2727 strcpy(value, com_token);
2729 // now that we have the key pair worked out...
2730 if (!strcmp("light", key))
2732 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
2736 light[0] = vec[0] * (1.0f / 256.0f);
2737 light[1] = vec[0] * (1.0f / 256.0f);
2738 light[2] = vec[0] * (1.0f / 256.0f);
2744 light[0] = vec[0] * (1.0f / 255.0f);
2745 light[1] = vec[1] * (1.0f / 255.0f);
2746 light[2] = vec[2] * (1.0f / 255.0f);
2750 else if (!strcmp("delay", key))
2752 else if (!strcmp("origin", key))
2753 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
2754 else if (!strcmp("angle", key))
2755 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
2756 else if (!strcmp("angles", key))
2757 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
2758 else if (!strcmp("color", key))
2759 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
2760 else if (!strcmp("wait", key))
2761 fadescale = atof(value);
2762 else if (!strcmp("classname", key))
2764 if (!strncmp(value, "light", 5))
2767 if (!strcmp(value, "light_fluoro"))
2772 overridecolor[0] = 1;
2773 overridecolor[1] = 1;
2774 overridecolor[2] = 1;
2776 if (!strcmp(value, "light_fluorospark"))
2781 overridecolor[0] = 1;
2782 overridecolor[1] = 1;
2783 overridecolor[2] = 1;
2785 if (!strcmp(value, "light_globe"))
2790 overridecolor[0] = 1;
2791 overridecolor[1] = 0.8;
2792 overridecolor[2] = 0.4;
2794 if (!strcmp(value, "light_flame_large_yellow"))
2799 overridecolor[0] = 1;
2800 overridecolor[1] = 0.5;
2801 overridecolor[2] = 0.1;
2803 if (!strcmp(value, "light_flame_small_yellow"))
2808 overridecolor[0] = 1;
2809 overridecolor[1] = 0.5;
2810 overridecolor[2] = 0.1;
2812 if (!strcmp(value, "light_torch_small_white"))
2817 overridecolor[0] = 1;
2818 overridecolor[1] = 0.5;
2819 overridecolor[2] = 0.1;
2821 if (!strcmp(value, "light_torch_small_walltorch"))
2826 overridecolor[0] = 1;
2827 overridecolor[1] = 0.5;
2828 overridecolor[2] = 0.1;
2832 else if (!strcmp("style", key))
2833 style = atoi(value);
2834 else if (cl.worldmodel->type == mod_brushq3)
2836 if (!strcmp("scale", key))
2837 lightscale = atof(value);
2838 if (!strcmp("fade", key))
2839 fadescale = atof(value);
2841 else if (!strcmp("skin", key))
2842 skin = (int)atof(value);
2843 else if (!strcmp("pflags", key))
2844 pflags = (int)atof(value);
2845 else if (!strcmp("effects", key))
2846 effects = (int)atof(value);
2850 if (lightscale <= 0)
2854 if (color[0] == color[1] && color[0] == color[2])
2856 color[0] *= overridecolor[0];
2857 color[1] *= overridecolor[1];
2858 color[2] *= overridecolor[2];
2860 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
2861 color[0] = color[0] * light[0];
2862 color[1] = color[1] * light[1];
2863 color[2] = color[2] * light[2];
2866 case LIGHTTYPE_MINUSX:
2868 case LIGHTTYPE_RECIPX:
2870 VectorScale(color, (1.0f / 16.0f), color);
2872 case LIGHTTYPE_RECIPXX:
2874 VectorScale(color, (1.0f / 16.0f), color);
2877 case LIGHTTYPE_NONE:
2881 case LIGHTTYPE_MINUSXX:
2884 VectorAdd(origin, originhack, origin);
2886 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);
2891 void R_Shadow_SetCursorLocationForView(void)
2893 vec_t dist, push, frac;
2894 vec3_t dest, endpos, normal;
2895 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
2896 frac = CL_TraceLine(r_vieworigin, dest, endpos, normal, true, NULL, SUPERCONTENTS_SOLID);
2899 dist = frac * r_editlights_cursordistance.value;
2900 push = r_editlights_cursorpushback.value;
2904 VectorMA(endpos, push, r_viewforward, endpos);
2905 VectorMA(endpos, r_editlights_cursorpushoff.value, normal, endpos);
2907 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2908 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2909 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2912 void R_Shadow_UpdateWorldLightSelection(void)
2914 if (r_editlights.integer)
2916 R_Shadow_SetCursorLocationForView();
2917 R_Shadow_SelectLightInView();
2918 R_Shadow_DrawLightSprites();
2921 R_Shadow_SelectLight(NULL);
2924 void R_Shadow_EditLights_Clear_f(void)
2926 R_Shadow_ClearWorldLights();
2929 void R_Shadow_EditLights_Reload_f(void)
2933 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
2934 R_Shadow_ClearWorldLights();
2935 R_Shadow_LoadWorldLights();
2936 if (r_shadow_worldlightchain == NULL)
2938 R_Shadow_LoadLightsFile();
2939 if (r_shadow_worldlightchain == NULL)
2940 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
2944 void R_Shadow_EditLights_Save_f(void)
2948 R_Shadow_SaveWorldLights();
2951 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
2953 R_Shadow_ClearWorldLights();
2954 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
2957 void R_Shadow_EditLights_ImportLightsFile_f(void)
2959 R_Shadow_ClearWorldLights();
2960 R_Shadow_LoadLightsFile();
2963 void R_Shadow_EditLights_Spawn_f(void)
2966 if (!r_editlights.integer)
2968 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
2971 if (Cmd_Argc() != 1)
2973 Con_Print("r_editlights_spawn does not take parameters\n");
2976 color[0] = color[1] = color[2] = 1;
2977 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL);
2980 void R_Shadow_EditLights_Edit_f(void)
2982 vec3_t origin, angles, color;
2983 vec_t radius, corona;
2985 char cubemapname[1024];
2986 if (!r_editlights.integer)
2988 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
2991 if (!r_shadow_selectedlight)
2993 Con_Print("No selected light.\n");
2996 VectorCopy(r_shadow_selectedlight->origin, origin);
2997 VectorCopy(r_shadow_selectedlight->angles, angles);
2998 VectorCopy(r_shadow_selectedlight->color, color);
2999 radius = r_shadow_selectedlight->radius;
3000 style = r_shadow_selectedlight->style;
3001 if (r_shadow_selectedlight->cubemapname)
3002 strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
3005 shadows = r_shadow_selectedlight->shadow;
3006 corona = r_shadow_selectedlight->corona;
3007 if (!strcmp(Cmd_Argv(1), "origin"))
3009 if (Cmd_Argc() != 5)
3011 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3014 origin[0] = atof(Cmd_Argv(2));
3015 origin[1] = atof(Cmd_Argv(3));
3016 origin[2] = atof(Cmd_Argv(4));
3018 else if (!strcmp(Cmd_Argv(1), "originx"))
3020 if (Cmd_Argc() != 3)
3022 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3025 origin[0] = atof(Cmd_Argv(2));
3027 else if (!strcmp(Cmd_Argv(1), "originy"))
3029 if (Cmd_Argc() != 3)
3031 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3034 origin[1] = atof(Cmd_Argv(2));
3036 else if (!strcmp(Cmd_Argv(1), "originz"))
3038 if (Cmd_Argc() != 3)
3040 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3043 origin[2] = atof(Cmd_Argv(2));
3045 else if (!strcmp(Cmd_Argv(1), "move"))
3047 if (Cmd_Argc() != 5)
3049 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3052 origin[0] += atof(Cmd_Argv(2));
3053 origin[1] += atof(Cmd_Argv(3));
3054 origin[2] += atof(Cmd_Argv(4));
3056 else if (!strcmp(Cmd_Argv(1), "movex"))
3058 if (Cmd_Argc() != 3)
3060 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3063 origin[0] += atof(Cmd_Argv(2));
3065 else if (!strcmp(Cmd_Argv(1), "movey"))
3067 if (Cmd_Argc() != 3)
3069 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3072 origin[1] += atof(Cmd_Argv(2));
3074 else if (!strcmp(Cmd_Argv(1), "movez"))
3076 if (Cmd_Argc() != 3)
3078 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3081 origin[2] += atof(Cmd_Argv(2));
3083 else if (!strcmp(Cmd_Argv(1), "angles"))
3085 if (Cmd_Argc() != 5)
3087 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3090 angles[0] = atof(Cmd_Argv(2));
3091 angles[1] = atof(Cmd_Argv(3));
3092 angles[2] = atof(Cmd_Argv(4));
3094 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3096 if (Cmd_Argc() != 3)
3098 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3101 angles[0] = atof(Cmd_Argv(2));
3103 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3105 if (Cmd_Argc() != 3)
3107 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3110 angles[1] = atof(Cmd_Argv(2));
3112 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3114 if (Cmd_Argc() != 3)
3116 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3119 angles[2] = atof(Cmd_Argv(2));
3121 else if (!strcmp(Cmd_Argv(1), "color"))
3123 if (Cmd_Argc() != 5)
3125 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3128 color[0] = atof(Cmd_Argv(2));
3129 color[1] = atof(Cmd_Argv(3));
3130 color[2] = atof(Cmd_Argv(4));
3132 else if (!strcmp(Cmd_Argv(1), "radius"))
3134 if (Cmd_Argc() != 3)
3136 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3139 radius = atof(Cmd_Argv(2));
3141 else if (!strcmp(Cmd_Argv(1), "style"))
3143 if (Cmd_Argc() != 3)
3145 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3148 style = atoi(Cmd_Argv(2));
3150 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3154 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3157 if (Cmd_Argc() == 3)
3158 strcpy(cubemapname, Cmd_Argv(2));
3162 else if (!strcmp(Cmd_Argv(1), "shadows"))
3164 if (Cmd_Argc() != 3)
3166 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3169 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3171 else if (!strcmp(Cmd_Argv(1), "corona"))
3173 if (Cmd_Argc() != 3)
3175 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3178 corona = atof(Cmd_Argv(2));
3182 Con_Print("usage: r_editlights_edit [property] [value]\n");
3183 Con_Print("Selected light's properties:\n");
3184 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3185 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3186 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3187 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3188 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3189 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3190 Con_Printf("Shadows: %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3191 Con_Printf("Cubemap: %s\n", r_shadow_selectedlight->cubemapname);
3194 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname);
3197 void R_Shadow_EditLights_EditAll_f(void)
3201 if (!r_editlights.integer)
3203 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
3207 for (light = r_shadow_worldlightchain;light;light = light->next)
3209 R_Shadow_SelectLight(light);
3210 R_Shadow_EditLights_Edit_f();
3214 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3218 if (!r_editlights.integer)
3222 sprintf(temp, "Cursor %f %f %f", r_editlights_cursorlocation[0], r_editlights_cursorlocation[1], r_editlights_cursorlocation[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3223 if (r_shadow_selectedlight == NULL)
3225 sprintf(temp, "Light properties");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3226 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;
3227 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;
3228 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;
3229 sprintf(temp, "Radius %f", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3230 sprintf(temp, "Corona %f", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3231 sprintf(temp, "Style %i", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3232 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;
3233 sprintf(temp, "Cubemap %s", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3236 void R_Shadow_EditLights_ToggleShadow_f(void)
3238 if (!r_editlights.integer)
3240 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3243 if (!r_shadow_selectedlight)
3245 Con_Print("No selected light.\n");
3248 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);
3251 void R_Shadow_EditLights_ToggleCorona_f(void)
3253 if (!r_editlights.integer)
3255 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3258 if (!r_shadow_selectedlight)
3260 Con_Print("No selected light.\n");
3263 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);
3266 void R_Shadow_EditLights_Remove_f(void)
3268 if (!r_editlights.integer)
3270 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
3273 if (!r_shadow_selectedlight)
3275 Con_Print("No selected light.\n");
3278 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3279 r_shadow_selectedlight = NULL;
3282 void R_Shadow_EditLights_Help_f(void)
3285 "Documentation on r_editlights system:\n"
3287 "r_editlights : enable/disable editing mode\n"
3288 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
3289 "r_editlights_cursorpushback : push back cursor this far from surface\n"
3290 "r_editlights_cursorpushoff : push cursor off surface this far\n"
3291 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
3292 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
3293 "r_editlights_rtlightssizescale : imported rtlight size scaling\n"
3294 "r_editlights_rtlightscolorscale : imported rtlight color scaling\n"
3296 "r_editlights_help : this help\n"
3297 "r_editlights_clear : remove all lights\n"
3298 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
3299 "r_editlights_save : save to .rtlights file\n"
3300 "r_editlights_spawn : create a light with default settings\n"
3301 "r_editlights_edit command : edit selected light - more documentation below\n"
3302 "r_editlights_remove : remove selected light\n"
3303 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
3304 "r_editlights_importlightentitiesfrommap : reload light entities\n"
3305 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
3307 "origin x y z : set light location\n"
3308 "originx x: set x component of light location\n"
3309 "originy y: set y component of light location\n"
3310 "originz z: set z component of light location\n"
3311 "move x y z : adjust light location\n"
3312 "movex x: adjust x component of light location\n"
3313 "movey y: adjust y component of light location\n"
3314 "movez z: adjust z component of light location\n"
3315 "angles x y z : set light angles\n"
3316 "anglesx x: set x component of light angles\n"
3317 "anglesy y: set y component of light angles\n"
3318 "anglesz z: set z component of light angles\n"
3319 "color r g b : set color of light (can be brighter than 1 1 1)\n"
3320 "radius radius : set radius (size) of light\n"
3321 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
3322 "cubemap basename : set filter cubemap of light (not yet supported)\n"
3323 "shadows 1/0 : turn on/off shadows\n"
3324 "corona n : set corona intensity\n"
3325 "<nothing> : print light properties to console\n"
3329 void R_Shadow_EditLights_CopyInfo_f(void)
3331 if (!r_editlights.integer)
3333 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
3336 if (!r_shadow_selectedlight)
3338 Con_Print("No selected light.\n");
3341 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
3342 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
3343 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
3344 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
3345 if (r_shadow_selectedlight->cubemapname)
3346 strcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname);
3348 r_shadow_bufferlight.cubemapname[0] = 0;
3349 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
3350 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
3353 void R_Shadow_EditLights_PasteInfo_f(void)
3355 if (!r_editlights.integer)
3357 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
3360 if (!r_shadow_selectedlight)
3362 Con_Print("No selected light.\n");
3365 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);
3368 void R_Shadow_EditLights_Init(void)
3370 Cvar_RegisterVariable(&r_editlights);
3371 Cvar_RegisterVariable(&r_editlights_cursordistance);
3372 Cvar_RegisterVariable(&r_editlights_cursorpushback);
3373 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
3374 Cvar_RegisterVariable(&r_editlights_cursorgrid);
3375 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
3376 Cvar_RegisterVariable(&r_editlights_rtlightssizescale);
3377 Cvar_RegisterVariable(&r_editlights_rtlightscolorscale);
3378 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
3379 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
3380 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
3381 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
3382 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
3383 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
3384 Cmd_AddCommand("r_editlights_editall", R_Shadow_EditLights_EditAll_f);
3385 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
3386 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
3387 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
3388 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
3389 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);
3390 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f);
3391 Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f);