3 Terminology: Stencil Shadow Volume (sometimes called Stencil Shadows)
4 An extrusion of the lit faces, beginning at the original geometry and ending
5 further from the light source than the original geometry (presumably at least
6 as far as the light's radius, if the light has a radius at all), capped at
7 both front and back to avoid any problems (extrusion from dark faces also
8 works but has a different set of problems)
10 This is rendered using Carmack's Reverse technique, in which backfaces behind
11 zbuffer (zfail) increment the stencil, and frontfaces behind zbuffer (zfail)
12 decrement the stencil, the result is a stencil value of zero where shadows
13 did not intersect the visible geometry, suitable as a stencil mask for
14 rendering lighting everywhere but shadow.
16 In our case we use a biased stencil clear of 128 to avoid requiring the
17 stencil wrap extension (but probably should support it), and to address
18 Creative's patent on this sort of technology we also draw the frontfaces
19 first, and backfaces second (decrement, increment).
22 This algorithm may be covered by Creative's patent (US Patent #6384822)
23 on Carmack's Reverse paper (which I have not read), however that patent
24 seems to be about drawing a stencil shadow from a model in an otherwise
25 unshadowed scene, where as realtime lighting technology draws light where
30 Terminology: Stencil Light Volume (sometimes called Light Volumes)
31 Similar to a Stencil Shadow Volume, but inverted; rather than containing the
32 areas in shadow it contanis the areas in light, this can only be built
33 quickly for certain limited cases (such as portal visibility from a point),
34 but is quite useful for some effects (sunlight coming from sky polygons is
35 one possible example, translucent occluders is another example).
39 Terminology: Optimized Stencil Shadow Volume
40 A Stencil Shadow Volume that has been processed sufficiently to ensure it has
41 no duplicate coverage of areas (no need to shadow an area twice), often this
42 greatly improves performance but is an operation too costly to use on moving
43 lights (however completely optimal Stencil Light Volumes can be constructed
48 Terminology: Per Pixel Lighting (sometimes abbreviated PPL)
49 Per pixel evaluation of lighting equations, at a bare minimum this involves
50 DOT3 shading of diffuse lighting (per pixel dotproduct of negated incidence
51 vector and surface normal, using a texture of the surface bumps, called a
52 NormalMap) if supported by hardware; in our case there is support for cards
53 which are incapable of DOT3, the quality is quite poor however. Additionally
54 it is desirable to have specular evaluation per pixel, per vertex
55 normalization of specular halfangle vectors causes noticable distortion but
56 is unavoidable on hardware without GL_ARB_fragment_program.
60 Terminology: Normalization CubeMap
61 A cubemap containing normalized dot3-encoded (vectors of length 1 or less
62 encoded as RGB colors) for any possible direction, this technique allows per
63 pixel calculation of incidence vector for per pixel lighting purposes, which
64 would not otherwise be possible per pixel without GL_ARB_fragment_program.
68 Terminology: 2D Attenuation Texturing
69 A very crude approximation of light attenuation with distance which results
70 in cylindrical light shapes which fade vertically as a streak (some games
71 such as Doom3 allow this to be rotated to be less noticable in specific
72 cases), the technique is simply modulating lighting by two 2D textures (which
73 can be the same) on different axes of projection (XY and Z, typically), this
74 is the best technique available without 3D Attenuation Texturing or
75 GL_ARB_fragment_program technology.
79 Terminology: 3D Attenuation Texturing
80 A slightly crude approximation of light attenuation with distance, its flaws
81 are limited radius and resolution (performance tradeoffs).
85 Terminology: 3D Attenuation-Normalization Texturing
86 A 3D Attenuation Texture merged with a Normalization CubeMap, by making the
87 vectors shorter the lighting becomes darker, a very effective optimization of
88 diffuse lighting if 3D Attenuation Textures are already used.
92 Terminology: Light Cubemap Filtering
93 A technique for modeling non-uniform light distribution according to
94 direction, for example projecting a stained glass window image onto a wall,
95 this is done by texturing the lighting with a cubemap.
99 Terminology: Light Projection Filtering
100 A technique for modeling shadowing of light passing through translucent
101 surfaces, allowing stained glass windows and other effects to be done more
102 elegantly than possible with Light Cubemap Filtering by applying an occluder
103 texture to the lighting combined with a stencil light volume to limit the lit
104 area (this allows evaluating multiple translucent occluders in a scene).
108 Terminology: Doom3 Lighting
109 A combination of Stencil Shadow Volume, Per Pixel Lighting, Normalization
110 CubeMap, 2D Attenuation Texturing, and Light Filtering, as demonstrated by
111 the (currently upcoming) game Doom3.
114 #include "quakedef.h"
115 #include "r_shadow.h"
116 #include "cl_collision.h"
120 extern void R_Shadow_EditLights_Init(void);
122 #define SHADOWSTAGE_NONE 0
123 #define SHADOWSTAGE_STENCIL 1
124 #define SHADOWSTAGE_LIGHT 2
125 #define SHADOWSTAGE_STENCILTWOSIDE 3
127 int r_shadowstage = SHADOWSTAGE_NONE;
129 mempool_t *r_shadow_mempool;
131 int maxshadowelements;
145 int r_shadow_buffer_numclusterpvsbytes;
146 qbyte *r_shadow_buffer_clusterpvs;
147 int *r_shadow_buffer_clusterlist;
149 int r_shadow_buffer_numsurfacepvsbytes;
150 qbyte *r_shadow_buffer_surfacepvs;
151 int *r_shadow_buffer_surfacelist;
153 rtexturepool_t *r_shadow_texturepool;
154 rtexture_t *r_shadow_normalcubetexture;
155 rtexture_t *r_shadow_attenuation2dtexture;
156 rtexture_t *r_shadow_attenuation3dtexture;
157 rtexture_t *r_shadow_blankbumptexture;
158 rtexture_t *r_shadow_blankglosstexture;
159 rtexture_t *r_shadow_blankwhitetexture;
161 // lights are reloaded when this changes
162 char r_shadow_mapname[MAX_QPATH];
164 // used only for light filters (cubemaps)
165 rtexturepool_t *r_shadow_filters_texturepool;
167 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0"};
168 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4"};
169 cvar_t r_shadow_cull = {0, "r_shadow_cull", "1"};
170 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1"};
171 cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1"};
172 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.25"};
173 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1"};
174 cvar_t r_shadow_lightattenuationpower = {0, "r_shadow_lightattenuationpower", "0.5"};
175 cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1"};
176 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1"};
177 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1"};
178 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000"};
179 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1"};
180 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "0"};
181 cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0"};
182 cvar_t r_shadow_realtime_world_dlightshadows = {CVAR_SAVE, "r_shadow_realtime_world_dlightshadows", "1"};
183 cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0"};
184 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1"};
185 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1"};
186 cvar_t r_shadow_shadow_polygonfactor = {0, "r_shadow_shadow_polygonfactor", "0"};
187 cvar_t r_shadow_shadow_polygonoffset = {0, "r_shadow_shadow_polygonoffset", "1"};
188 cvar_t r_shadow_singlepassvolumegeneration = {0, "r_shadow_singlepassvolumegeneration", "1"};
189 cvar_t r_shadow_staticworldlights = {0, "r_shadow_staticworldlights", "1"};
190 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1"};
191 cvar_t r_shadow_visiblevolumes = {0, "r_shadow_visiblevolumes", "0"};
192 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1"};
193 cvar_t r_editlights = {0, "r_editlights", "0"};
194 cvar_t r_editlights_cursordistance = {0, "r_editlights_distance", "1024"};
195 cvar_t r_editlights_cursorpushback = {0, "r_editlights_pushback", "0"};
196 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_pushoff", "4"};
197 cvar_t r_editlights_cursorgrid = {0, "r_editlights_grid", "4"};
198 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "0.8"};
199 cvar_t r_editlights_rtlightssizescale = {CVAR_SAVE, "r_editlights_rtlightssizescale", "0.7"};
200 cvar_t r_editlights_rtlightscolorscale = {CVAR_SAVE, "r_editlights_rtlightscolorscale", "2"};
202 int c_rt_lights, c_rt_clears, c_rt_scissored;
203 int c_rt_shadowmeshes, c_rt_shadowtris, c_rt_lightmeshes, c_rt_lighttris;
204 int c_rtcached_shadowmeshes, c_rtcached_shadowtris;
206 float r_shadow_attenpower, r_shadow_attenscale;
208 rtlight_t *r_shadow_compilingrtlight;
209 dlight_t *r_shadow_worldlightchain;
210 dlight_t *r_shadow_selectedlight;
211 dlight_t r_shadow_bufferlight;
212 vec3_t r_editlights_cursorlocation;
214 rtexture_t *lighttextures[5];
216 extern int con_vislines;
218 typedef struct cubemapinfo_s
225 #define MAX_CUBEMAPS 256
226 static int numcubemaps;
227 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
229 void R_Shadow_UncompileWorldLights(void);
230 void R_Shadow_ClearWorldLights(void);
231 void R_Shadow_SaveWorldLights(void);
232 void R_Shadow_LoadWorldLights(void);
233 void R_Shadow_LoadLightsFile(void);
234 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
235 void R_Shadow_EditLights_Reload_f(void);
236 void R_Shadow_ValidateCvars(void);
237 static void R_Shadow_MakeTextures(void);
238 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light);
240 void r_shadow_start(void)
242 // allocate vertex processing arrays
244 r_shadow_normalcubetexture = NULL;
245 r_shadow_attenuation2dtexture = NULL;
246 r_shadow_attenuation3dtexture = NULL;
247 r_shadow_blankbumptexture = NULL;
248 r_shadow_blankglosstexture = NULL;
249 r_shadow_blankwhitetexture = NULL;
250 r_shadow_texturepool = NULL;
251 r_shadow_filters_texturepool = NULL;
252 R_Shadow_ValidateCvars();
253 R_Shadow_MakeTextures();
254 maxshadowelements = 0;
255 shadowelements = NULL;
263 shadowmarklist = NULL;
265 r_shadow_buffer_numclusterpvsbytes = 0;
266 r_shadow_buffer_clusterpvs = NULL;
267 r_shadow_buffer_clusterlist = NULL;
268 r_shadow_buffer_numsurfacepvsbytes = 0;
269 r_shadow_buffer_surfacepvs = NULL;
270 r_shadow_buffer_surfacelist = NULL;
273 void r_shadow_shutdown(void)
275 R_Shadow_UncompileWorldLights();
277 r_shadow_normalcubetexture = NULL;
278 r_shadow_attenuation2dtexture = NULL;
279 r_shadow_attenuation3dtexture = NULL;
280 r_shadow_blankbumptexture = NULL;
281 r_shadow_blankglosstexture = NULL;
282 r_shadow_blankwhitetexture = NULL;
283 R_FreeTexturePool(&r_shadow_texturepool);
284 R_FreeTexturePool(&r_shadow_filters_texturepool);
285 maxshadowelements = 0;
287 Mem_Free(shadowelements);
288 shadowelements = NULL;
291 Mem_Free(vertexupdate);
294 Mem_Free(vertexremap);
300 Mem_Free(shadowmark);
303 Mem_Free(shadowmarklist);
304 shadowmarklist = NULL;
306 r_shadow_buffer_numclusterpvsbytes = 0;
307 if (r_shadow_buffer_clusterpvs)
308 Mem_Free(r_shadow_buffer_clusterpvs);
309 r_shadow_buffer_clusterpvs = NULL;
310 if (r_shadow_buffer_clusterlist)
311 Mem_Free(r_shadow_buffer_clusterlist);
312 r_shadow_buffer_clusterlist = NULL;
313 r_shadow_buffer_numsurfacepvsbytes = 0;
314 if (r_shadow_buffer_surfacepvs)
315 Mem_Free(r_shadow_buffer_surfacepvs);
316 r_shadow_buffer_surfacepvs = NULL;
317 if (r_shadow_buffer_surfacelist)
318 Mem_Free(r_shadow_buffer_surfacelist);
319 r_shadow_buffer_surfacelist = NULL;
322 void r_shadow_newmap(void)
326 void R_Shadow_Help_f(void)
329 "Documentation on r_shadow system:\n"
331 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
332 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
333 "r_shadow_debuglight : render only this light number (-1 = all)\n"
334 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
335 "r_shadow_gloss2intensity : brightness of forced gloss\n"
336 "r_shadow_glossintensity : brightness of textured gloss\n"
337 "r_shadow_lightattenuationpower : used to generate attenuation texture\n"
338 "r_shadow_lightattenuationscale : used to generate attenuation texture\n"
339 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
340 "r_shadow_portallight : use portal visibility for static light precomputation\n"
341 "r_shadow_projectdistance : shadow volume projection distance\n"
342 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
343 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
344 "r_shadow_realtime_world : use high quality world lighting mode\n"
345 "r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n"
346 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
347 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
348 "r_shadow_scissor : use scissor optimization\n"
349 "r_shadow_shadow_polygonfactor : nudge shadow volumes closer/further\n"
350 "r_shadow_shadow_polygonoffset : nudge shadow volumes closer/further\n"
351 "r_shadow_singlepassvolumegeneration : selects shadow volume algorithm\n"
352 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
353 "r_shadow_visiblevolumes : useful for performance testing; bright = slow!\n"
355 "r_shadow_help : this help\n"
359 void R_Shadow_Init(void)
361 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
362 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
363 Cvar_RegisterVariable(&r_shadow_cull);
364 Cvar_RegisterVariable(&r_shadow_debuglight);
365 Cvar_RegisterVariable(&r_shadow_gloss);
366 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
367 Cvar_RegisterVariable(&r_shadow_glossintensity);
368 Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
369 Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
370 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
371 Cvar_RegisterVariable(&r_shadow_portallight);
372 Cvar_RegisterVariable(&r_shadow_projectdistance);
373 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
374 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
375 Cvar_RegisterVariable(&r_shadow_realtime_world);
376 Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows);
377 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
378 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
379 Cvar_RegisterVariable(&r_shadow_scissor);
380 Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor);
381 Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset);
382 Cvar_RegisterVariable(&r_shadow_singlepassvolumegeneration);
383 Cvar_RegisterVariable(&r_shadow_staticworldlights);
384 Cvar_RegisterVariable(&r_shadow_texture3d);
385 Cvar_RegisterVariable(&r_shadow_visiblevolumes);
386 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
387 if (gamemode == GAME_TENEBRAE)
389 Cvar_SetValue("r_shadow_gloss", 2);
390 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
392 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f);
393 R_Shadow_EditLights_Init();
394 r_shadow_mempool = Mem_AllocPool("R_Shadow", 0, NULL);
395 r_shadow_worldlightchain = NULL;
396 maxshadowelements = 0;
397 shadowelements = NULL;
405 shadowmarklist = NULL;
407 r_shadow_buffer_numclusterpvsbytes = 0;
408 r_shadow_buffer_clusterpvs = NULL;
409 r_shadow_buffer_clusterlist = NULL;
410 r_shadow_buffer_numsurfacepvsbytes = 0;
411 r_shadow_buffer_surfacepvs = NULL;
412 r_shadow_buffer_surfacelist = NULL;
413 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
416 matrix4x4_t matrix_attenuationxyz =
419 {0.5, 0.0, 0.0, 0.5},
420 {0.0, 0.5, 0.0, 0.5},
421 {0.0, 0.0, 0.5, 0.5},
426 matrix4x4_t matrix_attenuationz =
429 {0.0, 0.0, 0.5, 0.5},
430 {0.0, 0.0, 0.0, 0.5},
431 {0.0, 0.0, 0.0, 0.5},
436 int *R_Shadow_ResizeShadowElements(int numtris)
438 // make sure shadowelements is big enough for this volume
439 if (maxshadowelements < numtris * 24)
441 maxshadowelements = numtris * 24;
443 Mem_Free(shadowelements);
444 shadowelements = Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int));
446 return shadowelements;
449 void R_Shadow_EnlargeClusterBuffer(int numclusters)
451 int numclusterpvsbytes = (((numclusters + 7) >> 3) + 255) & ~255;
452 if (r_shadow_buffer_numclusterpvsbytes < numclusterpvsbytes)
454 if (r_shadow_buffer_clusterpvs)
455 Mem_Free(r_shadow_buffer_clusterpvs);
456 if (r_shadow_buffer_clusterlist)
457 Mem_Free(r_shadow_buffer_clusterlist);
458 r_shadow_buffer_numclusterpvsbytes = numclusterpvsbytes;
459 r_shadow_buffer_clusterpvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numclusterpvsbytes);
460 r_shadow_buffer_clusterlist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numclusterpvsbytes * 8 * sizeof(*r_shadow_buffer_clusterlist));
464 void R_Shadow_EnlargeSurfaceBuffer(int numsurfaces)
466 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
467 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
469 if (r_shadow_buffer_surfacepvs)
470 Mem_Free(r_shadow_buffer_surfacepvs);
471 if (r_shadow_buffer_surfacelist)
472 Mem_Free(r_shadow_buffer_surfacelist);
473 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
474 r_shadow_buffer_surfacepvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes);
475 r_shadow_buffer_surfacelist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
479 void R_Shadow_PrepareShadowMark(int numtris)
481 // make sure shadowmark is big enough for this volume
482 if (maxshadowmark < numtris)
484 maxshadowmark = numtris;
486 Mem_Free(shadowmark);
488 Mem_Free(shadowmarklist);
489 shadowmark = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmark));
490 shadowmarklist = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmarklist));
494 // if shadowmarkcount wrapped we clear the array and adjust accordingly
495 if (shadowmarkcount == 0)
498 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
503 int R_Shadow_ConstructShadowVolume(int innumvertices, int innumtris, const int *inelement3i, const int *inneighbor3i, const float *invertex3f, int *outnumvertices, int *outelement3i, float *outvertex3f, const float *projectorigin, float projectdistance, int numshadowmarktris, const int *shadowmarktris)
505 int i, j, tris = 0, vr[3], t, outvertices = 0;
509 if (maxvertexupdate < innumvertices)
511 maxvertexupdate = innumvertices;
513 Mem_Free(vertexupdate);
515 Mem_Free(vertexremap);
516 vertexupdate = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
517 vertexremap = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
521 if (vertexupdatenum == 0)
524 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
525 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
528 for (i = 0;i < numshadowmarktris;i++)
529 shadowmark[shadowmarktris[i]] = shadowmarkcount;
531 for (i = 0;i < numshadowmarktris;i++)
533 t = shadowmarktris[i];
534 e = inelement3i + t * 3;
535 // make sure the vertices are created
536 for (j = 0;j < 3;j++)
538 if (vertexupdate[e[j]] != vertexupdatenum)
540 vertexupdate[e[j]] = vertexupdatenum;
541 vertexremap[e[j]] = outvertices;
542 v = invertex3f + e[j] * 3;
544 outvertex3f[0] = v[0];
545 outvertex3f[1] = v[1];
546 outvertex3f[2] = v[2];
547 outvertex3f[3] = v[0] + 1000000 * (v[0] - projectorigin[0]);
548 outvertex3f[4] = v[1] + 1000000 * (v[1] - projectorigin[1]);
549 outvertex3f[5] = v[2] + 1000000 * (v[2] - projectorigin[2]);
553 VectorSubtract(v, projectorigin, temp);
554 f = projectdistance / VectorLength(temp);
555 VectorCopy(v, outvertex3f);
556 VectorMA(projectorigin, f, temp, (outvertex3f + 3));
565 for (i = 0;i < numshadowmarktris;i++)
567 t = shadowmarktris[i];
568 e = inelement3i + t * 3;
569 n = inneighbor3i + t * 3;
570 // output the front and back triangles
571 outelement3i[0] = vertexremap[e[0]];
572 outelement3i[1] = vertexremap[e[1]];
573 outelement3i[2] = vertexremap[e[2]];
574 outelement3i[3] = vertexremap[e[2]] + 1;
575 outelement3i[4] = vertexremap[e[1]] + 1;
576 outelement3i[5] = vertexremap[e[0]] + 1;
579 // output the sides (facing outward from this triangle)
580 if (shadowmark[n[0]] != shadowmarkcount)
582 vr[0] = vertexremap[e[0]];
583 vr[1] = vertexremap[e[1]];
584 outelement3i[0] = vr[1];
585 outelement3i[1] = vr[0];
586 outelement3i[2] = vr[0] + 1;
587 outelement3i[3] = vr[1];
588 outelement3i[4] = vr[0] + 1;
589 outelement3i[5] = vr[1] + 1;
593 if (shadowmark[n[1]] != shadowmarkcount)
595 vr[1] = vertexremap[e[1]];
596 vr[2] = vertexremap[e[2]];
597 outelement3i[0] = vr[2];
598 outelement3i[1] = vr[1];
599 outelement3i[2] = vr[1] + 1;
600 outelement3i[3] = vr[2];
601 outelement3i[4] = vr[1] + 1;
602 outelement3i[5] = vr[2] + 1;
606 if (shadowmark[n[2]] != shadowmarkcount)
608 vr[0] = vertexremap[e[0]];
609 vr[2] = vertexremap[e[2]];
610 outelement3i[0] = vr[0];
611 outelement3i[1] = vr[2];
612 outelement3i[2] = vr[2] + 1;
613 outelement3i[3] = vr[0];
614 outelement3i[4] = vr[2] + 1;
615 outelement3i[5] = vr[0] + 1;
621 *outnumvertices = outvertices;
625 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)
628 if (projectdistance < 0.1)
630 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
633 if (!numverts || !nummarktris)
635 // make sure shadowelements is big enough for this volume
636 if (maxshadowelements < nummarktris * 24)
637 R_Shadow_ResizeShadowElements((nummarktris + 256) * 24);
638 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, varray_vertex3f2, projectorigin, projectdistance, nummarktris, marktris);
639 R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements);
642 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)
647 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
649 tend = firsttriangle + numtris;
650 if (surfacemins[0] >= lightmins[0] && surfacemaxs[0] <= lightmaxs[0]
651 && surfacemins[1] >= lightmins[1] && surfacemaxs[1] <= lightmaxs[1]
652 && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2])
654 // surface box entirely inside light box, no box cull
655 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
656 if (PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
657 shadowmarklist[numshadowmark++] = t;
661 // surface box not entirely inside light box, cull each triangle
662 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
664 v[0] = invertex3f + e[0] * 3;
665 v[1] = invertex3f + e[1] * 3;
666 v[2] = invertex3f + e[2] * 3;
667 if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
668 && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
669 && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
670 && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
671 && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
672 && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
673 && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
674 shadowmarklist[numshadowmark++] = t;
679 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
682 if (r_shadow_compilingrtlight)
684 // if we're compiling an rtlight, capture the mesh
685 Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
688 memset(&m, 0, sizeof(m));
689 m.pointer_vertex = vertex3f;
691 GL_LockArrays(0, numvertices);
692 if (r_shadowstage == SHADOWSTAGE_STENCIL)
694 // increment stencil if backface is behind depthbuffer
695 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
696 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
697 R_Mesh_Draw(numvertices, numtriangles, element3i);
699 c_rt_shadowtris += numtriangles;
700 // decrement stencil if frontface is behind depthbuffer
701 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
702 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
704 R_Mesh_Draw(numvertices, numtriangles, element3i);
706 c_rt_shadowtris += numtriangles;
710 static void R_Shadow_MakeTextures(void)
712 int x, y, z, d, side;
713 float v[3], s, t, intensity;
715 R_FreeTexturePool(&r_shadow_texturepool);
716 r_shadow_texturepool = R_AllocTexturePool();
717 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
718 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
720 #define ATTEN2DSIZE 64
721 #define ATTEN3DSIZE 32
722 data = Mem_Alloc(tempmempool, max(6*NORMSIZE*NORMSIZE*4, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4)));
727 r_shadow_blankbumptexture = R_LoadTexture2D(r_shadow_texturepool, "blankbump", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
732 r_shadow_blankglosstexture = R_LoadTexture2D(r_shadow_texturepool, "blankgloss", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
737 r_shadow_blankwhitetexture = R_LoadTexture2D(r_shadow_texturepool, "blankwhite", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
738 if (gl_texturecubemap)
740 for (side = 0;side < 6;side++)
742 for (y = 0;y < NORMSIZE;y++)
744 for (x = 0;x < NORMSIZE;x++)
746 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
747 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
781 intensity = 127.0f / sqrt(DotProduct(v, v));
782 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+0] = 128.0f + intensity * v[0];
783 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+1] = 128.0f + intensity * v[1];
784 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+2] = 128.0f + intensity * v[2];
785 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+3] = 255;
789 r_shadow_normalcubetexture = R_LoadTextureCubeMap(r_shadow_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
792 r_shadow_normalcubetexture = NULL;
793 for (y = 0;y < ATTEN2DSIZE;y++)
795 for (x = 0;x < ATTEN2DSIZE;x++)
797 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
798 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
800 intensity = 1.0f - sqrt(DotProduct(v, v));
802 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
803 d = bound(0, intensity, 255);
804 data[(y*ATTEN2DSIZE+x)*4+0] = d;
805 data[(y*ATTEN2DSIZE+x)*4+1] = d;
806 data[(y*ATTEN2DSIZE+x)*4+2] = d;
807 data[(y*ATTEN2DSIZE+x)*4+3] = d;
810 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
811 if (r_shadow_texture3d.integer)
813 for (z = 0;z < ATTEN3DSIZE;z++)
815 for (y = 0;y < ATTEN3DSIZE;y++)
817 for (x = 0;x < ATTEN3DSIZE;x++)
819 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
820 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
821 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
822 intensity = 1.0f - sqrt(DotProduct(v, v));
824 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
825 d = bound(0, intensity, 255);
826 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
827 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
828 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
829 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
833 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
838 void R_Shadow_ValidateCvars(void)
840 if (r_shadow_texture3d.integer && !gl_texture3d)
841 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
842 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
843 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
846 void R_Shadow_Stage_Begin(void)
850 R_Shadow_ValidateCvars();
852 if (!r_shadow_attenuation2dtexture
853 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
854 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
855 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
856 R_Shadow_MakeTextures();
858 memset(&m, 0, sizeof(m));
859 GL_BlendFunc(GL_ONE, GL_ZERO);
863 GL_Color(0, 0, 0, 1);
864 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
865 qglEnable(GL_CULL_FACE);
866 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
867 r_shadowstage = SHADOWSTAGE_NONE;
869 c_rt_lights = c_rt_clears = c_rt_scissored = 0;
870 c_rt_shadowmeshes = c_rt_shadowtris = c_rt_lightmeshes = c_rt_lighttris = 0;
871 c_rtcached_shadowmeshes = c_rtcached_shadowtris = 0;
874 void R_Shadow_Stage_ShadowVolumes(void)
877 memset(&m, 0, sizeof(m));
879 GL_Color(1, 1, 1, 1);
880 GL_ColorMask(0, 0, 0, 0);
881 GL_BlendFunc(GL_ONE, GL_ZERO);
884 qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
885 //if (r_shadow_shadow_polygonoffset.value != 0)
887 // qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
888 // qglEnable(GL_POLYGON_OFFSET_FILL);
891 // qglDisable(GL_POLYGON_OFFSET_FILL);
892 qglDepthFunc(GL_LESS);
893 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
894 qglEnable(GL_STENCIL_TEST);
895 qglStencilFunc(GL_ALWAYS, 128, ~0);
896 if (gl_ext_stenciltwoside.integer)
898 r_shadowstage = SHADOWSTAGE_STENCILTWOSIDE;
899 qglDisable(GL_CULL_FACE);
900 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
901 qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
903 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
904 qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
906 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
910 r_shadowstage = SHADOWSTAGE_STENCIL;
911 qglEnable(GL_CULL_FACE);
913 // this is changed by every shadow render so its value here is unimportant
914 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
916 GL_Clear(GL_STENCIL_BUFFER_BIT);
918 // LordHavoc note: many shadow volumes reside entirely inside the world
919 // (that is to say they are entirely bounded by their lit surfaces),
920 // which can be optimized by handling things as an inverted light volume,
921 // with the shadow boundaries of the world being simulated by an altered
922 // (129) bias to stencil clearing on such lights
923 // FIXME: generate inverted light volumes for use as shadow volumes and
924 // optimize for them as noted above
927 void R_Shadow_Stage_Light(int shadowtest)
930 memset(&m, 0, sizeof(m));
932 GL_BlendFunc(GL_ONE, GL_ONE);
935 qglPolygonOffset(0, 0);
936 //qglDisable(GL_POLYGON_OFFSET_FILL);
937 GL_Color(1, 1, 1, 1);
938 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
939 qglDepthFunc(GL_EQUAL);
940 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
941 qglEnable(GL_CULL_FACE);
943 qglEnable(GL_STENCIL_TEST);
945 qglDisable(GL_STENCIL_TEST);
946 if (gl_support_stenciltwoside)
947 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
949 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
950 // only draw light where this geometry was already rendered AND the
951 // stencil is 128 (values other than this mean shadow)
952 qglStencilFunc(GL_EQUAL, 128, ~0);
953 r_shadowstage = SHADOWSTAGE_LIGHT;
957 void R_Shadow_Stage_End(void)
960 memset(&m, 0, sizeof(m));
962 GL_BlendFunc(GL_ONE, GL_ZERO);
965 qglPolygonOffset(0, 0);
966 //qglDisable(GL_POLYGON_OFFSET_FILL);
967 GL_Color(1, 1, 1, 1);
968 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
969 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
970 qglDepthFunc(GL_LEQUAL);
971 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
972 qglDisable(GL_STENCIL_TEST);
973 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
974 if (gl_support_stenciltwoside)
975 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
977 qglStencilFunc(GL_ALWAYS, 128, ~0);
978 r_shadowstage = SHADOWSTAGE_NONE;
981 int R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
983 int i, ix1, iy1, ix2, iy2;
984 float x1, y1, x2, y2, x, y, f;
987 if (!r_shadow_scissor.integer)
989 // if view is inside the box, just say yes it's visible
990 if (BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
992 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
995 for (i = 0;i < 3;i++)
997 if (r_viewforward[i] >= 0)
1008 f = DotProduct(r_viewforward, r_vieworigin) + 1;
1009 if (DotProduct(r_viewforward, v2) <= f)
1011 // entirely behind nearclip plane
1014 if (DotProduct(r_viewforward, v) >= f)
1016 // entirely infront of nearclip plane
1017 x1 = y1 = x2 = y2 = 0;
1018 for (i = 0;i < 8;i++)
1020 v[0] = (i & 1) ? mins[0] : maxs[0];
1021 v[1] = (i & 2) ? mins[1] : maxs[1];
1022 v[2] = (i & 4) ? mins[2] : maxs[2];
1024 GL_TransformToScreen(v, v2);
1025 //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]);
1044 // clipped by nearclip plane
1045 // this is nasty and crude...
1046 // create viewspace bbox
1047 for (i = 0;i < 8;i++)
1049 v[0] = ((i & 1) ? mins[0] : maxs[0]) - r_vieworigin[0];
1050 v[1] = ((i & 2) ? mins[1] : maxs[1]) - r_vieworigin[1];
1051 v[2] = ((i & 4) ? mins[2] : maxs[2]) - r_vieworigin[2];
1052 v2[0] = -DotProduct(v, r_viewleft);
1053 v2[1] = DotProduct(v, r_viewup);
1054 v2[2] = DotProduct(v, r_viewforward);
1057 if (smins[0] > v2[0]) smins[0] = v2[0];
1058 if (smaxs[0] < v2[0]) smaxs[0] = v2[0];
1059 if (smins[1] > v2[1]) smins[1] = v2[1];
1060 if (smaxs[1] < v2[1]) smaxs[1] = v2[1];
1061 if (smins[2] > v2[2]) smins[2] = v2[2];
1062 if (smaxs[2] < v2[2]) smaxs[2] = v2[2];
1066 smins[0] = smaxs[0] = v2[0];
1067 smins[1] = smaxs[1] = v2[1];
1068 smins[2] = smaxs[2] = v2[2];
1071 // now we have a bbox in viewspace
1072 // clip it to the view plane
1075 // return true if that culled the box
1076 if (smins[2] >= smaxs[2])
1078 // ok some of it is infront of the view, transform each corner back to
1079 // worldspace and then to screenspace and make screen rect
1080 // initialize these variables just to avoid compiler warnings
1081 x1 = y1 = x2 = y2 = 0;
1082 for (i = 0;i < 8;i++)
1084 v2[0] = (i & 1) ? smins[0] : smaxs[0];
1085 v2[1] = (i & 2) ? smins[1] : smaxs[1];
1086 v2[2] = (i & 4) ? smins[2] : smaxs[2];
1087 v[0] = v2[0] * -r_viewleft[0] + v2[1] * r_viewup[0] + v2[2] * r_viewforward[0] + r_vieworigin[0];
1088 v[1] = v2[0] * -r_viewleft[1] + v2[1] * r_viewup[1] + v2[2] * r_viewforward[1] + r_vieworigin[1];
1089 v[2] = v2[0] * -r_viewleft[2] + v2[1] * r_viewup[2] + v2[2] * r_viewforward[2] + r_vieworigin[2];
1091 GL_TransformToScreen(v, v2);
1092 //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]);
1109 // this code doesn't handle boxes with any points behind view properly
1110 x1 = 1000;x2 = -1000;
1111 y1 = 1000;y2 = -1000;
1112 for (i = 0;i < 8;i++)
1114 v[0] = (i & 1) ? mins[0] : maxs[0];
1115 v[1] = (i & 2) ? mins[1] : maxs[1];
1116 v[2] = (i & 4) ? mins[2] : maxs[2];
1118 GL_TransformToScreen(v, v2);
1119 //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]);
1137 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1138 if (ix1 < r_view_x) ix1 = r_view_x;
1139 if (iy1 < r_view_y) iy1 = r_view_y;
1140 if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
1141 if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
1142 if (ix2 <= ix1 || iy2 <= iy1)
1144 // set up the scissor rectangle
1145 GL_Scissor(ix1, vid.realheight - iy2, ix2 - ix1, iy2 - iy1);
1146 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1147 //qglEnable(GL_SCISSOR_TEST);
1152 static void R_Shadow_VertexShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1154 float *color4f = varray_color4f;
1155 float dist, dot, intensity, v[3], n[3];
1156 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1158 Matrix4x4_Transform(m, vertex3f, v);
1159 if ((dist = DotProduct(v, v)) < 1)
1161 Matrix4x4_Transform3x3(m, normal3f, n);
1162 if ((dot = DotProduct(n, v)) > 0)
1165 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1166 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1167 VectorScale(lightcolor, intensity, color4f);
1172 VectorClear(color4f);
1178 VectorClear(color4f);
1184 static void R_Shadow_VertexShadingWithZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1186 float *color4f = varray_color4f;
1187 float dist, dot, intensity, v[3], n[3];
1188 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1190 Matrix4x4_Transform(m, vertex3f, v);
1191 if ((dist = fabs(v[2])) < 1)
1193 Matrix4x4_Transform3x3(m, normal3f, n);
1194 if ((dot = DotProduct(n, v)) > 0)
1196 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1197 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1198 VectorScale(lightcolor, intensity, color4f);
1203 VectorClear(color4f);
1209 VectorClear(color4f);
1215 static void R_Shadow_VertexShading(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1217 float *color4f = varray_color4f;
1218 float dot, intensity, v[3], n[3];
1219 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1221 Matrix4x4_Transform(m, vertex3f, v);
1222 Matrix4x4_Transform3x3(m, normal3f, n);
1223 if ((dot = DotProduct(n, v)) > 0)
1225 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1226 VectorScale(lightcolor, intensity, color4f);
1231 VectorClear(color4f);
1237 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1238 #define USETEXMATRIX
1240 #ifndef USETEXMATRIX
1241 // this should be done in a texture matrix or vertex program when possible, but here's code to do it manually
1242 // if hardware texcoord manipulation is not available (or not suitable, this would really benefit from 3DNow! or SSE
1243 static void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1247 tc3f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1248 tc3f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1249 tc3f[2] = vertex3f[0] * matrix->m[2][0] + vertex3f[1] * matrix->m[2][1] + vertex3f[2] * matrix->m[2][2] + matrix->m[2][3];
1256 static void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1260 tc2f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1261 tc2f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1269 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)
1273 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1275 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1276 // the cubemap normalizes this for us
1277 out3f[0] = DotProduct(svector3f, lightdir);
1278 out3f[1] = DotProduct(tvector3f, lightdir);
1279 out3f[2] = DotProduct(normal3f, lightdir);
1283 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)
1286 float lightdir[3], eyedir[3], halfdir[3];
1287 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1289 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1290 VectorNormalizeFast(lightdir);
1291 VectorSubtract(vertex3f, relativeeyeorigin, eyedir);
1292 VectorNormalizeFast(eyedir);
1293 VectorAdd(lightdir, eyedir, halfdir);
1294 // the cubemap normalizes this for us
1295 out3f[0] = DotProduct(svector3f, halfdir);
1296 out3f[1] = DotProduct(tvector3f, halfdir);
1297 out3f[2] = DotProduct(normal3f, halfdir);
1301 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)
1304 float color[3], color2[3], colorscale;
1307 bumptexture = r_shadow_blankbumptexture;
1309 glosstexture = r_shadow_blankglosstexture;
1310 // FIXME: support EF_NODEPTHTEST
1311 GL_DepthMask(false);
1313 if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
1315 if (lighting & LIGHTING_DIFFUSE)
1318 colorscale = r_shadow_lightintensityscale.value;
1319 // colorscale accounts for how much we multiply the brightness
1322 // mult is how many times the final pass of the lighting will be
1323 // performed to get more brightness than otherwise possible.
1325 // Limit mult to 64 for sanity sake.
1326 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1328 // 3/2 3D combine path (Geforce3, Radeon 8500)
1329 memset(&m, 0, sizeof(m));
1330 m.pointer_vertex = vertex3f;
1331 m.tex[0] = R_GetTexture(bumptexture);
1332 m.texcombinergb[0] = GL_REPLACE;
1333 m.pointer_texcoord[0] = texcoord2f;
1334 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1335 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1336 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1337 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1338 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1340 m.pointer_texcoord3f[2] = vertex3f;
1341 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
1343 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1344 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1347 GL_ColorMask(0,0,0,1);
1348 GL_BlendFunc(GL_ONE, GL_ZERO);
1349 GL_LockArrays(0, numverts);
1350 R_Mesh_Draw(numverts, numtriangles, elements);
1351 GL_LockArrays(0, 0);
1353 c_rt_lighttris += numtriangles;
1355 memset(&m, 0, sizeof(m));
1356 m.pointer_vertex = vertex3f;
1357 m.tex[0] = R_GetTexture(basetexture);
1358 m.pointer_texcoord[0] = texcoord2f;
1361 m.texcubemap[1] = R_GetTexture(lightcubemap);
1363 m.pointer_texcoord3f[1] = vertex3f;
1364 m.texmatrix[1] = *matrix_modeltolight;
1366 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1367 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1371 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap)
1373 // 1/2/2 3D combine path (original Radeon)
1374 memset(&m, 0, sizeof(m));
1375 m.pointer_vertex = vertex3f;
1376 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1378 m.pointer_texcoord3f[0] = vertex3f;
1379 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1381 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1382 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1385 GL_ColorMask(0,0,0,1);
1386 GL_BlendFunc(GL_ONE, GL_ZERO);
1387 GL_LockArrays(0, numverts);
1388 R_Mesh_Draw(numverts, numtriangles, elements);
1389 GL_LockArrays(0, 0);
1391 c_rt_lighttris += numtriangles;
1393 memset(&m, 0, sizeof(m));
1394 m.pointer_vertex = vertex3f;
1395 m.tex[0] = R_GetTexture(bumptexture);
1396 m.texcombinergb[0] = GL_REPLACE;
1397 m.pointer_texcoord[0] = texcoord2f;
1398 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1399 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1400 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1401 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1403 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1404 GL_LockArrays(0, numverts);
1405 R_Mesh_Draw(numverts, numtriangles, elements);
1406 GL_LockArrays(0, 0);
1408 c_rt_lighttris += numtriangles;
1410 memset(&m, 0, sizeof(m));
1411 m.pointer_vertex = vertex3f;
1412 m.tex[0] = R_GetTexture(basetexture);
1413 m.pointer_texcoord[0] = texcoord2f;
1416 m.texcubemap[1] = R_GetTexture(lightcubemap);
1418 m.pointer_texcoord3f[1] = vertex3f;
1419 m.texmatrix[1] = *matrix_modeltolight;
1421 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1422 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1426 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap)
1428 // 2/2 3D combine path (original Radeon)
1429 memset(&m, 0, sizeof(m));
1430 m.pointer_vertex = vertex3f;
1431 m.tex[0] = R_GetTexture(bumptexture);
1432 m.texcombinergb[0] = GL_REPLACE;
1433 m.pointer_texcoord[0] = texcoord2f;
1434 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1435 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1436 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1437 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1439 GL_ColorMask(0,0,0,1);
1440 GL_BlendFunc(GL_ONE, GL_ZERO);
1441 GL_LockArrays(0, numverts);
1442 R_Mesh_Draw(numverts, numtriangles, elements);
1443 GL_LockArrays(0, 0);
1445 c_rt_lighttris += numtriangles;
1447 memset(&m, 0, sizeof(m));
1448 m.pointer_vertex = vertex3f;
1449 m.tex[0] = R_GetTexture(basetexture);
1450 m.pointer_texcoord[0] = texcoord2f;
1451 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1453 m.pointer_texcoord3f[1] = vertex3f;
1454 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1456 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1457 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1460 else if (r_textureunits.integer >= 4)
1462 // 4/2 2D combine path (Geforce3, Radeon 8500)
1463 memset(&m, 0, sizeof(m));
1464 m.pointer_vertex = vertex3f;
1465 m.tex[0] = R_GetTexture(bumptexture);
1466 m.texcombinergb[0] = GL_REPLACE;
1467 m.pointer_texcoord[0] = texcoord2f;
1468 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1469 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1470 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1471 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1472 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1474 m.pointer_texcoord3f[2] = vertex3f;
1475 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
1477 m.pointer_texcoord[2] = varray_texcoord2f[2];
1478 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1480 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1482 m.pointer_texcoord3f[3] = vertex3f;
1483 m.texmatrix[3] = *matrix_modeltoattenuationz;
1485 m.pointer_texcoord[3] = varray_texcoord2f[3];
1486 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[3], numverts, vertex3f, matrix_modeltoattenuationz);
1489 GL_ColorMask(0,0,0,1);
1490 GL_BlendFunc(GL_ONE, GL_ZERO);
1491 GL_LockArrays(0, numverts);
1492 R_Mesh_Draw(numverts, numtriangles, elements);
1493 GL_LockArrays(0, 0);
1495 c_rt_lighttris += numtriangles;
1497 memset(&m, 0, sizeof(m));
1498 m.pointer_vertex = vertex3f;
1499 m.tex[0] = R_GetTexture(basetexture);
1500 m.pointer_texcoord[0] = texcoord2f;
1503 m.texcubemap[1] = R_GetTexture(lightcubemap);
1505 m.pointer_texcoord3f[1] = vertex3f;
1506 m.texmatrix[1] = *matrix_modeltolight;
1508 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1509 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1515 // 2/2/2 2D combine path (any dot3 card)
1516 memset(&m, 0, sizeof(m));
1517 m.pointer_vertex = vertex3f;
1518 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1520 m.pointer_texcoord3f[0] = vertex3f;
1521 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1523 m.pointer_texcoord[0] = varray_texcoord2f[0];
1524 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1526 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1528 m.pointer_texcoord3f[1] = vertex3f;
1529 m.texmatrix[1] = *matrix_modeltoattenuationz;
1531 m.pointer_texcoord[1] = varray_texcoord2f[1];
1532 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1535 GL_ColorMask(0,0,0,1);
1536 GL_BlendFunc(GL_ONE, GL_ZERO);
1537 GL_LockArrays(0, numverts);
1538 R_Mesh_Draw(numverts, numtriangles, elements);
1539 GL_LockArrays(0, 0);
1541 c_rt_lighttris += numtriangles;
1543 memset(&m, 0, sizeof(m));
1544 m.pointer_vertex = vertex3f;
1545 m.tex[0] = R_GetTexture(bumptexture);
1546 m.texcombinergb[0] = GL_REPLACE;
1547 m.pointer_texcoord[0] = texcoord2f;
1548 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1549 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1550 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1551 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1553 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1554 GL_LockArrays(0, numverts);
1555 R_Mesh_Draw(numverts, numtriangles, elements);
1556 GL_LockArrays(0, 0);
1558 c_rt_lighttris += numtriangles;
1560 memset(&m, 0, sizeof(m));
1561 m.pointer_vertex = vertex3f;
1562 m.tex[0] = R_GetTexture(basetexture);
1563 m.pointer_texcoord[0] = texcoord2f;
1566 m.texcubemap[1] = R_GetTexture(lightcubemap);
1568 m.pointer_texcoord3f[1] = vertex3f;
1569 m.texmatrix[1] = *matrix_modeltolight;
1571 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1572 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1576 // this final code is shared
1578 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1579 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1580 VectorScale(lightcolor, colorscale, color2);
1581 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1583 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1584 GL_LockArrays(0, numverts);
1585 R_Mesh_Draw(numverts, numtriangles, elements);
1586 GL_LockArrays(0, 0);
1588 c_rt_lighttris += numtriangles;
1591 if ((lighting & LIGHTING_SPECULAR) && (r_shadow_gloss.integer >= 2 || (r_shadow_gloss.integer >= 1 && glosstexture != r_shadow_blankglosstexture)))
1593 // FIXME: detect blendsquare!
1594 //if (gl_support_blendsquare)
1596 colorscale = r_shadow_lightintensityscale.value * r_shadow_glossintensity.value;
1597 if (glosstexture == r_shadow_blankglosstexture)
1598 colorscale *= r_shadow_gloss2intensity.value;
1600 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1602 // 2/0/0/1/2 3D combine blendsquare path
1603 memset(&m, 0, sizeof(m));
1604 m.pointer_vertex = vertex3f;
1605 m.tex[0] = R_GetTexture(bumptexture);
1606 m.pointer_texcoord[0] = texcoord2f;
1607 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1608 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1609 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1610 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1612 GL_ColorMask(0,0,0,1);
1613 // this squares the result
1614 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1615 GL_LockArrays(0, numverts);
1616 R_Mesh_Draw(numverts, numtriangles, elements);
1617 GL_LockArrays(0, 0);
1619 c_rt_lighttris += numtriangles;
1621 memset(&m, 0, sizeof(m));
1622 m.pointer_vertex = vertex3f;
1624 GL_LockArrays(0, numverts);
1625 // square alpha in framebuffer a few times to make it shiny
1626 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1627 // these comments are a test run through this math for intensity 0.5
1628 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1629 // 0.25 * 0.25 = 0.0625 (this is another pass)
1630 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1631 R_Mesh_Draw(numverts, numtriangles, elements);
1633 c_rt_lighttris += numtriangles;
1634 R_Mesh_Draw(numverts, numtriangles, elements);
1636 c_rt_lighttris += numtriangles;
1637 GL_LockArrays(0, 0);
1639 memset(&m, 0, sizeof(m));
1640 m.pointer_vertex = vertex3f;
1641 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1643 m.pointer_texcoord3f[0] = vertex3f;
1644 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1646 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1647 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1650 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1651 GL_LockArrays(0, numverts);
1652 R_Mesh_Draw(numverts, numtriangles, elements);
1653 GL_LockArrays(0, 0);
1655 c_rt_lighttris += numtriangles;
1657 memset(&m, 0, sizeof(m));
1658 m.pointer_vertex = vertex3f;
1659 m.tex[0] = R_GetTexture(glosstexture);
1660 m.pointer_texcoord[0] = texcoord2f;
1663 m.texcubemap[1] = R_GetTexture(lightcubemap);
1665 m.pointer_texcoord3f[1] = vertex3f;
1666 m.texmatrix[1] = *matrix_modeltolight;
1668 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1669 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1673 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1675 // 2/0/0/2 3D combine blendsquare path
1676 memset(&m, 0, sizeof(m));
1677 m.pointer_vertex = vertex3f;
1678 m.tex[0] = R_GetTexture(bumptexture);
1679 m.pointer_texcoord[0] = texcoord2f;
1680 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1681 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1682 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1683 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1685 GL_ColorMask(0,0,0,1);
1686 // this squares the result
1687 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1688 GL_LockArrays(0, numverts);
1689 R_Mesh_Draw(numverts, numtriangles, elements);
1690 GL_LockArrays(0, 0);
1692 c_rt_lighttris += numtriangles;
1694 memset(&m, 0, sizeof(m));
1695 m.pointer_vertex = vertex3f;
1697 GL_LockArrays(0, numverts);
1698 // square alpha in framebuffer a few times to make it shiny
1699 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1700 // these comments are a test run through this math for intensity 0.5
1701 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1702 // 0.25 * 0.25 = 0.0625 (this is another pass)
1703 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1704 R_Mesh_Draw(numverts, numtriangles, elements);
1706 c_rt_lighttris += numtriangles;
1707 R_Mesh_Draw(numverts, numtriangles, elements);
1709 c_rt_lighttris += numtriangles;
1710 GL_LockArrays(0, 0);
1712 memset(&m, 0, sizeof(m));
1713 m.pointer_vertex = vertex3f;
1714 m.tex[0] = R_GetTexture(glosstexture);
1715 m.pointer_texcoord[0] = texcoord2f;
1716 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1718 m.pointer_texcoord3f[1] = vertex3f;
1719 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1721 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1722 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1727 // 2/0/0/2/2 2D combine blendsquare path
1728 memset(&m, 0, sizeof(m));
1729 m.pointer_vertex = vertex3f;
1730 m.tex[0] = R_GetTexture(bumptexture);
1731 m.pointer_texcoord[0] = texcoord2f;
1732 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1733 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1734 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1735 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1737 GL_ColorMask(0,0,0,1);
1738 // this squares the result
1739 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1740 GL_LockArrays(0, numverts);
1741 R_Mesh_Draw(numverts, numtriangles, elements);
1742 GL_LockArrays(0, 0);
1744 c_rt_lighttris += numtriangles;
1746 memset(&m, 0, sizeof(m));
1747 m.pointer_vertex = vertex3f;
1749 GL_LockArrays(0, numverts);
1750 // square alpha in framebuffer a few times to make it shiny
1751 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1752 // these comments are a test run through this math for intensity 0.5
1753 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1754 // 0.25 * 0.25 = 0.0625 (this is another pass)
1755 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1756 R_Mesh_Draw(numverts, numtriangles, elements);
1758 c_rt_lighttris += numtriangles;
1759 R_Mesh_Draw(numverts, numtriangles, elements);
1761 c_rt_lighttris += numtriangles;
1762 GL_LockArrays(0, 0);
1764 memset(&m, 0, sizeof(m));
1765 m.pointer_vertex = vertex3f;
1766 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1768 m.pointer_texcoord3f[0] = vertex3f;
1769 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1771 m.pointer_texcoord[0] = varray_texcoord2f[0];
1772 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1774 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1776 m.pointer_texcoord3f[1] = vertex3f;
1777 m.texmatrix[1] = *matrix_modeltoattenuationz;
1779 m.pointer_texcoord[1] = varray_texcoord2f[1];
1780 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1783 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1784 GL_LockArrays(0, numverts);
1785 R_Mesh_Draw(numverts, numtriangles, elements);
1786 GL_LockArrays(0, 0);
1788 c_rt_lighttris += numtriangles;
1790 memset(&m, 0, sizeof(m));
1791 m.pointer_vertex = vertex3f;
1792 m.tex[0] = R_GetTexture(glosstexture);
1793 m.pointer_texcoord[0] = texcoord2f;
1796 m.texcubemap[1] = R_GetTexture(lightcubemap);
1798 m.pointer_texcoord3f[1] = vertex3f;
1799 m.texmatrix[1] = *matrix_modeltolight;
1801 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1802 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1808 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1809 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1810 VectorScale(lightcolor, colorscale, color2);
1811 GL_LockArrays(0, numverts);
1812 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1814 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1815 R_Mesh_Draw(numverts, numtriangles, elements);
1817 c_rt_lighttris += numtriangles;
1819 GL_LockArrays(0, 0);
1824 if (lighting & LIGHTING_DIFFUSE)
1826 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1827 VectorScale(lightcolor, r_shadow_lightintensityscale.value, color2);
1828 memset(&m, 0, sizeof(m));
1829 m.pointer_vertex = vertex3f;
1830 m.pointer_color = varray_color4f;
1831 m.tex[0] = R_GetTexture(basetexture);
1832 m.pointer_texcoord[0] = texcoord2f;
1833 if (r_textureunits.integer >= 2)
1836 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1838 m.pointer_texcoord3f[1] = vertex3f;
1839 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1841 m.pointer_texcoord[1] = varray_texcoord2f[1];
1842 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1844 if (r_textureunits.integer >= 3)
1846 // Geforce3/Radeon class but not using dot3
1847 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1849 m.pointer_texcoord3f[2] = vertex3f;
1850 m.texmatrix[2] = *matrix_modeltoattenuationz;
1852 m.pointer_texcoord[2] = varray_texcoord2f[2];
1853 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationz);
1858 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1860 color[0] = bound(0, color2[0], 1);
1861 color[1] = bound(0, color2[1], 1);
1862 color[2] = bound(0, color2[2], 1);
1863 if (r_textureunits.integer >= 3)
1864 R_Shadow_VertexShading(numverts, vertex3f, normal3f, color, matrix_modeltolight);
1865 else if (r_textureunits.integer >= 2)
1866 R_Shadow_VertexShadingWithZAttenuation(numverts, vertex3f, normal3f, color, matrix_modeltolight);
1868 R_Shadow_VertexShadingWithXYZAttenuation(numverts, vertex3f, normal3f, color, matrix_modeltolight);
1869 GL_LockArrays(0, numverts);
1870 R_Mesh_Draw(numverts, numtriangles, elements);
1871 GL_LockArrays(0, 0);
1873 c_rt_lighttris += numtriangles;
1879 void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
1883 R_RTLight_Uncompile(rtlight);
1884 memset(rtlight, 0, sizeof(*rtlight));
1886 VectorCopy(light->origin, rtlight->shadoworigin);
1887 VectorCopy(light->color, rtlight->color);
1888 rtlight->radius = light->radius;
1889 //rtlight->cullradius = rtlight->radius;
1890 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
1891 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
1892 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
1893 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
1894 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
1895 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
1896 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
1897 rtlight->cubemapname[0] = 0;
1898 if (light->cubemapname[0])
1899 strcpy(rtlight->cubemapname, light->cubemapname);
1900 else if (light->cubemapnum > 0)
1901 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
1902 rtlight->shadow = light->shadow;
1903 rtlight->corona = light->corona;
1904 rtlight->style = light->style;
1905 rtlight->isstatic = isstatic;
1906 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
1907 // ConcatScale won't work here because this needs to scale rotate and
1908 // translate, not just rotate
1909 scale = 1.0f / rtlight->radius;
1910 for (k = 0;k < 3;k++)
1911 for (j = 0;j < 4;j++)
1912 rtlight->matrix_worldtolight.m[k][j] *= scale;
1913 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationxyz, &matrix_attenuationxyz, &rtlight->matrix_worldtolight);
1914 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationz, &matrix_attenuationz, &rtlight->matrix_worldtolight);
1916 rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
1917 rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
1918 VectorScale(rtlight->color, rtlight->radius * d_lightstylevalue[rtlight->style] * 0.125f, rtlight->lightmap_light);
1919 rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
1922 // compiles rtlight geometry
1923 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
1924 void R_RTLight_Compile(rtlight_t *rtlight)
1926 int shadowmeshes, shadowtris, lightmeshes, lighttris, numclusters, numsurfaces;
1927 entity_render_t *ent = &cl_entities[0].render;
1928 model_t *model = ent->model;
1930 // compile the light
1931 rtlight->compiled = true;
1932 rtlight->static_numclusters = 0;
1933 rtlight->static_numclusterpvsbytes = 0;
1934 rtlight->static_clusterlist = NULL;
1935 rtlight->static_clusterpvs = NULL;
1936 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
1937 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
1938 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
1939 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
1940 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
1941 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
1943 if (model && model->GetLightInfo)
1945 // this variable directs the DrawShadowVolume and DrawLight code to capture into the mesh chain instead of rendering
1946 r_shadow_compilingrtlight = rtlight;
1947 R_Shadow_EnlargeClusterBuffer(model->brush.num_pvsclusters);
1948 R_Shadow_EnlargeSurfaceBuffer(model->nummodelsurfaces);
1949 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);
1952 rtlight->static_numclusters = numclusters;
1953 rtlight->static_numclusterpvsbytes = (model->brush.num_pvsclusters + 7) >> 3;
1954 rtlight->static_clusterlist = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
1955 rtlight->static_clusterpvs = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusterpvsbytes);
1956 memcpy(rtlight->static_clusterlist, r_shadow_buffer_clusterlist, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
1957 memcpy(rtlight->static_clusterpvs, r_shadow_buffer_clusterpvs, rtlight->static_numclusterpvsbytes);
1959 if (model->DrawShadowVolume && rtlight->shadow)
1961 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
1962 model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
1963 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_shadow, false, false);
1965 if (model->DrawLight)
1967 rtlight->static_meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true);
1968 model->DrawLight(ent, rtlight->shadoworigin, vec3_origin, rtlight->radius, vec3_origin, &r_identitymatrix, &r_identitymatrix, &r_identitymatrix, NULL, numsurfaces, r_shadow_buffer_surfacelist);
1969 rtlight->static_meshchain_light = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_light, true, false);
1971 // switch back to rendering when DrawShadowVolume or DrawLight is called
1972 r_shadow_compilingrtlight = NULL;
1976 // use smallest available cullradius - box radius or light radius
1977 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
1978 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
1982 if (rtlight->static_meshchain_shadow)
1985 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
1988 shadowtris += mesh->numtriangles;
1994 if (rtlight->static_meshchain_light)
1997 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2000 lighttris += mesh->numtriangles;
2004 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);
2007 void R_RTLight_Uncompile(rtlight_t *rtlight)
2009 if (rtlight->compiled)
2011 if (rtlight->static_meshchain_shadow)
2012 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2013 rtlight->static_meshchain_shadow = NULL;
2014 if (rtlight->static_meshchain_light)
2015 Mod_ShadowMesh_Free(rtlight->static_meshchain_light);
2016 rtlight->static_meshchain_light = NULL;
2017 if (rtlight->static_clusterlist)
2018 Mem_Free(rtlight->static_clusterlist);
2019 rtlight->static_clusterlist = NULL;
2020 if (rtlight->static_clusterpvs)
2021 Mem_Free(rtlight->static_clusterpvs);
2022 rtlight->static_clusterpvs = NULL;
2023 rtlight->static_numclusters = 0;
2024 rtlight->static_numclusterpvsbytes = 0;
2025 rtlight->compiled = false;
2029 void R_Shadow_UncompileWorldLights(void)
2032 for (light = r_shadow_worldlightchain;light;light = light->next)
2033 R_RTLight_Uncompile(&light->rtlight);
2036 void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes)
2039 entity_render_t *ent;
2041 vec3_t relativelightorigin, relativeeyeorigin, lightcolor, lightcolor2;
2042 rtexture_t *cubemaptexture;
2043 matrix4x4_t matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz;
2044 int numclusters, numsurfaces;
2045 int *clusterlist, *surfacelist;
2047 vec3_t cullmins, cullmaxs;
2051 // loading is done before visibility checks because loading should happen
2052 // all at once at the start of a level, not when it stalls gameplay.
2053 // (especially important to benchmarks)
2054 if (rtlight->isstatic && !rtlight->compiled && r_shadow_staticworldlights.integer)
2055 R_RTLight_Compile(rtlight);
2056 if (rtlight->cubemapname[0])
2057 cubemaptexture = R_Shadow_Cubemap(rtlight->cubemapname);
2059 cubemaptexture = NULL;
2061 cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2062 cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2063 cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2064 cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2065 cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2066 cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2067 if (d_lightstylevalue[rtlight->style] <= 0)
2074 if (rtlight->compiled && r_shadow_staticworldlights.integer)
2076 // compiled light, world available and can receive realtime lighting
2077 // retrieve cluster information
2078 numclusters = rtlight->static_numclusters;
2079 clusterlist = rtlight->static_clusterlist;
2080 clusterpvs = rtlight->static_clusterpvs;
2081 VectorCopy(rtlight->cullmins, cullmins);
2082 VectorCopy(rtlight->cullmaxs, cullmaxs);
2084 else if (cl.worldmodel && cl.worldmodel->GetLightInfo)
2086 // dynamic light, world available and can receive realtime lighting
2087 // if the light box is offscreen, skip it right away
2088 if (R_CullBox(cullmins, cullmaxs))
2090 // calculate lit surfaces and clusters
2091 R_Shadow_EnlargeClusterBuffer(cl.worldmodel->brush.num_pvsclusters);
2092 R_Shadow_EnlargeSurfaceBuffer(cl.worldmodel->nummodelsurfaces);
2093 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);
2094 clusterlist = r_shadow_buffer_clusterlist;
2095 clusterpvs = r_shadow_buffer_clusterpvs;
2096 surfacelist = r_shadow_buffer_surfacelist;
2098 // if the reduced cluster bounds are offscreen, skip it
2099 if (R_CullBox(cullmins, cullmaxs))
2101 // check if light is illuminating any visible clusters
2104 for (i = 0;i < numclusters;i++)
2105 if (CHECKPVSBIT(r_pvsbits, clusterlist[i]))
2107 if (i == numclusters)
2110 // set up a scissor rectangle for this light
2111 if (R_Shadow_ScissorForBBox(cullmins, cullmaxs))
2114 f = d_lightstylevalue[rtlight->style] * (1.0f / 256.0f);
2115 VectorScale(rtlight->color, f, lightcolor);
2117 if (rtlight->selected)
2119 f = 2 + sin(realtime * M_PI * 4.0);
2120 VectorScale(lightcolor, f, lightcolor);
2124 shadow = rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows);
2126 if (shadow && (gl_stencil || visiblevolumes))
2128 if (!visiblevolumes)
2129 R_Shadow_Stage_ShadowVolumes();
2130 ent = &cl_entities[0].render;
2131 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2133 memset(&m, 0, sizeof(m));
2134 R_Mesh_Matrix(&ent->matrix);
2135 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2137 m.pointer_vertex = mesh->vertex3f;
2139 GL_LockArrays(0, mesh->numverts);
2140 if (r_shadowstage == SHADOWSTAGE_STENCIL)
2142 // decrement stencil if frontface is behind depthbuffer
2143 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2144 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2145 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2146 c_rtcached_shadowmeshes++;
2147 c_rtcached_shadowtris += mesh->numtriangles;
2148 // increment stencil if backface is behind depthbuffer
2149 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2150 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2152 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2153 c_rtcached_shadowmeshes++;
2154 c_rtcached_shadowtris += mesh->numtriangles;
2155 GL_LockArrays(0, 0);
2160 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2161 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, numsurfaces, surfacelist);
2163 if (r_drawentities.integer)
2165 for (i = 0;i < r_refdef.numentities;i++)
2167 ent = r_refdef.entities[i];
2169 if (r_shadow_cull.integer)
2171 if (!BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs))
2173 if (cl.worldmodel != NULL && cl.worldmodel->brush.BoxTouchingPVS != NULL && !cl.worldmodel->brush.BoxTouchingPVS(cl.worldmodel, clusterpvs, ent->mins, ent->maxs))
2176 if (!(ent->flags & RENDER_SHADOW) || !ent->model || !ent->model->DrawShadowVolume)
2178 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2179 // light emitting entities should not cast their own shadow
2180 if (VectorLength2(relativelightorigin) < 0.1)
2182 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, ent->model->nummodelsurfaces, ent->model->surfacelist);
2187 if (!visiblevolumes)
2189 R_Shadow_Stage_Light(shadow && gl_stencil);
2191 ent = &cl_entities[0].render;
2192 if (ent->model && ent->model->DrawLight && (ent->flags & RENDER_LIGHT))
2194 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2195 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2196 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2197 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2198 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2199 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2201 R_Mesh_Matrix(&ent->matrix);
2202 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2203 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);
2206 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, numsurfaces, surfacelist);
2208 if (r_drawentities.integer)
2210 for (i = 0;i < r_refdef.numentities;i++)
2212 ent = r_refdef.entities[i];
2213 // can't draw transparent entity lighting here because
2214 // transparent meshes are deferred for later
2215 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)
2217 VectorScale(lightcolor, ent->alpha, lightcolor2);
2218 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2219 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2220 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2221 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2222 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2223 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor2, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, ent->model->nummodelsurfaces, ent->model->surfacelist);
2230 void R_ShadowVolumeLighting(int visiblevolumes)
2236 if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2237 R_Shadow_EditLights_Reload_f();
2241 memset(&m, 0, sizeof(m));
2244 GL_BlendFunc(GL_ONE, GL_ONE);
2245 GL_DepthMask(false);
2246 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
2247 qglDisable(GL_CULL_FACE);
2248 GL_Color(0.0, 0.0125, 0.1, 1);
2251 R_Shadow_Stage_Begin();
2254 if (r_shadow_debuglight.integer >= 0)
2256 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2257 if (lnum == r_shadow_debuglight.integer)
2258 R_DrawRTLight(&light->rtlight, visiblevolumes);
2261 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2262 R_DrawRTLight(&light->rtlight, visiblevolumes);
2265 for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
2266 R_DrawRTLight(&light->rtlight, visiblevolumes);
2270 qglEnable(GL_CULL_FACE);
2271 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
2274 R_Shadow_Stage_End();
2277 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2278 typedef struct suffixinfo_s
2281 qboolean flipx, flipy, flipdiagonal;
2284 static suffixinfo_t suffix[3][6] =
2287 {"px", false, false, false},
2288 {"nx", false, false, false},
2289 {"py", false, false, false},
2290 {"ny", false, false, false},
2291 {"pz", false, false, false},
2292 {"nz", false, false, false}
2295 {"posx", false, false, false},
2296 {"negx", false, false, false},
2297 {"posy", false, false, false},
2298 {"negy", false, false, false},
2299 {"posz", false, false, false},
2300 {"negz", false, false, false}
2303 {"rt", true, false, true},
2304 {"lf", false, true, true},
2305 {"ft", true, true, false},
2306 {"bk", false, false, false},
2307 {"up", true, false, true},
2308 {"dn", true, false, true}
2312 static int componentorder[4] = {0, 1, 2, 3};
2314 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2316 int i, j, cubemapsize;
2317 qbyte *cubemappixels, *image_rgba;
2318 rtexture_t *cubemaptexture;
2320 // must start 0 so the first loadimagepixels has no requested width/height
2322 cubemappixels = NULL;
2323 cubemaptexture = NULL;
2324 // keep trying different suffix groups (posx, px, rt) until one loads
2325 for (j = 0;j < 3 && !cubemappixels;j++)
2327 // load the 6 images in the suffix group
2328 for (i = 0;i < 6;i++)
2330 // generate an image name based on the base and and suffix
2331 snprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2333 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2335 // an image loaded, make sure width and height are equal
2336 if (image_width == image_height)
2338 // if this is the first image to load successfully, allocate the cubemap memory
2339 if (!cubemappixels && image_width >= 1)
2341 cubemapsize = image_width;
2342 // note this clears to black, so unavailable sides are black
2343 cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2345 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2347 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);
2350 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2352 Mem_Free(image_rgba);
2356 // if a cubemap loaded, upload it
2359 if (!r_shadow_filters_texturepool)
2360 r_shadow_filters_texturepool = R_AllocTexturePool();
2361 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
2362 Mem_Free(cubemappixels);
2366 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
2367 for (j = 0;j < 3;j++)
2368 for (i = 0;i < 6;i++)
2369 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2370 Con_Print(" and was unable to find any of them.\n");
2372 return cubemaptexture;
2375 rtexture_t *R_Shadow_Cubemap(const char *basename)
2378 for (i = 0;i < numcubemaps;i++)
2379 if (!strcasecmp(cubemaps[i].basename, basename))
2380 return cubemaps[i].texture;
2381 if (i >= MAX_CUBEMAPS)
2384 strcpy(cubemaps[i].basename, basename);
2385 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
2386 return cubemaps[i].texture;
2389 void R_Shadow_FreeCubemaps(void)
2392 R_FreeTexturePool(&r_shadow_filters_texturepool);
2395 dlight_t *R_Shadow_NewWorldLight(void)
2398 light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
2399 light->next = r_shadow_worldlightchain;
2400 r_shadow_worldlightchain = light;
2404 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)
2406 VectorCopy(origin, light->origin);
2407 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
2408 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
2409 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
2410 light->color[0] = max(color[0], 0);
2411 light->color[1] = max(color[1], 0);
2412 light->color[2] = max(color[2], 0);
2413 light->radius = max(radius, 0);
2414 light->style = style;
2415 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
2417 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
2420 light->shadow = shadowenable;
2421 light->corona = corona;
2424 strlcpy(light->cubemapname, cubemapname, strlen(light->cubemapname));
2425 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
2427 R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
2430 void R_Shadow_FreeWorldLight(dlight_t *light)
2432 dlight_t **lightpointer;
2433 R_RTLight_Uncompile(&light->rtlight);
2434 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
2435 if (*lightpointer != light)
2436 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
2437 *lightpointer = light->next;
2441 void R_Shadow_ClearWorldLights(void)
2443 while (r_shadow_worldlightchain)
2444 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
2445 r_shadow_selectedlight = NULL;
2446 R_Shadow_FreeCubemaps();
2449 void R_Shadow_SelectLight(dlight_t *light)
2451 if (r_shadow_selectedlight)
2452 r_shadow_selectedlight->selected = false;
2453 r_shadow_selectedlight = light;
2454 if (r_shadow_selectedlight)
2455 r_shadow_selectedlight->selected = true;
2458 void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
2460 float scale = r_editlights_cursorgrid.value * 0.5f;
2461 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);
2464 void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
2467 const dlight_t *light;
2470 if (light->selected)
2471 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
2474 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);
2477 void R_Shadow_DrawLightSprites(void)
2483 for (i = 0;i < 5;i++)
2485 lighttextures[i] = NULL;
2486 if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1))))
2487 lighttextures[i] = pic->tex;
2490 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
2491 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, i % 5);
2492 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
2495 void R_Shadow_SelectLightInView(void)
2497 float bestrating, rating, temp[3];
2498 dlight_t *best, *light;
2501 for (light = r_shadow_worldlightchain;light;light = light->next)
2503 VectorSubtract(light->origin, r_vieworigin, temp);
2504 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
2507 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
2508 if (bestrating < rating && CL_TraceLine(light->origin, r_vieworigin, NULL, NULL, true, NULL, SUPERCONTENTS_SOLID) == 1.0f)
2510 bestrating = rating;
2515 R_Shadow_SelectLight(best);
2518 void R_Shadow_LoadWorldLights(void)
2520 int n, a, style, shadow;
2521 char name[MAX_QPATH], cubemapname[MAX_QPATH], *lightsstring, *s, *t;
2522 float origin[3], radius, color[3], angles[3], corona;
2523 if (cl.worldmodel == NULL)
2525 Con_Print("No map loaded.\n");
2528 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2529 strlcat (name, ".rtlights", sizeof (name));
2530 lightsstring = FS_LoadFile(name, tempmempool, false);
2540 for (;COM_Parse(t, true) && strcmp(
2541 if (COM_Parse(t, true))
2543 if (com_token[0] == '!')
2546 origin[0] = atof(com_token+1);
2549 origin[0] = atof(com_token);
2554 while (*s && *s != '\n')
2560 // check for modifier flags
2566 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]);
2568 VectorClear(angles);
2571 if (a < 9 || !strcmp(cubemapname, "\"\""))
2576 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);
2579 VectorScale(color, r_editlights_rtlightscolorscale.value, color);
2580 radius *= r_editlights_rtlightssizescale.value;
2581 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname);
2586 Con_Printf("invalid rtlights file \"%s\"\n", name);
2587 Mem_Free(lightsstring);
2591 void R_Shadow_SaveWorldLights(void)
2594 int bufchars, bufmaxchars;
2596 char name[MAX_QPATH];
2598 if (!r_shadow_worldlightchain)
2600 if (cl.worldmodel == NULL)
2602 Con_Print("No map loaded.\n");
2605 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2606 strlcat (name, ".rtlights", sizeof (name));
2607 bufchars = bufmaxchars = 0;
2609 for (light = r_shadow_worldlightchain;light;light = light->next)
2611 if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
2612 sprintf(line, "%s%f %f %f %f %f %f %f %d \"%s\" %f %f %f %f\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius / r_editlights_rtlightssizescale.value, light->color[0] / r_editlights_rtlightscolorscale.value, light->color[1] / r_editlights_rtlightscolorscale.value, light->color[2] / r_editlights_rtlightscolorscale.value, light->style, light->cubemapname, light->corona, light->angles[0], light->angles[1], light->angles[2]);
2614 sprintf(line, "%s%f %f %f %f %f %f %f %d\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius / r_editlights_rtlightssizescale.value, light->color[0] / r_editlights_rtlightscolorscale.value, light->color[1] / r_editlights_rtlightscolorscale.value, light->color[2] / r_editlights_rtlightscolorscale.value, light->style);
2615 if (bufchars + (int) strlen(line) > bufmaxchars)
2617 bufmaxchars = bufchars + strlen(line) + 2048;
2619 buf = Mem_Alloc(r_shadow_mempool, bufmaxchars);
2623 memcpy(buf, oldbuf, bufchars);
2629 memcpy(buf + bufchars, line, strlen(line));
2630 bufchars += strlen(line);
2634 FS_WriteFile(name, buf, bufchars);
2639 void R_Shadow_LoadLightsFile(void)
2642 char name[MAX_QPATH], *lightsstring, *s, *t;
2643 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
2644 if (cl.worldmodel == NULL)
2646 Con_Print("No map loaded.\n");
2649 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2650 strlcat (name, ".lights", sizeof (name));
2651 lightsstring = FS_LoadFile(name, tempmempool, false);
2659 while (*s && *s != '\n')
2664 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);
2668 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);
2671 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
2672 radius = bound(15, radius, 4096);
2673 VectorScale(color, (2.0f / (8388608.0f)), color);
2674 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL);
2679 Con_Printf("invalid lights file \"%s\"\n", name);
2680 Mem_Free(lightsstring);
2684 // tyrlite/hmap2 light types in the delay field
2685 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
2687 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
2689 int entnum, style, islight, skin, pflags, effects, type, n;
2690 char key[256], value[1024];
2691 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
2694 if (cl.worldmodel == NULL)
2696 Con_Print("No map loaded.\n");
2699 data = cl.worldmodel->brush.entities;
2702 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
2704 type = LIGHTTYPE_MINUSX;
2705 origin[0] = origin[1] = origin[2] = 0;
2706 originhack[0] = originhack[1] = originhack[2] = 0;
2707 angles[0] = angles[1] = angles[2] = 0;
2708 color[0] = color[1] = color[2] = 1;
2709 light[0] = light[1] = light[2] = 1;light[3] = 300;
2710 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
2720 if (!COM_ParseToken(&data, false))
2722 if (com_token[0] == '}')
2723 break; // end of entity
2724 if (com_token[0] == '_')
2725 strcpy(key, com_token + 1);
2727 strcpy(key, com_token);
2728 while (key[strlen(key)-1] == ' ') // remove trailing spaces
2729 key[strlen(key)-1] = 0;
2730 if (!COM_ParseToken(&data, false))
2732 strcpy(value, com_token);
2734 // now that we have the key pair worked out...
2735 if (!strcmp("light", key))
2737 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
2741 light[0] = vec[0] * (1.0f / 256.0f);
2742 light[1] = vec[0] * (1.0f / 256.0f);
2743 light[2] = vec[0] * (1.0f / 256.0f);
2749 light[0] = vec[0] * (1.0f / 255.0f);
2750 light[1] = vec[1] * (1.0f / 255.0f);
2751 light[2] = vec[2] * (1.0f / 255.0f);
2755 else if (!strcmp("delay", key))
2757 else if (!strcmp("origin", key))
2758 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
2759 else if (!strcmp("angle", key))
2760 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
2761 else if (!strcmp("angles", key))
2762 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
2763 else if (!strcmp("color", key))
2764 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
2765 else if (!strcmp("wait", key))
2766 fadescale = atof(value);
2767 else if (!strcmp("classname", key))
2769 if (!strncmp(value, "light", 5))
2772 if (!strcmp(value, "light_fluoro"))
2777 overridecolor[0] = 1;
2778 overridecolor[1] = 1;
2779 overridecolor[2] = 1;
2781 if (!strcmp(value, "light_fluorospark"))
2786 overridecolor[0] = 1;
2787 overridecolor[1] = 1;
2788 overridecolor[2] = 1;
2790 if (!strcmp(value, "light_globe"))
2795 overridecolor[0] = 1;
2796 overridecolor[1] = 0.8;
2797 overridecolor[2] = 0.4;
2799 if (!strcmp(value, "light_flame_large_yellow"))
2804 overridecolor[0] = 1;
2805 overridecolor[1] = 0.5;
2806 overridecolor[2] = 0.1;
2808 if (!strcmp(value, "light_flame_small_yellow"))
2813 overridecolor[0] = 1;
2814 overridecolor[1] = 0.5;
2815 overridecolor[2] = 0.1;
2817 if (!strcmp(value, "light_torch_small_white"))
2822 overridecolor[0] = 1;
2823 overridecolor[1] = 0.5;
2824 overridecolor[2] = 0.1;
2826 if (!strcmp(value, "light_torch_small_walltorch"))
2831 overridecolor[0] = 1;
2832 overridecolor[1] = 0.5;
2833 overridecolor[2] = 0.1;
2837 else if (!strcmp("style", key))
2838 style = atoi(value);
2839 else if (cl.worldmodel->type == mod_brushq3)
2841 if (!strcmp("scale", key))
2842 lightscale = atof(value);
2843 if (!strcmp("fade", key))
2844 fadescale = atof(value);
2846 else if (!strcmp("skin", key))
2847 skin = (int)atof(value);
2848 else if (!strcmp("pflags", key))
2849 pflags = (int)atof(value);
2850 else if (!strcmp("effects", key))
2851 effects = (int)atof(value);
2855 if (lightscale <= 0)
2859 if (color[0] == color[1] && color[0] == color[2])
2861 color[0] *= overridecolor[0];
2862 color[1] *= overridecolor[1];
2863 color[2] *= overridecolor[2];
2865 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
2866 color[0] = color[0] * light[0];
2867 color[1] = color[1] * light[1];
2868 color[2] = color[2] * light[2];
2871 case LIGHTTYPE_MINUSX:
2873 case LIGHTTYPE_RECIPX:
2875 VectorScale(color, (1.0f / 16.0f), color);
2877 case LIGHTTYPE_RECIPXX:
2879 VectorScale(color, (1.0f / 16.0f), color);
2882 case LIGHTTYPE_NONE:
2886 case LIGHTTYPE_MINUSXX:
2889 VectorAdd(origin, originhack, origin);
2891 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);
2896 void R_Shadow_SetCursorLocationForView(void)
2898 vec_t dist, push, frac;
2899 vec3_t dest, endpos, normal;
2900 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
2901 frac = CL_TraceLine(r_vieworigin, dest, endpos, normal, true, NULL, SUPERCONTENTS_SOLID);
2904 dist = frac * r_editlights_cursordistance.value;
2905 push = r_editlights_cursorpushback.value;
2909 VectorMA(endpos, push, r_viewforward, endpos);
2910 VectorMA(endpos, r_editlights_cursorpushoff.value, normal, endpos);
2912 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2913 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2914 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2917 void R_Shadow_UpdateWorldLightSelection(void)
2919 if (r_editlights.integer)
2921 R_Shadow_SetCursorLocationForView();
2922 R_Shadow_SelectLightInView();
2923 R_Shadow_DrawLightSprites();
2926 R_Shadow_SelectLight(NULL);
2929 void R_Shadow_EditLights_Clear_f(void)
2931 R_Shadow_ClearWorldLights();
2934 void R_Shadow_EditLights_Reload_f(void)
2938 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
2939 R_Shadow_ClearWorldLights();
2940 R_Shadow_LoadWorldLights();
2941 if (r_shadow_worldlightchain == NULL)
2943 R_Shadow_LoadLightsFile();
2944 if (r_shadow_worldlightchain == NULL)
2945 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
2949 void R_Shadow_EditLights_Save_f(void)
2953 R_Shadow_SaveWorldLights();
2956 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
2958 R_Shadow_ClearWorldLights();
2959 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
2962 void R_Shadow_EditLights_ImportLightsFile_f(void)
2964 R_Shadow_ClearWorldLights();
2965 R_Shadow_LoadLightsFile();
2968 void R_Shadow_EditLights_Spawn_f(void)
2971 if (!r_editlights.integer)
2973 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
2976 if (Cmd_Argc() != 1)
2978 Con_Print("r_editlights_spawn does not take parameters\n");
2981 color[0] = color[1] = color[2] = 1;
2982 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL);
2985 void R_Shadow_EditLights_Edit_f(void)
2987 vec3_t origin, angles, color;
2988 vec_t radius, corona;
2990 char cubemapname[1024];
2991 if (!r_editlights.integer)
2993 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
2996 if (!r_shadow_selectedlight)
2998 Con_Print("No selected light.\n");
3001 VectorCopy(r_shadow_selectedlight->origin, origin);
3002 VectorCopy(r_shadow_selectedlight->angles, angles);
3003 VectorCopy(r_shadow_selectedlight->color, color);
3004 radius = r_shadow_selectedlight->radius;
3005 style = r_shadow_selectedlight->style;
3006 if (r_shadow_selectedlight->cubemapname)
3007 strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
3010 shadows = r_shadow_selectedlight->shadow;
3011 corona = r_shadow_selectedlight->corona;
3012 if (!strcmp(Cmd_Argv(1), "origin"))
3014 if (Cmd_Argc() != 5)
3016 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3019 origin[0] = atof(Cmd_Argv(2));
3020 origin[1] = atof(Cmd_Argv(3));
3021 origin[2] = atof(Cmd_Argv(4));
3023 else if (!strcmp(Cmd_Argv(1), "originx"))
3025 if (Cmd_Argc() != 3)
3027 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3030 origin[0] = atof(Cmd_Argv(2));
3032 else if (!strcmp(Cmd_Argv(1), "originy"))
3034 if (Cmd_Argc() != 3)
3036 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3039 origin[1] = atof(Cmd_Argv(2));
3041 else if (!strcmp(Cmd_Argv(1), "originz"))
3043 if (Cmd_Argc() != 3)
3045 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3048 origin[2] = atof(Cmd_Argv(2));
3050 else if (!strcmp(Cmd_Argv(1), "move"))
3052 if (Cmd_Argc() != 5)
3054 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3057 origin[0] += atof(Cmd_Argv(2));
3058 origin[1] += atof(Cmd_Argv(3));
3059 origin[2] += atof(Cmd_Argv(4));
3061 else if (!strcmp(Cmd_Argv(1), "movex"))
3063 if (Cmd_Argc() != 3)
3065 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3068 origin[0] += atof(Cmd_Argv(2));
3070 else if (!strcmp(Cmd_Argv(1), "movey"))
3072 if (Cmd_Argc() != 3)
3074 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3077 origin[1] += atof(Cmd_Argv(2));
3079 else if (!strcmp(Cmd_Argv(1), "movez"))
3081 if (Cmd_Argc() != 3)
3083 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3086 origin[2] += atof(Cmd_Argv(2));
3088 else if (!strcmp(Cmd_Argv(1), "angles"))
3090 if (Cmd_Argc() != 5)
3092 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3095 angles[0] = atof(Cmd_Argv(2));
3096 angles[1] = atof(Cmd_Argv(3));
3097 angles[2] = atof(Cmd_Argv(4));
3099 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3101 if (Cmd_Argc() != 3)
3103 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3106 angles[0] = atof(Cmd_Argv(2));
3108 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3110 if (Cmd_Argc() != 3)
3112 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3115 angles[1] = atof(Cmd_Argv(2));
3117 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3119 if (Cmd_Argc() != 3)
3121 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3124 angles[2] = atof(Cmd_Argv(2));
3126 else if (!strcmp(Cmd_Argv(1), "color"))
3128 if (Cmd_Argc() != 5)
3130 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3133 color[0] = atof(Cmd_Argv(2));
3134 color[1] = atof(Cmd_Argv(3));
3135 color[2] = atof(Cmd_Argv(4));
3137 else if (!strcmp(Cmd_Argv(1), "radius"))
3139 if (Cmd_Argc() != 3)
3141 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3144 radius = atof(Cmd_Argv(2));
3146 else if (!strcmp(Cmd_Argv(1), "style"))
3148 if (Cmd_Argc() != 3)
3150 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3153 style = atoi(Cmd_Argv(2));
3155 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3159 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3162 if (Cmd_Argc() == 3)
3163 strcpy(cubemapname, Cmd_Argv(2));
3167 else if (!strcmp(Cmd_Argv(1), "shadows"))
3169 if (Cmd_Argc() != 3)
3171 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3174 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3176 else if (!strcmp(Cmd_Argv(1), "corona"))
3178 if (Cmd_Argc() != 3)
3180 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3183 corona = atof(Cmd_Argv(2));
3187 Con_Print("usage: r_editlights_edit [property] [value]\n");
3188 Con_Print("Selected light's properties:\n");
3189 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3190 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3191 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3192 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3193 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3194 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3195 Con_Printf("Shadows: %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3196 Con_Printf("Cubemap: %s\n", r_shadow_selectedlight->cubemapname);
3199 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname);
3202 void R_Shadow_EditLights_EditAll_f(void)
3206 if (!r_editlights.integer)
3208 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
3212 for (light = r_shadow_worldlightchain;light;light = light->next)
3214 R_Shadow_SelectLight(light);
3215 R_Shadow_EditLights_Edit_f();
3219 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3223 if (!r_editlights.integer)
3227 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;
3228 if (r_shadow_selectedlight == NULL)
3230 sprintf(temp, "Light properties");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3231 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;
3232 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;
3233 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;
3234 sprintf(temp, "Radius %f", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3235 sprintf(temp, "Corona %f", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3236 sprintf(temp, "Style %i", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3237 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;
3238 sprintf(temp, "Cubemap %s", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3241 void R_Shadow_EditLights_ToggleShadow_f(void)
3243 if (!r_editlights.integer)
3245 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3248 if (!r_shadow_selectedlight)
3250 Con_Print("No selected light.\n");
3253 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);
3256 void R_Shadow_EditLights_ToggleCorona_f(void)
3258 if (!r_editlights.integer)
3260 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3263 if (!r_shadow_selectedlight)
3265 Con_Print("No selected light.\n");
3268 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);
3271 void R_Shadow_EditLights_Remove_f(void)
3273 if (!r_editlights.integer)
3275 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
3278 if (!r_shadow_selectedlight)
3280 Con_Print("No selected light.\n");
3283 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3284 r_shadow_selectedlight = NULL;
3287 void R_Shadow_EditLights_Help_f(void)
3290 "Documentation on r_editlights system:\n"
3292 "r_editlights : enable/disable editing mode\n"
3293 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
3294 "r_editlights_cursorpushback : push back cursor this far from surface\n"
3295 "r_editlights_cursorpushoff : push cursor off surface this far\n"
3296 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
3297 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
3298 "r_editlights_rtlightssizescale : imported rtlight size scaling\n"
3299 "r_editlights_rtlightscolorscale : imported rtlight color scaling\n"
3301 "r_editlights_help : this help\n"
3302 "r_editlights_clear : remove all lights\n"
3303 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
3304 "r_editlights_save : save to .rtlights file\n"
3305 "r_editlights_spawn : create a light with default settings\n"
3306 "r_editlights_edit command : edit selected light - more documentation below\n"
3307 "r_editlights_remove : remove selected light\n"
3308 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
3309 "r_editlights_importlightentitiesfrommap : reload light entities\n"
3310 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
3312 "origin x y z : set light location\n"
3313 "originx x: set x component of light location\n"
3314 "originy y: set y component of light location\n"
3315 "originz z: set z component of light location\n"
3316 "move x y z : adjust light location\n"
3317 "movex x: adjust x component of light location\n"
3318 "movey y: adjust y component of light location\n"
3319 "movez z: adjust z component of light location\n"
3320 "angles x y z : set light angles\n"
3321 "anglesx x: set x component of light angles\n"
3322 "anglesy y: set y component of light angles\n"
3323 "anglesz z: set z component of light angles\n"
3324 "color r g b : set color of light (can be brighter than 1 1 1)\n"
3325 "radius radius : set radius (size) of light\n"
3326 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
3327 "cubemap basename : set filter cubemap of light (not yet supported)\n"
3328 "shadows 1/0 : turn on/off shadows\n"
3329 "corona n : set corona intensity\n"
3330 "<nothing> : print light properties to console\n"
3334 void R_Shadow_EditLights_CopyInfo_f(void)
3336 if (!r_editlights.integer)
3338 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
3341 if (!r_shadow_selectedlight)
3343 Con_Print("No selected light.\n");
3346 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
3347 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
3348 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
3349 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
3350 if (r_shadow_selectedlight->cubemapname)
3351 strcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname);
3353 r_shadow_bufferlight.cubemapname[0] = 0;
3354 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
3355 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
3358 void R_Shadow_EditLights_PasteInfo_f(void)
3360 if (!r_editlights.integer)
3362 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
3365 if (!r_shadow_selectedlight)
3367 Con_Print("No selected light.\n");
3370 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);
3373 void R_Shadow_EditLights_Init(void)
3375 Cvar_RegisterVariable(&r_editlights);
3376 Cvar_RegisterVariable(&r_editlights_cursordistance);
3377 Cvar_RegisterVariable(&r_editlights_cursorpushback);
3378 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
3379 Cvar_RegisterVariable(&r_editlights_cursorgrid);
3380 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
3381 Cvar_RegisterVariable(&r_editlights_rtlightssizescale);
3382 Cvar_RegisterVariable(&r_editlights_rtlightscolorscale);
3383 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
3384 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
3385 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
3386 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
3387 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
3388 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
3389 Cmd_AddCommand("r_editlights_editall", R_Shadow_EditLights_EditAll_f);
3390 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
3391 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
3392 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
3393 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
3394 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);
3395 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f);
3396 Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f);