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 GLhandleARB r_shadow_program_light_diffusegloss = 0;
230 GLhandleARB r_shadow_program_light_diffuse = 0;
231 GLhandleARB r_shadow_program_light_gloss = 0;
233 void R_Shadow_UncompileWorldLights(void);
234 void R_Shadow_ClearWorldLights(void);
235 void R_Shadow_SaveWorldLights(void);
236 void R_Shadow_LoadWorldLights(void);
237 void R_Shadow_LoadLightsFile(void);
238 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
239 void R_Shadow_EditLights_Reload_f(void);
240 void R_Shadow_ValidateCvars(void);
241 static void R_Shadow_MakeTextures(void);
242 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light);
244 // beginnings of GL_ARB_shaders support, not done yet
245 GLhandleARB GL_Backend_LoadProgram(const char *vertexshaderfilename, const char *fragmentshaderfilename)
250 void GL_Backend_FreeProgram(GLhandleARB prog)
254 void r_shadow_start(void)
256 // allocate vertex processing arrays
258 r_shadow_normalcubetexture = NULL;
259 r_shadow_attenuation2dtexture = NULL;
260 r_shadow_attenuation3dtexture = NULL;
261 r_shadow_blankbumptexture = NULL;
262 r_shadow_blankglosstexture = NULL;
263 r_shadow_blankwhitetexture = NULL;
264 r_shadow_texturepool = NULL;
265 r_shadow_filters_texturepool = NULL;
266 R_Shadow_ValidateCvars();
267 R_Shadow_MakeTextures();
268 maxshadowelements = 0;
269 shadowelements = NULL;
277 shadowmarklist = NULL;
279 r_shadow_buffer_numclusterpvsbytes = 0;
280 r_shadow_buffer_clusterpvs = NULL;
281 r_shadow_buffer_clusterlist = NULL;
282 r_shadow_buffer_numsurfacepvsbytes = 0;
283 r_shadow_buffer_surfacepvs = NULL;
284 r_shadow_buffer_surfacelist = NULL;
285 if (gl_support_fragment_shader)
287 r_shadow_program_light_diffusegloss = GL_Backend_LoadProgram("glsl/diffusegloss.vert", "glsl/diffusegloss.frag");
288 r_shadow_program_light_diffuse = GL_Backend_LoadProgram("glsl/diffuse.vert", "glsl/diffuse.frag");
289 r_shadow_program_light_gloss = GL_Backend_LoadProgram("glsl/gloss.vert", "glsl/gloss.frag");
293 void r_shadow_shutdown(void)
295 R_Shadow_UncompileWorldLights();
296 GL_Backend_FreeProgram(r_shadow_program_light_diffusegloss);
297 r_shadow_program_light_diffusegloss = 0;
298 GL_Backend_FreeProgram(r_shadow_program_light_diffuse);
299 r_shadow_program_light_diffuse = 0;
300 GL_Backend_FreeProgram(r_shadow_program_light_gloss);
301 r_shadow_program_light_gloss = 0;
303 r_shadow_normalcubetexture = NULL;
304 r_shadow_attenuation2dtexture = NULL;
305 r_shadow_attenuation3dtexture = NULL;
306 r_shadow_blankbumptexture = NULL;
307 r_shadow_blankglosstexture = NULL;
308 r_shadow_blankwhitetexture = NULL;
309 R_FreeTexturePool(&r_shadow_texturepool);
310 R_FreeTexturePool(&r_shadow_filters_texturepool);
311 maxshadowelements = 0;
313 Mem_Free(shadowelements);
314 shadowelements = NULL;
317 Mem_Free(vertexupdate);
320 Mem_Free(vertexremap);
326 Mem_Free(shadowmark);
329 Mem_Free(shadowmarklist);
330 shadowmarklist = NULL;
332 r_shadow_buffer_numclusterpvsbytes = 0;
333 if (r_shadow_buffer_clusterpvs)
334 Mem_Free(r_shadow_buffer_clusterpvs);
335 r_shadow_buffer_clusterpvs = NULL;
336 if (r_shadow_buffer_clusterlist)
337 Mem_Free(r_shadow_buffer_clusterlist);
338 r_shadow_buffer_clusterlist = NULL;
339 r_shadow_buffer_numsurfacepvsbytes = 0;
340 if (r_shadow_buffer_surfacepvs)
341 Mem_Free(r_shadow_buffer_surfacepvs);
342 r_shadow_buffer_surfacepvs = NULL;
343 if (r_shadow_buffer_surfacelist)
344 Mem_Free(r_shadow_buffer_surfacelist);
345 r_shadow_buffer_surfacelist = NULL;
348 void r_shadow_newmap(void)
352 void R_Shadow_Help_f(void)
355 "Documentation on r_shadow system:\n"
357 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
358 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
359 "r_shadow_debuglight : render only this light number (-1 = all)\n"
360 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
361 "r_shadow_gloss2intensity : brightness of forced gloss\n"
362 "r_shadow_glossintensity : brightness of textured gloss\n"
363 "r_shadow_lightattenuationpower : used to generate attenuation texture\n"
364 "r_shadow_lightattenuationscale : used to generate attenuation texture\n"
365 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
366 "r_shadow_portallight : use portal visibility for static light precomputation\n"
367 "r_shadow_projectdistance : shadow volume projection distance\n"
368 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
369 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
370 "r_shadow_realtime_world : use high quality world lighting mode\n"
371 "r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n"
372 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
373 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
374 "r_shadow_scissor : use scissor optimization\n"
375 "r_shadow_shadow_polygonfactor : nudge shadow volumes closer/further\n"
376 "r_shadow_shadow_polygonoffset : nudge shadow volumes closer/further\n"
377 "r_shadow_singlepassvolumegeneration : selects shadow volume algorithm\n"
378 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
379 "r_shadow_visiblevolumes : useful for performance testing; bright = slow!\n"
381 "r_shadow_help : this help\n"
385 void R_Shadow_Init(void)
387 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
388 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
389 Cvar_RegisterVariable(&r_shadow_cull);
390 Cvar_RegisterVariable(&r_shadow_debuglight);
391 Cvar_RegisterVariable(&r_shadow_gloss);
392 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
393 Cvar_RegisterVariable(&r_shadow_glossintensity);
394 Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
395 Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
396 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
397 Cvar_RegisterVariable(&r_shadow_portallight);
398 Cvar_RegisterVariable(&r_shadow_projectdistance);
399 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
400 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
401 Cvar_RegisterVariable(&r_shadow_realtime_world);
402 Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows);
403 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
404 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
405 Cvar_RegisterVariable(&r_shadow_scissor);
406 Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor);
407 Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset);
408 Cvar_RegisterVariable(&r_shadow_singlepassvolumegeneration);
409 Cvar_RegisterVariable(&r_shadow_staticworldlights);
410 Cvar_RegisterVariable(&r_shadow_texture3d);
411 Cvar_RegisterVariable(&r_shadow_visiblevolumes);
412 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
413 if (gamemode == GAME_TENEBRAE)
415 Cvar_SetValue("r_shadow_gloss", 2);
416 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
418 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f);
419 R_Shadow_EditLights_Init();
420 r_shadow_mempool = Mem_AllocPool("R_Shadow", 0, NULL);
421 r_shadow_worldlightchain = NULL;
422 maxshadowelements = 0;
423 shadowelements = NULL;
431 shadowmarklist = NULL;
433 r_shadow_buffer_numclusterpvsbytes = 0;
434 r_shadow_buffer_clusterpvs = NULL;
435 r_shadow_buffer_clusterlist = NULL;
436 r_shadow_buffer_numsurfacepvsbytes = 0;
437 r_shadow_buffer_surfacepvs = NULL;
438 r_shadow_buffer_surfacelist = NULL;
439 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
442 matrix4x4_t matrix_attenuationxyz =
445 {0.5, 0.0, 0.0, 0.5},
446 {0.0, 0.5, 0.0, 0.5},
447 {0.0, 0.0, 0.5, 0.5},
452 matrix4x4_t matrix_attenuationz =
455 {0.0, 0.0, 0.5, 0.5},
456 {0.0, 0.0, 0.0, 0.5},
457 {0.0, 0.0, 0.0, 0.5},
462 int *R_Shadow_ResizeShadowElements(int numtris)
464 // make sure shadowelements is big enough for this volume
465 if (maxshadowelements < numtris * 24)
467 maxshadowelements = numtris * 24;
469 Mem_Free(shadowelements);
470 shadowelements = Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int));
472 return shadowelements;
475 void R_Shadow_EnlargeClusterBuffer(int numclusters)
477 int numclusterpvsbytes = (((numclusters + 7) >> 3) + 255) & ~255;
478 if (r_shadow_buffer_numclusterpvsbytes < numclusterpvsbytes)
480 if (r_shadow_buffer_clusterpvs)
481 Mem_Free(r_shadow_buffer_clusterpvs);
482 if (r_shadow_buffer_clusterlist)
483 Mem_Free(r_shadow_buffer_clusterlist);
484 r_shadow_buffer_numclusterpvsbytes = numclusterpvsbytes;
485 r_shadow_buffer_clusterpvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numclusterpvsbytes);
486 r_shadow_buffer_clusterlist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numclusterpvsbytes * 8 * sizeof(*r_shadow_buffer_clusterlist));
490 void R_Shadow_EnlargeSurfaceBuffer(int numsurfaces)
492 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
493 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
495 if (r_shadow_buffer_surfacepvs)
496 Mem_Free(r_shadow_buffer_surfacepvs);
497 if (r_shadow_buffer_surfacelist)
498 Mem_Free(r_shadow_buffer_surfacelist);
499 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
500 r_shadow_buffer_surfacepvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes);
501 r_shadow_buffer_surfacelist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
505 void R_Shadow_PrepareShadowMark(int numtris)
507 // make sure shadowmark is big enough for this volume
508 if (maxshadowmark < numtris)
510 maxshadowmark = numtris;
512 Mem_Free(shadowmark);
514 Mem_Free(shadowmarklist);
515 shadowmark = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmark));
516 shadowmarklist = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmarklist));
520 // if shadowmarkcount wrapped we clear the array and adjust accordingly
521 if (shadowmarkcount == 0)
524 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
529 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)
531 int i, j, tris = 0, vr[3], t, outvertices = 0;
536 if (maxvertexupdate < innumvertices)
538 maxvertexupdate = innumvertices;
540 Mem_Free(vertexupdate);
542 Mem_Free(vertexremap);
543 vertexupdate = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
544 vertexremap = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
548 if (vertexupdatenum == 0)
551 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
552 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
555 for (i = 0;i < numshadowmarktris;i++)
556 shadowmark[shadowmarktris[i]] = shadowmarkcount;
558 for (i = 0;i < numshadowmarktris;i++)
560 t = shadowmarktris[i];
561 e = inelement3i + t * 3;
562 // make sure the vertices are created
563 for (j = 0;j < 3;j++)
565 if (vertexupdate[e[j]] != vertexupdatenum)
567 vertexupdate[e[j]] = vertexupdatenum;
568 vertexremap[e[j]] = outvertices;
569 v = invertex3f + e[j] * 3;
570 // project one copy of the vertex to the sphere radius of the light
571 // (FIXME: would projecting it to the light box be better?)
572 VectorSubtract(v, projectorigin, temp);
573 f = projectdistance / VectorLength(temp);
574 VectorCopy(v, outvertex3f);
575 VectorMA(projectorigin, f, temp, (outvertex3f + 3));
582 for (i = 0;i < numshadowmarktris;i++)
584 t = shadowmarktris[i];
585 e = inelement3i + t * 3;
586 n = inneighbor3i + t * 3;
587 // output the front and back triangles
588 outelement3i[0] = vertexremap[e[0]];
589 outelement3i[1] = vertexremap[e[1]];
590 outelement3i[2] = vertexremap[e[2]];
591 outelement3i[3] = vertexremap[e[2]] + 1;
592 outelement3i[4] = vertexremap[e[1]] + 1;
593 outelement3i[5] = vertexremap[e[0]] + 1;
596 // output the sides (facing outward from this triangle)
597 if (shadowmark[n[0]] != shadowmarkcount)
599 vr[0] = vertexremap[e[0]];
600 vr[1] = vertexremap[e[1]];
601 outelement3i[0] = vr[1];
602 outelement3i[1] = vr[0];
603 outelement3i[2] = vr[0] + 1;
604 outelement3i[3] = vr[1];
605 outelement3i[4] = vr[0] + 1;
606 outelement3i[5] = vr[1] + 1;
610 if (shadowmark[n[1]] != shadowmarkcount)
612 vr[1] = vertexremap[e[1]];
613 vr[2] = vertexremap[e[2]];
614 outelement3i[0] = vr[2];
615 outelement3i[1] = vr[1];
616 outelement3i[2] = vr[1] + 1;
617 outelement3i[3] = vr[2];
618 outelement3i[4] = vr[1] + 1;
619 outelement3i[5] = vr[2] + 1;
623 if (shadowmark[n[2]] != shadowmarkcount)
625 vr[0] = vertexremap[e[0]];
626 vr[2] = vertexremap[e[2]];
627 outelement3i[0] = vr[0];
628 outelement3i[1] = vr[2];
629 outelement3i[2] = vr[2] + 1;
630 outelement3i[3] = vr[0];
631 outelement3i[4] = vr[2] + 1;
632 outelement3i[5] = vr[0] + 1;
638 *outnumvertices = outvertices;
642 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)
645 if (projectdistance < 0.1)
647 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
650 if (!numverts || !nummarktris)
652 // make sure shadowelements is big enough for this volume
653 if (maxshadowelements < nummarktris * 24)
654 R_Shadow_ResizeShadowElements((nummarktris + 256) * 24);
655 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, varray_vertex3f2, projectorigin, projectdistance, nummarktris, marktris);
656 R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements);
659 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)
664 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
666 tend = firsttriangle + numtris;
667 if (surfacemins[0] >= lightmins[0] && surfacemaxs[0] <= lightmaxs[0]
668 && surfacemins[1] >= lightmins[1] && surfacemaxs[1] <= lightmaxs[1]
669 && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2])
671 // surface box entirely inside light box, no box cull
672 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
673 if (PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
674 shadowmarklist[numshadowmark++] = t;
678 // surface box not entirely inside light box, cull each triangle
679 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
681 v[0] = invertex3f + e[0] * 3;
682 v[1] = invertex3f + e[1] * 3;
683 v[2] = invertex3f + e[2] * 3;
684 if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
685 && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
686 && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
687 && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
688 && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
689 && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
690 && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
691 shadowmarklist[numshadowmark++] = t;
696 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
699 if (r_shadow_compilingrtlight)
701 // if we're compiling an rtlight, capture the mesh
702 Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
705 memset(&m, 0, sizeof(m));
706 m.pointer_vertex = vertex3f;
708 GL_LockArrays(0, numvertices);
709 if (r_shadowstage == SHADOWSTAGE_STENCIL)
711 // increment stencil if backface is behind depthbuffer
712 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
713 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
714 R_Mesh_Draw(numvertices, numtriangles, element3i);
716 c_rt_shadowtris += numtriangles;
717 // decrement stencil if frontface is behind depthbuffer
718 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
719 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
721 R_Mesh_Draw(numvertices, numtriangles, element3i);
723 c_rt_shadowtris += numtriangles;
727 static void R_Shadow_MakeTextures(void)
729 int x, y, z, d, side;
730 float v[3], s, t, intensity;
732 R_FreeTexturePool(&r_shadow_texturepool);
733 r_shadow_texturepool = R_AllocTexturePool();
734 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
735 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
737 #define ATTEN2DSIZE 64
738 #define ATTEN3DSIZE 32
739 data = Mem_Alloc(tempmempool, max(6*NORMSIZE*NORMSIZE*4, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4)));
744 r_shadow_blankbumptexture = R_LoadTexture2D(r_shadow_texturepool, "blankbump", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
749 r_shadow_blankglosstexture = R_LoadTexture2D(r_shadow_texturepool, "blankgloss", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
754 r_shadow_blankwhitetexture = R_LoadTexture2D(r_shadow_texturepool, "blankwhite", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
755 if (gl_texturecubemap)
757 for (side = 0;side < 6;side++)
759 for (y = 0;y < NORMSIZE;y++)
761 for (x = 0;x < NORMSIZE;x++)
763 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
764 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
798 intensity = 127.0f / sqrt(DotProduct(v, v));
799 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+0] = 128.0f + intensity * v[0];
800 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+1] = 128.0f + intensity * v[1];
801 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+2] = 128.0f + intensity * v[2];
802 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+3] = 255;
806 r_shadow_normalcubetexture = R_LoadTextureCubeMap(r_shadow_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
809 r_shadow_normalcubetexture = NULL;
810 for (y = 0;y < ATTEN2DSIZE;y++)
812 for (x = 0;x < ATTEN2DSIZE;x++)
814 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
815 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
817 intensity = 1.0f - sqrt(DotProduct(v, v));
819 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
820 d = bound(0, intensity, 255);
821 data[(y*ATTEN2DSIZE+x)*4+0] = d;
822 data[(y*ATTEN2DSIZE+x)*4+1] = d;
823 data[(y*ATTEN2DSIZE+x)*4+2] = d;
824 data[(y*ATTEN2DSIZE+x)*4+3] = d;
827 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
828 if (r_shadow_texture3d.integer)
830 for (z = 0;z < ATTEN3DSIZE;z++)
832 for (y = 0;y < ATTEN3DSIZE;y++)
834 for (x = 0;x < ATTEN3DSIZE;x++)
836 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
837 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
838 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
839 intensity = 1.0f - sqrt(DotProduct(v, v));
841 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
842 d = bound(0, intensity, 255);
843 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
844 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
845 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
846 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
850 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
855 void R_Shadow_ValidateCvars(void)
857 if (r_shadow_texture3d.integer && !gl_texture3d)
858 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
859 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
860 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
863 void R_Shadow_Stage_Begin(void)
867 R_Shadow_ValidateCvars();
869 if (!r_shadow_attenuation2dtexture
870 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
871 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
872 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
873 R_Shadow_MakeTextures();
875 memset(&m, 0, sizeof(m));
876 GL_BlendFunc(GL_ONE, GL_ZERO);
880 GL_Color(0, 0, 0, 1);
881 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
882 qglEnable(GL_CULL_FACE);
883 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
884 r_shadowstage = SHADOWSTAGE_NONE;
886 c_rt_lights = c_rt_clears = c_rt_scissored = 0;
887 c_rt_shadowmeshes = c_rt_shadowtris = c_rt_lightmeshes = c_rt_lighttris = 0;
888 c_rtcached_shadowmeshes = c_rtcached_shadowtris = 0;
891 void R_Shadow_Stage_ShadowVolumes(void)
894 memset(&m, 0, sizeof(m));
896 GL_Color(1, 1, 1, 1);
897 GL_ColorMask(0, 0, 0, 0);
898 GL_BlendFunc(GL_ONE, GL_ZERO);
901 qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
902 //if (r_shadow_shadow_polygonoffset.value != 0)
904 // qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
905 // qglEnable(GL_POLYGON_OFFSET_FILL);
908 // qglDisable(GL_POLYGON_OFFSET_FILL);
909 qglDepthFunc(GL_LESS);
910 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
911 qglEnable(GL_STENCIL_TEST);
912 qglStencilFunc(GL_ALWAYS, 128, ~0);
913 if (gl_ext_stenciltwoside.integer)
915 r_shadowstage = SHADOWSTAGE_STENCILTWOSIDE;
916 qglDisable(GL_CULL_FACE);
917 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
918 qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
920 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
921 qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
923 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
927 r_shadowstage = SHADOWSTAGE_STENCIL;
928 qglEnable(GL_CULL_FACE);
930 // this is changed by every shadow render so its value here is unimportant
931 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
933 GL_Clear(GL_STENCIL_BUFFER_BIT);
935 // LordHavoc note: many shadow volumes reside entirely inside the world
936 // (that is to say they are entirely bounded by their lit surfaces),
937 // which can be optimized by handling things as an inverted light volume,
938 // with the shadow boundaries of the world being simulated by an altered
939 // (129) bias to stencil clearing on such lights
940 // FIXME: generate inverted light volumes for use as shadow volumes and
941 // optimize for them as noted above
944 void R_Shadow_Stage_Light(int shadowtest)
947 memset(&m, 0, sizeof(m));
949 GL_BlendFunc(GL_ONE, GL_ONE);
952 qglPolygonOffset(0, 0);
953 //qglDisable(GL_POLYGON_OFFSET_FILL);
954 GL_Color(1, 1, 1, 1);
955 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
956 qglDepthFunc(GL_EQUAL);
957 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
958 qglEnable(GL_CULL_FACE);
960 qglEnable(GL_STENCIL_TEST);
962 qglDisable(GL_STENCIL_TEST);
963 if (gl_support_stenciltwoside)
964 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
966 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
967 // only draw light where this geometry was already rendered AND the
968 // stencil is 128 (values other than this mean shadow)
969 qglStencilFunc(GL_EQUAL, 128, ~0);
970 r_shadowstage = SHADOWSTAGE_LIGHT;
974 void R_Shadow_Stage_End(void)
977 memset(&m, 0, sizeof(m));
979 GL_BlendFunc(GL_ONE, GL_ZERO);
982 qglPolygonOffset(0, 0);
983 //qglDisable(GL_POLYGON_OFFSET_FILL);
984 GL_Color(1, 1, 1, 1);
985 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
986 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
987 qglDepthFunc(GL_LEQUAL);
988 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
989 qglDisable(GL_STENCIL_TEST);
990 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
991 if (gl_support_stenciltwoside)
992 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
994 qglStencilFunc(GL_ALWAYS, 128, ~0);
995 r_shadowstage = SHADOWSTAGE_NONE;
998 int R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1000 int i, ix1, iy1, ix2, iy2;
1001 float x1, y1, x2, y2, x, y, f;
1002 vec3_t smins, smaxs;
1004 if (!r_shadow_scissor.integer)
1006 // if view is inside the box, just say yes it's visible
1007 if (BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
1009 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1012 for (i = 0;i < 3;i++)
1014 if (r_viewforward[i] >= 0)
1025 f = DotProduct(r_viewforward, r_vieworigin) + 1;
1026 if (DotProduct(r_viewforward, v2) <= f)
1028 // entirely behind nearclip plane
1031 if (DotProduct(r_viewforward, v) >= f)
1033 // entirely infront of nearclip plane
1034 x1 = y1 = x2 = y2 = 0;
1035 for (i = 0;i < 8;i++)
1037 v[0] = (i & 1) ? mins[0] : maxs[0];
1038 v[1] = (i & 2) ? mins[1] : maxs[1];
1039 v[2] = (i & 4) ? mins[2] : maxs[2];
1041 GL_TransformToScreen(v, v2);
1042 //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]);
1061 // clipped by nearclip plane
1062 // this is nasty and crude...
1063 // create viewspace bbox
1064 for (i = 0;i < 8;i++)
1066 v[0] = ((i & 1) ? mins[0] : maxs[0]) - r_vieworigin[0];
1067 v[1] = ((i & 2) ? mins[1] : maxs[1]) - r_vieworigin[1];
1068 v[2] = ((i & 4) ? mins[2] : maxs[2]) - r_vieworigin[2];
1069 v2[0] = -DotProduct(v, r_viewleft);
1070 v2[1] = DotProduct(v, r_viewup);
1071 v2[2] = DotProduct(v, r_viewforward);
1074 if (smins[0] > v2[0]) smins[0] = v2[0];
1075 if (smaxs[0] < v2[0]) smaxs[0] = v2[0];
1076 if (smins[1] > v2[1]) smins[1] = v2[1];
1077 if (smaxs[1] < v2[1]) smaxs[1] = v2[1];
1078 if (smins[2] > v2[2]) smins[2] = v2[2];
1079 if (smaxs[2] < v2[2]) smaxs[2] = v2[2];
1083 smins[0] = smaxs[0] = v2[0];
1084 smins[1] = smaxs[1] = v2[1];
1085 smins[2] = smaxs[2] = v2[2];
1088 // now we have a bbox in viewspace
1089 // clip it to the view plane
1092 // return true if that culled the box
1093 if (smins[2] >= smaxs[2])
1095 // ok some of it is infront of the view, transform each corner back to
1096 // worldspace and then to screenspace and make screen rect
1097 // initialize these variables just to avoid compiler warnings
1098 x1 = y1 = x2 = y2 = 0;
1099 for (i = 0;i < 8;i++)
1101 v2[0] = (i & 1) ? smins[0] : smaxs[0];
1102 v2[1] = (i & 2) ? smins[1] : smaxs[1];
1103 v2[2] = (i & 4) ? smins[2] : smaxs[2];
1104 v[0] = v2[0] * -r_viewleft[0] + v2[1] * r_viewup[0] + v2[2] * r_viewforward[0] + r_vieworigin[0];
1105 v[1] = v2[0] * -r_viewleft[1] + v2[1] * r_viewup[1] + v2[2] * r_viewforward[1] + r_vieworigin[1];
1106 v[2] = v2[0] * -r_viewleft[2] + v2[1] * r_viewup[2] + v2[2] * r_viewforward[2] + r_vieworigin[2];
1108 GL_TransformToScreen(v, v2);
1109 //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]);
1126 // this code doesn't handle boxes with any points behind view properly
1127 x1 = 1000;x2 = -1000;
1128 y1 = 1000;y2 = -1000;
1129 for (i = 0;i < 8;i++)
1131 v[0] = (i & 1) ? mins[0] : maxs[0];
1132 v[1] = (i & 2) ? mins[1] : maxs[1];
1133 v[2] = (i & 4) ? mins[2] : maxs[2];
1135 GL_TransformToScreen(v, v2);
1136 //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]);
1154 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1155 if (ix1 < r_view_x) ix1 = r_view_x;
1156 if (iy1 < r_view_y) iy1 = r_view_y;
1157 if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
1158 if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
1159 if (ix2 <= ix1 || iy2 <= iy1)
1161 // set up the scissor rectangle
1162 GL_Scissor(ix1, vid.realheight - iy2, ix2 - ix1, iy2 - iy1);
1163 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1164 //qglEnable(GL_SCISSOR_TEST);
1169 static void R_Shadow_VertexShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1171 float *color4f = varray_color4f;
1172 float dist, dot, intensity, v[3], n[3];
1173 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1175 Matrix4x4_Transform(m, vertex3f, v);
1176 if ((dist = DotProduct(v, v)) < 1)
1178 Matrix4x4_Transform3x3(m, normal3f, n);
1179 if ((dot = DotProduct(n, v)) > 0)
1182 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1183 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1184 VectorScale(lightcolor, intensity, color4f);
1189 VectorClear(color4f);
1195 VectorClear(color4f);
1201 static void R_Shadow_VertexShadingWithZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1203 float *color4f = varray_color4f;
1204 float dist, dot, intensity, v[3], n[3];
1205 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1207 Matrix4x4_Transform(m, vertex3f, v);
1208 if ((dist = fabs(v[2])) < 1)
1210 Matrix4x4_Transform3x3(m, normal3f, n);
1211 if ((dot = DotProduct(n, v)) > 0)
1213 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1214 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1215 VectorScale(lightcolor, intensity, color4f);
1220 VectorClear(color4f);
1226 VectorClear(color4f);
1232 static void R_Shadow_VertexShading(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1234 float *color4f = varray_color4f;
1235 float dot, intensity, v[3], n[3];
1236 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1238 Matrix4x4_Transform(m, vertex3f, v);
1239 Matrix4x4_Transform3x3(m, normal3f, n);
1240 if ((dot = DotProduct(n, v)) > 0)
1242 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1243 VectorScale(lightcolor, intensity, color4f);
1248 VectorClear(color4f);
1254 static void R_Shadow_VertexNoShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *lightcolor, const matrix4x4_t *m)
1256 float *color4f = varray_color4f;
1257 float dist, intensity, v[3];
1258 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1260 Matrix4x4_Transform(m, vertex3f, v);
1261 if ((dist = DotProduct(v, v)) < 1)
1264 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1265 VectorScale(lightcolor, intensity, color4f);
1270 VectorClear(color4f);
1276 static void R_Shadow_VertexNoShadingWithZAttenuation(int numverts, const float *vertex3f, const float *lightcolor, const matrix4x4_t *m)
1278 float *color4f = varray_color4f;
1279 float dist, intensity, v[3];
1280 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1282 Matrix4x4_Transform(m, vertex3f, v);
1283 if ((dist = fabs(v[2])) < 1)
1285 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1286 VectorScale(lightcolor, intensity, color4f);
1291 VectorClear(color4f);
1297 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1298 #define USETEXMATRIX
1300 #ifndef USETEXMATRIX
1301 // this should be done in a texture matrix or vertex program when possible, but here's code to do it manually
1302 // if hardware texcoord manipulation is not available (or not suitable, this would really benefit from 3DNow! or SSE
1303 static void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1307 tc3f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1308 tc3f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1309 tc3f[2] = vertex3f[0] * matrix->m[2][0] + vertex3f[1] * matrix->m[2][1] + vertex3f[2] * matrix->m[2][2] + matrix->m[2][3];
1316 static void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1320 tc2f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1321 tc2f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1329 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)
1333 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1335 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1336 // the cubemap normalizes this for us
1337 out3f[0] = DotProduct(svector3f, lightdir);
1338 out3f[1] = DotProduct(tvector3f, lightdir);
1339 out3f[2] = DotProduct(normal3f, lightdir);
1343 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)
1346 float lightdir[3], eyedir[3], halfdir[3];
1347 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1349 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1350 VectorNormalizeFast(lightdir);
1351 VectorSubtract(vertex3f, relativeeyeorigin, eyedir);
1352 VectorNormalizeFast(eyedir);
1353 VectorAdd(lightdir, eyedir, halfdir);
1354 // the cubemap normalizes this for us
1355 out3f[0] = DotProduct(svector3f, halfdir);
1356 out3f[1] = DotProduct(tvector3f, halfdir);
1357 out3f[2] = DotProduct(normal3f, halfdir);
1361 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, vec_t ambientscale, vec_t diffusescale, vec_t specularscale)
1364 float color[3], color2[3], colorscale;
1367 bumptexture = r_shadow_blankbumptexture;
1369 glosstexture = r_shadow_blankglosstexture;
1370 // FIXME: support EF_NODEPTHTEST
1371 GL_DepthMask(false);
1373 if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
1378 colorscale = r_shadow_lightintensityscale.value * ambientscale;
1379 // colorscale accounts for how much we multiply the brightness
1382 // mult is how many times the final pass of the lighting will be
1383 // performed to get more brightness than otherwise possible.
1385 // Limit mult to 64 for sanity sake.
1386 if (r_shadow_texture3d.integer && lightcubemap && r_textureunits.integer >= 4)
1388 // 3 3D combine path (Geforce3, Radeon 8500)
1389 memset(&m, 0, sizeof(m));
1390 m.pointer_vertex = vertex3f;
1391 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1393 m.pointer_texcoord3f[0] = vertex3f;
1394 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1396 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1397 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1399 m.tex[1] = R_GetTexture(basetexture);
1400 m.pointer_texcoord[1] = texcoord2f;
1401 m.texcubemap[2] = R_GetTexture(lightcubemap);
1403 m.pointer_texcoord3f[2] = vertex3f;
1404 m.texmatrix[2] = *matrix_modeltolight;
1406 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1407 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2], numverts, vertex3f, matrix_modeltolight);
1410 else if (r_shadow_texture3d.integer && !lightcubemap && r_textureunits.integer >= 2)
1412 // 2 3D combine path (Geforce3, original Radeon)
1413 memset(&m, 0, sizeof(m));
1414 m.pointer_vertex = vertex3f;
1415 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1417 m.pointer_texcoord3f[0] = vertex3f;
1418 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1420 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1421 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1423 m.tex[1] = R_GetTexture(basetexture);
1424 m.pointer_texcoord[1] = texcoord2f;
1426 else if (r_textureunits.integer >= 4 && lightcubemap)
1428 // 4 2D combine path (Geforce3, Radeon 8500)
1429 memset(&m, 0, sizeof(m));
1430 m.pointer_vertex = vertex3f;
1431 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1433 m.pointer_texcoord3f[0] = vertex3f;
1434 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1436 m.pointer_texcoord[0] = varray_texcoord2f[0];
1437 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1439 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1441 m.pointer_texcoord3f[1] = vertex3f;
1442 m.texmatrix[1] = *matrix_modeltoattenuationz;
1444 m.pointer_texcoord[1] = varray_texcoord2f[1];
1445 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1447 m.tex[2] = R_GetTexture(basetexture);
1448 m.pointer_texcoord[2] = texcoord2f;
1451 m.texcubemap[3] = R_GetTexture(lightcubemap);
1453 m.pointer_texcoord3f[3] = vertex3f;
1454 m.texmatrix[3] = *matrix_modeltolight;
1456 m.pointer_texcoord3f[3] = varray_texcoord3f[3];
1457 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[3], numverts, vertex3f, matrix_modeltolight);
1461 else if (r_textureunits.integer >= 3 && !lightcubemap)
1463 // 3 2D combine path (Geforce3, original Radeon)
1464 memset(&m, 0, sizeof(m));
1465 m.pointer_vertex = vertex3f;
1466 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1468 m.pointer_texcoord3f[0] = vertex3f;
1469 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1471 m.pointer_texcoord[0] = varray_texcoord2f[0];
1472 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1474 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1476 m.pointer_texcoord3f[1] = vertex3f;
1477 m.texmatrix[1] = *matrix_modeltoattenuationz;
1479 m.pointer_texcoord[1] = varray_texcoord2f[1];
1480 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1482 m.tex[2] = R_GetTexture(basetexture);
1483 m.pointer_texcoord[2] = texcoord2f;
1487 // 2/2/2 2D combine path (any dot3 card)
1488 memset(&m, 0, sizeof(m));
1489 m.pointer_vertex = vertex3f;
1490 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1492 m.pointer_texcoord3f[0] = vertex3f;
1493 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1495 m.pointer_texcoord[0] = varray_texcoord2f[0];
1496 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1498 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1500 m.pointer_texcoord3f[1] = vertex3f;
1501 m.texmatrix[1] = *matrix_modeltoattenuationz;
1503 m.pointer_texcoord[1] = varray_texcoord2f[1];
1504 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1507 GL_ColorMask(0,0,0,1);
1508 GL_BlendFunc(GL_ONE, GL_ZERO);
1509 GL_LockArrays(0, numverts);
1510 R_Mesh_Draw(numverts, numtriangles, elements);
1511 GL_LockArrays(0, 0);
1513 c_rt_lighttris += numtriangles;
1515 memset(&m, 0, sizeof(m));
1516 m.pointer_vertex = vertex3f;
1517 m.tex[0] = R_GetTexture(basetexture);
1518 m.pointer_texcoord[0] = texcoord2f;
1521 m.texcubemap[1] = R_GetTexture(lightcubemap);
1523 m.pointer_texcoord3f[1] = vertex3f;
1524 m.texmatrix[1] = *matrix_modeltolight;
1526 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1527 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1531 // this final code is shared
1533 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1534 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1535 VectorScale(lightcolor, colorscale, color2);
1536 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1538 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1539 GL_LockArrays(0, numverts);
1540 R_Mesh_Draw(numverts, numtriangles, elements);
1541 GL_LockArrays(0, 0);
1543 c_rt_lighttris += numtriangles;
1549 colorscale = r_shadow_lightintensityscale.value * diffusescale;
1550 // colorscale accounts for how much we multiply the brightness
1553 // mult is how many times the final pass of the lighting will be
1554 // performed to get more brightness than otherwise possible.
1556 // Limit mult to 64 for sanity sake.
1557 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1559 // 3/2 3D combine path (Geforce3, Radeon 8500)
1560 memset(&m, 0, sizeof(m));
1561 m.pointer_vertex = vertex3f;
1562 m.tex[0] = R_GetTexture(bumptexture);
1563 m.texcombinergb[0] = GL_REPLACE;
1564 m.pointer_texcoord[0] = texcoord2f;
1565 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1566 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1567 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1568 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1569 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1571 m.pointer_texcoord3f[2] = vertex3f;
1572 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
1574 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1575 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1578 GL_ColorMask(0,0,0,1);
1579 GL_BlendFunc(GL_ONE, GL_ZERO);
1580 GL_LockArrays(0, numverts);
1581 R_Mesh_Draw(numverts, numtriangles, elements);
1582 GL_LockArrays(0, 0);
1584 c_rt_lighttris += numtriangles;
1586 memset(&m, 0, sizeof(m));
1587 m.pointer_vertex = vertex3f;
1588 m.tex[0] = R_GetTexture(basetexture);
1589 m.pointer_texcoord[0] = texcoord2f;
1592 m.texcubemap[1] = R_GetTexture(lightcubemap);
1594 m.pointer_texcoord3f[1] = vertex3f;
1595 m.texmatrix[1] = *matrix_modeltolight;
1597 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1598 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1602 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap)
1604 // 1/2/2 3D combine path (original Radeon)
1605 memset(&m, 0, sizeof(m));
1606 m.pointer_vertex = vertex3f;
1607 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1609 m.pointer_texcoord3f[0] = vertex3f;
1610 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1612 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1613 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1616 GL_ColorMask(0,0,0,1);
1617 GL_BlendFunc(GL_ONE, GL_ZERO);
1618 GL_LockArrays(0, numverts);
1619 R_Mesh_Draw(numverts, numtriangles, elements);
1620 GL_LockArrays(0, 0);
1622 c_rt_lighttris += numtriangles;
1624 memset(&m, 0, sizeof(m));
1625 m.pointer_vertex = vertex3f;
1626 m.tex[0] = R_GetTexture(bumptexture);
1627 m.texcombinergb[0] = GL_REPLACE;
1628 m.pointer_texcoord[0] = texcoord2f;
1629 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1630 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1631 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1632 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1634 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1635 GL_LockArrays(0, numverts);
1636 R_Mesh_Draw(numverts, numtriangles, elements);
1637 GL_LockArrays(0, 0);
1639 c_rt_lighttris += numtriangles;
1641 memset(&m, 0, sizeof(m));
1642 m.pointer_vertex = vertex3f;
1643 m.tex[0] = R_GetTexture(basetexture);
1644 m.pointer_texcoord[0] = texcoord2f;
1647 m.texcubemap[1] = R_GetTexture(lightcubemap);
1649 m.pointer_texcoord3f[1] = vertex3f;
1650 m.texmatrix[1] = *matrix_modeltolight;
1652 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1653 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1657 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap)
1659 // 2/2 3D combine path (original Radeon)
1660 memset(&m, 0, sizeof(m));
1661 m.pointer_vertex = vertex3f;
1662 m.tex[0] = R_GetTexture(bumptexture);
1663 m.texcombinergb[0] = GL_REPLACE;
1664 m.pointer_texcoord[0] = texcoord2f;
1665 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1666 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1667 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1668 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1670 GL_ColorMask(0,0,0,1);
1671 GL_BlendFunc(GL_ONE, GL_ZERO);
1672 GL_LockArrays(0, numverts);
1673 R_Mesh_Draw(numverts, numtriangles, elements);
1674 GL_LockArrays(0, 0);
1676 c_rt_lighttris += numtriangles;
1678 memset(&m, 0, sizeof(m));
1679 m.pointer_vertex = vertex3f;
1680 m.tex[0] = R_GetTexture(basetexture);
1681 m.pointer_texcoord[0] = texcoord2f;
1682 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1684 m.pointer_texcoord3f[1] = vertex3f;
1685 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1687 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1688 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1691 else if (r_textureunits.integer >= 4)
1693 // 4/2 2D combine path (Geforce3, Radeon 8500)
1694 memset(&m, 0, sizeof(m));
1695 m.pointer_vertex = vertex3f;
1696 m.tex[0] = R_GetTexture(bumptexture);
1697 m.texcombinergb[0] = GL_REPLACE;
1698 m.pointer_texcoord[0] = texcoord2f;
1699 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1700 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1701 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1702 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1703 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1705 m.pointer_texcoord3f[2] = vertex3f;
1706 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
1708 m.pointer_texcoord[2] = varray_texcoord2f[2];
1709 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1711 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1713 m.pointer_texcoord3f[3] = vertex3f;
1714 m.texmatrix[3] = *matrix_modeltoattenuationz;
1716 m.pointer_texcoord[3] = varray_texcoord2f[3];
1717 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[3], numverts, vertex3f, matrix_modeltoattenuationz);
1720 GL_ColorMask(0,0,0,1);
1721 GL_BlendFunc(GL_ONE, GL_ZERO);
1722 GL_LockArrays(0, numverts);
1723 R_Mesh_Draw(numverts, numtriangles, elements);
1724 GL_LockArrays(0, 0);
1726 c_rt_lighttris += numtriangles;
1728 memset(&m, 0, sizeof(m));
1729 m.pointer_vertex = vertex3f;
1730 m.tex[0] = R_GetTexture(basetexture);
1731 m.pointer_texcoord[0] = texcoord2f;
1734 m.texcubemap[1] = R_GetTexture(lightcubemap);
1736 m.pointer_texcoord3f[1] = vertex3f;
1737 m.texmatrix[1] = *matrix_modeltolight;
1739 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1740 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1746 // 2/2/2 2D combine path (any dot3 card)
1747 memset(&m, 0, sizeof(m));
1748 m.pointer_vertex = vertex3f;
1749 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1751 m.pointer_texcoord3f[0] = vertex3f;
1752 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1754 m.pointer_texcoord[0] = varray_texcoord2f[0];
1755 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1757 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1759 m.pointer_texcoord3f[1] = vertex3f;
1760 m.texmatrix[1] = *matrix_modeltoattenuationz;
1762 m.pointer_texcoord[1] = varray_texcoord2f[1];
1763 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1766 GL_ColorMask(0,0,0,1);
1767 GL_BlendFunc(GL_ONE, GL_ZERO);
1768 GL_LockArrays(0, numverts);
1769 R_Mesh_Draw(numverts, numtriangles, elements);
1770 GL_LockArrays(0, 0);
1772 c_rt_lighttris += numtriangles;
1774 memset(&m, 0, sizeof(m));
1775 m.pointer_vertex = vertex3f;
1776 m.tex[0] = R_GetTexture(bumptexture);
1777 m.texcombinergb[0] = GL_REPLACE;
1778 m.pointer_texcoord[0] = texcoord2f;
1779 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1780 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1781 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1782 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1784 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1785 GL_LockArrays(0, numverts);
1786 R_Mesh_Draw(numverts, numtriangles, elements);
1787 GL_LockArrays(0, 0);
1789 c_rt_lighttris += numtriangles;
1791 memset(&m, 0, sizeof(m));
1792 m.pointer_vertex = vertex3f;
1793 m.tex[0] = R_GetTexture(basetexture);
1794 m.pointer_texcoord[0] = texcoord2f;
1797 m.texcubemap[1] = R_GetTexture(lightcubemap);
1799 m.pointer_texcoord3f[1] = vertex3f;
1800 m.texmatrix[1] = *matrix_modeltolight;
1802 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1803 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1807 // this final code is shared
1809 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1810 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1811 VectorScale(lightcolor, colorscale, color2);
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 GL_LockArrays(0, numverts);
1816 R_Mesh_Draw(numverts, numtriangles, elements);
1817 GL_LockArrays(0, 0);
1819 c_rt_lighttris += numtriangles;
1822 if (specularscale && (r_shadow_gloss.integer >= 2 || (r_shadow_gloss.integer >= 1 && glosstexture != r_shadow_blankglosstexture)))
1824 // FIXME: detect blendsquare!
1825 //if (gl_support_blendsquare)
1827 colorscale = r_shadow_lightintensityscale.value * r_shadow_glossintensity.value * specularscale;
1828 if (glosstexture == r_shadow_blankglosstexture)
1829 colorscale *= r_shadow_gloss2intensity.value;
1831 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1833 // 2/0/0/1/2 3D combine blendsquare path
1834 memset(&m, 0, sizeof(m));
1835 m.pointer_vertex = vertex3f;
1836 m.tex[0] = R_GetTexture(bumptexture);
1837 m.pointer_texcoord[0] = texcoord2f;
1838 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1839 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1840 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1841 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1843 GL_ColorMask(0,0,0,1);
1844 // this squares the result
1845 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1846 GL_LockArrays(0, numverts);
1847 R_Mesh_Draw(numverts, numtriangles, elements);
1848 GL_LockArrays(0, 0);
1850 c_rt_lighttris += numtriangles;
1852 memset(&m, 0, sizeof(m));
1853 m.pointer_vertex = vertex3f;
1855 GL_LockArrays(0, numverts);
1856 // square alpha in framebuffer a few times to make it shiny
1857 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1858 // these comments are a test run through this math for intensity 0.5
1859 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1860 // 0.25 * 0.25 = 0.0625 (this is another pass)
1861 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1862 R_Mesh_Draw(numverts, numtriangles, elements);
1864 c_rt_lighttris += numtriangles;
1865 R_Mesh_Draw(numverts, numtriangles, elements);
1867 c_rt_lighttris += numtriangles;
1868 GL_LockArrays(0, 0);
1870 memset(&m, 0, sizeof(m));
1871 m.pointer_vertex = vertex3f;
1872 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1874 m.pointer_texcoord3f[0] = vertex3f;
1875 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1877 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1878 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1881 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1882 GL_LockArrays(0, numverts);
1883 R_Mesh_Draw(numverts, numtriangles, elements);
1884 GL_LockArrays(0, 0);
1886 c_rt_lighttris += numtriangles;
1888 memset(&m, 0, sizeof(m));
1889 m.pointer_vertex = vertex3f;
1890 m.tex[0] = R_GetTexture(glosstexture);
1891 m.pointer_texcoord[0] = texcoord2f;
1894 m.texcubemap[1] = R_GetTexture(lightcubemap);
1896 m.pointer_texcoord3f[1] = vertex3f;
1897 m.texmatrix[1] = *matrix_modeltolight;
1899 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1900 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1904 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1906 // 2/0/0/2 3D combine blendsquare path
1907 memset(&m, 0, sizeof(m));
1908 m.pointer_vertex = vertex3f;
1909 m.tex[0] = R_GetTexture(bumptexture);
1910 m.pointer_texcoord[0] = texcoord2f;
1911 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1912 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1913 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1914 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1916 GL_ColorMask(0,0,0,1);
1917 // this squares the result
1918 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1919 GL_LockArrays(0, numverts);
1920 R_Mesh_Draw(numverts, numtriangles, elements);
1921 GL_LockArrays(0, 0);
1923 c_rt_lighttris += numtriangles;
1925 memset(&m, 0, sizeof(m));
1926 m.pointer_vertex = vertex3f;
1928 GL_LockArrays(0, numverts);
1929 // square alpha in framebuffer a few times to make it shiny
1930 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1931 // these comments are a test run through this math for intensity 0.5
1932 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1933 // 0.25 * 0.25 = 0.0625 (this is another pass)
1934 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1935 R_Mesh_Draw(numverts, numtriangles, elements);
1937 c_rt_lighttris += numtriangles;
1938 R_Mesh_Draw(numverts, numtriangles, elements);
1940 c_rt_lighttris += numtriangles;
1941 GL_LockArrays(0, 0);
1943 memset(&m, 0, sizeof(m));
1944 m.pointer_vertex = vertex3f;
1945 m.tex[0] = R_GetTexture(glosstexture);
1946 m.pointer_texcoord[0] = texcoord2f;
1947 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1949 m.pointer_texcoord3f[1] = vertex3f;
1950 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1952 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1953 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1958 // 2/0/0/2/2 2D combine blendsquare path
1959 memset(&m, 0, sizeof(m));
1960 m.pointer_vertex = vertex3f;
1961 m.tex[0] = R_GetTexture(bumptexture);
1962 m.pointer_texcoord[0] = texcoord2f;
1963 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1964 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1965 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1966 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1968 GL_ColorMask(0,0,0,1);
1969 // this squares the result
1970 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1971 GL_LockArrays(0, numverts);
1972 R_Mesh_Draw(numverts, numtriangles, elements);
1973 GL_LockArrays(0, 0);
1975 c_rt_lighttris += numtriangles;
1977 memset(&m, 0, sizeof(m));
1978 m.pointer_vertex = vertex3f;
1980 GL_LockArrays(0, numverts);
1981 // square alpha in framebuffer a few times to make it shiny
1982 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1983 // these comments are a test run through this math for intensity 0.5
1984 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1985 // 0.25 * 0.25 = 0.0625 (this is another pass)
1986 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1987 R_Mesh_Draw(numverts, numtriangles, elements);
1989 c_rt_lighttris += numtriangles;
1990 R_Mesh_Draw(numverts, numtriangles, elements);
1992 c_rt_lighttris += numtriangles;
1993 GL_LockArrays(0, 0);
1995 memset(&m, 0, sizeof(m));
1996 m.pointer_vertex = vertex3f;
1997 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1999 m.pointer_texcoord3f[0] = vertex3f;
2000 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
2002 m.pointer_texcoord[0] = varray_texcoord2f[0];
2003 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
2005 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2007 m.pointer_texcoord3f[1] = vertex3f;
2008 m.texmatrix[1] = *matrix_modeltoattenuationz;
2010 m.pointer_texcoord[1] = varray_texcoord2f[1];
2011 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
2014 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2015 GL_LockArrays(0, numverts);
2016 R_Mesh_Draw(numverts, numtriangles, elements);
2017 GL_LockArrays(0, 0);
2019 c_rt_lighttris += numtriangles;
2021 memset(&m, 0, sizeof(m));
2022 m.pointer_vertex = vertex3f;
2023 m.tex[0] = R_GetTexture(glosstexture);
2024 m.pointer_texcoord[0] = texcoord2f;
2027 m.texcubemap[1] = R_GetTexture(lightcubemap);
2029 m.pointer_texcoord3f[1] = vertex3f;
2030 m.texmatrix[1] = *matrix_modeltolight;
2032 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2033 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
2039 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2040 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2041 VectorScale(lightcolor, colorscale, color2);
2042 GL_LockArrays(0, numverts);
2043 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2045 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2046 R_Mesh_Draw(numverts, numtriangles, elements);
2048 c_rt_lighttris += numtriangles;
2050 GL_LockArrays(0, 0);
2057 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2058 VectorScale(lightcolor, r_shadow_lightintensityscale.value * ambientscale, color2);
2059 memset(&m, 0, sizeof(m));
2060 m.pointer_vertex = vertex3f;
2061 m.tex[0] = R_GetTexture(basetexture);
2062 m.pointer_texcoord[0] = texcoord2f;
2063 if (r_textureunits.integer >= 2)
2066 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2068 m.pointer_texcoord3f[1] = vertex3f;
2069 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2071 m.pointer_texcoord[1] = varray_texcoord2f[1];
2072 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
2074 if (r_textureunits.integer >= 3)
2076 // Geforce3/Radeon class but not using dot3
2077 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2079 m.pointer_texcoord3f[2] = vertex3f;
2080 m.texmatrix[2] = *matrix_modeltoattenuationz;
2082 m.pointer_texcoord[2] = varray_texcoord2f[2];
2083 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationz);
2088 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2090 color[0] = bound(0, color2[0], 1);
2091 color[1] = bound(0, color2[1], 1);
2092 color[2] = bound(0, color2[2], 1);
2093 if (r_textureunits.integer >= 3)
2095 GL_Color(color[0], color[1], color[2], 1);
2096 m.pointer_color = NULL;
2098 else if (r_textureunits.integer >= 2)
2100 R_Shadow_VertexNoShadingWithZAttenuation(numverts, vertex3f, color, matrix_modeltolight);
2101 m.pointer_color = varray_color4f;
2105 R_Shadow_VertexNoShadingWithXYZAttenuation(numverts, vertex3f, color, matrix_modeltolight);
2106 m.pointer_color = varray_color4f;
2108 GL_LockArrays(0, numverts);
2109 R_Mesh_Draw(numverts, numtriangles, elements);
2110 GL_LockArrays(0, 0);
2112 c_rt_lighttris += numtriangles;
2117 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2118 VectorScale(lightcolor, r_shadow_lightintensityscale.value * diffusescale, color2);
2119 memset(&m, 0, sizeof(m));
2120 m.pointer_vertex = vertex3f;
2121 m.pointer_color = varray_color4f;
2122 m.tex[0] = R_GetTexture(basetexture);
2123 m.pointer_texcoord[0] = texcoord2f;
2124 if (r_textureunits.integer >= 2)
2127 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2129 m.pointer_texcoord3f[1] = vertex3f;
2130 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2132 m.pointer_texcoord[1] = varray_texcoord2f[1];
2133 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
2135 if (r_textureunits.integer >= 3)
2137 // Geforce3/Radeon class but not using dot3
2138 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2140 m.pointer_texcoord3f[2] = vertex3f;
2141 m.texmatrix[2] = *matrix_modeltoattenuationz;
2143 m.pointer_texcoord[2] = varray_texcoord2f[2];
2144 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationz);
2149 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2151 color[0] = bound(0, color2[0], 1);
2152 color[1] = bound(0, color2[1], 1);
2153 color[2] = bound(0, color2[2], 1);
2154 if (r_textureunits.integer >= 3)
2155 R_Shadow_VertexShading(numverts, vertex3f, normal3f, color, matrix_modeltolight);
2156 else if (r_textureunits.integer >= 2)
2157 R_Shadow_VertexShadingWithZAttenuation(numverts, vertex3f, normal3f, color, matrix_modeltolight);
2159 R_Shadow_VertexShadingWithXYZAttenuation(numverts, vertex3f, normal3f, color, matrix_modeltolight);
2160 GL_LockArrays(0, numverts);
2161 R_Mesh_Draw(numverts, numtriangles, elements);
2162 GL_LockArrays(0, 0);
2164 c_rt_lighttris += numtriangles;
2170 void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
2174 R_RTLight_Uncompile(rtlight);
2175 memset(rtlight, 0, sizeof(*rtlight));
2177 VectorCopy(light->origin, rtlight->shadoworigin);
2178 VectorCopy(light->color, rtlight->color);
2179 rtlight->radius = light->radius;
2180 //rtlight->cullradius = rtlight->radius;
2181 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2182 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2183 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2184 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2185 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2186 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2187 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2188 rtlight->cubemapname[0] = 0;
2189 if (light->cubemapname[0])
2190 strcpy(rtlight->cubemapname, light->cubemapname);
2191 else if (light->cubemapnum > 0)
2192 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
2193 rtlight->shadow = light->shadow;
2194 rtlight->corona = light->corona;
2195 rtlight->style = light->style;
2196 rtlight->isstatic = isstatic;
2197 rtlight->coronasizescale = light->coronasizescale;
2198 rtlight->ambientscale = light->ambientscale;
2199 rtlight->diffusescale = light->diffusescale;
2200 rtlight->specularscale = light->specularscale;
2201 rtlight->flags = light->flags;
2202 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
2203 // ConcatScale won't work here because this needs to scale rotate and
2204 // translate, not just rotate
2205 scale = 1.0f / rtlight->radius;
2206 for (k = 0;k < 3;k++)
2207 for (j = 0;j < 4;j++)
2208 rtlight->matrix_worldtolight.m[k][j] *= scale;
2209 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationxyz, &matrix_attenuationxyz, &rtlight->matrix_worldtolight);
2210 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationz, &matrix_attenuationz, &rtlight->matrix_worldtolight);
2212 rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
2213 rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
2214 VectorScale(rtlight->color, rtlight->radius * (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * 0.125f, rtlight->lightmap_light);
2215 rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
2218 // compiles rtlight geometry
2219 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2220 void R_RTLight_Compile(rtlight_t *rtlight)
2222 int shadowmeshes, shadowtris, lightmeshes, lighttris, numclusters, numsurfaces;
2223 entity_render_t *ent = &cl_entities[0].render;
2224 model_t *model = ent->model;
2226 // compile the light
2227 rtlight->compiled = true;
2228 rtlight->static_numclusters = 0;
2229 rtlight->static_numclusterpvsbytes = 0;
2230 rtlight->static_clusterlist = NULL;
2231 rtlight->static_clusterpvs = NULL;
2232 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2233 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2234 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2235 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2236 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2237 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2239 if (model && model->GetLightInfo)
2241 // this variable directs the DrawShadowVolume and DrawLight code to capture into the mesh chain instead of rendering
2242 r_shadow_compilingrtlight = rtlight;
2243 R_Shadow_EnlargeClusterBuffer(model->brush.num_pvsclusters);
2244 R_Shadow_EnlargeSurfaceBuffer(model->nummodelsurfaces);
2245 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);
2248 rtlight->static_numclusters = numclusters;
2249 rtlight->static_numclusterpvsbytes = (model->brush.num_pvsclusters + 7) >> 3;
2250 rtlight->static_clusterlist = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
2251 rtlight->static_clusterpvs = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusterpvsbytes);
2252 memcpy(rtlight->static_clusterlist, r_shadow_buffer_clusterlist, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
2253 memcpy(rtlight->static_clusterpvs, r_shadow_buffer_clusterpvs, rtlight->static_numclusterpvsbytes);
2255 if (model->DrawShadowVolume && rtlight->shadow)
2257 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
2258 model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2259 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_shadow, false, false);
2261 if (model->DrawLight)
2263 rtlight->static_meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true);
2264 model->DrawLight(ent, rtlight->shadoworigin, vec3_origin, rtlight->radius, vec3_origin, &r_identitymatrix, &r_identitymatrix, &r_identitymatrix, NULL, 0, 0, 0, numsurfaces, r_shadow_buffer_surfacelist);
2265 rtlight->static_meshchain_light = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_light, true, false);
2267 // switch back to rendering when DrawShadowVolume or DrawLight is called
2268 r_shadow_compilingrtlight = NULL;
2272 // use smallest available cullradius - box radius or light radius
2273 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2274 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2278 if (rtlight->static_meshchain_shadow)
2281 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2284 shadowtris += mesh->numtriangles;
2290 if (rtlight->static_meshchain_light)
2293 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2296 lighttris += mesh->numtriangles;
2300 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);
2303 void R_RTLight_Uncompile(rtlight_t *rtlight)
2305 if (rtlight->compiled)
2307 if (rtlight->static_meshchain_shadow)
2308 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2309 rtlight->static_meshchain_shadow = NULL;
2310 if (rtlight->static_meshchain_light)
2311 Mod_ShadowMesh_Free(rtlight->static_meshchain_light);
2312 rtlight->static_meshchain_light = NULL;
2313 if (rtlight->static_clusterlist)
2314 Mem_Free(rtlight->static_clusterlist);
2315 rtlight->static_clusterlist = NULL;
2316 if (rtlight->static_clusterpvs)
2317 Mem_Free(rtlight->static_clusterpvs);
2318 rtlight->static_clusterpvs = NULL;
2319 rtlight->static_numclusters = 0;
2320 rtlight->static_numclusterpvsbytes = 0;
2321 rtlight->compiled = false;
2325 void R_Shadow_UncompileWorldLights(void)
2328 for (light = r_shadow_worldlightchain;light;light = light->next)
2329 R_RTLight_Uncompile(&light->rtlight);
2332 void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes)
2335 entity_render_t *ent;
2337 vec3_t relativelightorigin, relativeeyeorigin, lightcolor, lightcolor2;
2338 rtexture_t *cubemaptexture;
2339 matrix4x4_t matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz;
2340 int numclusters, numsurfaces;
2341 int *clusterlist, *surfacelist;
2343 vec3_t cullmins, cullmaxs;
2347 // loading is done before visibility checks because loading should happen
2348 // all at once at the start of a level, not when it stalls gameplay.
2349 // (especially important to benchmarks)
2350 if (rtlight->isstatic && !rtlight->compiled && r_shadow_staticworldlights.integer)
2351 R_RTLight_Compile(rtlight);
2352 if (rtlight->cubemapname[0])
2353 cubemaptexture = R_Shadow_Cubemap(rtlight->cubemapname);
2355 cubemaptexture = NULL;
2357 cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2358 cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2359 cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2360 cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2361 cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2362 cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2363 if (rtlight->style >= 0 && d_lightstylevalue[rtlight->style] <= 0)
2370 if (rtlight->compiled && r_shadow_staticworldlights.integer)
2372 // compiled light, world available and can receive realtime lighting
2373 // retrieve cluster information
2374 numclusters = rtlight->static_numclusters;
2375 clusterlist = rtlight->static_clusterlist;
2376 clusterpvs = rtlight->static_clusterpvs;
2377 VectorCopy(rtlight->cullmins, cullmins);
2378 VectorCopy(rtlight->cullmaxs, cullmaxs);
2380 else if (cl.worldmodel && cl.worldmodel->GetLightInfo)
2382 // dynamic light, world available and can receive realtime lighting
2383 // if the light box is offscreen, skip it right away
2384 if (R_CullBox(cullmins, cullmaxs))
2386 // calculate lit surfaces and clusters
2387 R_Shadow_EnlargeClusterBuffer(cl.worldmodel->brush.num_pvsclusters);
2388 R_Shadow_EnlargeSurfaceBuffer(cl.worldmodel->nummodelsurfaces);
2389 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);
2390 clusterlist = r_shadow_buffer_clusterlist;
2391 clusterpvs = r_shadow_buffer_clusterpvs;
2392 surfacelist = r_shadow_buffer_surfacelist;
2394 // if the reduced cluster bounds are offscreen, skip it
2395 if (R_CullBox(cullmins, cullmaxs))
2397 // check if light is illuminating any visible clusters
2400 for (i = 0;i < numclusters;i++)
2401 if (CHECKPVSBIT(r_pvsbits, clusterlist[i]))
2403 if (i == numclusters)
2406 // set up a scissor rectangle for this light
2407 if (R_Shadow_ScissorForBBox(cullmins, cullmaxs))
2410 f = (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f);
2411 VectorScale(rtlight->color, f, lightcolor);
2413 if (rtlight->selected)
2415 f = 2 + sin(realtime * M_PI * 4.0);
2416 VectorScale(lightcolor, f, lightcolor);
2420 shadow = rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows);
2422 if (shadow && (gl_stencil || visiblevolumes))
2424 if (!visiblevolumes)
2425 R_Shadow_Stage_ShadowVolumes();
2426 ent = &cl_entities[0].render;
2427 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2429 memset(&m, 0, sizeof(m));
2430 R_Mesh_Matrix(&ent->matrix);
2431 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2433 m.pointer_vertex = mesh->vertex3f;
2435 GL_LockArrays(0, mesh->numverts);
2436 if (r_shadowstage == SHADOWSTAGE_STENCIL)
2438 // decrement stencil if frontface is behind depthbuffer
2439 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2440 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2441 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2442 c_rtcached_shadowmeshes++;
2443 c_rtcached_shadowtris += mesh->numtriangles;
2444 // increment stencil if backface is behind depthbuffer
2445 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2446 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2448 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2449 c_rtcached_shadowmeshes++;
2450 c_rtcached_shadowtris += mesh->numtriangles;
2451 GL_LockArrays(0, 0);
2454 else if (numsurfaces)
2456 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2457 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, numsurfaces, surfacelist);
2459 if (r_drawentities.integer)
2461 for (i = 0;i < r_refdef.numentities;i++)
2463 ent = r_refdef.entities[i];
2465 if (r_shadow_cull.integer)
2467 if (!BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs))
2469 if (cl.worldmodel != NULL && cl.worldmodel->brush.BoxTouchingPVS != NULL && !cl.worldmodel->brush.BoxTouchingPVS(cl.worldmodel, clusterpvs, ent->mins, ent->maxs))
2472 if (!(ent->flags & RENDER_SHADOW) || !ent->model || !ent->model->DrawShadowVolume)
2474 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2475 // light emitting entities should not cast their own shadow
2476 if (VectorLength2(relativelightorigin) < 0.1)
2478 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, ent->model->nummodelsurfaces, ent->model->surfacelist);
2483 if (!visiblevolumes)
2485 R_Shadow_Stage_Light(shadow && gl_stencil);
2487 ent = &cl_entities[0].render;
2488 if (ent->model && ent->model->DrawLight && (ent->flags & RENDER_LIGHT))
2490 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2491 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2492 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2493 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2494 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2495 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2497 R_Mesh_Matrix(&ent->matrix);
2498 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2499 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, rtlight->ambientscale, rtlight->diffusescale, rtlight->specularscale);
2502 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, rtlight->ambientscale, rtlight->diffusescale, rtlight->specularscale, numsurfaces, surfacelist);
2504 if (r_drawentities.integer)
2506 for (i = 0;i < r_refdef.numentities;i++)
2508 ent = r_refdef.entities[i];
2509 // can't draw transparent entity lighting here because
2510 // transparent meshes are deferred for later
2511 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)
2513 VectorScale(lightcolor, ent->alpha, lightcolor2);
2514 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2515 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2516 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2517 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2518 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2519 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor2, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, rtlight->ambientscale, rtlight->diffusescale, rtlight->specularscale, ent->model->nummodelsurfaces, ent->model->surfacelist);
2526 void R_ShadowVolumeLighting(int visiblevolumes)
2532 if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2533 R_Shadow_EditLights_Reload_f();
2537 memset(&m, 0, sizeof(m));
2540 GL_BlendFunc(GL_ONE, GL_ONE);
2541 GL_DepthMask(false);
2542 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
2543 qglDisable(GL_CULL_FACE);
2544 GL_Color(0.0, 0.0125, 0.1, 1);
2547 R_Shadow_Stage_Begin();
2548 flag = r_rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2549 if (r_shadow_debuglight.integer >= 0)
2551 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2552 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
2553 R_DrawRTLight(&light->rtlight, visiblevolumes);
2556 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2557 if (light->flags & flag)
2558 R_DrawRTLight(&light->rtlight, visiblevolumes);
2560 for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
2561 R_DrawRTLight(&light->rtlight, visiblevolumes);
2565 qglEnable(GL_CULL_FACE);
2566 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
2569 R_Shadow_Stage_End();
2572 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2573 typedef struct suffixinfo_s
2576 qboolean flipx, flipy, flipdiagonal;
2579 static suffixinfo_t suffix[3][6] =
2582 {"px", false, false, false},
2583 {"nx", false, false, false},
2584 {"py", false, false, false},
2585 {"ny", false, false, false},
2586 {"pz", false, false, false},
2587 {"nz", false, false, false}
2590 {"posx", false, false, false},
2591 {"negx", false, false, false},
2592 {"posy", false, false, false},
2593 {"negy", false, false, false},
2594 {"posz", false, false, false},
2595 {"negz", false, false, false}
2598 {"rt", true, false, true},
2599 {"lf", false, true, true},
2600 {"ft", true, true, false},
2601 {"bk", false, false, false},
2602 {"up", true, false, true},
2603 {"dn", true, false, true}
2607 static int componentorder[4] = {0, 1, 2, 3};
2609 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2611 int i, j, cubemapsize;
2612 qbyte *cubemappixels, *image_rgba;
2613 rtexture_t *cubemaptexture;
2615 // must start 0 so the first loadimagepixels has no requested width/height
2617 cubemappixels = NULL;
2618 cubemaptexture = NULL;
2619 // keep trying different suffix groups (posx, px, rt) until one loads
2620 for (j = 0;j < 3 && !cubemappixels;j++)
2622 // load the 6 images in the suffix group
2623 for (i = 0;i < 6;i++)
2625 // generate an image name based on the base and and suffix
2626 snprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2628 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2630 // an image loaded, make sure width and height are equal
2631 if (image_width == image_height)
2633 // if this is the first image to load successfully, allocate the cubemap memory
2634 if (!cubemappixels && image_width >= 1)
2636 cubemapsize = image_width;
2637 // note this clears to black, so unavailable sides are black
2638 cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2640 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2642 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);
2645 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2647 Mem_Free(image_rgba);
2651 // if a cubemap loaded, upload it
2654 if (!r_shadow_filters_texturepool)
2655 r_shadow_filters_texturepool = R_AllocTexturePool();
2656 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
2657 Mem_Free(cubemappixels);
2661 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
2662 for (j = 0;j < 3;j++)
2663 for (i = 0;i < 6;i++)
2664 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2665 Con_Print(" and was unable to find any of them.\n");
2667 return cubemaptexture;
2670 rtexture_t *R_Shadow_Cubemap(const char *basename)
2673 for (i = 0;i < numcubemaps;i++)
2674 if (!strcasecmp(cubemaps[i].basename, basename))
2675 return cubemaps[i].texture;
2676 if (i >= MAX_CUBEMAPS)
2679 strcpy(cubemaps[i].basename, basename);
2680 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
2681 return cubemaps[i].texture;
2684 void R_Shadow_FreeCubemaps(void)
2687 R_FreeTexturePool(&r_shadow_filters_texturepool);
2690 dlight_t *R_Shadow_NewWorldLight(void)
2693 light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
2694 light->next = r_shadow_worldlightchain;
2695 r_shadow_worldlightchain = light;
2699 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, vec_t coronasizescale, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int flags)
2701 VectorCopy(origin, light->origin);
2702 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
2703 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
2704 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
2705 light->color[0] = max(color[0], 0);
2706 light->color[1] = max(color[1], 0);
2707 light->color[2] = max(color[2], 0);
2708 light->radius = max(radius, 0);
2709 light->style = style;
2710 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
2712 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
2715 light->shadow = shadowenable;
2716 light->corona = corona;
2719 strlcpy(light->cubemapname, cubemapname, strlen(light->cubemapname));
2720 light->coronasizescale = coronasizescale;
2721 light->ambientscale = ambientscale;
2722 light->diffusescale = diffusescale;
2723 light->specularscale = specularscale;
2724 light->flags = flags;
2725 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
2727 R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
2730 void R_Shadow_FreeWorldLight(dlight_t *light)
2732 dlight_t **lightpointer;
2733 R_RTLight_Uncompile(&light->rtlight);
2734 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
2735 if (*lightpointer != light)
2736 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
2737 *lightpointer = light->next;
2741 void R_Shadow_ClearWorldLights(void)
2743 while (r_shadow_worldlightchain)
2744 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
2745 r_shadow_selectedlight = NULL;
2746 R_Shadow_FreeCubemaps();
2749 void R_Shadow_SelectLight(dlight_t *light)
2751 if (r_shadow_selectedlight)
2752 r_shadow_selectedlight->selected = false;
2753 r_shadow_selectedlight = light;
2754 if (r_shadow_selectedlight)
2755 r_shadow_selectedlight->selected = true;
2758 void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
2760 float scale = r_editlights_cursorgrid.value * 0.5f;
2761 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);
2764 void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
2767 const dlight_t *light;
2770 if (light->selected)
2771 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
2774 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);
2777 void R_Shadow_DrawLightSprites(void)
2783 for (i = 0;i < 5;i++)
2785 lighttextures[i] = NULL;
2786 if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1))))
2787 lighttextures[i] = pic->tex;
2790 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
2791 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, i % 5);
2792 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
2795 void R_Shadow_SelectLightInView(void)
2797 float bestrating, rating, temp[3];
2798 dlight_t *best, *light;
2801 for (light = r_shadow_worldlightchain;light;light = light->next)
2803 VectorSubtract(light->origin, r_vieworigin, temp);
2804 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
2807 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
2808 if (bestrating < rating && CL_TraceLine(light->origin, r_vieworigin, NULL, NULL, true, NULL, SUPERCONTENTS_SOLID) == 1.0f)
2810 bestrating = rating;
2815 R_Shadow_SelectLight(best);
2818 void R_Shadow_LoadWorldLights(void)
2820 int n, a, style, shadow, flags;
2821 char name[MAX_QPATH], cubemapname[MAX_QPATH], *lightsstring, *s, *t;
2822 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
2823 if (cl.worldmodel == NULL)
2825 Con_Print("No map loaded.\n");
2828 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2829 strlcat (name, ".rtlights", sizeof (name));
2830 lightsstring = FS_LoadFile(name, tempmempool, false);
2840 for (;COM_Parse(t, true) && strcmp(
2841 if (COM_Parse(t, true))
2843 if (com_token[0] == '!')
2846 origin[0] = atof(com_token+1);
2849 origin[0] = atof(com_token);
2854 while (*s && *s != '\n')
2860 // check for modifier flags
2866 a = sscanf(t, "%f %f %f %f %f %f %f %d %s %f %f %f %f %f %f %f %f %i", &origin[0], &origin[1], &origin[2], &radius, &color[0], &color[1], &color[2], &style, cubemapname, &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
2868 flags = LIGHTFLAG_REALTIMEMODE;
2876 coronasizescale = 0.25f;
2878 VectorClear(angles);
2881 if (a < 9 || !strcmp(cubemapname, "\"\""))
2886 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] coronasizescale ambientscale diffusescale specularscale flags)\n", a, n + 1);
2889 VectorScale(color, r_editlights_rtlightscolorscale.value, color);
2890 radius *= r_editlights_rtlightssizescale.value;
2891 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
2896 Con_Printf("invalid rtlights file \"%s\"\n", name);
2897 Mem_Free(lightsstring);
2901 void R_Shadow_SaveWorldLights(void)
2904 int bufchars, bufmaxchars;
2906 char name[MAX_QPATH];
2908 if (!r_shadow_worldlightchain)
2910 if (cl.worldmodel == NULL)
2912 Con_Print("No map loaded.\n");
2915 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2916 strlcat (name, ".rtlights", sizeof (name));
2917 bufchars = bufmaxchars = 0;
2919 for (light = r_shadow_worldlightchain;light;light = light->next)
2921 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
2922 sprintf(line, "%s%f %f %f %f %f %f %f %d \"%s\" %f %f %f %f %f %f %f %f %i\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], light->coronasizescale, light->ambientscale, light->diffusescale, light->specularscale, light->flags);
2923 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
2924 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]);
2926 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);
2927 if (bufchars + (int) strlen(line) > bufmaxchars)
2929 bufmaxchars = bufchars + strlen(line) + 2048;
2931 buf = Mem_Alloc(r_shadow_mempool, bufmaxchars);
2935 memcpy(buf, oldbuf, bufchars);
2941 memcpy(buf + bufchars, line, strlen(line));
2942 bufchars += strlen(line);
2946 FS_WriteFile(name, buf, bufchars);
2951 void R_Shadow_LoadLightsFile(void)
2954 char name[MAX_QPATH], *lightsstring, *s, *t;
2955 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
2956 if (cl.worldmodel == NULL)
2958 Con_Print("No map loaded.\n");
2961 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2962 strlcat (name, ".lights", sizeof (name));
2963 lightsstring = FS_LoadFile(name, tempmempool, false);
2971 while (*s && *s != '\n')
2976 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);
2980 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);
2983 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
2984 radius = bound(15, radius, 4096);
2985 VectorScale(color, (2.0f / (8388608.0f)), color);
2986 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
2991 Con_Printf("invalid lights file \"%s\"\n", name);
2992 Mem_Free(lightsstring);
2996 // tyrlite/hmap2 light types in the delay field
2997 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
2999 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3001 int entnum, style, islight, skin, pflags, effects, type, n;
3004 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3005 char key[256], value[1024];
3007 if (cl.worldmodel == NULL)
3009 Con_Print("No map loaded.\n");
3012 // try to load a .ent file first
3013 FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
3014 strlcat (key, ".ent", sizeof (key));
3015 data = entfiledata = FS_LoadFile(key, tempmempool, true);
3016 // and if that is not found, fall back to the bsp file entity string
3018 data = cl.worldmodel->brush.entities;
3021 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
3023 type = LIGHTTYPE_MINUSX;
3024 origin[0] = origin[1] = origin[2] = 0;
3025 originhack[0] = originhack[1] = originhack[2] = 0;
3026 angles[0] = angles[1] = angles[2] = 0;
3027 color[0] = color[1] = color[2] = 1;
3028 light[0] = light[1] = light[2] = 1;light[3] = 300;
3029 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3039 if (!COM_ParseToken(&data, false))
3041 if (com_token[0] == '}')
3042 break; // end of entity
3043 if (com_token[0] == '_')
3044 strcpy(key, com_token + 1);
3046 strcpy(key, com_token);
3047 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3048 key[strlen(key)-1] = 0;
3049 if (!COM_ParseToken(&data, false))
3051 strcpy(value, com_token);
3053 // now that we have the key pair worked out...
3054 if (!strcmp("light", key))
3056 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3060 light[0] = vec[0] * (1.0f / 256.0f);
3061 light[1] = vec[0] * (1.0f / 256.0f);
3062 light[2] = vec[0] * (1.0f / 256.0f);
3068 light[0] = vec[0] * (1.0f / 255.0f);
3069 light[1] = vec[1] * (1.0f / 255.0f);
3070 light[2] = vec[2] * (1.0f / 255.0f);
3074 else if (!strcmp("delay", key))
3076 else if (!strcmp("origin", key))
3077 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3078 else if (!strcmp("angle", key))
3079 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3080 else if (!strcmp("angles", key))
3081 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3082 else if (!strcmp("color", key))
3083 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3084 else if (!strcmp("wait", key))
3085 fadescale = atof(value);
3086 else if (!strcmp("classname", key))
3088 if (!strncmp(value, "light", 5))
3091 if (!strcmp(value, "light_fluoro"))
3096 overridecolor[0] = 1;
3097 overridecolor[1] = 1;
3098 overridecolor[2] = 1;
3100 if (!strcmp(value, "light_fluorospark"))
3105 overridecolor[0] = 1;
3106 overridecolor[1] = 1;
3107 overridecolor[2] = 1;
3109 if (!strcmp(value, "light_globe"))
3114 overridecolor[0] = 1;
3115 overridecolor[1] = 0.8;
3116 overridecolor[2] = 0.4;
3118 if (!strcmp(value, "light_flame_large_yellow"))
3123 overridecolor[0] = 1;
3124 overridecolor[1] = 0.5;
3125 overridecolor[2] = 0.1;
3127 if (!strcmp(value, "light_flame_small_yellow"))
3132 overridecolor[0] = 1;
3133 overridecolor[1] = 0.5;
3134 overridecolor[2] = 0.1;
3136 if (!strcmp(value, "light_torch_small_white"))
3141 overridecolor[0] = 1;
3142 overridecolor[1] = 0.5;
3143 overridecolor[2] = 0.1;
3145 if (!strcmp(value, "light_torch_small_walltorch"))
3150 overridecolor[0] = 1;
3151 overridecolor[1] = 0.5;
3152 overridecolor[2] = 0.1;
3156 else if (!strcmp("style", key))
3157 style = atoi(value);
3158 else if (cl.worldmodel->type == mod_brushq3)
3160 if (!strcmp("scale", key))
3161 lightscale = atof(value);
3162 if (!strcmp("fade", key))
3163 fadescale = atof(value);
3165 else if (!strcmp("skin", key))
3166 skin = (int)atof(value);
3167 else if (!strcmp("pflags", key))
3168 pflags = (int)atof(value);
3169 else if (!strcmp("effects", key))
3170 effects = (int)atof(value);
3174 if (lightscale <= 0)
3178 if (color[0] == color[1] && color[0] == color[2])
3180 color[0] *= overridecolor[0];
3181 color[1] *= overridecolor[1];
3182 color[2] *= overridecolor[2];
3184 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3185 color[0] = color[0] * light[0];
3186 color[1] = color[1] * light[1];
3187 color[2] = color[2] * light[2];
3190 case LIGHTTYPE_MINUSX:
3192 case LIGHTTYPE_RECIPX:
3194 VectorScale(color, (1.0f / 16.0f), color);
3196 case LIGHTTYPE_RECIPXX:
3198 VectorScale(color, (1.0f / 16.0f), color);
3201 case LIGHTTYPE_NONE:
3205 case LIGHTTYPE_MINUSXX:
3208 VectorAdd(origin, originhack, origin);
3210 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, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3213 Mem_Free(entfiledata);
3217 void R_Shadow_SetCursorLocationForView(void)
3219 vec_t dist, push, frac;
3220 vec3_t dest, endpos, normal;
3221 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
3222 frac = CL_TraceLine(r_vieworigin, dest, endpos, normal, true, NULL, SUPERCONTENTS_SOLID);
3225 dist = frac * r_editlights_cursordistance.value;
3226 push = r_editlights_cursorpushback.value;
3230 VectorMA(endpos, push, r_viewforward, endpos);
3231 VectorMA(endpos, r_editlights_cursorpushoff.value, normal, endpos);
3233 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3234 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3235 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3238 void R_Shadow_UpdateWorldLightSelection(void)
3240 if (r_editlights.integer)
3242 R_Shadow_SetCursorLocationForView();
3243 R_Shadow_SelectLightInView();
3244 R_Shadow_DrawLightSprites();
3247 R_Shadow_SelectLight(NULL);
3250 void R_Shadow_EditLights_Clear_f(void)
3252 R_Shadow_ClearWorldLights();
3255 void R_Shadow_EditLights_Reload_f(void)
3259 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
3260 R_Shadow_ClearWorldLights();
3261 R_Shadow_LoadWorldLights();
3262 if (r_shadow_worldlightchain == NULL)
3264 R_Shadow_LoadLightsFile();
3265 if (r_shadow_worldlightchain == NULL)
3266 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3270 void R_Shadow_EditLights_Save_f(void)
3274 R_Shadow_SaveWorldLights();
3277 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3279 R_Shadow_ClearWorldLights();
3280 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3283 void R_Shadow_EditLights_ImportLightsFile_f(void)
3285 R_Shadow_ClearWorldLights();
3286 R_Shadow_LoadLightsFile();
3289 void R_Shadow_EditLights_Spawn_f(void)
3292 if (!r_editlights.integer)
3294 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3297 if (Cmd_Argc() != 1)
3299 Con_Print("r_editlights_spawn does not take parameters\n");
3302 color[0] = color[1] = color[2] = 1;
3303 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3306 void R_Shadow_EditLights_Edit_f(void)
3308 vec3_t origin, angles, color;
3309 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3310 int style, shadows, flags, normalmode, realtimemode;
3311 char cubemapname[1024];
3312 if (!r_editlights.integer)
3314 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3317 if (!r_shadow_selectedlight)
3319 Con_Print("No selected light.\n");
3322 VectorCopy(r_shadow_selectedlight->origin, origin);
3323 VectorCopy(r_shadow_selectedlight->angles, angles);
3324 VectorCopy(r_shadow_selectedlight->color, color);
3325 radius = r_shadow_selectedlight->radius;
3326 style = r_shadow_selectedlight->style;
3327 if (r_shadow_selectedlight->cubemapname)
3328 strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
3331 shadows = r_shadow_selectedlight->shadow;
3332 corona = r_shadow_selectedlight->corona;
3333 coronasizescale = r_shadow_selectedlight->coronasizescale;
3334 ambientscale = r_shadow_selectedlight->ambientscale;
3335 diffusescale = r_shadow_selectedlight->diffusescale;
3336 specularscale = r_shadow_selectedlight->specularscale;
3337 flags = r_shadow_selectedlight->flags;
3338 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3339 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3340 if (!strcmp(Cmd_Argv(1), "origin"))
3342 if (Cmd_Argc() != 5)
3344 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3347 origin[0] = atof(Cmd_Argv(2));
3348 origin[1] = atof(Cmd_Argv(3));
3349 origin[2] = atof(Cmd_Argv(4));
3351 else if (!strcmp(Cmd_Argv(1), "originx"))
3353 if (Cmd_Argc() != 3)
3355 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3358 origin[0] = atof(Cmd_Argv(2));
3360 else if (!strcmp(Cmd_Argv(1), "originy"))
3362 if (Cmd_Argc() != 3)
3364 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3367 origin[1] = atof(Cmd_Argv(2));
3369 else if (!strcmp(Cmd_Argv(1), "originz"))
3371 if (Cmd_Argc() != 3)
3373 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3376 origin[2] = atof(Cmd_Argv(2));
3378 else if (!strcmp(Cmd_Argv(1), "move"))
3380 if (Cmd_Argc() != 5)
3382 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3385 origin[0] += atof(Cmd_Argv(2));
3386 origin[1] += atof(Cmd_Argv(3));
3387 origin[2] += atof(Cmd_Argv(4));
3389 else if (!strcmp(Cmd_Argv(1), "movex"))
3391 if (Cmd_Argc() != 3)
3393 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3396 origin[0] += atof(Cmd_Argv(2));
3398 else if (!strcmp(Cmd_Argv(1), "movey"))
3400 if (Cmd_Argc() != 3)
3402 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3405 origin[1] += atof(Cmd_Argv(2));
3407 else if (!strcmp(Cmd_Argv(1), "movez"))
3409 if (Cmd_Argc() != 3)
3411 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3414 origin[2] += atof(Cmd_Argv(2));
3416 else if (!strcmp(Cmd_Argv(1), "angles"))
3418 if (Cmd_Argc() != 5)
3420 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3423 angles[0] = atof(Cmd_Argv(2));
3424 angles[1] = atof(Cmd_Argv(3));
3425 angles[2] = atof(Cmd_Argv(4));
3427 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3429 if (Cmd_Argc() != 3)
3431 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3434 angles[0] = atof(Cmd_Argv(2));
3436 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3438 if (Cmd_Argc() != 3)
3440 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3443 angles[1] = atof(Cmd_Argv(2));
3445 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3447 if (Cmd_Argc() != 3)
3449 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3452 angles[2] = atof(Cmd_Argv(2));
3454 else if (!strcmp(Cmd_Argv(1), "color"))
3456 if (Cmd_Argc() != 5)
3458 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3461 color[0] = atof(Cmd_Argv(2));
3462 color[1] = atof(Cmd_Argv(3));
3463 color[2] = atof(Cmd_Argv(4));
3465 else if (!strcmp(Cmd_Argv(1), "radius"))
3467 if (Cmd_Argc() != 3)
3469 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3472 radius = atof(Cmd_Argv(2));
3474 else if (!strcmp(Cmd_Argv(1), "style"))
3476 if (Cmd_Argc() != 3)
3478 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3481 style = atoi(Cmd_Argv(2));
3483 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3487 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3490 if (Cmd_Argc() == 3)
3491 strcpy(cubemapname, Cmd_Argv(2));
3495 else if (!strcmp(Cmd_Argv(1), "shadows"))
3497 if (Cmd_Argc() != 3)
3499 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3502 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3504 else if (!strcmp(Cmd_Argv(1), "corona"))
3506 if (Cmd_Argc() != 3)
3508 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3511 corona = atof(Cmd_Argv(2));
3513 else if (!strcmp(Cmd_Argv(1), "coronasize"))
3515 if (Cmd_Argc() != 3)
3517 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3520 coronasizescale = atof(Cmd_Argv(2));
3522 else if (!strcmp(Cmd_Argv(1), "ambient"))
3524 if (Cmd_Argc() != 3)
3526 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3529 ambientscale = atof(Cmd_Argv(2));
3531 else if (!strcmp(Cmd_Argv(1), "diffuse"))
3533 if (Cmd_Argc() != 3)
3535 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3538 diffusescale = atof(Cmd_Argv(2));
3540 else if (!strcmp(Cmd_Argv(1), "specular"))
3542 if (Cmd_Argc() != 3)
3544 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3547 specularscale = atof(Cmd_Argv(2));
3549 else if (!strcmp(Cmd_Argv(1), "normalmode"))
3551 if (Cmd_Argc() != 3)
3553 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3556 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3558 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
3560 if (Cmd_Argc() != 3)
3562 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3565 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3569 Con_Print("usage: r_editlights_edit [property] [value]\n");
3570 Con_Print("Selected light's properties:\n");
3571 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3572 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3573 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3574 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3575 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3576 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3577 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3578 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
3579 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
3580 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
3581 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
3582 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
3583 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
3584 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
3587 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
3588 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3591 void R_Shadow_EditLights_EditAll_f(void)
3595 if (!r_editlights.integer)
3597 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
3601 for (light = r_shadow_worldlightchain;light;light = light->next)
3603 R_Shadow_SelectLight(light);
3604 R_Shadow_EditLights_Edit_f();
3608 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3610 int lightnumber, lightcount;
3614 if (!r_editlights.integer)
3620 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
3621 if (light == r_shadow_selectedlight)
3622 lightnumber = lightcount;
3623 sprintf(temp, "Cursor %f %f %f Total Lights %i", r_editlights_cursorlocation[0], r_editlights_cursorlocation[1], r_editlights_cursorlocation[2], lightcount);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3624 if (r_shadow_selectedlight == NULL)
3626 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3627 sprintf(temp, "Origin : %f %f %f\n", 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;
3628 sprintf(temp, "Angles : %f %f %f\n", 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;
3629 sprintf(temp, "Color : %f %f %f\n", 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;
3630 sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3631 sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3632 sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3633 sprintf(temp, "Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3634 sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3635 sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3636 sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3637 sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3638 sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3639 sprintf(temp, "NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3640 sprintf(temp, "RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3643 void R_Shadow_EditLights_ToggleShadow_f(void)
3645 if (!r_editlights.integer)
3647 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3650 if (!r_shadow_selectedlight)
3652 Con_Print("No selected light.\n");
3655 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, r_shadow_selectedlight->coronasizescale, r_shadow_selectedlight->ambientscale, r_shadow_selectedlight->diffusescale, r_shadow_selectedlight->specularscale, r_shadow_selectedlight->flags);
3658 void R_Shadow_EditLights_ToggleCorona_f(void)
3660 if (!r_editlights.integer)
3662 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3665 if (!r_shadow_selectedlight)
3667 Con_Print("No selected light.\n");
3670 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, r_shadow_selectedlight->coronasizescale, r_shadow_selectedlight->ambientscale, r_shadow_selectedlight->diffusescale, r_shadow_selectedlight->specularscale, r_shadow_selectedlight->flags);
3673 void R_Shadow_EditLights_Remove_f(void)
3675 if (!r_editlights.integer)
3677 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
3680 if (!r_shadow_selectedlight)
3682 Con_Print("No selected light.\n");
3685 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3686 r_shadow_selectedlight = NULL;
3689 void R_Shadow_EditLights_Help_f(void)
3692 "Documentation on r_editlights system:\n"
3694 "r_editlights : enable/disable editing mode\n"
3695 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
3696 "r_editlights_cursorpushback : push back cursor this far from surface\n"
3697 "r_editlights_cursorpushoff : push cursor off surface this far\n"
3698 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
3699 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
3700 "r_editlights_rtlightssizescale : imported rtlight size scaling\n"
3701 "r_editlights_rtlightscolorscale : imported rtlight color scaling\n"
3703 "r_editlights_help : this help\n"
3704 "r_editlights_clear : remove all lights\n"
3705 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
3706 "r_editlights_save : save to .rtlights file\n"
3707 "r_editlights_spawn : create a light with default settings\n"
3708 "r_editlights_edit command : edit selected light - more documentation below\n"
3709 "r_editlights_remove : remove selected light\n"
3710 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
3711 "r_editlights_importlightentitiesfrommap : reload light entities\n"
3712 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
3714 "origin x y z : set light location\n"
3715 "originx x: set x component of light location\n"
3716 "originy y: set y component of light location\n"
3717 "originz z: set z component of light location\n"
3718 "move x y z : adjust light location\n"
3719 "movex x: adjust x component of light location\n"
3720 "movey y: adjust y component of light location\n"
3721 "movez z: adjust z component of light location\n"
3722 "angles x y z : set light angles\n"
3723 "anglesx x: set x component of light angles\n"
3724 "anglesy y: set y component of light angles\n"
3725 "anglesz z: set z component of light angles\n"
3726 "color r g b : set color of light (can be brighter than 1 1 1)\n"
3727 "radius radius : set radius (size) of light\n"
3728 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
3729 "cubemap basename : set filter cubemap of light (not yet supported)\n"
3730 "shadows 1/0 : turn on/off shadows\n"
3731 "corona n : set corona intensity\n"
3732 "coronasize n : set corona size (0-1)\n"
3733 "ambient n : set ambient intensity (0-1)\n"
3734 "diffuse n : set diffuse intensity (0-1)\n"
3735 "specular n : set specular intensity (0-1)\n"
3736 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
3737 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
3738 "<nothing> : print light properties to console\n"
3742 void R_Shadow_EditLights_CopyInfo_f(void)
3744 if (!r_editlights.integer)
3746 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
3749 if (!r_shadow_selectedlight)
3751 Con_Print("No selected light.\n");
3754 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
3755 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
3756 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
3757 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
3758 if (r_shadow_selectedlight->cubemapname)
3759 strcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname);
3761 r_shadow_bufferlight.cubemapname[0] = 0;
3762 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
3763 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
3764 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
3765 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
3766 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
3767 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
3768 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
3771 void R_Shadow_EditLights_PasteInfo_f(void)
3773 if (!r_editlights.integer)
3775 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
3778 if (!r_shadow_selectedlight)
3780 Con_Print("No selected light.\n");
3783 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, r_shadow_bufferlight.coronasizescale, r_shadow_bufferlight.ambientscale, r_shadow_bufferlight.diffusescale, r_shadow_bufferlight.specularscale, r_shadow_bufferlight.flags);
3786 void R_Shadow_EditLights_Init(void)
3788 Cvar_RegisterVariable(&r_editlights);
3789 Cvar_RegisterVariable(&r_editlights_cursordistance);
3790 Cvar_RegisterVariable(&r_editlights_cursorpushback);
3791 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
3792 Cvar_RegisterVariable(&r_editlights_cursorgrid);
3793 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
3794 Cvar_RegisterVariable(&r_editlights_rtlightssizescale);
3795 Cvar_RegisterVariable(&r_editlights_rtlightscolorscale);
3796 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
3797 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
3798 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
3799 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
3800 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
3801 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
3802 Cmd_AddCommand("r_editlights_editall", R_Shadow_EditLights_EditAll_f);
3803 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
3804 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
3805 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
3806 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
3807 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);
3808 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f);
3809 Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f);