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 normally rendered using Carmack's Reverse technique, in which
11 backfaces behind zbuffer (zfail) increment the stencil, and frontfaces behind
12 zbuffer (zfail) decrement the stencil, the result is a stencil value of zero
13 where shadows did not intersect the visible geometry, suitable as a stencil
14 mask for rendering lighting everywhere but shadow.
16 In our case to hopefully avoid the Creative Labs patent, we draw the backfaces
17 as decrement and the frontfaces as increment, and we redefine the DepthFunc to
18 GL_LESS (the patent uses GL_GEQUAL) which causes zfail when behind surfaces
19 and zpass when infront (the patent draws where zpass with a GL_GEQUAL test),
20 additionally we clear stencil to 128 to avoid the need for the unclamped
21 incr/decr extension (not related to patent).
24 This algorithm may be covered by Creative's patent (US Patent #6384822),
25 however that patent is quite specific about increment on backfaces and
26 decrement on frontfaces where zpass with GL_GEQUAL depth test, which is
27 opposite this implementation and partially opposite Carmack's Reverse paper
28 (which uses GL_LESS, but increments on backfaces and decrements on frontfaces).
32 Terminology: Stencil Light Volume (sometimes called Light Volumes)
33 Similar to a Stencil Shadow Volume, but inverted; rather than containing the
34 areas in shadow it contains the areas in light, this can only be built
35 quickly for certain limited cases (such as portal visibility from a point),
36 but is quite useful for some effects (sunlight coming from sky polygons is
37 one possible example, translucent occluders is another example).
41 Terminology: Optimized Stencil Shadow Volume
42 A Stencil Shadow Volume that has been processed sufficiently to ensure it has
43 no duplicate coverage of areas (no need to shadow an area twice), often this
44 greatly improves performance but is an operation too costly to use on moving
45 lights (however completely optimal Stencil Light Volumes can be constructed
50 Terminology: Per Pixel Lighting (sometimes abbreviated PPL)
51 Per pixel evaluation of lighting equations, at a bare minimum this involves
52 DOT3 shading of diffuse lighting (per pixel dotproduct of negated incidence
53 vector and surface normal, using a texture of the surface bumps, called a
54 NormalMap) if supported by hardware; in our case there is support for cards
55 which are incapable of DOT3, the quality is quite poor however. Additionally
56 it is desirable to have specular evaluation per pixel, per vertex
57 normalization of specular halfangle vectors causes noticable distortion but
58 is unavoidable on hardware without GL_ARB_fragment_program or
59 GL_ARB_fragment_shader.
63 Terminology: Normalization CubeMap
64 A cubemap containing normalized dot3-encoded (vectors of length 1 or less
65 encoded as RGB colors) for any possible direction, this technique allows per
66 pixel calculation of incidence vector for per pixel lighting purposes, which
67 would not otherwise be possible per pixel without GL_ARB_fragment_program or
68 GL_ARB_fragment_shader.
72 Terminology: 2D+1D Attenuation Texturing
73 A very crude approximation of light attenuation with distance which results
74 in cylindrical light shapes which fade vertically as a streak (some games
75 such as Doom3 allow this to be rotated to be less noticable in specific
76 cases), the technique is simply modulating lighting by two 2D textures (which
77 can be the same) on different axes of projection (XY and Z, typically), this
78 is the second best technique available without 3D Attenuation Texturing,
79 GL_ARB_fragment_program or GL_ARB_fragment_shader technology.
83 Terminology: 2D+1D Inverse Attenuation Texturing
84 A clever method described in papers on the Abducted engine, this has a squared
85 distance texture (bright on the outside, black in the middle), which is used
86 twice using GL_ADD blending, the result of this is used in an inverse modulate
87 (GL_ONE_MINUS_DST_ALPHA, GL_ZERO) to implement the equation
88 lighting*=(1-((X*X+Y*Y)+(Z*Z))) which is spherical (unlike 2D+1D attenuation
93 Terminology: 3D Attenuation Texturing
94 A slightly crude approximation of light attenuation with distance, its flaws
95 are limited radius and resolution (performance tradeoffs).
99 Terminology: 3D Attenuation-Normalization Texturing
100 A 3D Attenuation Texture merged with a Normalization CubeMap, by making the
101 vectors shorter the lighting becomes darker, a very effective optimization of
102 diffuse lighting if 3D Attenuation Textures are already used.
106 Terminology: Light Cubemap Filtering
107 A technique for modeling non-uniform light distribution according to
108 direction, for example a lantern may use a cubemap to describe the light
109 emission pattern of the cage around the lantern (as well as soot buildup
110 discoloring the light in certain areas), often also used for softened grate
111 shadows and light shining through a stained glass window (done crudely by
112 texturing the lighting with a cubemap), another good example would be a disco
113 light. This technique is used heavily in many games (Doom3 does not support
118 Terminology: Light Projection Filtering
119 A technique for modeling shadowing of light passing through translucent
120 surfaces, allowing stained glass windows and other effects to be done more
121 elegantly than possible with Light Cubemap Filtering by applying an occluder
122 texture to the lighting combined with a stencil light volume to limit the lit
123 area, this technique is used by Doom3 for spotlights and flashlights, among
124 other things, this can also be used more generally to render light passing
125 through multiple translucent occluders in a scene (using a light volume to
126 describe the area beyond the occluder, and thus mask off rendering of all
131 Terminology: Doom3 Lighting
132 A combination of Stencil Shadow Volume, Per Pixel Lighting, Normalization
133 CubeMap, 2D+1D Attenuation Texturing, and Light Projection Filtering, as
134 demonstrated by the game Doom3.
137 #include "quakedef.h"
138 #include "r_shadow.h"
139 #include "cl_collision.h"
143 extern void R_Shadow_EditLights_Init(void);
145 typedef enum r_shadow_rendermode_e
147 R_SHADOW_RENDERMODE_NONE,
148 R_SHADOW_RENDERMODE_STENCIL,
149 R_SHADOW_RENDERMODE_STENCILTWOSIDE,
150 R_SHADOW_RENDERMODE_LIGHT_VERTEX,
151 R_SHADOW_RENDERMODE_LIGHT_DOT3,
152 R_SHADOW_RENDERMODE_LIGHT_GLSL,
153 R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
154 R_SHADOW_RENDERMODE_VISIBLELIGHTING,
156 r_shadow_rendermode_t;
158 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
159 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
160 r_shadow_rendermode_t r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_NONE;
162 mempool_t *r_shadow_mempool;
164 int maxshadowelements;
178 int r_shadow_buffer_numleafpvsbytes;
179 unsigned char *r_shadow_buffer_leafpvs;
180 int *r_shadow_buffer_leaflist;
182 int r_shadow_buffer_numsurfacepvsbytes;
183 unsigned char *r_shadow_buffer_surfacepvs;
184 int *r_shadow_buffer_surfacelist;
186 rtexturepool_t *r_shadow_texturepool;
187 rtexture_t *r_shadow_attenuation2dtexture;
188 rtexture_t *r_shadow_attenuation3dtexture;
190 // lights are reloaded when this changes
191 char r_shadow_mapname[MAX_QPATH];
193 // used only for light filters (cubemaps)
194 rtexturepool_t *r_shadow_filters_texturepool;
196 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0", "generate fake bumpmaps from diffuse textures at this bumpyness, try 4 to match tenebrae, higher values increase depth, requires r_restart to take effect"};
197 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4", "what magnitude to interpret _bump.tga textures as, higher values increase depth, requires r_restart to take effect"};
198 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
199 cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1", "0 disables gloss (specularity) rendering, 1 uses gloss if textures are found, 2 forces a flat metallic specular effect on everything without textures (similar to tenebrae)"};
200 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.25", "how bright the forced flat gloss should look if r_shadow_gloss is 2"};
201 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
202 cvar_t r_shadow_lightattenuationpower = {0, "r_shadow_lightattenuationpower", "0.5", "changes attenuation texture generation (does not affect r_glsl lighting)"};
203 cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1", "changes attenuation texture generation (does not affect r_glsl lighting)"};
204 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
205 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"};
206 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000", "how far to cast shadows"};
207 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
208 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
209 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal culling optimizations on dynamic lights (slow! you probably don't want this!)"};
210 cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0", "enables rendering of full world lighting (whether loaded from the map, or a .rtlights file, or a .ent file, or a .lights file produced by hlight)"};
211 cvar_t r_shadow_realtime_world_dlightshadows = {CVAR_SAVE, "r_shadow_realtime_world_dlightshadows", "1", "enables shadows from dynamic lights when using full world lighting"};
212 cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0", "brightness to render lightmaps when using full world lighting, try 0.5 for a tenebrae-like appearance"};
213 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
214 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
215 cvar_t r_shadow_realtime_world_compileshadow = {0, "r_shadow_realtime_world_compileshadow", "1", "enables compilation of shadows from world lights for higher performance rendering"};
216 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1", "use scissor optimization of light rendering (restricts rendering to the portion of the screen affected by the light)"};
217 cvar_t r_shadow_shadow_polygonfactor = {0, "r_shadow_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
218 cvar_t r_shadow_shadow_polygonoffset = {0, "r_shadow_shadow_polygonoffset", "1", "how much to push shadow volumes into the distance when rendering, to reduce chances of zfighting artifacts (should not be less than 0)"};
219 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1", "use 3D voxel textures for spherical attenuation rather than cylindrical (does not affect r_glsl lighting)"};
220 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
221 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
222 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
223 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
224 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
225 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
226 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
228 float r_shadow_attenpower, r_shadow_attenscale;
230 rtlight_t *r_shadow_compilingrtlight;
231 dlight_t *r_shadow_worldlightchain;
232 dlight_t *r_shadow_selectedlight;
233 dlight_t r_shadow_bufferlight;
234 vec3_t r_editlights_cursorlocation;
236 extern int con_vislines;
238 typedef struct cubemapinfo_s
245 #define MAX_CUBEMAPS 256
246 static int numcubemaps;
247 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
249 void R_Shadow_UncompileWorldLights(void);
250 void R_Shadow_ClearWorldLights(void);
251 void R_Shadow_SaveWorldLights(void);
252 void R_Shadow_LoadWorldLights(void);
253 void R_Shadow_LoadLightsFile(void);
254 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
255 void R_Shadow_EditLights_Reload_f(void);
256 void R_Shadow_ValidateCvars(void);
257 static void R_Shadow_MakeTextures(void);
258 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light);
260 void r_shadow_start(void)
262 // allocate vertex processing arrays
264 r_shadow_attenuation2dtexture = NULL;
265 r_shadow_attenuation3dtexture = NULL;
266 r_shadow_texturepool = NULL;
267 r_shadow_filters_texturepool = NULL;
268 R_Shadow_ValidateCvars();
269 R_Shadow_MakeTextures();
270 maxshadowelements = 0;
271 shadowelements = NULL;
279 shadowmarklist = NULL;
281 r_shadow_buffer_numleafpvsbytes = 0;
282 r_shadow_buffer_leafpvs = NULL;
283 r_shadow_buffer_leaflist = NULL;
284 r_shadow_buffer_numsurfacepvsbytes = 0;
285 r_shadow_buffer_surfacepvs = NULL;
286 r_shadow_buffer_surfacelist = NULL;
289 void r_shadow_shutdown(void)
291 R_Shadow_UncompileWorldLights();
293 r_shadow_attenuation2dtexture = NULL;
294 r_shadow_attenuation3dtexture = NULL;
295 R_FreeTexturePool(&r_shadow_texturepool);
296 R_FreeTexturePool(&r_shadow_filters_texturepool);
297 maxshadowelements = 0;
299 Mem_Free(shadowelements);
300 shadowelements = NULL;
303 Mem_Free(vertexupdate);
306 Mem_Free(vertexremap);
312 Mem_Free(shadowmark);
315 Mem_Free(shadowmarklist);
316 shadowmarklist = NULL;
318 r_shadow_buffer_numleafpvsbytes = 0;
319 if (r_shadow_buffer_leafpvs)
320 Mem_Free(r_shadow_buffer_leafpvs);
321 r_shadow_buffer_leafpvs = NULL;
322 if (r_shadow_buffer_leaflist)
323 Mem_Free(r_shadow_buffer_leaflist);
324 r_shadow_buffer_leaflist = NULL;
325 r_shadow_buffer_numsurfacepvsbytes = 0;
326 if (r_shadow_buffer_surfacepvs)
327 Mem_Free(r_shadow_buffer_surfacepvs);
328 r_shadow_buffer_surfacepvs = NULL;
329 if (r_shadow_buffer_surfacelist)
330 Mem_Free(r_shadow_buffer_surfacelist);
331 r_shadow_buffer_surfacelist = NULL;
334 void r_shadow_newmap(void)
338 void R_Shadow_Help_f(void)
341 "Documentation on r_shadow system:\n"
343 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
344 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
345 "r_shadow_debuglight : render only this light number (-1 = all)\n"
346 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
347 "r_shadow_gloss2intensity : brightness of forced gloss\n"
348 "r_shadow_glossintensity : brightness of textured gloss\n"
349 "r_shadow_lightattenuationpower : used to generate attenuation texture\n"
350 "r_shadow_lightattenuationscale : used to generate attenuation texture\n"
351 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
352 "r_shadow_portallight : use portal visibility for static light precomputation\n"
353 "r_shadow_projectdistance : shadow volume projection distance\n"
354 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
355 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
356 "r_shadow_realtime_dlight_portalculling : work hard to reduce graphics work\n"
357 "r_shadow_realtime_world : use high quality world lighting mode\n"
358 "r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n"
359 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
360 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
361 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
362 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
363 "r_shadow_scissor : use scissor optimization\n"
364 "r_shadow_shadow_polygonfactor : nudge shadow volumes closer/further\n"
365 "r_shadow_shadow_polygonoffset : nudge shadow volumes closer/further\n"
366 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
367 "r_showlighting : useful for performance testing; bright = slow!\n"
368 "r_showshadowvolumes : useful for performance testing; bright = slow!\n"
370 "r_shadow_help : this help\n"
374 void R_Shadow_Init(void)
376 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
377 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
378 Cvar_RegisterVariable(&r_shadow_debuglight);
379 Cvar_RegisterVariable(&r_shadow_gloss);
380 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
381 Cvar_RegisterVariable(&r_shadow_glossintensity);
382 Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
383 Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
384 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
385 Cvar_RegisterVariable(&r_shadow_portallight);
386 Cvar_RegisterVariable(&r_shadow_projectdistance);
387 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
388 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
389 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
390 Cvar_RegisterVariable(&r_shadow_realtime_world);
391 Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows);
392 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
393 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
394 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
395 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
396 Cvar_RegisterVariable(&r_shadow_scissor);
397 Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor);
398 Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset);
399 Cvar_RegisterVariable(&r_shadow_texture3d);
400 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
401 if (gamemode == GAME_TENEBRAE)
403 Cvar_SetValue("r_shadow_gloss", 2);
404 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
406 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f, "prints documentation on console commands and variables used by realtime lighting and shadowing system");
407 R_Shadow_EditLights_Init();
408 r_shadow_mempool = Mem_AllocPool("R_Shadow", 0, NULL);
409 r_shadow_worldlightchain = NULL;
410 maxshadowelements = 0;
411 shadowelements = NULL;
419 shadowmarklist = NULL;
421 r_shadow_buffer_numleafpvsbytes = 0;
422 r_shadow_buffer_leafpvs = NULL;
423 r_shadow_buffer_leaflist = NULL;
424 r_shadow_buffer_numsurfacepvsbytes = 0;
425 r_shadow_buffer_surfacepvs = NULL;
426 r_shadow_buffer_surfacelist = NULL;
427 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
430 matrix4x4_t matrix_attenuationxyz =
433 {0.5, 0.0, 0.0, 0.5},
434 {0.0, 0.5, 0.0, 0.5},
435 {0.0, 0.0, 0.5, 0.5},
440 matrix4x4_t matrix_attenuationz =
443 {0.0, 0.0, 0.5, 0.5},
444 {0.0, 0.0, 0.0, 0.5},
445 {0.0, 0.0, 0.0, 0.5},
450 int *R_Shadow_ResizeShadowElements(int numtris)
452 // make sure shadowelements is big enough for this volume
453 if (maxshadowelements < numtris * 24)
455 maxshadowelements = numtris * 24;
457 Mem_Free(shadowelements);
458 shadowelements = (int *)Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int));
460 return shadowelements;
463 static void R_Shadow_EnlargeLeafSurfaceBuffer(int numleafs, int numsurfaces)
465 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
466 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
467 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
469 if (r_shadow_buffer_leafpvs)
470 Mem_Free(r_shadow_buffer_leafpvs);
471 if (r_shadow_buffer_leaflist)
472 Mem_Free(r_shadow_buffer_leaflist);
473 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
474 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numleafpvsbytes);
475 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
477 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
479 if (r_shadow_buffer_surfacepvs)
480 Mem_Free(r_shadow_buffer_surfacepvs);
481 if (r_shadow_buffer_surfacelist)
482 Mem_Free(r_shadow_buffer_surfacelist);
483 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
484 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes);
485 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
489 void R_Shadow_PrepareShadowMark(int numtris)
491 // make sure shadowmark is big enough for this volume
492 if (maxshadowmark < numtris)
494 maxshadowmark = numtris;
496 Mem_Free(shadowmark);
498 Mem_Free(shadowmarklist);
499 shadowmark = (int *)Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmark));
500 shadowmarklist = (int *)Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmarklist));
504 // if shadowmarkcount wrapped we clear the array and adjust accordingly
505 if (shadowmarkcount == 0)
508 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
513 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)
516 int outtriangles = 0, outvertices = 0;
520 if (maxvertexupdate < innumvertices)
522 maxvertexupdate = innumvertices;
524 Mem_Free(vertexupdate);
526 Mem_Free(vertexremap);
527 vertexupdate = (int *)Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
528 vertexremap = (int *)Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
532 if (vertexupdatenum == 0)
535 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
536 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
539 for (i = 0;i < numshadowmarktris;i++)
540 shadowmark[shadowmarktris[i]] = shadowmarkcount;
542 for (i = 0;i < numshadowmarktris;i++)
544 element = inelement3i + shadowmarktris[i] * 3;
545 // make sure the vertices are created
546 for (j = 0;j < 3;j++)
548 if (vertexupdate[element[j]] != vertexupdatenum)
550 float ratio, direction[3];
551 vertexupdate[element[j]] = vertexupdatenum;
552 vertexremap[element[j]] = outvertices;
553 vertex = invertex3f + element[j] * 3;
554 // project one copy of the vertex to the sphere radius of the light
555 // (FIXME: would projecting it to the light box be better?)
556 VectorSubtract(vertex, projectorigin, direction);
557 ratio = projectdistance / VectorLength(direction);
558 VectorCopy(vertex, outvertex3f);
559 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
566 for (i = 0;i < numshadowmarktris;i++)
568 int remappedelement[3];
570 const int *neighbortriangle;
572 markindex = shadowmarktris[i] * 3;
573 element = inelement3i + markindex;
574 neighbortriangle = inneighbor3i + markindex;
575 // output the front and back triangles
576 outelement3i[0] = vertexremap[element[0]];
577 outelement3i[1] = vertexremap[element[1]];
578 outelement3i[2] = vertexremap[element[2]];
579 outelement3i[3] = vertexremap[element[2]] + 1;
580 outelement3i[4] = vertexremap[element[1]] + 1;
581 outelement3i[5] = vertexremap[element[0]] + 1;
585 // output the sides (facing outward from this triangle)
586 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
588 remappedelement[0] = vertexremap[element[0]];
589 remappedelement[1] = vertexremap[element[1]];
590 outelement3i[0] = remappedelement[1];
591 outelement3i[1] = remappedelement[0];
592 outelement3i[2] = remappedelement[0] + 1;
593 outelement3i[3] = remappedelement[1];
594 outelement3i[4] = remappedelement[0] + 1;
595 outelement3i[5] = remappedelement[1] + 1;
600 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
602 remappedelement[1] = vertexremap[element[1]];
603 remappedelement[2] = vertexremap[element[2]];
604 outelement3i[0] = remappedelement[2];
605 outelement3i[1] = remappedelement[1];
606 outelement3i[2] = remappedelement[1] + 1;
607 outelement3i[3] = remappedelement[2];
608 outelement3i[4] = remappedelement[1] + 1;
609 outelement3i[5] = remappedelement[2] + 1;
614 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
616 remappedelement[0] = vertexremap[element[0]];
617 remappedelement[2] = vertexremap[element[2]];
618 outelement3i[0] = remappedelement[0];
619 outelement3i[1] = remappedelement[2];
620 outelement3i[2] = remappedelement[2] + 1;
621 outelement3i[3] = remappedelement[0];
622 outelement3i[4] = remappedelement[2] + 1;
623 outelement3i[5] = remappedelement[0] + 1;
630 *outnumvertices = outvertices;
634 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)
637 if (projectdistance < 0.1)
639 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
642 if (!numverts || !nummarktris)
644 // make sure shadowelements is big enough for this volume
645 if (maxshadowelements < nummarktris * 24)
646 R_Shadow_ResizeShadowElements((nummarktris + 256) * 24);
647 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, varray_vertex3f2, projectorigin, projectdistance, nummarktris, marktris);
648 renderstats.lights_dynamicshadowtriangles += tris;
649 R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements);
652 void R_Shadow_MarkVolumeFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const vec3_t projectorigin, const vec3_t lightmins, const vec3_t lightmaxs, const vec3_t surfacemins, const vec3_t surfacemaxs)
657 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
659 tend = firsttriangle + numtris;
660 if (surfacemins[0] >= lightmins[0] && surfacemaxs[0] <= lightmaxs[0]
661 && surfacemins[1] >= lightmins[1] && surfacemaxs[1] <= lightmaxs[1]
662 && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2])
664 // surface box entirely inside light box, no box cull
665 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
666 if (PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
667 shadowmarklist[numshadowmark++] = t;
671 // surface box not entirely inside light box, cull each triangle
672 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
674 v[0] = invertex3f + e[0] * 3;
675 v[1] = invertex3f + e[1] * 3;
676 v[2] = invertex3f + e[2] * 3;
677 if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
678 && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
679 && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
680 && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
681 && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
682 && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
683 && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
684 shadowmarklist[numshadowmark++] = t;
689 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
692 if (r_shadow_compilingrtlight)
694 // if we're compiling an rtlight, capture the mesh
695 Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
698 renderstats.lights_shadowtriangles += numtriangles;
699 memset(&m, 0, sizeof(m));
700 m.pointer_vertex = vertex3f;
702 GL_LockArrays(0, numvertices);
703 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
705 // decrement stencil if backface is behind depthbuffer
706 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
707 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
708 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
709 // increment stencil if frontface is behind depthbuffer
710 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
711 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
713 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
717 static void R_Shadow_MakeTextures(void)
720 float v[3], intensity;
722 R_FreeTexturePool(&r_shadow_texturepool);
723 r_shadow_texturepool = R_AllocTexturePool();
724 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
725 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
726 #define ATTEN2DSIZE 64
727 #define ATTEN3DSIZE 32
728 data = (unsigned char *)Mem_Alloc(tempmempool, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4));
729 for (y = 0;y < ATTEN2DSIZE;y++)
731 for (x = 0;x < ATTEN2DSIZE;x++)
733 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
734 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
736 intensity = 1.0f - sqrt(DotProduct(v, v));
738 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
739 d = bound(0, intensity, 255);
740 data[(y*ATTEN2DSIZE+x)*4+0] = d;
741 data[(y*ATTEN2DSIZE+x)*4+1] = d;
742 data[(y*ATTEN2DSIZE+x)*4+2] = d;
743 data[(y*ATTEN2DSIZE+x)*4+3] = d;
746 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
747 if (r_shadow_texture3d.integer)
749 for (z = 0;z < ATTEN3DSIZE;z++)
751 for (y = 0;y < ATTEN3DSIZE;y++)
753 for (x = 0;x < ATTEN3DSIZE;x++)
755 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
756 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
757 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
758 intensity = 1.0f - sqrt(DotProduct(v, v));
760 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
761 d = bound(0, intensity, 255);
762 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
763 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
764 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
765 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
769 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
774 void R_Shadow_ValidateCvars(void)
776 if (r_shadow_texture3d.integer && !gl_texture3d)
777 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
778 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
779 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
782 // light currently being rendered
783 rtlight_t *r_shadow_rtlight;
785 // this is the location of the eye in entity space
786 vec3_t r_shadow_entityeyeorigin;
787 // this is the location of the light in entity space
788 vec3_t r_shadow_entitylightorigin;
789 // this transforms entity coordinates to light filter cubemap coordinates
790 // (also often used for other purposes)
791 matrix4x4_t r_shadow_entitytolight;
792 // based on entitytolight this transforms -1 to +1 to 0 to 1 for purposes
793 // of attenuation texturing in full 3D (Z result often ignored)
794 matrix4x4_t r_shadow_entitytoattenuationxyz;
795 // this transforms only the Z to S, and T is always 0.5
796 matrix4x4_t r_shadow_entitytoattenuationz;
798 void R_Shadow_RenderMode_Begin(void)
802 R_Shadow_ValidateCvars();
804 if (!r_shadow_attenuation2dtexture
805 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
806 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
807 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
808 R_Shadow_MakeTextures();
810 memset(&m, 0, sizeof(m));
812 GL_BlendFunc(GL_ONE, GL_ZERO);
815 GL_Color(0, 0, 0, 1);
816 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
817 qglEnable(GL_CULL_FACE);
818 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
820 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
822 if (gl_ext_stenciltwoside.integer)
823 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
825 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
827 if (r_glsl.integer && gl_support_fragment_shader)
828 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
829 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
830 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
832 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
835 void R_Shadow_RenderMode_ActiveLight(rtlight_t *rtlight)
837 r_shadow_rtlight = rtlight;
840 void R_Shadow_RenderMode_Reset(void)
843 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
845 qglUseProgramObjectARB(0);
846 // HACK HACK HACK: work around for bug in NVIDIAI 6xxx drivers that causes GL_OUT_OF_MEMORY and/or software rendering
847 qglBegin(GL_TRIANGLES);
851 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
852 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
853 memset(&m, 0, sizeof(m));
857 void R_Shadow_RenderMode_StencilShadowVolumes(void)
859 R_Shadow_RenderMode_Reset();
860 GL_Color(1, 1, 1, 1);
861 GL_ColorMask(0, 0, 0, 0);
862 GL_BlendFunc(GL_ONE, GL_ZERO);
866 qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
867 //if (r_shadow_shadow_polygonoffset.value != 0)
869 // qglPolygonOffset(r_shadow_shadow_polygonfactor.value, r_shadow_shadow_polygonoffset.value);
870 // qglEnable(GL_POLYGON_OFFSET_FILL);
873 // qglDisable(GL_POLYGON_OFFSET_FILL);
874 qglDepthFunc(GL_LESS);
875 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
876 qglEnable(GL_STENCIL_TEST);
877 qglStencilFunc(GL_ALWAYS, 128, ~0);
878 r_shadow_rendermode = r_shadow_shadowingrendermode;
879 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
881 qglDisable(GL_CULL_FACE);
882 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
883 qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
885 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
886 qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
888 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
892 qglEnable(GL_CULL_FACE);
894 // this is changed by every shadow render so its value here is unimportant
895 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
897 GL_Clear(GL_STENCIL_BUFFER_BIT);
898 renderstats.lights_clears++;
901 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent)
903 R_Shadow_RenderMode_Reset();
904 GL_BlendFunc(GL_ONE, GL_ONE);
908 qglPolygonOffset(0, 0);
909 //qglDisable(GL_POLYGON_OFFSET_FILL);
910 GL_Color(1, 1, 1, 1);
911 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
913 qglDepthFunc(GL_LEQUAL);
915 qglDepthFunc(GL_EQUAL);
916 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
917 qglEnable(GL_CULL_FACE);
919 qglEnable(GL_STENCIL_TEST);
921 qglDisable(GL_STENCIL_TEST);
923 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
924 // only draw light where this geometry was already rendered AND the
925 // stencil is 128 (values other than this mean shadow)
926 qglStencilFunc(GL_EQUAL, 128, ~0);
927 r_shadow_rendermode = r_shadow_lightingrendermode;
928 // do global setup needed for the chosen lighting mode
929 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
931 R_Mesh_TexCoordPointer(1, 3, varray_svector3f);
932 R_Mesh_TexCoordPointer(2, 3, varray_tvector3f);
933 R_Mesh_TexCoordPointer(3, 3, varray_normal3f);
934 R_Mesh_TexBind(0, R_GetTexture(r_texture_blanknormalmap)); // normal
935 R_Mesh_TexBind(1, R_GetTexture(r_texture_white)); // diffuse
936 R_Mesh_TexBind(2, R_GetTexture(r_texture_white)); // gloss
937 R_Mesh_TexBindCubeMap(3, R_GetTexture(r_shadow_rtlight->currentcubemap)); // light filter
938 R_Mesh_TexBind(4, R_GetTexture(r_texture_fogattenuation)); // fog
939 R_Mesh_TexBind(5, R_GetTexture(r_texture_white)); // pants
940 R_Mesh_TexBind(6, R_GetTexture(r_texture_white)); // shirt
941 //R_Mesh_TexMatrix(3, r_shadow_entitytolight); // light filter matrix
942 GL_BlendFunc(GL_ONE, GL_ONE);
943 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
948 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
950 R_Shadow_RenderMode_Reset();
951 GL_BlendFunc(GL_ONE, GL_ONE);
953 GL_DepthTest(!r_showdisabledepthtest.integer);
955 qglPolygonOffset(0, 0);
956 GL_Color(0.0, 0.0125, 0.1, 1);
957 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
958 qglDepthFunc(GL_GEQUAL);
959 qglCullFace(GL_FRONT); // this culls back
960 qglDisable(GL_CULL_FACE);
961 qglDisable(GL_STENCIL_TEST);
962 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
965 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
967 R_Shadow_RenderMode_Reset();
968 GL_BlendFunc(GL_ONE, GL_ONE);
970 GL_DepthTest(!r_showdisabledepthtest.integer);
972 qglPolygonOffset(0, 0);
973 GL_Color(0.1, 0.0125, 0, 1);
974 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
976 qglDepthFunc(GL_LEQUAL);
978 qglDepthFunc(GL_EQUAL);
979 qglCullFace(GL_FRONT); // this culls back
980 qglEnable(GL_CULL_FACE);
982 qglEnable(GL_STENCIL_TEST);
984 qglDisable(GL_STENCIL_TEST);
985 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
988 void R_Shadow_RenderMode_End(void)
990 R_Shadow_RenderMode_Reset();
991 R_Shadow_RenderMode_ActiveLight(NULL);
992 GL_BlendFunc(GL_ONE, GL_ZERO);
996 qglPolygonOffset(0, 0);
997 //qglDisable(GL_POLYGON_OFFSET_FILL);
998 GL_Color(1, 1, 1, 1);
999 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1000 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1001 qglDepthFunc(GL_LEQUAL);
1002 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
1003 qglEnable(GL_CULL_FACE);
1004 qglDisable(GL_STENCIL_TEST);
1005 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1006 if (gl_support_stenciltwoside)
1007 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1009 qglStencilFunc(GL_ALWAYS, 128, ~0);
1010 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1013 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1015 int i, ix1, iy1, ix2, iy2;
1016 float x1, y1, x2, y2;
1019 mplane_t planes[11];
1020 float vertex3f[256*3];
1022 // if view is inside the light box, just say yes it's visible
1023 if (BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
1025 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1029 // create a temporary brush describing the area the light can affect in worldspace
1030 VectorNegate(frustum[0].normal, planes[ 0].normal);planes[ 0].dist = -frustum[0].dist;
1031 VectorNegate(frustum[1].normal, planes[ 1].normal);planes[ 1].dist = -frustum[1].dist;
1032 VectorNegate(frustum[2].normal, planes[ 2].normal);planes[ 2].dist = -frustum[2].dist;
1033 VectorNegate(frustum[3].normal, planes[ 3].normal);planes[ 3].dist = -frustum[3].dist;
1034 VectorNegate(frustum[4].normal, planes[ 4].normal);planes[ 4].dist = -frustum[4].dist;
1035 VectorSet (planes[ 5].normal, 1, 0, 0); planes[ 5].dist = maxs[0];
1036 VectorSet (planes[ 6].normal, -1, 0, 0); planes[ 6].dist = -mins[0];
1037 VectorSet (planes[ 7].normal, 0, 1, 0); planes[ 7].dist = maxs[1];
1038 VectorSet (planes[ 8].normal, 0, -1, 0); planes[ 8].dist = -mins[1];
1039 VectorSet (planes[ 9].normal, 0, 0, 1); planes[ 9].dist = maxs[2];
1040 VectorSet (planes[10].normal, 0, 0, -1); planes[10].dist = -mins[2];
1042 // turn the brush into a mesh
1043 memset(&mesh, 0, sizeof(rmesh_t));
1044 mesh.maxvertices = 256;
1045 mesh.vertex3f = vertex3f;
1046 mesh.epsilon2 = (1.0f / (32.0f * 32.0f));
1047 R_Mesh_AddBrushMeshFromPlanes(&mesh, 11, planes);
1049 // if that mesh is empty, the light is not visible at all
1050 if (!mesh.numvertices)
1053 if (!r_shadow_scissor.integer)
1056 // if that mesh is not empty, check what area of the screen it covers
1057 x1 = y1 = x2 = y2 = 0;
1059 for (i = 0;i < mesh.numvertices;i++)
1061 VectorCopy(mesh.vertex3f + i * 3, v);
1062 GL_TransformToScreen(v, v2);
1063 //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]);
1066 if (x1 > v2[0]) x1 = v2[0];
1067 if (x2 < v2[0]) x2 = v2[0];
1068 if (y1 > v2[1]) y1 = v2[1];
1069 if (y2 < v2[1]) y2 = v2[1];
1078 // now convert the scissor rectangle to integer screen coordinates
1083 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1085 // clamp it to the screen
1086 if (ix1 < r_view_x) ix1 = r_view_x;
1087 if (iy1 < r_view_y) iy1 = r_view_y;
1088 if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
1089 if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
1091 // if it is inside out, it's not visible
1092 if (ix2 <= ix1 || iy2 <= iy1)
1095 // the light area is visible, set up the scissor rectangle
1096 GL_Scissor(ix1, vid.height - iy2, ix2 - ix1, iy2 - iy1);
1097 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1098 //qglEnable(GL_SCISSOR_TEST);
1099 renderstats.lights_scissored++;
1103 extern float *rsurface_vertex3f;
1104 extern float *rsurface_svector3f;
1105 extern float *rsurface_tvector3f;
1106 extern float *rsurface_normal3f;
1107 extern void RSurf_SetVertexPointer(const entity_render_t *ent, const texture_t *texture, const msurface_t *surface, const vec3_t modelorg, qboolean generatenormals, qboolean generatetangents);
1109 static void R_Shadow_RenderSurfacesLighting_Light_Vertex_Shading(const msurface_t *surface, const float *diffusecolor, const float *ambientcolor)
1111 int numverts = surface->num_vertices;
1112 float *vertex3f = rsurface_vertex3f + 3 * surface->num_firstvertex;
1113 float *normal3f = rsurface_normal3f + 3 * surface->num_firstvertex;
1114 float *color4f = varray_color4f + 4 * surface->num_firstvertex;
1115 float dist, dot, distintensity, shadeintensity, v[3], n[3];
1116 if (r_textureunits.integer >= 3)
1118 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1120 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1121 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1122 if ((dot = DotProduct(n, v)) < 0)
1124 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1125 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]);
1126 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]);
1127 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]);
1130 float f = VERTEXFOGTABLE(VectorDistance(v, r_shadow_entityeyeorigin));
1131 VectorScale(color4f, f, color4f);
1135 VectorClear(color4f);
1139 else if (r_textureunits.integer >= 2)
1141 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1143 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1144 if ((dist = fabs(v[2])) < 1)
1146 distintensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1147 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1148 if ((dot = DotProduct(n, v)) < 0)
1150 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1151 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1152 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1153 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1157 color4f[0] = ambientcolor[0] * distintensity;
1158 color4f[1] = ambientcolor[1] * distintensity;
1159 color4f[2] = ambientcolor[2] * distintensity;
1163 float f = VERTEXFOGTABLE(VectorDistance(v, r_shadow_entityeyeorigin));
1164 VectorScale(color4f, f, color4f);
1168 VectorClear(color4f);
1174 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1176 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1177 if ((dist = DotProduct(v, v)) < 1)
1180 distintensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1181 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1182 if ((dot = DotProduct(n, v)) < 0)
1184 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1185 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1186 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1187 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1191 color4f[0] = ambientcolor[0] * distintensity;
1192 color4f[1] = ambientcolor[1] * distintensity;
1193 color4f[2] = ambientcolor[2] * distintensity;
1197 float f = VERTEXFOGTABLE(VectorDistance(v, r_shadow_entityeyeorigin));
1198 VectorScale(color4f, f, color4f);
1202 VectorClear(color4f);
1208 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1210 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)
1214 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1216 VectorSubtract(relativelightorigin, vertex3f, lightdir);
1217 // the cubemap normalizes this for us
1218 out3f[0] = DotProduct(svector3f, lightdir);
1219 out3f[1] = DotProduct(tvector3f, lightdir);
1220 out3f[2] = DotProduct(normal3f, lightdir);
1224 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)
1227 float lightdir[3], eyedir[3], halfdir[3];
1228 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1230 VectorSubtract(relativelightorigin, vertex3f, lightdir);
1231 VectorNormalize(lightdir);
1232 VectorSubtract(relativeeyeorigin, vertex3f, eyedir);
1233 VectorNormalize(eyedir);
1234 VectorAdd(lightdir, eyedir, halfdir);
1235 // the cubemap normalizes this for us
1236 out3f[0] = DotProduct(svector3f, halfdir);
1237 out3f[1] = DotProduct(tvector3f, halfdir);
1238 out3f[2] = DotProduct(normal3f, halfdir);
1242 static void R_Shadow_RenderSurfacesLighting_VisibleLighting(const entity_render_t *ent, const texture_t *texture, int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, qboolean dopants, qboolean doshirt)
1244 // used to display how many times a surface is lit for level design purposes
1245 int surfacelistindex;
1247 GL_Color(0.1, 0.025, 0, 1);
1248 memset(&m, 0, sizeof(m));
1250 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1252 const msurface_t *surface = surfacelist[surfacelistindex];
1253 RSurf_SetVertexPointer(ent, texture, surface, r_shadow_entityeyeorigin, false, false);
1254 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1255 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle);
1256 GL_LockArrays(0, 0);
1260 static void R_Shadow_RenderSurfacesLighting_Light_GLSL(const entity_render_t *ent, const texture_t *texture, int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, qboolean dopants, qboolean doshirt)
1262 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
1263 int surfacelistindex;
1264 R_SetupSurfaceShader(ent, texture, r_shadow_entityeyeorigin, lightcolorbase, false);
1265 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1267 const msurface_t *surface = surfacelist[surfacelistindex];
1268 const int *elements = surface->groupmesh->data_element3i + surface->num_firsttriangle * 3;
1269 RSurf_SetVertexPointer(ent, texture, surface, r_shadow_entityeyeorigin, false, true);
1270 R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
1271 R_Mesh_TexCoordPointer(1, 3, rsurface_svector3f);
1272 R_Mesh_TexCoordPointer(2, 3, rsurface_tvector3f);
1273 R_Mesh_TexCoordPointer(3, 3, rsurface_normal3f);
1274 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1275 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1276 GL_LockArrays(0, 0);
1280 static void R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(const entity_render_t *ent, const texture_t *texture, const msurface_t *surface, const vec3_t lightcolorbase, rtexture_t *basetexture, float colorscale)
1285 const int *elements = surface->groupmesh->data_element3i + surface->num_firsttriangle * 3;
1287 // colorscale accounts for how much we multiply the brightness
1290 // mult is how many times the final pass of the lighting will be
1291 // performed to get more brightness than otherwise possible.
1293 // Limit mult to 64 for sanity sake.
1294 if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1296 // 3 3D combine path (Geforce3, Radeon 8500)
1297 memset(&m, 0, sizeof(m));
1298 m.pointer_vertex = rsurface_vertex3f;
1299 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1300 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1301 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1302 m.tex[1] = R_GetTexture(basetexture);
1303 m.pointer_texcoord[1] = surface->groupmesh->data_texcoordtexture2f;
1304 m.texmatrix[1] = texture->currenttexmatrix;
1305 m.texcubemap[2] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1306 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1307 m.texmatrix[2] = r_shadow_entitytolight;
1308 GL_BlendFunc(GL_ONE, GL_ONE);
1310 else if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1312 // 2 3D combine path (Geforce3, original Radeon)
1313 memset(&m, 0, sizeof(m));
1314 m.pointer_vertex = rsurface_vertex3f;
1315 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1316 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1317 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1318 m.tex[1] = R_GetTexture(basetexture);
1319 m.pointer_texcoord[1] = surface->groupmesh->data_texcoordtexture2f;
1320 m.texmatrix[1] = texture->currenttexmatrix;
1321 GL_BlendFunc(GL_ONE, GL_ONE);
1323 else if (r_textureunits.integer >= 4 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1325 // 4 2D combine path (Geforce3, Radeon 8500)
1326 memset(&m, 0, sizeof(m));
1327 m.pointer_vertex = rsurface_vertex3f;
1328 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1329 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1330 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1331 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1332 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1333 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1334 m.tex[2] = R_GetTexture(basetexture);
1335 m.pointer_texcoord[2] = surface->groupmesh->data_texcoordtexture2f;
1336 m.texmatrix[2] = texture->currenttexmatrix;
1337 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1339 m.texcubemap[3] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1340 m.pointer_texcoord3f[3] = rsurface_vertex3f;
1341 m.texmatrix[3] = r_shadow_entitytolight;
1343 GL_BlendFunc(GL_ONE, GL_ONE);
1345 else if (r_textureunits.integer >= 3 && r_shadow_rtlight->currentcubemap == r_texture_whitecube)
1347 // 3 2D combine path (Geforce3, original Radeon)
1348 memset(&m, 0, sizeof(m));
1349 m.pointer_vertex = rsurface_vertex3f;
1350 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1351 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1352 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1353 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1354 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1355 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1356 m.tex[2] = R_GetTexture(basetexture);
1357 m.pointer_texcoord[2] = surface->groupmesh->data_texcoordtexture2f;
1358 m.texmatrix[2] = texture->currenttexmatrix;
1359 GL_BlendFunc(GL_ONE, GL_ONE);
1363 // 2/2/2 2D combine path (any dot3 card)
1364 memset(&m, 0, sizeof(m));
1365 m.pointer_vertex = rsurface_vertex3f;
1366 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1367 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1368 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1369 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1370 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1371 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1373 GL_ColorMask(0,0,0,1);
1374 GL_BlendFunc(GL_ONE, GL_ZERO);
1375 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1376 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1377 GL_LockArrays(0, 0);
1379 memset(&m, 0, sizeof(m));
1380 m.pointer_vertex = rsurface_vertex3f;
1381 m.tex[0] = R_GetTexture(basetexture);
1382 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1383 m.texmatrix[0] = texture->currenttexmatrix;
1384 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1386 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1387 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1388 m.texmatrix[1] = r_shadow_entitytolight;
1390 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1392 // this final code is shared
1394 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1395 VectorScale(lightcolorbase, colorscale, color2);
1396 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1397 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1399 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1400 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1402 GL_LockArrays(0, 0);
1405 static void R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(const entity_render_t *ent, const texture_t *texture, const msurface_t *surface, const vec3_t lightcolorbase, rtexture_t *basetexture, rtexture_t *normalmaptexture, float colorscale)
1410 const int *elements = surface->groupmesh->data_element3i + surface->num_firsttriangle * 3;
1412 // colorscale accounts for how much we multiply the brightness
1415 // mult is how many times the final pass of the lighting will be
1416 // performed to get more brightness than otherwise possible.
1418 // Limit mult to 64 for sanity sake.
1419 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1421 // 3/2 3D combine path (Geforce3, Radeon 8500)
1422 memset(&m, 0, sizeof(m));
1423 m.pointer_vertex = rsurface_vertex3f;
1424 m.tex[0] = R_GetTexture(normalmaptexture);
1425 m.texcombinergb[0] = GL_REPLACE;
1426 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1427 m.texmatrix[0] = texture->currenttexmatrix;
1428 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1429 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1430 m.pointer_texcoord3f[1] = varray_texcoord3f;
1431 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin);
1432 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1433 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1434 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
1436 GL_ColorMask(0,0,0,1);
1437 GL_BlendFunc(GL_ONE, GL_ZERO);
1438 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1439 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1440 GL_LockArrays(0, 0);
1442 memset(&m, 0, sizeof(m));
1443 m.pointer_vertex = rsurface_vertex3f;
1444 m.tex[0] = R_GetTexture(basetexture);
1445 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1446 m.texmatrix[0] = texture->currenttexmatrix;
1447 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1449 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1450 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1451 m.texmatrix[1] = r_shadow_entitytolight;
1453 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1455 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1457 // 1/2/2 3D combine path (original Radeon)
1458 memset(&m, 0, sizeof(m));
1459 m.pointer_vertex = rsurface_vertex3f;
1460 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1461 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1462 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1464 GL_ColorMask(0,0,0,1);
1465 GL_BlendFunc(GL_ONE, GL_ZERO);
1466 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1467 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1468 GL_LockArrays(0, 0);
1470 memset(&m, 0, sizeof(m));
1471 m.pointer_vertex = rsurface_vertex3f;
1472 m.tex[0] = R_GetTexture(normalmaptexture);
1473 m.texcombinergb[0] = GL_REPLACE;
1474 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1475 m.texmatrix[0] = texture->currenttexmatrix;
1476 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1477 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1478 m.pointer_texcoord3f[1] = varray_texcoord3f;
1479 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin);
1481 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1482 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1483 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1484 GL_LockArrays(0, 0);
1486 memset(&m, 0, sizeof(m));
1487 m.pointer_vertex = rsurface_vertex3f;
1488 m.tex[0] = R_GetTexture(basetexture);
1489 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1490 m.texmatrix[0] = texture->currenttexmatrix;
1491 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1493 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1494 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1495 m.texmatrix[1] = r_shadow_entitytolight;
1497 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1499 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap == r_texture_whitecube)
1501 // 2/2 3D combine path (original Radeon)
1502 memset(&m, 0, sizeof(m));
1503 m.pointer_vertex = rsurface_vertex3f;
1504 m.tex[0] = R_GetTexture(normalmaptexture);
1505 m.texcombinergb[0] = GL_REPLACE;
1506 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1507 m.texmatrix[0] = texture->currenttexmatrix;
1508 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1509 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1510 m.pointer_texcoord3f[1] = varray_texcoord3f;
1511 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin);
1513 GL_ColorMask(0,0,0,1);
1514 GL_BlendFunc(GL_ONE, GL_ZERO);
1515 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1516 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1517 GL_LockArrays(0, 0);
1519 memset(&m, 0, sizeof(m));
1520 m.pointer_vertex = rsurface_vertex3f;
1521 m.tex[0] = R_GetTexture(basetexture);
1522 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1523 m.texmatrix[0] = texture->currenttexmatrix;
1524 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1525 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1526 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
1527 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1529 else if (r_textureunits.integer >= 4)
1531 // 4/2 2D combine path (Geforce3, Radeon 8500)
1532 memset(&m, 0, sizeof(m));
1533 m.pointer_vertex = rsurface_vertex3f;
1534 m.tex[0] = R_GetTexture(normalmaptexture);
1535 m.texcombinergb[0] = GL_REPLACE;
1536 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1537 m.texmatrix[0] = texture->currenttexmatrix;
1538 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1539 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1540 m.pointer_texcoord3f[1] = varray_texcoord3f;
1541 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin);
1542 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1543 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1544 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
1545 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1546 m.pointer_texcoord3f[3] = rsurface_vertex3f;
1547 m.texmatrix[3] = r_shadow_entitytoattenuationz;
1549 GL_ColorMask(0,0,0,1);
1550 GL_BlendFunc(GL_ONE, GL_ZERO);
1551 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1552 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1553 GL_LockArrays(0, 0);
1555 memset(&m, 0, sizeof(m));
1556 m.pointer_vertex = rsurface_vertex3f;
1557 m.tex[0] = R_GetTexture(basetexture);
1558 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1559 m.texmatrix[0] = texture->currenttexmatrix;
1560 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1562 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1563 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1564 m.texmatrix[1] = r_shadow_entitytolight;
1566 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1570 // 2/2/2 2D combine path (any dot3 card)
1571 memset(&m, 0, sizeof(m));
1572 m.pointer_vertex = rsurface_vertex3f;
1573 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1574 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1575 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1576 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1577 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1578 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1580 GL_ColorMask(0,0,0,1);
1581 GL_BlendFunc(GL_ONE, GL_ZERO);
1582 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1583 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1584 GL_LockArrays(0, 0);
1586 memset(&m, 0, sizeof(m));
1587 m.pointer_vertex = rsurface_vertex3f;
1588 m.tex[0] = R_GetTexture(normalmaptexture);
1589 m.texcombinergb[0] = GL_REPLACE;
1590 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1591 m.texmatrix[0] = texture->currenttexmatrix;
1592 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1593 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1594 m.pointer_texcoord3f[1] = varray_texcoord3f;
1595 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin);
1597 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1598 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1599 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1600 GL_LockArrays(0, 0);
1602 memset(&m, 0, sizeof(m));
1603 m.pointer_vertex = rsurface_vertex3f;
1604 m.tex[0] = R_GetTexture(basetexture);
1605 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1606 m.texmatrix[0] = texture->currenttexmatrix;
1607 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1609 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1610 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1611 m.texmatrix[1] = r_shadow_entitytolight;
1613 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1615 // this final code is shared
1617 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1618 VectorScale(lightcolorbase, colorscale, color2);
1619 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1620 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1622 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1623 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1625 GL_LockArrays(0, 0);
1628 static void R_Shadow_RenderSurfacesLighting_Light_Dot3_SpecularPass(const entity_render_t *ent, const texture_t *texture, const msurface_t *surface, const vec3_t lightcolorbase, rtexture_t *glosstexture, rtexture_t *normalmaptexture, float colorscale)
1633 const int *elements = surface->groupmesh->data_element3i + surface->num_firsttriangle * 3;
1634 // FIXME: detect blendsquare!
1635 //if (!gl_support_blendsquare)
1638 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap != r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
1640 // 2/0/0/1/2 3D combine blendsquare path
1641 memset(&m, 0, sizeof(m));
1642 m.pointer_vertex = rsurface_vertex3f;
1643 m.tex[0] = R_GetTexture(normalmaptexture);
1644 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1645 m.texmatrix[0] = texture->currenttexmatrix;
1646 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1647 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1648 m.pointer_texcoord3f[1] = varray_texcoord3f;
1649 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin, r_shadow_entityeyeorigin);
1651 GL_ColorMask(0,0,0,1);
1652 // this squares the result
1653 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1654 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1655 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1656 GL_LockArrays(0, 0);
1658 memset(&m, 0, sizeof(m));
1659 m.pointer_vertex = rsurface_vertex3f;
1661 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1662 // square alpha in framebuffer a few times to make it shiny
1663 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1664 // these comments are a test run through this math for intensity 0.5
1665 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1666 // 0.25 * 0.25 = 0.0625 (this is another pass)
1667 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1668 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1669 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1670 GL_LockArrays(0, 0);
1672 memset(&m, 0, sizeof(m));
1673 m.pointer_vertex = rsurface_vertex3f;
1674 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1675 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1676 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1678 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1679 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1680 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1681 GL_LockArrays(0, 0);
1683 memset(&m, 0, sizeof(m));
1684 m.pointer_vertex = rsurface_vertex3f;
1685 m.tex[0] = R_GetTexture(glosstexture);
1686 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1687 m.texmatrix[0] = texture->currenttexmatrix;
1688 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1690 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1691 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1692 m.texmatrix[1] = r_shadow_entitytolight;
1694 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1696 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
1698 // 2/0/0/2 3D combine blendsquare path
1699 memset(&m, 0, sizeof(m));
1700 m.pointer_vertex = rsurface_vertex3f;
1701 m.tex[0] = R_GetTexture(normalmaptexture);
1702 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1703 m.texmatrix[0] = texture->currenttexmatrix;
1704 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1705 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1706 m.pointer_texcoord3f[1] = varray_texcoord3f;
1707 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin, r_shadow_entityeyeorigin);
1709 GL_ColorMask(0,0,0,1);
1710 // this squares the result
1711 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1712 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1713 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1714 GL_LockArrays(0, 0);
1716 memset(&m, 0, sizeof(m));
1717 m.pointer_vertex = rsurface_vertex3f;
1719 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1720 // square alpha in framebuffer a few times to make it shiny
1721 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1722 // these comments are a test run through this math for intensity 0.5
1723 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1724 // 0.25 * 0.25 = 0.0625 (this is another pass)
1725 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1726 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1727 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1728 GL_LockArrays(0, 0);
1730 memset(&m, 0, sizeof(m));
1731 m.pointer_vertex = rsurface_vertex3f;
1732 m.tex[0] = R_GetTexture(glosstexture);
1733 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1734 m.texmatrix[0] = texture->currenttexmatrix;
1735 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1736 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1737 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
1738 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1742 // 2/0/0/2/2 2D combine blendsquare path
1743 memset(&m, 0, sizeof(m));
1744 m.pointer_vertex = rsurface_vertex3f;
1745 m.tex[0] = R_GetTexture(normalmaptexture);
1746 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1747 m.texmatrix[0] = texture->currenttexmatrix;
1748 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1749 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1750 m.pointer_texcoord3f[1] = varray_texcoord3f;
1751 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin, r_shadow_entityeyeorigin);
1753 GL_ColorMask(0,0,0,1);
1754 // this squares the result
1755 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1756 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1757 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1758 GL_LockArrays(0, 0);
1760 memset(&m, 0, sizeof(m));
1761 m.pointer_vertex = rsurface_vertex3f;
1763 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1764 // square alpha in framebuffer a few times to make it shiny
1765 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1766 // these comments are a test run through this math for intensity 0.5
1767 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1768 // 0.25 * 0.25 = 0.0625 (this is another pass)
1769 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1770 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1771 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1772 GL_LockArrays(0, 0);
1774 memset(&m, 0, sizeof(m));
1775 m.pointer_vertex = rsurface_vertex3f;
1776 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1777 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1778 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1779 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1780 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1781 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1783 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1784 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1785 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1786 GL_LockArrays(0, 0);
1788 memset(&m, 0, sizeof(m));
1789 m.pointer_vertex = rsurface_vertex3f;
1790 m.tex[0] = R_GetTexture(glosstexture);
1791 m.pointer_texcoord[0] = surface->groupmesh->data_texcoordtexture2f;
1792 m.texmatrix[0] = texture->currenttexmatrix;
1793 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1795 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1796 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1797 m.texmatrix[1] = r_shadow_entitytolight;
1799 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1802 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1803 VectorScale(lightcolorbase, colorscale, color2);
1804 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1805 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1807 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1808 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1810 GL_LockArrays(0, 0);
1813 static void R_Shadow_RenderSurfacesLighting_Light_Dot3(const entity_render_t *ent, const texture_t *texture, int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, qboolean dopants, qboolean doshirt)
1815 // ARB path (any Geforce, any Radeon)
1816 int surfacelistindex;
1817 qboolean doambient = r_shadow_rtlight->ambientscale > 0;
1818 qboolean dodiffuse = r_shadow_rtlight->diffusescale > 0;
1819 qboolean dospecular = specularscale > 0;
1820 if (!doambient && !dodiffuse && !dospecular)
1822 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1824 const msurface_t *surface = surfacelist[surfacelistindex];
1825 RSurf_SetVertexPointer(ent, texture, surface, r_shadow_entityeyeorigin, false, true);
1827 R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(ent, texture, surface, lightcolorbase, basetexture, r_shadow_rtlight->ambientscale);
1829 R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(ent, texture, surface, lightcolorbase, basetexture, normalmaptexture, r_shadow_rtlight->diffusescale);
1833 R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(ent, texture, surface, lightcolorpants, pantstexture, r_shadow_rtlight->ambientscale);
1835 R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(ent, texture, surface, lightcolorpants, pantstexture, normalmaptexture, r_shadow_rtlight->diffusescale);
1840 R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(ent, texture, surface, lightcolorshirt, shirttexture, r_shadow_rtlight->ambientscale);
1842 R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(ent, texture, surface, lightcolorshirt, shirttexture, normalmaptexture, r_shadow_rtlight->diffusescale);
1845 R_Shadow_RenderSurfacesLighting_Light_Dot3_SpecularPass(ent, texture, surface, lightcolorbase, glosstexture, normalmaptexture, specularscale);
1849 void R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(const msurface_t *surface, vec3_t diffusecolor2, vec3_t ambientcolor2)
1852 const int *elements = surface->groupmesh->data_element3i + surface->num_firsttriangle * 3;
1853 R_Shadow_RenderSurfacesLighting_Light_Vertex_Shading(surface, diffusecolor2, ambientcolor2);
1854 for (renders = 0;renders < 64 && (ambientcolor2[0] > renders || ambientcolor2[1] > renders || ambientcolor2[2] > renders || diffusecolor2[0] > renders || diffusecolor2[1] > renders || diffusecolor2[2] > renders);renders++)
1859 // due to low fillrate on the cards this vertex lighting path is
1860 // designed for, we manually cull all triangles that do not
1861 // contain a lit vertex
1864 int newnumtriangles;
1866 int newelements[3072];
1868 newnumtriangles = 0;
1870 for (i = 0, e = elements;i < surface->num_triangles;i++, e += 3)
1872 if (newnumtriangles >= 1024)
1874 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1875 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, newnumtriangles, newelements);
1876 GL_LockArrays(0, 0);
1877 newnumtriangles = 0;
1880 if (VectorLength2(varray_color4f + e[0] * 4) + VectorLength2(varray_color4f + e[1] * 4) + VectorLength2(varray_color4f + e[2] * 4) >= 0.01)
1890 if (newnumtriangles >= 1)
1892 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1893 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, newnumtriangles, newelements);
1894 GL_LockArrays(0, 0);
1900 for (i = 0, c = varray_color4f + 4 * surface->num_firstvertex;i < surface->num_vertices;i++, c += 4)
1901 if (VectorLength2(c))
1905 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1906 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1907 GL_LockArrays(0, 0);
1909 // now reduce the intensity for the next overbright pass
1910 for (i = 0, c = varray_color4f + 4 * surface->num_firstvertex;i < surface->num_vertices;i++, c += 4)
1912 c[0] = max(0, c[0] - 1);
1913 c[1] = max(0, c[1] - 1);
1914 c[2] = max(0, c[2] - 1);
1919 static void R_Shadow_RenderSurfacesLighting_Light_Vertex(const entity_render_t *ent, const texture_t *texture, int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, qboolean dopants, qboolean doshirt)
1921 int surfacelistindex;
1922 float ambientcolorbase[3], diffusecolorbase[3];
1923 float ambientcolorpants[3], diffusecolorpants[3];
1924 float ambientcolorshirt[3], diffusecolorshirt[3];
1926 VectorScale(lightcolorbase, r_shadow_rtlight->ambientscale * 2, ambientcolorbase);
1927 VectorScale(lightcolorbase, r_shadow_rtlight->diffusescale * 2, diffusecolorbase);
1928 VectorScale(lightcolorpants, r_shadow_rtlight->ambientscale * 2, ambientcolorpants);
1929 VectorScale(lightcolorpants, r_shadow_rtlight->diffusescale * 2, diffusecolorpants);
1930 VectorScale(lightcolorshirt, r_shadow_rtlight->ambientscale * 2, ambientcolorshirt);
1931 VectorScale(lightcolorshirt, r_shadow_rtlight->diffusescale * 2, diffusecolorshirt);
1932 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1933 memset(&m, 0, sizeof(m));
1934 m.tex[0] = R_GetTexture(basetexture);
1935 if (r_textureunits.integer >= 2)
1938 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1939 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
1940 if (r_textureunits.integer >= 3)
1942 // Geforce3/Radeon class but not using dot3
1943 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1944 m.texmatrix[2] = r_shadow_entitytoattenuationz;
1947 m.pointer_color = varray_color4f;
1949 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1951 const msurface_t *surface = surfacelist[surfacelistindex];
1952 RSurf_SetVertexPointer(ent, texture, surface, r_shadow_entityeyeorigin, true, false);
1953 // OpenGL 1.1 path (anything)
1954 R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
1955 R_Mesh_TexMatrix(0, &texture->currenttexmatrix);
1956 if (r_textureunits.integer >= 2)
1959 R_Mesh_TexCoordPointer(1, 3, rsurface_vertex3f);
1960 if (r_textureunits.integer >= 3)
1962 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
1963 R_Mesh_TexCoordPointer(2, 3, rsurface_vertex3f);
1966 R_Mesh_TexBind(0, R_GetTexture(basetexture));
1967 R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(surface, diffusecolorbase, ambientcolorbase);
1970 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
1971 R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(surface, diffusecolorpants, ambientcolorpants);
1975 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
1976 R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(surface, diffusecolorshirt, ambientcolorshirt);
1981 void R_Shadow_RenderSurfacesLighting(const entity_render_t *ent, const texture_t *texture, int numsurfaces, msurface_t **surfacelist)
1983 // FIXME: support MATERIALFLAG_NODEPTHTEST
1984 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
1985 // calculate colors to render this texture with
1986 lightcolorbase[0] = r_shadow_rtlight->currentcolor[0] * ent->colormod[0] * texture->currentalpha;
1987 lightcolorbase[1] = r_shadow_rtlight->currentcolor[1] * ent->colormod[1] * texture->currentalpha;
1988 lightcolorbase[2] = r_shadow_rtlight->currentcolor[2] * ent->colormod[2] * texture->currentalpha;
1989 if ((r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorbase) + (r_shadow_rtlight->specularscale * texture->specularscale) * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
1991 if ((texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) || (ent->flags & RENDER_NOCULLFACE))
1992 qglDisable(GL_CULL_FACE);
1994 qglEnable(GL_CULL_FACE);
1995 if (texture->colormapping)
1997 qboolean dopants = texture->skin.pants != NULL && VectorLength2(ent->colormap_pantscolor) >= (1.0f / 1048576.0f);
1998 qboolean doshirt = texture->skin.shirt != NULL && VectorLength2(ent->colormap_shirtcolor) >= (1.0f / 1048576.0f);
2001 lightcolorpants[0] = lightcolorbase[0] * ent->colormap_pantscolor[0];
2002 lightcolorpants[1] = lightcolorbase[1] * ent->colormap_pantscolor[1];
2003 lightcolorpants[2] = lightcolorbase[2] * ent->colormap_pantscolor[2];
2006 VectorClear(lightcolorpants);
2009 lightcolorshirt[0] = lightcolorbase[0] * ent->colormap_shirtcolor[0];
2010 lightcolorshirt[1] = lightcolorbase[1] * ent->colormap_shirtcolor[1];
2011 lightcolorshirt[2] = lightcolorbase[2] * ent->colormap_shirtcolor[2];
2014 VectorClear(lightcolorshirt);
2015 switch (r_shadow_rendermode)
2017 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2018 R_Shadow_RenderSurfacesLighting_VisibleLighting(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, texture->basetexture, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, texture->glosstexture, r_shadow_rtlight->specularscale * texture->specularscale, dopants, doshirt);
2020 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2021 R_Shadow_RenderSurfacesLighting_Light_GLSL(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, texture->basetexture, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, texture->glosstexture, r_shadow_rtlight->specularscale * texture->specularscale, dopants, doshirt);
2023 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2024 R_Shadow_RenderSurfacesLighting_Light_Dot3(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, texture->basetexture, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, texture->glosstexture, r_shadow_rtlight->specularscale * texture->specularscale, dopants, doshirt);
2026 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2027 R_Shadow_RenderSurfacesLighting_Light_Vertex(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, texture->basetexture, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, texture->glosstexture, r_shadow_rtlight->specularscale * texture->specularscale, dopants, doshirt);
2030 Con_Printf("R_Shadow_RenderSurfacesLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2036 switch (r_shadow_rendermode)
2038 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2039 R_Shadow_RenderSurfacesLighting_VisibleLighting(ent, texture, numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, texture->basetexture, r_texture_black, r_texture_black, texture->skin.nmap, texture->glosstexture, r_shadow_rtlight->specularscale * texture->specularscale, false, false);
2041 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2042 R_Shadow_RenderSurfacesLighting_Light_GLSL(ent, texture, numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, texture->basetexture, r_texture_black, r_texture_black, texture->skin.nmap, texture->glosstexture, r_shadow_rtlight->specularscale * texture->specularscale, false, false);
2044 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2045 R_Shadow_RenderSurfacesLighting_Light_Dot3(ent, texture, numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, texture->basetexture, r_texture_black, r_texture_black, texture->skin.nmap, texture->glosstexture, r_shadow_rtlight->specularscale * texture->specularscale, false, false);
2047 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2048 R_Shadow_RenderSurfacesLighting_Light_Vertex(ent, texture, numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, texture->basetexture, r_texture_black, r_texture_black, texture->skin.nmap, texture->glosstexture, r_shadow_rtlight->specularscale * texture->specularscale, false, false);
2051 Con_Printf("R_Shadow_RenderSurfacesLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2057 void R_RTLight_Update(dlight_t *light, int isstatic)
2061 rtlight_t *rtlight = &light->rtlight;
2062 R_RTLight_Uncompile(rtlight);
2063 memset(rtlight, 0, sizeof(*rtlight));
2065 VectorCopy(light->origin, rtlight->shadoworigin);
2066 VectorCopy(light->color, rtlight->color);
2067 rtlight->radius = light->radius;
2068 //rtlight->cullradius = rtlight->radius;
2069 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2070 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2071 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2072 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2073 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2074 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2075 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2076 rtlight->cubemapname[0] = 0;
2077 if (light->cubemapname[0])
2078 strcpy(rtlight->cubemapname, light->cubemapname);
2079 else if (light->cubemapnum > 0)
2080 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
2081 rtlight->shadow = light->shadow;
2082 rtlight->corona = light->corona;
2083 rtlight->style = light->style;
2084 rtlight->isstatic = isstatic;
2085 rtlight->coronasizescale = light->coronasizescale;
2086 rtlight->ambientscale = light->ambientscale;
2087 rtlight->diffusescale = light->diffusescale;
2088 rtlight->specularscale = light->specularscale;
2089 rtlight->flags = light->flags;
2090 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
2091 // ConcatScale won't work here because this needs to scale rotate and
2092 // translate, not just rotate
2093 scale = 1.0f / rtlight->radius;
2094 for (k = 0;k < 3;k++)
2095 for (j = 0;j < 4;j++)
2096 rtlight->matrix_worldtolight.m[k][j] *= scale;
2099 // compiles rtlight geometry
2100 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2101 void R_RTLight_Compile(rtlight_t *rtlight)
2103 int shadowmeshes, shadowtris, numleafs, numleafpvsbytes, numsurfaces;
2104 entity_render_t *ent = r_refdef.worldentity;
2105 model_t *model = r_refdef.worldmodel;
2106 unsigned char *data;
2108 // compile the light
2109 rtlight->compiled = true;
2110 rtlight->static_numleafs = 0;
2111 rtlight->static_numleafpvsbytes = 0;
2112 rtlight->static_leaflist = NULL;
2113 rtlight->static_leafpvs = NULL;
2114 rtlight->static_numsurfaces = 0;
2115 rtlight->static_surfacelist = NULL;
2116 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2117 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2118 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2119 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2120 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2121 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2123 if (model && model->GetLightInfo)
2125 // this variable must be set for the CompileShadowVolume code
2126 r_shadow_compilingrtlight = rtlight;
2127 R_Shadow_EnlargeLeafSurfaceBuffer(model->brush.num_leafs, model->num_surfaces);
2128 model->GetLightInfo(ent, rtlight->shadoworigin, rtlight->radius, rtlight->cullmins, rtlight->cullmaxs, r_shadow_buffer_leaflist, r_shadow_buffer_leafpvs, &numleafs, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces);
2129 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2130 data = (unsigned char *)Mem_Alloc(r_shadow_mempool, sizeof(int) * numleafs + numleafpvsbytes + sizeof(int) * numsurfaces);
2131 rtlight->static_numleafs = numleafs;
2132 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2133 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2134 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2135 rtlight->static_numsurfaces = numsurfaces;
2136 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2138 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2139 if (numleafpvsbytes)
2140 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2142 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2143 if (model->CompileShadowVolume && rtlight->shadow)
2144 model->CompileShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2145 // now we're done compiling the rtlight
2146 r_shadow_compilingrtlight = NULL;
2150 // use smallest available cullradius - box radius or light radius
2151 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2152 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2156 if (rtlight->static_meshchain_shadow)
2159 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2162 shadowtris += mesh->numtriangles;
2166 Con_DPrintf("static light built: %f %f %f : %f %f %f box, %i shadow volume 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);
2169 void R_RTLight_Uncompile(rtlight_t *rtlight)
2171 if (rtlight->compiled)
2173 if (rtlight->static_meshchain_shadow)
2174 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2175 rtlight->static_meshchain_shadow = NULL;
2176 // these allocations are grouped
2177 if (rtlight->static_leaflist)
2178 Mem_Free(rtlight->static_leaflist);
2179 rtlight->static_numleafs = 0;
2180 rtlight->static_numleafpvsbytes = 0;
2181 rtlight->static_leaflist = NULL;
2182 rtlight->static_leafpvs = NULL;
2183 rtlight->static_numsurfaces = 0;
2184 rtlight->static_surfacelist = NULL;
2185 rtlight->compiled = false;
2189 void R_Shadow_UncompileWorldLights(void)
2192 for (light = r_shadow_worldlightchain;light;light = light->next)
2193 R_RTLight_Uncompile(&light->rtlight);
2196 void R_Shadow_DrawEntityShadow(entity_render_t *ent, int numsurfaces, int *surfacelist)
2198 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
2199 vec_t relativeshadowradius;
2200 if (ent == r_refdef.worldentity)
2202 if (r_shadow_rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2205 R_Mesh_Matrix(&ent->matrix);
2206 for (mesh = r_shadow_rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2208 renderstats.lights_shadowtriangles += mesh->numtriangles;
2209 R_Mesh_VertexPointer(mesh->vertex3f);
2210 GL_LockArrays(0, mesh->numverts);
2211 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
2213 // decrement stencil if backface is behind depthbuffer
2214 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2215 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2216 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2217 // increment stencil if frontface is behind depthbuffer
2218 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2219 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2221 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2222 GL_LockArrays(0, 0);
2225 else if (numsurfaces)
2227 R_Mesh_Matrix(&ent->matrix);
2228 ent->model->DrawShadowVolume(ent, r_shadow_rtlight->shadoworigin, r_shadow_rtlight->radius, numsurfaces, surfacelist, r_shadow_rtlight->cullmins, r_shadow_rtlight->cullmaxs);
2233 Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, relativeshadoworigin);
2234 relativeshadowradius = r_shadow_rtlight->radius / ent->scale;
2235 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
2236 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
2237 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
2238 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
2239 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
2240 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
2241 R_Mesh_Matrix(&ent->matrix);
2242 ent->model->DrawShadowVolume(ent, relativeshadoworigin, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2246 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
2248 // set up properties for rendering light onto this entity
2249 Matrix4x4_Concat(&r_shadow_entitytolight, &r_shadow_rtlight->matrix_worldtolight, &ent->matrix);
2250 Matrix4x4_Concat(&r_shadow_entitytoattenuationxyz, &matrix_attenuationxyz, &r_shadow_entitytolight);
2251 Matrix4x4_Concat(&r_shadow_entitytoattenuationz, &matrix_attenuationz, &r_shadow_entitytolight);
2252 Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, r_shadow_entitylightorigin);
2253 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, r_shadow_entityeyeorigin);
2254 R_Mesh_Matrix(&ent->matrix);
2257 void R_Shadow_DrawEntityLight(entity_render_t *ent, int numsurfaces, int *surfacelist)
2259 R_Shadow_SetupEntityLight(ent);
2260 if (ent == r_refdef.worldentity)
2261 ent->model->DrawLight(ent, numsurfaces, surfacelist);
2263 ent->model->DrawLight(ent, ent->model->nummodelsurfaces, ent->model->surfacelist);
2266 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
2270 int numleafs, numsurfaces;
2271 int *leaflist, *surfacelist;
2272 unsigned char *leafpvs;
2273 int numlightentities;
2274 int numshadowentities;
2275 entity_render_t *lightentities[MAX_EDICTS];
2276 entity_render_t *shadowentities[MAX_EDICTS];
2278 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
2279 // skip lights that are basically invisible (color 0 0 0)
2280 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
2283 // loading is done before visibility checks because loading should happen
2284 // all at once at the start of a level, not when it stalls gameplay.
2285 // (especially important to benchmarks)
2287 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2288 R_RTLight_Compile(rtlight);
2290 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
2292 // look up the light style value at this time
2293 f = (rtlight->style >= 0 ? r_refdef.lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2294 VectorScale(rtlight->color, f, rtlight->currentcolor);
2296 if (rtlight->selected)
2298 f = 2 + sin(realtime * M_PI * 4.0);
2299 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
2303 // if lightstyle is currently off, don't draw the light
2304 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
2307 // if the light box is offscreen, skip it
2308 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2311 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2313 // compiled light, world available and can receive realtime lighting
2314 // retrieve leaf information
2315 numleafs = rtlight->static_numleafs;
2316 leaflist = rtlight->static_leaflist;
2317 leafpvs = rtlight->static_leafpvs;
2318 numsurfaces = rtlight->static_numsurfaces;
2319 surfacelist = rtlight->static_surfacelist;
2321 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2323 // dynamic light, world available and can receive realtime lighting
2324 // calculate lit surfaces and leafs
2325 R_Shadow_EnlargeLeafSurfaceBuffer(r_refdef.worldmodel->brush.num_leafs, r_refdef.worldmodel->num_surfaces);
2326 r_refdef.worldmodel->GetLightInfo(r_refdef.worldentity, rtlight->shadoworigin, rtlight->radius, rtlight->cullmins, rtlight->cullmaxs, r_shadow_buffer_leaflist, r_shadow_buffer_leafpvs, &numleafs, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces);
2327 leaflist = r_shadow_buffer_leaflist;
2328 leafpvs = r_shadow_buffer_leafpvs;
2329 surfacelist = r_shadow_buffer_surfacelist;
2330 // if the reduced leaf bounds are offscreen, skip it
2331 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2343 // check if light is illuminating any visible leafs
2346 for (i = 0;i < numleafs;i++)
2347 if (r_worldleafvisible[leaflist[i]])
2352 // set up a scissor rectangle for this light
2353 if (R_Shadow_ScissorForBBox(rtlight->cullmins, rtlight->cullmaxs))
2356 // make a list of lit entities and shadow casting entities
2357 numlightentities = 0;
2358 numshadowentities = 0;
2359 // don't count the world unless some surfaces are actually lit
2362 lightentities[numlightentities++] = r_refdef.worldentity;
2363 shadowentities[numshadowentities++] = r_refdef.worldentity;
2365 // add dynamic entities that are lit by the light
2366 if (r_drawentities.integer)
2368 for (i = 0;i < r_refdef.numentities;i++)
2370 entity_render_t *ent = r_refdef.entities[i];
2371 if (BoxesOverlap(ent->mins, ent->maxs, rtlight->cullmins, rtlight->cullmaxs)
2373 && !(ent->flags & RENDER_TRANSPARENT)
2374 && (r_refdef.worldmodel == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs)))
2376 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2377 if ((ent->flags & RENDER_SHADOW) && ent->model->DrawShadowVolume && VectorDistance2(ent->origin, rtlight->shadoworigin) > 0.1)
2378 shadowentities[numshadowentities++] = ent;
2379 if (ent->visframe == r_framecount && (ent->flags & RENDER_LIGHT) && ent->model->DrawLight)
2380 lightentities[numlightentities++] = ent;
2385 // return if there's nothing at all to light
2386 if (!numlightentities)
2389 // don't let sound skip if going slow
2390 if (r_refdef.extraupdate)
2393 // make this the active rtlight for rendering purposes
2394 R_Shadow_RenderMode_ActiveLight(rtlight);
2395 // count this light in the r_speeds
2396 renderstats.lights++;
2399 if (numshadowentities && rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows))
2401 // draw stencil shadow volumes to mask off pixels that are in shadow
2402 // so that they won't receive lighting
2406 R_Shadow_RenderMode_StencilShadowVolumes();
2407 for (i = 0;i < numshadowentities;i++)
2408 R_Shadow_DrawEntityShadow(shadowentities[i], numsurfaces, surfacelist);
2411 // optionally draw visible shape of the shadow volumes
2412 // for performance analysis by level designers
2413 if (r_showshadowvolumes.integer)
2415 R_Shadow_RenderMode_VisibleShadowVolumes();
2416 for (i = 0;i < numshadowentities;i++)
2417 R_Shadow_DrawEntityShadow(shadowentities[i], numsurfaces, surfacelist);
2421 if (numlightentities)
2423 // draw lighting in the unmasked areas
2424 R_Shadow_RenderMode_Lighting(usestencil, false);
2425 for (i = 0;i < numlightentities;i++)
2426 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
2428 // optionally draw the illuminated areas
2429 // for performance analysis by level designers
2430 if (r_showlighting.integer)
2432 R_Shadow_RenderMode_VisibleLighting(usestencil && !r_showdisabledepthtest.integer, false);
2433 for (i = 0;i < numlightentities;i++)
2434 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
2439 void R_ShadowVolumeLighting(qboolean visible)
2444 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2445 R_Shadow_EditLights_Reload_f();
2447 R_Shadow_RenderMode_Begin();
2449 flag = r_rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2450 if (r_shadow_debuglight.integer >= 0)
2452 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2453 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
2454 R_DrawRTLight(&light->rtlight, visible);
2457 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2458 if (light->flags & flag)
2459 R_DrawRTLight(&light->rtlight, visible);
2461 for (lnum = 0;lnum < r_refdef.numlights;lnum++)
2462 R_DrawRTLight(&r_refdef.lights[lnum]->rtlight, visible);
2464 R_Shadow_RenderMode_End();
2467 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2468 typedef struct suffixinfo_s
2471 qboolean flipx, flipy, flipdiagonal;
2474 static suffixinfo_t suffix[3][6] =
2477 {"px", false, false, false},
2478 {"nx", false, false, false},
2479 {"py", false, false, false},
2480 {"ny", false, false, false},
2481 {"pz", false, false, false},
2482 {"nz", false, false, false}
2485 {"posx", false, false, false},
2486 {"negx", false, false, false},
2487 {"posy", false, false, false},
2488 {"negy", false, false, false},
2489 {"posz", false, false, false},
2490 {"negz", false, false, false}
2493 {"rt", true, false, true},
2494 {"lf", false, true, true},
2495 {"ft", true, true, false},
2496 {"bk", false, false, false},
2497 {"up", true, false, true},
2498 {"dn", true, false, true}
2502 static int componentorder[4] = {0, 1, 2, 3};
2504 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2506 int i, j, cubemapsize;
2507 unsigned char *cubemappixels, *image_rgba;
2508 rtexture_t *cubemaptexture;
2510 // must start 0 so the first loadimagepixels has no requested width/height
2512 cubemappixels = NULL;
2513 cubemaptexture = NULL;
2514 // keep trying different suffix groups (posx, px, rt) until one loads
2515 for (j = 0;j < 3 && !cubemappixels;j++)
2517 // load the 6 images in the suffix group
2518 for (i = 0;i < 6;i++)
2520 // generate an image name based on the base and and suffix
2521 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2523 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2525 // an image loaded, make sure width and height are equal
2526 if (image_width == image_height)
2528 // if this is the first image to load successfully, allocate the cubemap memory
2529 if (!cubemappixels && image_width >= 1)
2531 cubemapsize = image_width;
2532 // note this clears to black, so unavailable sides are black
2533 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2535 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2537 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);
2540 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2542 Mem_Free(image_rgba);
2546 // if a cubemap loaded, upload it
2549 if (!r_shadow_filters_texturepool)
2550 r_shadow_filters_texturepool = R_AllocTexturePool();
2551 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
2552 Mem_Free(cubemappixels);
2556 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
2557 for (j = 0;j < 3;j++)
2558 for (i = 0;i < 6;i++)
2559 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2560 Con_Print(" and was unable to find any of them.\n");
2562 return cubemaptexture;
2565 rtexture_t *R_Shadow_Cubemap(const char *basename)
2568 for (i = 0;i < numcubemaps;i++)
2569 if (!strcasecmp(cubemaps[i].basename, basename))
2570 return cubemaps[i].texture;
2571 if (i >= MAX_CUBEMAPS)
2572 return r_texture_whitecube;
2574 strcpy(cubemaps[i].basename, basename);
2575 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
2576 if (!cubemaps[i].texture)
2577 cubemaps[i].texture = r_texture_whitecube;
2578 return cubemaps[i].texture;
2581 void R_Shadow_FreeCubemaps(void)
2584 R_FreeTexturePool(&r_shadow_filters_texturepool);
2587 dlight_t *R_Shadow_NewWorldLight(void)
2590 light = (dlight_t *)Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
2591 light->next = r_shadow_worldlightchain;
2592 r_shadow_worldlightchain = light;
2596 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)
2598 VectorCopy(origin, light->origin);
2599 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
2600 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
2601 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
2602 light->color[0] = max(color[0], 0);
2603 light->color[1] = max(color[1], 0);
2604 light->color[2] = max(color[2], 0);
2605 light->radius = max(radius, 0);
2606 light->style = style;
2607 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
2609 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
2612 light->shadow = shadowenable;
2613 light->corona = corona;
2616 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
2617 light->coronasizescale = coronasizescale;
2618 light->ambientscale = ambientscale;
2619 light->diffusescale = diffusescale;
2620 light->specularscale = specularscale;
2621 light->flags = flags;
2622 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
2624 R_RTLight_Update(light, true);
2627 void R_Shadow_FreeWorldLight(dlight_t *light)
2629 dlight_t **lightpointer;
2630 R_RTLight_Uncompile(&light->rtlight);
2631 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
2632 if (*lightpointer != light)
2633 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain");
2634 *lightpointer = light->next;
2638 void R_Shadow_ClearWorldLights(void)
2640 while (r_shadow_worldlightchain)
2641 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
2642 r_shadow_selectedlight = NULL;
2643 R_Shadow_FreeCubemaps();
2646 void R_Shadow_SelectLight(dlight_t *light)
2648 if (r_shadow_selectedlight)
2649 r_shadow_selectedlight->selected = false;
2650 r_shadow_selectedlight = light;
2651 if (r_shadow_selectedlight)
2652 r_shadow_selectedlight->selected = true;
2655 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
2657 float scale = r_editlights_cursorgrid.value * 0.5f;
2658 R_DrawSprite(GL_SRC_ALPHA, GL_ONE, r_crosshairs[1]->tex, NULL, false, r_editlights_cursorlocation, r_viewright, r_viewup, scale, -scale, -scale, scale, 1, 1, 1, 0.5f);
2661 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
2664 const dlight_t *light = (dlight_t *)ent;
2666 if (light->selected)
2667 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
2670 R_DrawSprite(GL_SRC_ALPHA, GL_ONE, r_crosshairs[surfacenumber]->tex, NULL, false, light->origin, r_viewright, r_viewup, 8, -8, -8, 8, intensity, intensity, intensity, 0.5);
2673 void R_Shadow_DrawLightSprites(void)
2678 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
2679 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 1+(i % 5), &light->rtlight);
2680 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
2683 void R_Shadow_SelectLightInView(void)
2685 float bestrating, rating, temp[3];
2686 dlight_t *best, *light;
2689 for (light = r_shadow_worldlightchain;light;light = light->next)
2691 VectorSubtract(light->origin, r_vieworigin, temp);
2692 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
2695 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
2696 if (bestrating < rating && CL_TraceBox(light->origin, vec3_origin, vec3_origin, r_vieworigin, true, NULL, SUPERCONTENTS_SOLID, false).fraction == 1.0f)
2698 bestrating = rating;
2703 R_Shadow_SelectLight(best);
2706 void R_Shadow_LoadWorldLights(void)
2708 int n, a, style, shadow, flags;
2709 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
2710 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
2711 if (r_refdef.worldmodel == NULL)
2713 Con_Print("No map loaded.\n");
2716 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
2717 strlcat (name, ".rtlights", sizeof (name));
2718 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
2728 for (;COM_Parse(t, true) && strcmp(
2729 if (COM_Parse(t, true))
2731 if (com_token[0] == '!')
2734 origin[0] = atof(com_token+1);
2737 origin[0] = atof(com_token);
2742 while (*s && *s != '\n' && *s != '\r')
2748 // check for modifier flags
2755 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);
2758 flags = LIGHTFLAG_REALTIMEMODE;
2766 coronasizescale = 0.25f;
2768 VectorClear(angles);
2771 if (a < 9 || !strcmp(cubemapname, "\"\""))
2773 // remove quotes on cubemapname
2774 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
2776 cubemapname[strlen(cubemapname)-1] = 0;
2777 strcpy(cubemapname, cubemapname + 1);
2781 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);
2784 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
2792 Con_Printf("invalid rtlights file \"%s\"\n", name);
2793 Mem_Free(lightsstring);
2797 void R_Shadow_SaveWorldLights(void)
2800 size_t bufchars, bufmaxchars;
2802 char name[MAX_QPATH];
2803 char line[MAX_INPUTLINE];
2804 if (!r_shadow_worldlightchain)
2806 if (r_refdef.worldmodel == NULL)
2808 Con_Print("No map loaded.\n");
2811 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
2812 strlcat (name, ".rtlights", sizeof (name));
2813 bufchars = bufmaxchars = 0;
2815 for (light = r_shadow_worldlightchain;light;light = light->next)
2817 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
2818 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, light->color[0], light->color[1], light->color[2], 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);
2819 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
2820 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, light->color[0], light->color[1], light->color[2], light->style, light->cubemapname, light->corona, light->angles[0], light->angles[1], light->angles[2]);
2822 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, light->color[0], light->color[1], light->color[2], light->style);
2823 if (bufchars + strlen(line) > bufmaxchars)
2825 bufmaxchars = bufchars + strlen(line) + 2048;
2827 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
2831 memcpy(buf, oldbuf, bufchars);
2837 memcpy(buf + bufchars, line, strlen(line));
2838 bufchars += strlen(line);
2842 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
2847 void R_Shadow_LoadLightsFile(void)
2850 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
2851 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
2852 if (r_refdef.worldmodel == NULL)
2854 Con_Print("No map loaded.\n");
2857 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
2858 strlcat (name, ".lights", sizeof (name));
2859 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
2867 while (*s && *s != '\n' && *s != '\r')
2873 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);
2877 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);
2880 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
2881 radius = bound(15, radius, 4096);
2882 VectorScale(color, (2.0f / (8388608.0f)), color);
2883 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
2891 Con_Printf("invalid lights file \"%s\"\n", name);
2892 Mem_Free(lightsstring);
2896 // tyrlite/hmap2 light types in the delay field
2897 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
2899 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
2901 int entnum, style, islight, skin, pflags, effects, type, n;
2904 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
2905 char key[256], value[MAX_INPUTLINE];
2907 if (r_refdef.worldmodel == NULL)
2909 Con_Print("No map loaded.\n");
2912 // try to load a .ent file first
2913 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
2914 strlcat (key, ".ent", sizeof (key));
2915 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
2916 // and if that is not found, fall back to the bsp file entity string
2918 data = r_refdef.worldmodel->brush.entities;
2921 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
2923 type = LIGHTTYPE_MINUSX;
2924 origin[0] = origin[1] = origin[2] = 0;
2925 originhack[0] = originhack[1] = originhack[2] = 0;
2926 angles[0] = angles[1] = angles[2] = 0;
2927 color[0] = color[1] = color[2] = 1;
2928 light[0] = light[1] = light[2] = 1;light[3] = 300;
2929 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
2939 if (!COM_ParseToken(&data, false))
2941 if (com_token[0] == '}')
2942 break; // end of entity
2943 if (com_token[0] == '_')
2944 strcpy(key, com_token + 1);
2946 strcpy(key, com_token);
2947 while (key[strlen(key)-1] == ' ') // remove trailing spaces
2948 key[strlen(key)-1] = 0;
2949 if (!COM_ParseToken(&data, false))
2951 strcpy(value, com_token);
2953 // now that we have the key pair worked out...
2954 if (!strcmp("light", key))
2956 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
2960 light[0] = vec[0] * (1.0f / 256.0f);
2961 light[1] = vec[0] * (1.0f / 256.0f);
2962 light[2] = vec[0] * (1.0f / 256.0f);
2968 light[0] = vec[0] * (1.0f / 255.0f);
2969 light[1] = vec[1] * (1.0f / 255.0f);
2970 light[2] = vec[2] * (1.0f / 255.0f);
2974 else if (!strcmp("delay", key))
2976 else if (!strcmp("origin", key))
2977 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
2978 else if (!strcmp("angle", key))
2979 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
2980 else if (!strcmp("angles", key))
2981 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
2982 else if (!strcmp("color", key))
2983 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
2984 else if (!strcmp("wait", key))
2985 fadescale = atof(value);
2986 else if (!strcmp("classname", key))
2988 if (!strncmp(value, "light", 5))
2991 if (!strcmp(value, "light_fluoro"))
2996 overridecolor[0] = 1;
2997 overridecolor[1] = 1;
2998 overridecolor[2] = 1;
3000 if (!strcmp(value, "light_fluorospark"))
3005 overridecolor[0] = 1;
3006 overridecolor[1] = 1;
3007 overridecolor[2] = 1;
3009 if (!strcmp(value, "light_globe"))
3014 overridecolor[0] = 1;
3015 overridecolor[1] = 0.8;
3016 overridecolor[2] = 0.4;
3018 if (!strcmp(value, "light_flame_large_yellow"))
3023 overridecolor[0] = 1;
3024 overridecolor[1] = 0.5;
3025 overridecolor[2] = 0.1;
3027 if (!strcmp(value, "light_flame_small_yellow"))
3032 overridecolor[0] = 1;
3033 overridecolor[1] = 0.5;
3034 overridecolor[2] = 0.1;
3036 if (!strcmp(value, "light_torch_small_white"))
3041 overridecolor[0] = 1;
3042 overridecolor[1] = 0.5;
3043 overridecolor[2] = 0.1;
3045 if (!strcmp(value, "light_torch_small_walltorch"))
3050 overridecolor[0] = 1;
3051 overridecolor[1] = 0.5;
3052 overridecolor[2] = 0.1;
3056 else if (!strcmp("style", key))
3057 style = atoi(value);
3058 else if (!strcmp("skin", key))
3059 skin = (int)atof(value);
3060 else if (!strcmp("pflags", key))
3061 pflags = (int)atof(value);
3062 else if (!strcmp("effects", key))
3063 effects = (int)atof(value);
3064 else if (r_refdef.worldmodel->type == mod_brushq3)
3066 if (!strcmp("scale", key))
3067 lightscale = atof(value);
3068 if (!strcmp("fade", key))
3069 fadescale = atof(value);
3074 if (lightscale <= 0)
3078 if (color[0] == color[1] && color[0] == color[2])
3080 color[0] *= overridecolor[0];
3081 color[1] *= overridecolor[1];
3082 color[2] *= overridecolor[2];
3084 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3085 color[0] = color[0] * light[0];
3086 color[1] = color[1] * light[1];
3087 color[2] = color[2] * light[2];
3090 case LIGHTTYPE_MINUSX:
3092 case LIGHTTYPE_RECIPX:
3094 VectorScale(color, (1.0f / 16.0f), color);
3096 case LIGHTTYPE_RECIPXX:
3098 VectorScale(color, (1.0f / 16.0f), color);
3101 case LIGHTTYPE_NONE:
3105 case LIGHTTYPE_MINUSXX:
3108 VectorAdd(origin, originhack, origin);
3110 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);
3113 Mem_Free(entfiledata);
3117 void R_Shadow_SetCursorLocationForView(void)
3120 vec3_t dest, endpos;
3122 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
3123 trace = CL_TraceBox(r_vieworigin, vec3_origin, vec3_origin, dest, true, NULL, SUPERCONTENTS_SOLID, false);
3124 if (trace.fraction < 1)
3126 dist = trace.fraction * r_editlights_cursordistance.value;
3127 push = r_editlights_cursorpushback.value;
3131 VectorMA(trace.endpos, push, r_viewforward, endpos);
3132 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
3136 VectorClear( endpos );
3138 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3139 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3140 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3143 void R_Shadow_UpdateWorldLightSelection(void)
3145 if (r_editlights.integer)
3147 R_Shadow_SetCursorLocationForView();
3148 R_Shadow_SelectLightInView();
3149 R_Shadow_DrawLightSprites();
3152 R_Shadow_SelectLight(NULL);
3155 void R_Shadow_EditLights_Clear_f(void)
3157 R_Shadow_ClearWorldLights();
3160 void R_Shadow_EditLights_Reload_f(void)
3162 if (!r_refdef.worldmodel)
3164 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3165 R_Shadow_ClearWorldLights();
3166 R_Shadow_LoadWorldLights();
3167 if (r_shadow_worldlightchain == NULL)
3169 R_Shadow_LoadLightsFile();
3170 if (r_shadow_worldlightchain == NULL)
3171 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3175 void R_Shadow_EditLights_Save_f(void)
3177 if (!r_refdef.worldmodel)
3179 R_Shadow_SaveWorldLights();
3182 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3184 R_Shadow_ClearWorldLights();
3185 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3188 void R_Shadow_EditLights_ImportLightsFile_f(void)
3190 R_Shadow_ClearWorldLights();
3191 R_Shadow_LoadLightsFile();
3194 void R_Shadow_EditLights_Spawn_f(void)
3197 if (!r_editlights.integer)
3199 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3202 if (Cmd_Argc() != 1)
3204 Con_Print("r_editlights_spawn does not take parameters\n");
3207 color[0] = color[1] = color[2] = 1;
3208 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3211 void R_Shadow_EditLights_Edit_f(void)
3213 vec3_t origin, angles, color;
3214 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3215 int style, shadows, flags, normalmode, realtimemode;
3216 char cubemapname[MAX_INPUTLINE];
3217 if (!r_editlights.integer)
3219 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3222 if (!r_shadow_selectedlight)
3224 Con_Print("No selected light.\n");
3227 VectorCopy(r_shadow_selectedlight->origin, origin);
3228 VectorCopy(r_shadow_selectedlight->angles, angles);
3229 VectorCopy(r_shadow_selectedlight->color, color);
3230 radius = r_shadow_selectedlight->radius;
3231 style = r_shadow_selectedlight->style;
3232 if (r_shadow_selectedlight->cubemapname)
3233 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
3236 shadows = r_shadow_selectedlight->shadow;
3237 corona = r_shadow_selectedlight->corona;
3238 coronasizescale = r_shadow_selectedlight->coronasizescale;
3239 ambientscale = r_shadow_selectedlight->ambientscale;
3240 diffusescale = r_shadow_selectedlight->diffusescale;
3241 specularscale = r_shadow_selectedlight->specularscale;
3242 flags = r_shadow_selectedlight->flags;
3243 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3244 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3245 if (!strcmp(Cmd_Argv(1), "origin"))
3247 if (Cmd_Argc() != 5)
3249 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3252 origin[0] = atof(Cmd_Argv(2));
3253 origin[1] = atof(Cmd_Argv(3));
3254 origin[2] = atof(Cmd_Argv(4));
3256 else if (!strcmp(Cmd_Argv(1), "originx"))
3258 if (Cmd_Argc() != 3)
3260 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3263 origin[0] = atof(Cmd_Argv(2));
3265 else if (!strcmp(Cmd_Argv(1), "originy"))
3267 if (Cmd_Argc() != 3)
3269 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3272 origin[1] = atof(Cmd_Argv(2));
3274 else if (!strcmp(Cmd_Argv(1), "originz"))
3276 if (Cmd_Argc() != 3)
3278 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3281 origin[2] = atof(Cmd_Argv(2));
3283 else if (!strcmp(Cmd_Argv(1), "move"))
3285 if (Cmd_Argc() != 5)
3287 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3290 origin[0] += atof(Cmd_Argv(2));
3291 origin[1] += atof(Cmd_Argv(3));
3292 origin[2] += atof(Cmd_Argv(4));
3294 else if (!strcmp(Cmd_Argv(1), "movex"))
3296 if (Cmd_Argc() != 3)
3298 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3301 origin[0] += atof(Cmd_Argv(2));
3303 else if (!strcmp(Cmd_Argv(1), "movey"))
3305 if (Cmd_Argc() != 3)
3307 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3310 origin[1] += atof(Cmd_Argv(2));
3312 else if (!strcmp(Cmd_Argv(1), "movez"))
3314 if (Cmd_Argc() != 3)
3316 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3319 origin[2] += atof(Cmd_Argv(2));
3321 else if (!strcmp(Cmd_Argv(1), "angles"))
3323 if (Cmd_Argc() != 5)
3325 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3328 angles[0] = atof(Cmd_Argv(2));
3329 angles[1] = atof(Cmd_Argv(3));
3330 angles[2] = atof(Cmd_Argv(4));
3332 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3334 if (Cmd_Argc() != 3)
3336 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3339 angles[0] = atof(Cmd_Argv(2));
3341 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3343 if (Cmd_Argc() != 3)
3345 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3348 angles[1] = atof(Cmd_Argv(2));
3350 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3352 if (Cmd_Argc() != 3)
3354 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3357 angles[2] = atof(Cmd_Argv(2));
3359 else if (!strcmp(Cmd_Argv(1), "color"))
3361 if (Cmd_Argc() != 5)
3363 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3366 color[0] = atof(Cmd_Argv(2));
3367 color[1] = atof(Cmd_Argv(3));
3368 color[2] = atof(Cmd_Argv(4));
3370 else if (!strcmp(Cmd_Argv(1), "radius"))
3372 if (Cmd_Argc() != 3)
3374 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3377 radius = atof(Cmd_Argv(2));
3379 else if (!strcmp(Cmd_Argv(1), "colorscale"))
3381 if (Cmd_Argc() == 3)
3383 double scale = atof(Cmd_Argv(2));
3390 if (Cmd_Argc() != 5)
3392 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
3395 color[0] *= atof(Cmd_Argv(2));
3396 color[1] *= atof(Cmd_Argv(3));
3397 color[2] *= atof(Cmd_Argv(4));
3400 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
3402 if (Cmd_Argc() != 3)
3404 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3407 radius *= atof(Cmd_Argv(2));
3409 else if (!strcmp(Cmd_Argv(1), "style"))
3411 if (Cmd_Argc() != 3)
3413 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3416 style = atoi(Cmd_Argv(2));
3418 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3422 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3425 if (Cmd_Argc() == 3)
3426 strcpy(cubemapname, Cmd_Argv(2));
3430 else if (!strcmp(Cmd_Argv(1), "shadows"))
3432 if (Cmd_Argc() != 3)
3434 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3437 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3439 else if (!strcmp(Cmd_Argv(1), "corona"))
3441 if (Cmd_Argc() != 3)
3443 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3446 corona = atof(Cmd_Argv(2));
3448 else if (!strcmp(Cmd_Argv(1), "coronasize"))
3450 if (Cmd_Argc() != 3)
3452 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3455 coronasizescale = atof(Cmd_Argv(2));
3457 else if (!strcmp(Cmd_Argv(1), "ambient"))
3459 if (Cmd_Argc() != 3)
3461 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3464 ambientscale = atof(Cmd_Argv(2));
3466 else if (!strcmp(Cmd_Argv(1), "diffuse"))
3468 if (Cmd_Argc() != 3)
3470 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3473 diffusescale = atof(Cmd_Argv(2));
3475 else if (!strcmp(Cmd_Argv(1), "specular"))
3477 if (Cmd_Argc() != 3)
3479 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3482 specularscale = atof(Cmd_Argv(2));
3484 else if (!strcmp(Cmd_Argv(1), "normalmode"))
3486 if (Cmd_Argc() != 3)
3488 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3491 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3493 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
3495 if (Cmd_Argc() != 3)
3497 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3500 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3504 Con_Print("usage: r_editlights_edit [property] [value]\n");
3505 Con_Print("Selected light's properties:\n");
3506 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3507 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3508 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3509 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3510 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3511 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3512 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3513 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
3514 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
3515 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
3516 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
3517 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
3518 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
3519 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
3522 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
3523 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3526 void R_Shadow_EditLights_EditAll_f(void)
3530 if (!r_editlights.integer)
3532 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
3536 for (light = r_shadow_worldlightchain;light;light = light->next)
3538 R_Shadow_SelectLight(light);
3539 R_Shadow_EditLights_Edit_f();
3543 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3545 int lightnumber, lightcount;
3549 if (!r_editlights.integer)
3555 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
3556 if (light == r_shadow_selectedlight)
3557 lightnumber = lightcount;
3558 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;
3559 if (r_shadow_selectedlight == NULL)
3561 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3562 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;
3563 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;
3564 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;
3565 sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3566 sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3567 sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3568 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;
3569 sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3570 sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3571 sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3572 sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3573 sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3574 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;
3575 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;
3578 void R_Shadow_EditLights_ToggleShadow_f(void)
3580 if (!r_editlights.integer)
3582 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3585 if (!r_shadow_selectedlight)
3587 Con_Print("No selected light.\n");
3590 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);
3593 void R_Shadow_EditLights_ToggleCorona_f(void)
3595 if (!r_editlights.integer)
3597 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3600 if (!r_shadow_selectedlight)
3602 Con_Print("No selected light.\n");
3605 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);
3608 void R_Shadow_EditLights_Remove_f(void)
3610 if (!r_editlights.integer)
3612 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
3615 if (!r_shadow_selectedlight)
3617 Con_Print("No selected light.\n");
3620 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3621 r_shadow_selectedlight = NULL;
3624 void R_Shadow_EditLights_Help_f(void)
3627 "Documentation on r_editlights system:\n"
3629 "r_editlights : enable/disable editing mode\n"
3630 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
3631 "r_editlights_cursorpushback : push back cursor this far from surface\n"
3632 "r_editlights_cursorpushoff : push cursor off surface this far\n"
3633 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
3634 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
3636 "r_editlights_help : this help\n"
3637 "r_editlights_clear : remove all lights\n"
3638 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
3639 "r_editlights_save : save to .rtlights file\n"
3640 "r_editlights_spawn : create a light with default settings\n"
3641 "r_editlights_edit command : edit selected light - more documentation below\n"
3642 "r_editlights_remove : remove selected light\n"
3643 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
3644 "r_editlights_importlightentitiesfrommap : reload light entities\n"
3645 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
3647 "origin x y z : set light location\n"
3648 "originx x: set x component of light location\n"
3649 "originy y: set y component of light location\n"
3650 "originz z: set z component of light location\n"
3651 "move x y z : adjust light location\n"
3652 "movex x: adjust x component of light location\n"
3653 "movey y: adjust y component of light location\n"
3654 "movez z: adjust z component of light location\n"
3655 "angles x y z : set light angles\n"
3656 "anglesx x: set x component of light angles\n"
3657 "anglesy y: set y component of light angles\n"
3658 "anglesz z: set z component of light angles\n"
3659 "color r g b : set color of light (can be brighter than 1 1 1)\n"
3660 "radius radius : set radius (size) of light\n"
3661 "colorscale grey : multiply color of light (1 does nothing)\n"
3662 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
3663 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
3664 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
3665 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
3666 "cubemap basename : set filter cubemap of light (not yet supported)\n"
3667 "shadows 1/0 : turn on/off shadows\n"
3668 "corona n : set corona intensity\n"
3669 "coronasize n : set corona size (0-1)\n"
3670 "ambient n : set ambient intensity (0-1)\n"
3671 "diffuse n : set diffuse intensity (0-1)\n"
3672 "specular n : set specular intensity (0-1)\n"
3673 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
3674 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
3675 "<nothing> : print light properties to console\n"
3679 void R_Shadow_EditLights_CopyInfo_f(void)
3681 if (!r_editlights.integer)
3683 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
3686 if (!r_shadow_selectedlight)
3688 Con_Print("No selected light.\n");
3691 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
3692 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
3693 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
3694 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
3695 if (r_shadow_selectedlight->cubemapname)
3696 strcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname);
3698 r_shadow_bufferlight.cubemapname[0] = 0;
3699 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
3700 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
3701 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
3702 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
3703 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
3704 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
3705 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
3708 void R_Shadow_EditLights_PasteInfo_f(void)
3710 if (!r_editlights.integer)
3712 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
3715 if (!r_shadow_selectedlight)
3717 Con_Print("No selected light.\n");
3720 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);
3723 void R_Shadow_EditLights_Init(void)
3725 Cvar_RegisterVariable(&r_editlights);
3726 Cvar_RegisterVariable(&r_editlights_cursordistance);
3727 Cvar_RegisterVariable(&r_editlights_cursorpushback);
3728 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
3729 Cvar_RegisterVariable(&r_editlights_cursorgrid);
3730 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
3731 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
3732 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
3733 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f, "reloads rtlights file (or imports from .lights file or .ent file or the map itself)");
3734 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
3735 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
3736 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
3737 Cmd_AddCommand("r_editlights_editall", R_Shadow_EditLights_EditAll_f, "changes a property on ALL lights at once (tip: use radiusscale and colorscale to alter these properties)");
3738 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
3739 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
3740 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
3741 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
3742 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
3743 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
3744 Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f, "apply the stored properties onto the selected light (making it exactly identical except for origin)");