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_SEPARATESTENCIL,
150 R_SHADOW_RENDERMODE_STENCILTWOSIDE,
151 R_SHADOW_RENDERMODE_LIGHT_VERTEX,
152 R_SHADOW_RENDERMODE_LIGHT_DOT3,
153 R_SHADOW_RENDERMODE_LIGHT_GLSL,
154 R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
155 R_SHADOW_RENDERMODE_VISIBLELIGHTING,
157 r_shadow_rendermode_t;
159 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
160 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
161 r_shadow_rendermode_t r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_NONE;
163 int maxshadowtriangles;
166 int maxshadowvertices;
167 float *shadowvertex3f;
180 int r_shadow_buffer_numleafpvsbytes;
181 unsigned char *r_shadow_buffer_visitingleafpvs;
182 unsigned char *r_shadow_buffer_leafpvs;
183 int *r_shadow_buffer_leaflist;
185 int r_shadow_buffer_numsurfacepvsbytes;
186 unsigned char *r_shadow_buffer_surfacepvs;
187 int *r_shadow_buffer_surfacelist;
189 int r_shadow_buffer_numshadowtrispvsbytes;
190 unsigned char *r_shadow_buffer_shadowtrispvs;
191 int r_shadow_buffer_numlighttrispvsbytes;
192 unsigned char *r_shadow_buffer_lighttrispvs;
194 rtexturepool_t *r_shadow_texturepool;
195 rtexture_t *r_shadow_attenuationgradienttexture;
196 rtexture_t *r_shadow_attenuation2dtexture;
197 rtexture_t *r_shadow_attenuation3dtexture;
198 rtexture_t *r_shadow_lightcorona;
200 // lights are reloaded when this changes
201 char r_shadow_mapname[MAX_QPATH];
203 // used only for light filters (cubemaps)
204 rtexturepool_t *r_shadow_filters_texturepool;
206 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"};
207 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"};
208 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
209 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
210 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)"};
211 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.125", "how bright the forced flat gloss should look if r_shadow_gloss is 2"};
212 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
213 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
214 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "1", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
215 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
216 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
217 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
218 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
219 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"};
220 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000", "how far to cast shadows"};
221 cvar_t r_shadow_frontsidecasting = {0, "r_shadow_frontsidecasting", "1", "whether to cast shadows from illuminated triangles (front side of model) or unlit triangles (back side of model)"};
222 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
223 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
224 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
225 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
226 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)"};
227 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"};
228 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
229 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
230 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"};
231 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation"};
232 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation"};
233 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)"};
234 cvar_t r_shadow_culltriangles = {0, "r_shadow_culltriangles", "1", "performs more expensive tests to remove unnecessary triangles of lit surfaces"};
235 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
236 cvar_t r_shadow_polygonoffset = {0, "r_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)"};
237 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)"};
238 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
239 cvar_t r_coronas_occlusionsizescale = {CVAR_SAVE, "r_coronas_occlusionsizescale", "0.1", "size of light source for corona occlusion checksm the proportion of hidden pixels controls corona intensity"};
240 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
241 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
242 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
243 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
244 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
245 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
246 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
247 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
248 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
249 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
251 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
252 #define ATTENTABLESIZE 256
253 // 1D gradient, 2D circle and 3D sphere attenuation textures
254 #define ATTEN1DSIZE 32
255 #define ATTEN2DSIZE 64
256 #define ATTEN3DSIZE 32
258 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
259 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
260 static float r_shadow_attentable[ATTENTABLESIZE+1];
262 rtlight_t *r_shadow_compilingrtlight;
263 static memexpandablearray_t r_shadow_worldlightsarray;
264 dlight_t *r_shadow_selectedlight;
265 dlight_t r_shadow_bufferlight;
266 vec3_t r_editlights_cursorlocation;
268 extern int con_vislines;
270 typedef struct cubemapinfo_s
277 #define MAX_CUBEMAPS 256
278 static int numcubemaps;
279 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
281 void R_Shadow_UncompileWorldLights(void);
282 void R_Shadow_ClearWorldLights(void);
283 void R_Shadow_SaveWorldLights(void);
284 void R_Shadow_LoadWorldLights(void);
285 void R_Shadow_LoadLightsFile(void);
286 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
287 void R_Shadow_EditLights_Reload_f(void);
288 void R_Shadow_ValidateCvars(void);
289 static void R_Shadow_MakeTextures(void);
291 // VorteX: custom editor light sprites
292 #define EDLIGHTSPRSIZE 8
293 cachepic_t *r_editlights_sprcursor;
294 cachepic_t *r_editlights_sprlight;
295 cachepic_t *r_editlights_sprnoshadowlight;
296 cachepic_t *r_editlights_sprcubemaplight;
297 cachepic_t *r_editlights_sprcubemapnoshadowlight;
298 cachepic_t *r_editlights_sprselection;
300 void r_shadow_start(void)
302 // allocate vertex processing arrays
304 r_shadow_attenuationgradienttexture = NULL;
305 r_shadow_attenuation2dtexture = NULL;
306 r_shadow_attenuation3dtexture = NULL;
307 r_shadow_texturepool = NULL;
308 r_shadow_filters_texturepool = NULL;
309 R_Shadow_ValidateCvars();
310 R_Shadow_MakeTextures();
311 maxshadowtriangles = 0;
312 shadowelements = NULL;
313 maxshadowvertices = 0;
314 shadowvertex3f = NULL;
322 shadowmarklist = NULL;
324 r_shadow_buffer_numleafpvsbytes = 0;
325 r_shadow_buffer_visitingleafpvs = NULL;
326 r_shadow_buffer_leafpvs = NULL;
327 r_shadow_buffer_leaflist = NULL;
328 r_shadow_buffer_numsurfacepvsbytes = 0;
329 r_shadow_buffer_surfacepvs = NULL;
330 r_shadow_buffer_surfacelist = NULL;
331 r_shadow_buffer_numshadowtrispvsbytes = 0;
332 r_shadow_buffer_shadowtrispvs = NULL;
333 r_shadow_buffer_numlighttrispvsbytes = 0;
334 r_shadow_buffer_lighttrispvs = NULL;
337 void r_shadow_shutdown(void)
339 R_Shadow_UncompileWorldLights();
341 r_shadow_attenuationgradienttexture = NULL;
342 r_shadow_attenuation2dtexture = NULL;
343 r_shadow_attenuation3dtexture = NULL;
344 R_FreeTexturePool(&r_shadow_texturepool);
345 R_FreeTexturePool(&r_shadow_filters_texturepool);
346 maxshadowtriangles = 0;
348 Mem_Free(shadowelements);
349 shadowelements = NULL;
351 Mem_Free(shadowvertex3f);
352 shadowvertex3f = NULL;
355 Mem_Free(vertexupdate);
358 Mem_Free(vertexremap);
364 Mem_Free(shadowmark);
367 Mem_Free(shadowmarklist);
368 shadowmarklist = NULL;
370 r_shadow_buffer_numleafpvsbytes = 0;
371 if (r_shadow_buffer_visitingleafpvs)
372 Mem_Free(r_shadow_buffer_visitingleafpvs);
373 r_shadow_buffer_visitingleafpvs = NULL;
374 if (r_shadow_buffer_leafpvs)
375 Mem_Free(r_shadow_buffer_leafpvs);
376 r_shadow_buffer_leafpvs = NULL;
377 if (r_shadow_buffer_leaflist)
378 Mem_Free(r_shadow_buffer_leaflist);
379 r_shadow_buffer_leaflist = NULL;
380 r_shadow_buffer_numsurfacepvsbytes = 0;
381 if (r_shadow_buffer_surfacepvs)
382 Mem_Free(r_shadow_buffer_surfacepvs);
383 r_shadow_buffer_surfacepvs = NULL;
384 if (r_shadow_buffer_surfacelist)
385 Mem_Free(r_shadow_buffer_surfacelist);
386 r_shadow_buffer_surfacelist = NULL;
387 r_shadow_buffer_numshadowtrispvsbytes = 0;
388 if (r_shadow_buffer_shadowtrispvs)
389 Mem_Free(r_shadow_buffer_shadowtrispvs);
390 r_shadow_buffer_numlighttrispvsbytes = 0;
391 if (r_shadow_buffer_lighttrispvs)
392 Mem_Free(r_shadow_buffer_lighttrispvs);
395 void r_shadow_newmap(void)
397 if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
398 R_Shadow_EditLights_Reload_f();
401 void R_Shadow_Help_f(void)
404 "Documentation on r_shadow system:\n"
406 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
407 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
408 "r_shadow_debuglight : render only this light number (-1 = all)\n"
409 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
410 "r_shadow_gloss2intensity : brightness of forced gloss\n"
411 "r_shadow_glossintensity : brightness of textured gloss\n"
412 "r_shadow_lightattenuationlinearscale : used to generate attenuation texture\n"
413 "r_shadow_lightattenuationdividebias : used to generate attenuation texture\n"
414 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
415 "r_shadow_lightradiusscale : scale rendering radius of all lights\n"
416 "r_shadow_portallight : use portal visibility for static light precomputation\n"
417 "r_shadow_projectdistance : shadow volume projection distance\n"
418 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
419 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
420 "r_shadow_realtime_world : use high quality world lighting mode\n"
421 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
422 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
423 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
424 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
425 "r_shadow_scissor : use scissor optimization\n"
426 "r_shadow_polygonfactor : nudge shadow volumes closer/further\n"
427 "r_shadow_polygonoffset : nudge shadow volumes closer/further\n"
428 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
429 "r_showlighting : useful for performance testing; bright = slow!\n"
430 "r_showshadowvolumes : useful for performance testing; bright = slow!\n"
432 "r_shadow_help : this help\n"
436 void R_Shadow_Init(void)
438 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
439 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
440 Cvar_RegisterVariable(&r_shadow_usenormalmap);
441 Cvar_RegisterVariable(&r_shadow_debuglight);
442 Cvar_RegisterVariable(&r_shadow_gloss);
443 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
444 Cvar_RegisterVariable(&r_shadow_glossintensity);
445 Cvar_RegisterVariable(&r_shadow_glossexponent);
446 Cvar_RegisterVariable(&r_shadow_glossexact);
447 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
448 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
449 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
450 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
451 Cvar_RegisterVariable(&r_shadow_portallight);
452 Cvar_RegisterVariable(&r_shadow_projectdistance);
453 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
454 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
455 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
456 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
457 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
458 Cvar_RegisterVariable(&r_shadow_realtime_world);
459 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
460 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
461 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
462 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
463 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
464 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
465 Cvar_RegisterVariable(&r_shadow_scissor);
466 Cvar_RegisterVariable(&r_shadow_culltriangles);
467 Cvar_RegisterVariable(&r_shadow_polygonfactor);
468 Cvar_RegisterVariable(&r_shadow_polygonoffset);
469 Cvar_RegisterVariable(&r_shadow_texture3d);
470 Cvar_RegisterVariable(&r_coronas);
471 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
472 Cvar_RegisterVariable(&r_coronas_occlusionquery);
473 Cvar_RegisterVariable(&gl_flashblend);
474 Cvar_RegisterVariable(&gl_ext_separatestencil);
475 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
476 if (gamemode == GAME_TENEBRAE)
478 Cvar_SetValue("r_shadow_gloss", 2);
479 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
481 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f, "prints documentation on console commands and variables used by realtime lighting and shadowing system");
482 R_Shadow_EditLights_Init();
483 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
484 maxshadowtriangles = 0;
485 shadowelements = NULL;
486 maxshadowvertices = 0;
487 shadowvertex3f = NULL;
495 shadowmarklist = NULL;
497 r_shadow_buffer_numleafpvsbytes = 0;
498 r_shadow_buffer_visitingleafpvs = NULL;
499 r_shadow_buffer_leafpvs = NULL;
500 r_shadow_buffer_leaflist = NULL;
501 r_shadow_buffer_numsurfacepvsbytes = 0;
502 r_shadow_buffer_surfacepvs = NULL;
503 r_shadow_buffer_surfacelist = NULL;
504 r_shadow_buffer_shadowtrispvs = NULL;
505 r_shadow_buffer_lighttrispvs = NULL;
506 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
509 matrix4x4_t matrix_attenuationxyz =
512 {0.5, 0.0, 0.0, 0.5},
513 {0.0, 0.5, 0.0, 0.5},
514 {0.0, 0.0, 0.5, 0.5},
519 matrix4x4_t matrix_attenuationz =
522 {0.0, 0.0, 0.5, 0.5},
523 {0.0, 0.0, 0.0, 0.5},
524 {0.0, 0.0, 0.0, 0.5},
529 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles)
531 // make sure shadowelements is big enough for this volume
532 if (maxshadowtriangles < numtriangles)
534 maxshadowtriangles = numtriangles;
536 Mem_Free(shadowelements);
537 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[24]));
539 // make sure shadowvertex3f is big enough for this volume
540 if (maxshadowvertices < numvertices)
542 maxshadowvertices = numvertices;
544 Mem_Free(shadowvertex3f);
545 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[6]));
549 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
551 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
552 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
553 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
554 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
555 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
557 if (r_shadow_buffer_visitingleafpvs)
558 Mem_Free(r_shadow_buffer_visitingleafpvs);
559 if (r_shadow_buffer_leafpvs)
560 Mem_Free(r_shadow_buffer_leafpvs);
561 if (r_shadow_buffer_leaflist)
562 Mem_Free(r_shadow_buffer_leaflist);
563 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
564 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
565 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
566 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
568 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
570 if (r_shadow_buffer_surfacepvs)
571 Mem_Free(r_shadow_buffer_surfacepvs);
572 if (r_shadow_buffer_surfacelist)
573 Mem_Free(r_shadow_buffer_surfacelist);
574 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
575 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
576 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
578 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
580 if (r_shadow_buffer_shadowtrispvs)
581 Mem_Free(r_shadow_buffer_shadowtrispvs);
582 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
583 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
585 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
587 if (r_shadow_buffer_lighttrispvs)
588 Mem_Free(r_shadow_buffer_lighttrispvs);
589 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
590 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
594 void R_Shadow_PrepareShadowMark(int numtris)
596 // make sure shadowmark is big enough for this volume
597 if (maxshadowmark < numtris)
599 maxshadowmark = numtris;
601 Mem_Free(shadowmark);
603 Mem_Free(shadowmarklist);
604 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
605 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
609 // if shadowmarkcount wrapped we clear the array and adjust accordingly
610 if (shadowmarkcount == 0)
613 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
618 static int R_Shadow_ConstructShadowVolume_ZFail(int innumvertices, int innumtris, const int *inelement3i, const int *inneighbor3i, const float *invertex3f, int *outnumvertices, int *outelement3i, float *outvertex3f, const float *projectorigin, const float *projectdirection, float projectdistance, int numshadowmarktris, const int *shadowmarktris)
621 int outtriangles = 0, outvertices = 0;
624 float ratio, direction[3], projectvector[3];
626 if (projectdirection)
627 VectorScale(projectdirection, projectdistance, projectvector);
629 VectorClear(projectvector);
631 // create the vertices
632 if (projectdirection)
634 for (i = 0;i < numshadowmarktris;i++)
636 element = inelement3i + shadowmarktris[i] * 3;
637 for (j = 0;j < 3;j++)
639 if (vertexupdate[element[j]] != vertexupdatenum)
641 vertexupdate[element[j]] = vertexupdatenum;
642 vertexremap[element[j]] = outvertices;
643 vertex = invertex3f + element[j] * 3;
644 // project one copy of the vertex according to projectvector
645 VectorCopy(vertex, outvertex3f);
646 VectorAdd(vertex, projectvector, (outvertex3f + 3));
655 for (i = 0;i < numshadowmarktris;i++)
657 element = inelement3i + shadowmarktris[i] * 3;
658 for (j = 0;j < 3;j++)
660 if (vertexupdate[element[j]] != vertexupdatenum)
662 vertexupdate[element[j]] = vertexupdatenum;
663 vertexremap[element[j]] = outvertices;
664 vertex = invertex3f + element[j] * 3;
665 // project one copy of the vertex to the sphere radius of the light
666 // (FIXME: would projecting it to the light box be better?)
667 VectorSubtract(vertex, projectorigin, direction);
668 ratio = projectdistance / VectorLength(direction);
669 VectorCopy(vertex, outvertex3f);
670 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
678 if (r_shadow_frontsidecasting.integer)
680 for (i = 0;i < numshadowmarktris;i++)
682 int remappedelement[3];
684 const int *neighbortriangle;
686 markindex = shadowmarktris[i] * 3;
687 element = inelement3i + markindex;
688 neighbortriangle = inneighbor3i + markindex;
689 // output the front and back triangles
690 outelement3i[0] = vertexremap[element[0]];
691 outelement3i[1] = vertexremap[element[1]];
692 outelement3i[2] = vertexremap[element[2]];
693 outelement3i[3] = vertexremap[element[2]] + 1;
694 outelement3i[4] = vertexremap[element[1]] + 1;
695 outelement3i[5] = vertexremap[element[0]] + 1;
699 // output the sides (facing outward from this triangle)
700 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
702 remappedelement[0] = vertexremap[element[0]];
703 remappedelement[1] = vertexremap[element[1]];
704 outelement3i[0] = remappedelement[1];
705 outelement3i[1] = remappedelement[0];
706 outelement3i[2] = remappedelement[0] + 1;
707 outelement3i[3] = remappedelement[1];
708 outelement3i[4] = remappedelement[0] + 1;
709 outelement3i[5] = remappedelement[1] + 1;
714 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
716 remappedelement[1] = vertexremap[element[1]];
717 remappedelement[2] = vertexremap[element[2]];
718 outelement3i[0] = remappedelement[2];
719 outelement3i[1] = remappedelement[1];
720 outelement3i[2] = remappedelement[1] + 1;
721 outelement3i[3] = remappedelement[2];
722 outelement3i[4] = remappedelement[1] + 1;
723 outelement3i[5] = remappedelement[2] + 1;
728 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
730 remappedelement[0] = vertexremap[element[0]];
731 remappedelement[2] = vertexremap[element[2]];
732 outelement3i[0] = remappedelement[0];
733 outelement3i[1] = remappedelement[2];
734 outelement3i[2] = remappedelement[2] + 1;
735 outelement3i[3] = remappedelement[0];
736 outelement3i[4] = remappedelement[2] + 1;
737 outelement3i[5] = remappedelement[0] + 1;
746 for (i = 0;i < numshadowmarktris;i++)
748 int remappedelement[3];
750 const int *neighbortriangle;
752 markindex = shadowmarktris[i] * 3;
753 element = inelement3i + markindex;
754 neighbortriangle = inneighbor3i + markindex;
755 // output the front and back triangles
756 outelement3i[0] = vertexremap[element[2]];
757 outelement3i[1] = vertexremap[element[1]];
758 outelement3i[2] = vertexremap[element[0]];
759 outelement3i[3] = vertexremap[element[0]] + 1;
760 outelement3i[4] = vertexremap[element[1]] + 1;
761 outelement3i[5] = vertexremap[element[2]] + 1;
765 // output the sides (facing outward from this triangle)
766 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
768 remappedelement[0] = vertexremap[element[0]];
769 remappedelement[1] = vertexremap[element[1]];
770 outelement3i[0] = remappedelement[0];
771 outelement3i[1] = remappedelement[1];
772 outelement3i[2] = remappedelement[1] + 1;
773 outelement3i[3] = remappedelement[0];
774 outelement3i[4] = remappedelement[1] + 1;
775 outelement3i[5] = remappedelement[0] + 1;
780 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
782 remappedelement[1] = vertexremap[element[1]];
783 remappedelement[2] = vertexremap[element[2]];
784 outelement3i[0] = remappedelement[1];
785 outelement3i[1] = remappedelement[2];
786 outelement3i[2] = remappedelement[2] + 1;
787 outelement3i[3] = remappedelement[1];
788 outelement3i[4] = remappedelement[2] + 1;
789 outelement3i[5] = remappedelement[1] + 1;
794 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
796 remappedelement[0] = vertexremap[element[0]];
797 remappedelement[2] = vertexremap[element[2]];
798 outelement3i[0] = remappedelement[2];
799 outelement3i[1] = remappedelement[0];
800 outelement3i[2] = remappedelement[0] + 1;
801 outelement3i[3] = remappedelement[2];
802 outelement3i[4] = remappedelement[0] + 1;
803 outelement3i[5] = remappedelement[2] + 1;
811 *outnumvertices = outvertices;
816 static int R_Shadow_ConstructShadowVolume_ZPass(int innumvertices, int innumtris, const int *inelement3i, const int *inneighbor3i, const float *invertex3f, int *outnumvertices, int *outelement3i, float *outvertex3f, const float *projectorigin, const float *projectdirection, float projectdistance, int numshadowmarktris, const int *shadowmarktris)
819 int outtriangles = 0, outvertices = 0;
822 float ratio, direction[3], projectvector[3];
825 if (projectdirection)
826 VectorScale(projectdirection, projectdistance, projectvector);
828 VectorClear(projectvector);
830 for (i = 0;i < numshadowmarktris;i++)
832 int remappedelement[3];
834 const int *neighbortriangle;
836 markindex = shadowmarktris[i] * 3;
837 neighbortriangle = inneighbor3i + markindex;
838 side[0] = shadowmark[neighbortriangle[0]] != shadowmarkcount;
839 side[1] = shadowmark[neighbortriangle[1]] != shadowmarkcount;
840 side[2] = shadowmark[neighbortriangle[2]] != shadowmarkcount;
841 if (side[0] + side[1] + side[2] == 0)
845 element = inelement3i + markindex;
847 for (j = 0;j < 3;j++)
849 if (side[j] + side[j+1] == 0)
852 if (vertexupdate[k] != vertexupdatenum)
854 vertexupdate[k] = vertexupdatenum;
855 vertexremap[k] = outvertices;
856 vertex = invertex3f + element[j] * 3;
857 VectorCopy(vertex, outvertex3f);
858 if (projectdirection)
860 // project one copy of the vertex according to projectvector
861 VectorAdd(vertex, projectvector, (outvertex3f + 3));
865 // project one copy of the vertex to the sphere radius of the light
866 // (FIXME: would projecting it to the light box be better?)
867 VectorSubtract(vertex, projectorigin, direction);
868 ratio = projectdistance / VectorLength(direction);
869 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
876 // output the sides (facing outward from this triangle)
879 remappedelement[0] = vertexremap[element[0]];
880 remappedelement[1] = vertexremap[element[1]];
881 outelement3i[0] = remappedelement[1];
882 outelement3i[1] = remappedelement[0];
883 outelement3i[2] = remappedelement[0] + 1;
884 outelement3i[3] = remappedelement[1];
885 outelement3i[4] = remappedelement[0] + 1;
886 outelement3i[5] = remappedelement[1] + 1;
893 remappedelement[1] = vertexremap[element[1]];
894 remappedelement[2] = vertexremap[element[2]];
895 outelement3i[0] = remappedelement[2];
896 outelement3i[1] = remappedelement[1];
897 outelement3i[2] = remappedelement[1] + 1;
898 outelement3i[3] = remappedelement[2];
899 outelement3i[4] = remappedelement[1] + 1;
900 outelement3i[5] = remappedelement[2] + 1;
907 remappedelement[0] = vertexremap[element[0]];
908 remappedelement[2] = vertexremap[element[2]];
909 outelement3i[0] = remappedelement[0];
910 outelement3i[1] = remappedelement[2];
911 outelement3i[2] = remappedelement[2] + 1;
912 outelement3i[3] = remappedelement[0];
913 outelement3i[4] = remappedelement[2] + 1;
914 outelement3i[5] = remappedelement[0] + 1;
921 *outnumvertices = outvertices;
926 void R_Shadow_MarkVolumeFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const vec3_t projectorigin, const vec3_t projectdirection, const vec3_t lightmins, const vec3_t lightmaxs, const vec3_t surfacemins, const vec3_t surfacemaxs)
932 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
934 tend = firsttriangle + numtris;
935 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
937 // surface box entirely inside light box, no box cull
938 if (projectdirection)
940 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
942 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
943 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
944 shadowmarklist[numshadowmark++] = t;
949 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
950 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
951 shadowmarklist[numshadowmark++] = t;
956 // surface box not entirely inside light box, cull each triangle
957 if (projectdirection)
959 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
961 v[0] = invertex3f + e[0] * 3;
962 v[1] = invertex3f + e[1] * 3;
963 v[2] = invertex3f + e[2] * 3;
964 TriangleNormal(v[0], v[1], v[2], normal);
965 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
966 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
967 shadowmarklist[numshadowmark++] = t;
972 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
974 v[0] = invertex3f + e[0] * 3;
975 v[1] = invertex3f + e[1] * 3;
976 v[2] = invertex3f + e[2] * 3;
977 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
978 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
979 shadowmarklist[numshadowmark++] = t;
985 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
990 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
992 // check if the shadow volume intersects the near plane
994 // a ray between the eye and light origin may intersect the caster,
995 // indicating that the shadow may touch the eye location, however we must
996 // test the near plane (a polygon), not merely the eye location, so it is
997 // easiest to enlarge the caster bounding shape slightly for this.
1003 void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, const vec3_t projectdirection, float projectdistance, int nummarktris, const int *marktris, vec3_t trismins, vec3_t trismaxs)
1005 int i, tris, outverts;
1006 if (projectdistance < 0.1)
1008 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1011 if (!numverts || !nummarktris)
1013 // make sure shadowelements is big enough for this volume
1014 if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
1015 R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
1017 if (maxvertexupdate < numverts)
1019 maxvertexupdate = numverts;
1021 Mem_Free(vertexupdate);
1023 Mem_Free(vertexremap);
1024 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1025 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1026 vertexupdatenum = 0;
1029 if (vertexupdatenum == 0)
1031 vertexupdatenum = 1;
1032 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1033 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1036 for (i = 0;i < nummarktris;i++)
1037 shadowmark[marktris[i]] = shadowmarkcount;
1039 if (r_shadow_compilingrtlight)
1041 // if we're compiling an rtlight, capture the mesh
1042 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1043 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1047 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1048 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1049 r_refdef.stats.lights_shadowtriangles += tris;
1051 R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
1052 GL_LockArrays(0, outverts);
1053 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
1055 // decrement stencil if backface is behind depthbuffer
1056 GL_CullFace(r_refdef.view.cullface_front);
1057 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1058 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1059 // increment stencil if frontface is behind depthbuffer
1060 GL_CullFace(r_refdef.view.cullface_back);
1061 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1063 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1064 GL_LockArrays(0, 0);
1069 static void R_Shadow_MakeTextures_MakeCorona(void)
1073 unsigned char pixels[32][32][4];
1074 for (y = 0;y < 32;y++)
1076 dy = (y - 15.5f) * (1.0f / 16.0f);
1077 for (x = 0;x < 32;x++)
1079 dx = (x - 15.5f) * (1.0f / 16.0f);
1080 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1081 a = bound(0, a, 255);
1082 pixels[y][x][0] = a;
1083 pixels[y][x][1] = a;
1084 pixels[y][x][2] = a;
1085 pixels[y][x][3] = 255;
1088 r_shadow_lightcorona = R_LoadTexture2D(r_shadow_texturepool, "lightcorona", 32, 32, &pixels[0][0][0], TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_FORCELINEAR, NULL);
1091 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1093 float dist = sqrt(x*x+y*y+z*z);
1094 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1095 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1096 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1099 static void R_Shadow_MakeTextures(void)
1102 float intensity, dist;
1104 R_FreeTexturePool(&r_shadow_texturepool);
1105 r_shadow_texturepool = R_AllocTexturePool();
1106 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1107 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1108 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1109 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1110 for (x = 0;x <= ATTENTABLESIZE;x++)
1112 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1113 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1114 r_shadow_attentable[x] = bound(0, intensity, 1);
1116 // 1D gradient texture
1117 for (x = 0;x < ATTEN1DSIZE;x++)
1118 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1119 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, NULL);
1120 // 2D circle texture
1121 for (y = 0;y < ATTEN2DSIZE;y++)
1122 for (x = 0;x < ATTEN2DSIZE;x++)
1123 data[y*ATTEN2DSIZE+x] = R_Shadow_MakeTextures_SamplePoint(((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375), ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375), 0);
1124 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, NULL);
1125 // 3D sphere texture
1126 if (r_shadow_texture3d.integer && gl_texture3d)
1128 for (z = 0;z < ATTEN3DSIZE;z++)
1129 for (y = 0;y < ATTEN3DSIZE;y++)
1130 for (x = 0;x < ATTEN3DSIZE;x++)
1131 data[(z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x] = R_Shadow_MakeTextures_SamplePoint(((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375), ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375), ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375));
1132 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, NULL);
1135 r_shadow_attenuation3dtexture = NULL;
1138 R_Shadow_MakeTextures_MakeCorona();
1140 // Editor light sprites
1141 r_editlights_sprcursor = Draw_CachePic ("gfx/editlights/cursor");
1142 r_editlights_sprlight = Draw_CachePic ("gfx/editlights/light");
1143 r_editlights_sprnoshadowlight = Draw_CachePic ("gfx/editlights/noshadow");
1144 r_editlights_sprcubemaplight = Draw_CachePic ("gfx/editlights/cubemaplight");
1145 r_editlights_sprcubemapnoshadowlight = Draw_CachePic ("gfx/editlights/cubemapnoshadowlight");
1146 r_editlights_sprselection = Draw_CachePic ("gfx/editlights/selection");
1149 void R_Shadow_ValidateCvars(void)
1151 if (r_shadow_texture3d.integer && !gl_texture3d)
1152 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1153 if (gl_ext_separatestencil.integer && !gl_support_separatestencil)
1154 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1155 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1156 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1159 void R_Shadow_RenderMode_Begin(void)
1161 R_Shadow_ValidateCvars();
1163 if (!r_shadow_attenuation2dtexture
1164 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1165 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1166 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1167 R_Shadow_MakeTextures();
1170 R_Mesh_ColorPointer(NULL, 0, 0);
1171 R_Mesh_ResetTextureState();
1172 GL_BlendFunc(GL_ONE, GL_ZERO);
1173 GL_DepthRange(0, 1);
1174 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1176 GL_DepthMask(false);
1177 GL_Color(0, 0, 0, 1);
1178 GL_Scissor(r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
1180 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1182 if (gl_ext_separatestencil.integer)
1183 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
1184 else if (gl_ext_stenciltwoside.integer)
1185 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
1187 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
1189 if (r_glsl.integer && gl_support_fragment_shader)
1190 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1191 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
1192 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
1194 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1197 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1199 rsurface.rtlight = rtlight;
1202 void R_Shadow_RenderMode_Reset(void)
1205 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
1207 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1209 R_Mesh_ColorPointer(NULL, 0, 0);
1210 R_Mesh_ResetTextureState();
1211 GL_DepthRange(0, 1);
1213 GL_DepthMask(false);
1214 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1215 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1216 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1217 qglStencilMask(~0);CHECKGLERROR
1218 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1219 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1220 GL_CullFace(r_refdef.view.cullface_back);
1221 GL_Color(1, 1, 1, 1);
1222 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1223 GL_BlendFunc(GL_ONE, GL_ZERO);
1224 R_SetupGenericShader(false);
1227 void R_Shadow_ClearStencil(void)
1230 GL_Clear(GL_STENCIL_BUFFER_BIT);
1231 r_refdef.stats.lights_clears++;
1234 void R_Shadow_RenderMode_StencilShadowVolumes(void)
1237 R_Shadow_RenderMode_Reset();
1238 GL_ColorMask(0, 0, 0, 0);
1239 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1240 R_SetupDepthOrShadowShader();
1241 qglDepthFunc(GL_LESS);CHECKGLERROR
1242 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1243 r_shadow_rendermode = r_shadow_shadowingrendermode;
1244 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SEPARATESTENCIL)
1246 GL_CullFace(GL_NONE);
1247 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1248 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1250 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
1252 GL_CullFace(GL_NONE);
1253 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1254 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1255 qglStencilMask(~0);CHECKGLERROR
1256 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1257 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1258 qglStencilMask(~0);CHECKGLERROR
1259 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1263 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent)
1266 R_Shadow_RenderMode_Reset();
1267 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1270 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1274 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1275 // only draw light where this geometry was already rendered AND the
1276 // stencil is 128 (values other than this mean shadow)
1277 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1279 r_shadow_rendermode = r_shadow_lightingrendermode;
1280 // do global setup needed for the chosen lighting mode
1281 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1283 R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap)); // light filter
1284 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
1286 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_VERTEX)
1287 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
1288 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1291 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
1294 R_Shadow_RenderMode_Reset();
1295 GL_BlendFunc(GL_ONE, GL_ONE);
1296 GL_DepthRange(0, 1);
1297 GL_DepthTest(r_showshadowvolumes.integer < 2);
1298 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
1299 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1300 GL_CullFace(GL_NONE);
1301 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
1304 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
1307 R_Shadow_RenderMode_Reset();
1308 GL_BlendFunc(GL_ONE, GL_ONE);
1309 GL_DepthRange(0, 1);
1310 GL_DepthTest(r_showlighting.integer < 2);
1311 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
1314 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1318 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1319 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1321 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
1324 void R_Shadow_RenderMode_End(void)
1327 R_Shadow_RenderMode_Reset();
1328 R_Shadow_RenderMode_ActiveLight(NULL);
1330 GL_Scissor(r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
1331 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1334 int bboxedges[12][2] =
1353 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1355 int i, ix1, iy1, ix2, iy2;
1356 float x1, y1, x2, y2;
1358 float vertex[20][3];
1367 if (!r_shadow_scissor.integer)
1370 // if view is inside the light box, just say yes it's visible
1371 if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
1373 GL_Scissor(r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
1377 x1 = y1 = x2 = y2 = 0;
1379 // transform all corners that are infront of the nearclip plane
1380 VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
1381 plane4f[3] = r_refdef.view.frustum[4].dist;
1383 for (i = 0;i < 8;i++)
1385 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
1386 dist[i] = DotProduct4(corner[i], plane4f);
1387 sign[i] = dist[i] > 0;
1390 VectorCopy(corner[i], vertex[numvertices]);
1394 // if some points are behind the nearclip, add clipped edge points to make
1395 // sure that the scissor boundary is complete
1396 if (numvertices > 0 && numvertices < 8)
1398 // add clipped edge points
1399 for (i = 0;i < 12;i++)
1401 j = bboxedges[i][0];
1402 k = bboxedges[i][1];
1403 if (sign[j] != sign[k])
1405 f = dist[j] / (dist[j] - dist[k]);
1406 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
1412 // if we have no points to check, the light is behind the view plane
1416 // if we have some points to transform, check what screen area is covered
1417 x1 = y1 = x2 = y2 = 0;
1419 //Con_Printf("%i vertices to transform...\n", numvertices);
1420 for (i = 0;i < numvertices;i++)
1422 VectorCopy(vertex[i], v);
1423 GL_TransformToScreen(v, v2);
1424 //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]);
1427 if (x1 > v2[0]) x1 = v2[0];
1428 if (x2 < v2[0]) x2 = v2[0];
1429 if (y1 > v2[1]) y1 = v2[1];
1430 if (y2 < v2[1]) y2 = v2[1];
1439 // now convert the scissor rectangle to integer screen coordinates
1440 ix1 = (int)(x1 - 1.0f);
1441 iy1 = (int)(y1 - 1.0f);
1442 ix2 = (int)(x2 + 1.0f);
1443 iy2 = (int)(y2 + 1.0f);
1444 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1446 // clamp it to the screen
1447 if (ix1 < r_refdef.view.x) ix1 = r_refdef.view.x;
1448 if (iy1 < r_refdef.view.y) iy1 = r_refdef.view.y;
1449 if (ix2 > r_refdef.view.x + r_refdef.view.width) ix2 = r_refdef.view.x + r_refdef.view.width;
1450 if (iy2 > r_refdef.view.y + r_refdef.view.height) iy2 = r_refdef.view.y + r_refdef.view.height;
1452 // if it is inside out, it's not visible
1453 if (ix2 <= ix1 || iy2 <= iy1)
1456 // the light area is visible, set up the scissor rectangle
1457 GL_Scissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1458 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);CHECKGLERROR
1459 //qglEnable(GL_SCISSOR_TEST);CHECKGLERROR
1460 r_refdef.stats.lights_scissored++;
1464 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
1466 float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1467 float *normal3f = rsurface.normal3f + 3 * firstvertex;
1468 float *color4f = rsurface.array_color4f + 4 * firstvertex;
1469 float dist, dot, distintensity, shadeintensity, v[3], n[3];
1470 if (r_textureunits.integer >= 3)
1472 if (VectorLength2(diffusecolor) > 0)
1474 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1476 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1477 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1478 if ((dot = DotProduct(n, v)) < 0)
1480 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1481 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
1484 VectorCopy(ambientcolor, color4f);
1485 if (r_refdef.fogenabled)
1488 f = FogPoint_Model(vertex3f);
1489 VectorScale(color4f, f, color4f);
1496 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1498 VectorCopy(ambientcolor, color4f);
1499 if (r_refdef.fogenabled)
1502 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1503 f = FogPoint_Model(vertex3f);
1504 VectorScale(color4f, f, color4f);
1510 else if (r_textureunits.integer >= 2)
1512 if (VectorLength2(diffusecolor) > 0)
1514 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1516 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1517 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1519 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1520 if ((dot = DotProduct(n, v)) < 0)
1522 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1523 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1524 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1525 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1529 color4f[0] = ambientcolor[0] * distintensity;
1530 color4f[1] = ambientcolor[1] * distintensity;
1531 color4f[2] = ambientcolor[2] * distintensity;
1533 if (r_refdef.fogenabled)
1536 f = FogPoint_Model(vertex3f);
1537 VectorScale(color4f, f, color4f);
1541 VectorClear(color4f);
1547 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1549 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1550 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1552 color4f[0] = ambientcolor[0] * distintensity;
1553 color4f[1] = ambientcolor[1] * distintensity;
1554 color4f[2] = ambientcolor[2] * distintensity;
1555 if (r_refdef.fogenabled)
1558 f = FogPoint_Model(vertex3f);
1559 VectorScale(color4f, f, color4f);
1563 VectorClear(color4f);
1570 if (VectorLength2(diffusecolor) > 0)
1572 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1574 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1575 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1577 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
1578 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1579 if ((dot = DotProduct(n, v)) < 0)
1581 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1582 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1583 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1584 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1588 color4f[0] = ambientcolor[0] * distintensity;
1589 color4f[1] = ambientcolor[1] * distintensity;
1590 color4f[2] = ambientcolor[2] * distintensity;
1592 if (r_refdef.fogenabled)
1595 f = FogPoint_Model(vertex3f);
1596 VectorScale(color4f, f, color4f);
1600 VectorClear(color4f);
1606 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1608 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1609 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1611 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
1612 color4f[0] = ambientcolor[0] * distintensity;
1613 color4f[1] = ambientcolor[1] * distintensity;
1614 color4f[2] = ambientcolor[2] * distintensity;
1615 if (r_refdef.fogenabled)
1618 f = FogPoint_Model(vertex3f);
1619 VectorScale(color4f, f, color4f);
1623 VectorClear(color4f);
1630 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1632 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
1635 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
1636 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1637 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
1638 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
1639 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
1641 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1643 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
1644 // the cubemap normalizes this for us
1645 out3f[0] = DotProduct(svector3f, lightdir);
1646 out3f[1] = DotProduct(tvector3f, lightdir);
1647 out3f[2] = DotProduct(normal3f, lightdir);
1651 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
1654 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
1655 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1656 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
1657 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
1658 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
1659 float lightdir[3], eyedir[3], halfdir[3];
1660 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1662 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
1663 VectorNormalize(lightdir);
1664 VectorSubtract(rsurface.modelorg, vertex3f, eyedir);
1665 VectorNormalize(eyedir);
1666 VectorAdd(lightdir, eyedir, halfdir);
1667 // the cubemap normalizes this for us
1668 out3f[0] = DotProduct(svector3f, halfdir);
1669 out3f[1] = DotProduct(tvector3f, halfdir);
1670 out3f[2] = DotProduct(normal3f, halfdir);
1674 static void R_Shadow_RenderLighting_VisibleLighting(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject, 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 ambientscale, float diffusescale, float specularscale, qboolean dopants, qboolean doshirt)
1676 // used to display how many times a surface is lit for level design purposes
1677 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
1680 static void R_Shadow_RenderLighting_Light_GLSL(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject, 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 ambientscale, float diffusescale, float specularscale, qboolean dopants, qboolean doshirt)
1682 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
1683 R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
1684 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND))
1685 R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
1687 R_Mesh_ColorPointer(NULL, 0, 0);
1688 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
1689 R_Mesh_TexBind(GL20TU_NORMAL, R_GetTexture(rsurface.texture->currentskinframe->nmap));
1690 R_Mesh_TexBind(GL20TU_COLOR, R_GetTexture(rsurface.texture->basetexture));
1691 R_Mesh_TexBind(GL20TU_GLOSS, R_GetTexture(rsurface.texture->glosstexture));
1692 if (rsurface.texture->backgroundcurrentskinframe)
1694 R_Mesh_TexBind(GL20TU_SECONDARY_NORMAL, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->nmap));
1695 R_Mesh_TexBind(GL20TU_SECONDARY_COLOR, R_GetTexture(rsurface.texture->backgroundbasetexture));
1696 R_Mesh_TexBind(GL20TU_SECONDARY_GLOSS, R_GetTexture(rsurface.texture->backgroundglosstexture));
1698 //R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap));
1699 R_Mesh_TexBind(GL20TU_FOGMASK, R_GetTexture(r_texture_fogattenuation));
1700 if(rsurface.texture->colormapping)
1702 R_Mesh_TexBind(GL20TU_PANTS, R_GetTexture(rsurface.texture->currentskinframe->pants));
1703 R_Mesh_TexBind(GL20TU_SHIRT, R_GetTexture(rsurface.texture->currentskinframe->shirt));
1705 R_Mesh_TexBind(GL20TU_ATTENUATION, R_GetTexture(r_shadow_attenuationgradienttexture));
1706 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
1707 R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
1708 R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
1709 R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
1710 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1712 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1714 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
1715 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1717 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1721 static void R_Shadow_RenderLighting_Light_Dot3_Finalize(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject, float r, float g, float b)
1723 // shared final code for all the dot3 layers
1725 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
1726 for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
1728 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
1729 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
1733 static void R_Shadow_RenderLighting_Light_Dot3_AmbientPass(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject, const vec3_t lightcolorbase, rtexture_t *basetexture, float colorscale)
1736 // colorscale accounts for how much we multiply the brightness
1739 // mult is how many times the final pass of the lighting will be
1740 // performed to get more brightness than otherwise possible.
1742 // Limit mult to 64 for sanity sake.
1744 if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1746 // 3 3D combine path (Geforce3, Radeon 8500)
1747 memset(&m, 0, sizeof(m));
1748 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1749 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1750 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1751 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1752 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1753 m.tex[1] = R_GetTexture(basetexture);
1754 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
1755 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
1756 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
1757 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
1758 m.texcubemap[2] = R_GetTexture(rsurface.rtlight->currentcubemap);
1759 m.pointer_texcoord3f[2] = rsurface.vertex3f;
1760 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
1761 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
1762 m.texmatrix[2] = rsurface.entitytolight;
1763 GL_BlendFunc(GL_ONE, GL_ONE);
1765 else if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1767 // 2 3D combine path (Geforce3, original Radeon)
1768 memset(&m, 0, sizeof(m));
1769 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1770 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1771 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1772 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1773 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1774 m.tex[1] = R_GetTexture(basetexture);
1775 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
1776 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
1777 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
1778 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
1779 GL_BlendFunc(GL_ONE, GL_ONE);
1781 else if (r_textureunits.integer >= 4 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
1783 // 4 2D combine path (Geforce3, Radeon 8500)
1784 memset(&m, 0, sizeof(m));
1785 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1786 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1787 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1788 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1789 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1790 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1791 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1792 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1793 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1794 m.texmatrix[1] = rsurface.entitytoattenuationz;
1795 m.tex[2] = R_GetTexture(basetexture);
1796 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
1797 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
1798 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
1799 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
1800 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1802 m.texcubemap[3] = R_GetTexture(rsurface.rtlight->currentcubemap);
1803 m.pointer_texcoord3f[3] = rsurface.vertex3f;
1804 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
1805 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
1806 m.texmatrix[3] = rsurface.entitytolight;
1808 GL_BlendFunc(GL_ONE, GL_ONE);
1810 else if (r_textureunits.integer >= 3 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
1812 // 3 2D combine path (Geforce3, original Radeon)
1813 memset(&m, 0, sizeof(m));
1814 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1815 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1816 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1817 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1818 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1819 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1820 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1821 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1822 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1823 m.texmatrix[1] = rsurface.entitytoattenuationz;
1824 m.tex[2] = R_GetTexture(basetexture);
1825 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
1826 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
1827 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
1828 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
1829 GL_BlendFunc(GL_ONE, GL_ONE);
1833 // 2/2/2 2D combine path (any dot3 card)
1834 memset(&m, 0, sizeof(m));
1835 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1836 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1837 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1838 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1839 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1840 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1841 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1842 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1843 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1844 m.texmatrix[1] = rsurface.entitytoattenuationz;
1845 R_Mesh_TextureState(&m);
1846 GL_ColorMask(0,0,0,1);
1847 GL_BlendFunc(GL_ONE, GL_ZERO);
1848 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
1851 memset(&m, 0, sizeof(m));
1852 m.tex[0] = R_GetTexture(basetexture);
1853 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1854 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1855 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1856 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1857 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1859 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1860 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1861 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1862 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1863 m.texmatrix[1] = rsurface.entitytolight;
1865 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1867 // this final code is shared
1868 R_Mesh_TextureState(&m);
1869 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1872 static void R_Shadow_RenderLighting_Light_Dot3_DiffusePass(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject, const vec3_t lightcolorbase, rtexture_t *basetexture, rtexture_t *normalmaptexture, float colorscale)
1875 // colorscale accounts for how much we multiply the brightness
1878 // mult is how many times the final pass of the lighting will be
1879 // performed to get more brightness than otherwise possible.
1881 // Limit mult to 64 for sanity sake.
1883 // generate normalization cubemap texcoords
1884 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
1885 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1887 // 3/2 3D combine path (Geforce3, Radeon 8500)
1888 memset(&m, 0, sizeof(m));
1889 m.tex[0] = R_GetTexture(normalmaptexture);
1890 m.texcombinergb[0] = GL_REPLACE;
1891 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1892 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1893 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1894 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1895 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1896 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1897 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1898 m.pointer_texcoord_bufferobject[1] = 0;
1899 m.pointer_texcoord_bufferoffset[1] = 0;
1900 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1901 m.pointer_texcoord3f[2] = rsurface.vertex3f;
1902 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
1903 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
1904 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
1905 R_Mesh_TextureState(&m);
1906 GL_ColorMask(0,0,0,1);
1907 GL_BlendFunc(GL_ONE, GL_ZERO);
1908 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
1911 memset(&m, 0, sizeof(m));
1912 m.tex[0] = R_GetTexture(basetexture);
1913 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1914 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1915 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1916 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1917 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1919 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1920 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1921 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1922 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1923 m.texmatrix[1] = rsurface.entitytolight;
1925 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1927 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
1929 // 1/2/2 3D combine path (original Radeon)
1930 memset(&m, 0, sizeof(m));
1931 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1932 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1933 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1934 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1935 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1936 R_Mesh_TextureState(&m);
1937 GL_ColorMask(0,0,0,1);
1938 GL_BlendFunc(GL_ONE, GL_ZERO);
1939 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
1942 memset(&m, 0, sizeof(m));
1943 m.tex[0] = R_GetTexture(normalmaptexture);
1944 m.texcombinergb[0] = GL_REPLACE;
1945 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1946 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1947 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1948 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1949 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1950 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1951 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1952 m.pointer_texcoord_bufferobject[1] = 0;
1953 m.pointer_texcoord_bufferoffset[1] = 0;
1954 R_Mesh_TextureState(&m);
1955 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1956 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
1959 memset(&m, 0, sizeof(m));
1960 m.tex[0] = R_GetTexture(basetexture);
1961 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1962 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1963 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1964 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1965 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1967 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1968 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1969 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1970 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1971 m.texmatrix[1] = rsurface.entitytolight;
1973 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1975 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
1977 // 2/2 3D combine path (original Radeon)
1978 memset(&m, 0, sizeof(m));
1979 m.tex[0] = R_GetTexture(normalmaptexture);
1980 m.texcombinergb[0] = GL_REPLACE;
1981 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1982 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1983 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1984 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1985 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1986 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1987 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1988 m.pointer_texcoord_bufferobject[1] = 0;
1989 m.pointer_texcoord_bufferoffset[1] = 0;
1990 R_Mesh_TextureState(&m);
1991 GL_ColorMask(0,0,0,1);
1992 GL_BlendFunc(GL_ONE, GL_ZERO);
1993 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
1996 memset(&m, 0, sizeof(m));
1997 m.tex[0] = R_GetTexture(basetexture);
1998 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1999 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2000 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2001 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2002 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2003 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2004 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2005 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2006 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2007 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2009 else if (r_textureunits.integer >= 4)
2011 // 4/2 2D combine path (Geforce3, Radeon 8500)
2012 memset(&m, 0, sizeof(m));
2013 m.tex[0] = R_GetTexture(normalmaptexture);
2014 m.texcombinergb[0] = GL_REPLACE;
2015 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2016 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2017 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2018 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2019 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2020 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2021 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2022 m.pointer_texcoord_bufferobject[1] = 0;
2023 m.pointer_texcoord_bufferoffset[1] = 0;
2024 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2025 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2026 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2027 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2028 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2029 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2030 m.pointer_texcoord3f[3] = rsurface.vertex3f;
2031 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2032 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2033 m.texmatrix[3] = rsurface.entitytoattenuationz;
2034 R_Mesh_TextureState(&m);
2035 GL_ColorMask(0,0,0,1);
2036 GL_BlendFunc(GL_ONE, GL_ZERO);
2037 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2040 memset(&m, 0, sizeof(m));
2041 m.tex[0] = R_GetTexture(basetexture);
2042 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2043 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2044 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2045 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2046 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2048 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2049 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2050 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2051 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2052 m.texmatrix[1] = rsurface.entitytolight;
2054 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2058 // 2/2/2 2D combine path (any dot3 card)
2059 memset(&m, 0, sizeof(m));
2060 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2061 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2062 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2063 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2064 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2065 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2066 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2067 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2068 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2069 m.texmatrix[1] = rsurface.entitytoattenuationz;
2070 R_Mesh_TextureState(&m);
2071 GL_ColorMask(0,0,0,1);
2072 GL_BlendFunc(GL_ONE, GL_ZERO);
2073 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2076 memset(&m, 0, sizeof(m));
2077 m.tex[0] = R_GetTexture(normalmaptexture);
2078 m.texcombinergb[0] = GL_REPLACE;
2079 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2080 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2081 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2082 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2083 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2084 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2085 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2086 m.pointer_texcoord_bufferobject[1] = 0;
2087 m.pointer_texcoord_bufferoffset[1] = 0;
2088 R_Mesh_TextureState(&m);
2089 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2090 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2093 memset(&m, 0, sizeof(m));
2094 m.tex[0] = R_GetTexture(basetexture);
2095 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2096 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2097 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2098 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2099 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2101 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2102 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2103 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2104 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2105 m.texmatrix[1] = rsurface.entitytolight;
2107 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2109 // this final code is shared
2110 R_Mesh_TextureState(&m);
2111 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
2114 static void R_Shadow_RenderLighting_Light_Dot3_SpecularPass(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject, const vec3_t lightcolorbase, rtexture_t *glosstexture, rtexture_t *normalmaptexture, float colorscale)
2116 float glossexponent;
2118 // FIXME: detect blendsquare!
2119 //if (!gl_support_blendsquare)
2122 // generate normalization cubemap texcoords
2123 R_Shadow_GenTexCoords_Specular_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2124 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2126 // 2/0/0/1/2 3D combine blendsquare path
2127 memset(&m, 0, sizeof(m));
2128 m.tex[0] = R_GetTexture(normalmaptexture);
2129 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2130 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2131 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2132 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2133 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2134 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2135 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2136 m.pointer_texcoord_bufferobject[1] = 0;
2137 m.pointer_texcoord_bufferoffset[1] = 0;
2138 R_Mesh_TextureState(&m);
2139 GL_ColorMask(0,0,0,1);
2140 // this squares the result
2141 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2142 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2144 // second and third pass
2145 R_Mesh_ResetTextureState();
2146 // square alpha in framebuffer a few times to make it shiny
2147 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2148 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2149 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2152 memset(&m, 0, sizeof(m));
2153 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2154 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2155 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2156 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2157 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2158 R_Mesh_TextureState(&m);
2159 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2160 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2163 memset(&m, 0, sizeof(m));
2164 m.tex[0] = R_GetTexture(glosstexture);
2165 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2166 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2167 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2168 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2169 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2171 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2172 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2173 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2174 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2175 m.texmatrix[1] = rsurface.entitytolight;
2177 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2179 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
2181 // 2/0/0/2 3D combine blendsquare path
2182 memset(&m, 0, sizeof(m));
2183 m.tex[0] = R_GetTexture(normalmaptexture);
2184 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2185 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2186 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2187 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2188 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2189 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2190 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2191 m.pointer_texcoord_bufferobject[1] = 0;
2192 m.pointer_texcoord_bufferoffset[1] = 0;
2193 R_Mesh_TextureState(&m);
2194 GL_ColorMask(0,0,0,1);
2195 // this squares the result
2196 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2197 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2199 // second and third pass
2200 R_Mesh_ResetTextureState();
2201 // square alpha in framebuffer a few times to make it shiny
2202 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2203 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2204 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2207 memset(&m, 0, sizeof(m));
2208 m.tex[0] = R_GetTexture(glosstexture);
2209 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2210 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2211 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2212 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2213 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2214 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2215 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2216 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2217 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2218 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2222 // 2/0/0/2/2 2D combine blendsquare path
2223 memset(&m, 0, sizeof(m));
2224 m.tex[0] = R_GetTexture(normalmaptexture);
2225 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2226 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2227 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2228 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2229 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2230 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2231 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2232 m.pointer_texcoord_bufferobject[1] = 0;
2233 m.pointer_texcoord_bufferoffset[1] = 0;
2234 R_Mesh_TextureState(&m);
2235 GL_ColorMask(0,0,0,1);
2236 // this squares the result
2237 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2238 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2240 // second and third pass
2241 R_Mesh_ResetTextureState();
2242 // square alpha in framebuffer a few times to make it shiny
2243 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2244 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2245 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2248 memset(&m, 0, sizeof(m));
2249 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2250 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2251 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2252 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2253 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2254 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2255 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2256 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2257 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2258 m.texmatrix[1] = rsurface.entitytoattenuationz;
2259 R_Mesh_TextureState(&m);
2260 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2261 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2264 memset(&m, 0, sizeof(m));
2265 m.tex[0] = R_GetTexture(glosstexture);
2266 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2267 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2268 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2269 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2270 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2272 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2273 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2274 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2275 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2276 m.texmatrix[1] = rsurface.entitytolight;
2278 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2280 // this final code is shared
2281 R_Mesh_TextureState(&m);
2282 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
2285 static void R_Shadow_RenderLighting_Light_Dot3(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject, 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 ambientscale, float diffusescale, float specularscale, qboolean dopants, qboolean doshirt)
2287 // ARB path (any Geforce, any Radeon)
2288 qboolean doambient = ambientscale > 0;
2289 qboolean dodiffuse = diffusescale > 0;
2290 qboolean dospecular = specularscale > 0;
2291 if (!doambient && !dodiffuse && !dospecular)
2293 R_Mesh_ColorPointer(NULL, 0, 0);
2295 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, ambientscale * r_refdef.view.colorscale);
2297 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2301 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, ambientscale * r_refdef.view.colorscale);
2303 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2308 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, ambientscale * r_refdef.view.colorscale);
2310 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2313 R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_refdef.view.colorscale);
2316 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2323 int newnumtriangles;
2327 int maxtriangles = 4096;
2328 int newelements[4096*3];
2329 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
2330 for (renders = 0;renders < 64;renders++)
2335 newnumtriangles = 0;
2337 // due to low fillrate on the cards this vertex lighting path is
2338 // designed for, we manually cull all triangles that do not
2339 // contain a lit vertex
2340 // this builds batches of triangles from multiple surfaces and
2341 // renders them at once
2342 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2344 if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
2346 if (newnumtriangles)
2348 newfirstvertex = min(newfirstvertex, e[0]);
2349 newlastvertex = max(newlastvertex, e[0]);
2353 newfirstvertex = e[0];
2354 newlastvertex = e[0];
2356 newfirstvertex = min(newfirstvertex, e[1]);
2357 newlastvertex = max(newlastvertex, e[1]);
2358 newfirstvertex = min(newfirstvertex, e[2]);
2359 newlastvertex = max(newlastvertex, e[2]);
2365 if (newnumtriangles >= maxtriangles)
2367 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2368 newnumtriangles = 0;
2374 if (newnumtriangles >= 1)
2376 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2379 // if we couldn't find any lit triangles, exit early
2382 // now reduce the intensity for the next overbright pass
2383 // we have to clamp to 0 here incase the drivers have improper
2384 // handling of negative colors
2385 // (some old drivers even have improper handling of >1 color)
2387 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2389 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2391 c[0] = max(0, c[0] - 1);
2392 c[1] = max(0, c[1] - 1);
2393 c[2] = max(0, c[2] - 1);
2405 static void R_Shadow_RenderLighting_Light_Vertex(int firstvertex, int numvertices, int numtriangles, const int *element3i, 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 ambientscale, float diffusescale, float specularscale, qboolean dopants, qboolean doshirt)
2407 // OpenGL 1.1 path (anything)
2408 float ambientcolorbase[3], diffusecolorbase[3];
2409 float ambientcolorpants[3], diffusecolorpants[3];
2410 float ambientcolorshirt[3], diffusecolorshirt[3];
2412 VectorScale(lightcolorbase, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorbase);
2413 VectorScale(lightcolorbase, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorbase);
2414 VectorScale(lightcolorpants, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorpants);
2415 VectorScale(lightcolorpants, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorpants);
2416 VectorScale(lightcolorshirt, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorshirt);
2417 VectorScale(lightcolorshirt, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorshirt);
2418 memset(&m, 0, sizeof(m));
2419 m.tex[0] = R_GetTexture(basetexture);
2420 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2421 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2422 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2423 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2424 if (r_textureunits.integer >= 2)
2427 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2428 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2429 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2430 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2431 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2432 if (r_textureunits.integer >= 3)
2434 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
2435 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2436 m.texmatrix[2] = rsurface.entitytoattenuationz;
2437 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2438 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2439 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2442 R_Mesh_TextureState(&m);
2443 //R_Mesh_TexBind(0, R_GetTexture(basetexture));
2444 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
2447 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
2448 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
2452 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
2453 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
2457 extern cvar_t gl_lightmaps;
2458 void R_Shadow_RenderLighting(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject)
2460 float ambientscale, diffusescale, specularscale;
2461 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
2463 // calculate colors to render this texture with
2464 lightcolorbase[0] = rsurface.rtlight->currentcolor[0] * rsurface.texture->dlightcolor[0];
2465 lightcolorbase[1] = rsurface.rtlight->currentcolor[1] * rsurface.texture->dlightcolor[1];
2466 lightcolorbase[2] = rsurface.rtlight->currentcolor[2] * rsurface.texture->dlightcolor[2];
2467 ambientscale = rsurface.rtlight->ambientscale;
2468 diffusescale = rsurface.rtlight->diffusescale;
2469 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2470 if (!r_shadow_usenormalmap.integer)
2472 ambientscale += 1.0f * diffusescale;
2476 if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
2478 RSurf_SetupDepthAndCulling();
2479 nmap = rsurface.texture->currentskinframe->nmap;
2480 if (gl_lightmaps.integer)
2481 nmap = r_texture_blanknormalmap;
2482 if (rsurface.texture->colormapping && !gl_lightmaps.integer)
2484 qboolean dopants = rsurface.texture->currentskinframe->pants != NULL && VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f);
2485 qboolean doshirt = rsurface.texture->currentskinframe->shirt != NULL && VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f);
2488 lightcolorpants[0] = lightcolorbase[0] * rsurface.colormap_pantscolor[0];
2489 lightcolorpants[1] = lightcolorbase[1] * rsurface.colormap_pantscolor[1];
2490 lightcolorpants[2] = lightcolorbase[2] * rsurface.colormap_pantscolor[2];
2493 VectorClear(lightcolorpants);
2496 lightcolorshirt[0] = lightcolorbase[0] * rsurface.colormap_shirtcolor[0];
2497 lightcolorshirt[1] = lightcolorbase[1] * rsurface.colormap_shirtcolor[1];
2498 lightcolorshirt[2] = lightcolorbase[2] * rsurface.colormap_shirtcolor[2];
2501 VectorClear(lightcolorshirt);
2502 switch (r_shadow_rendermode)
2504 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2505 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2506 R_Shadow_RenderLighting_VisibleLighting(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface.texture->basetexture, rsurface.texture->currentskinframe->pants, rsurface.texture->currentskinframe->shirt, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, dopants, doshirt);
2508 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2509 R_Shadow_RenderLighting_Light_GLSL(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface.texture->basetexture, rsurface.texture->currentskinframe->pants, rsurface.texture->currentskinframe->shirt, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, dopants, doshirt);
2511 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2512 R_Shadow_RenderLighting_Light_Dot3(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface.texture->basetexture, rsurface.texture->currentskinframe->pants, rsurface.texture->currentskinframe->shirt, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, dopants, doshirt);
2514 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2515 R_Shadow_RenderLighting_Light_Vertex(firstvertex, numvertices, numtriangles, element3i + firsttriangle * 3, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface.texture->basetexture, rsurface.texture->currentskinframe->pants, rsurface.texture->currentskinframe->shirt, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, dopants, doshirt);
2518 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2524 switch (r_shadow_rendermode)
2526 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2527 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2528 R_Shadow_RenderLighting_VisibleLighting(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, vec3_origin, vec3_origin, rsurface.texture->basetexture, r_texture_black, r_texture_black, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, false, false);
2530 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2531 R_Shadow_RenderLighting_Light_GLSL(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, vec3_origin, vec3_origin, rsurface.texture->basetexture, r_texture_black, r_texture_black, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, false, false);
2533 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2534 R_Shadow_RenderLighting_Light_Dot3(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, vec3_origin, vec3_origin, rsurface.texture->basetexture, r_texture_black, r_texture_black, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, false, false);
2536 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2537 R_Shadow_RenderLighting_Light_Vertex(firstvertex, numvertices, numtriangles, element3i + firsttriangle * 3, lightcolorbase, vec3_origin, vec3_origin, rsurface.texture->basetexture, r_texture_black, r_texture_black, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, false, false);
2540 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2546 void R_RTLight_Update(rtlight_t *rtlight, int isstatic, matrix4x4_t *matrix, vec3_t color, int style, const char *cubemapname, qboolean shadow, vec_t corona, vec_t coronasizescale, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int flags)
2548 matrix4x4_t tempmatrix = *matrix;
2549 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2551 // if this light has been compiled before, free the associated data
2552 R_RTLight_Uncompile(rtlight);
2554 // clear it completely to avoid any lingering data
2555 memset(rtlight, 0, sizeof(*rtlight));
2557 // copy the properties
2558 rtlight->matrix_lighttoworld = tempmatrix;
2559 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2560 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2561 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2562 VectorCopy(color, rtlight->color);
2563 rtlight->cubemapname[0] = 0;
2564 if (cubemapname && cubemapname[0])
2565 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2566 rtlight->shadow = shadow;
2567 rtlight->corona = corona;
2568 rtlight->style = style;
2569 rtlight->isstatic = isstatic;
2570 rtlight->coronasizescale = coronasizescale;
2571 rtlight->ambientscale = ambientscale;
2572 rtlight->diffusescale = diffusescale;
2573 rtlight->specularscale = specularscale;
2574 rtlight->flags = flags;
2576 // compute derived data
2577 //rtlight->cullradius = rtlight->radius;
2578 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2579 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2580 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2581 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2582 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2583 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2584 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2587 // compiles rtlight geometry
2588 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2589 void R_RTLight_Compile(rtlight_t *rtlight)
2592 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2593 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
2594 entity_render_t *ent = r_refdef.scene.worldentity;
2595 dp_model_t *model = r_refdef.scene.worldmodel;
2596 unsigned char *data;
2599 // compile the light
2600 rtlight->compiled = true;
2601 rtlight->static_numleafs = 0;
2602 rtlight->static_numleafpvsbytes = 0;
2603 rtlight->static_leaflist = NULL;
2604 rtlight->static_leafpvs = NULL;
2605 rtlight->static_numsurfaces = 0;
2606 rtlight->static_surfacelist = NULL;
2607 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2608 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2609 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2610 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2611 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2612 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2614 if (model && model->GetLightInfo)
2616 // this variable must be set for the CompileShadowVolume code
2617 r_shadow_compilingrtlight = rtlight;
2618 R_Shadow_EnlargeLeafSurfaceTrisBuffer(model->brush.num_leafs, model->num_surfaces, model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles, model->surfmesh.num_triangles);
2619 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, r_shadow_buffer_shadowtrispvs, r_shadow_buffer_lighttrispvs, r_shadow_buffer_visitingleafpvs);
2620 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2621 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
2622 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
2623 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
2624 rtlight->static_numsurfaces = numsurfaces;
2625 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2626 rtlight->static_numleafs = numleafs;
2627 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2628 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2629 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2630 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
2631 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
2632 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
2633 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
2634 if (rtlight->static_numsurfaces)
2635 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2636 if (rtlight->static_numleafs)
2637 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2638 if (rtlight->static_numleafpvsbytes)
2639 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2640 if (rtlight->static_numshadowtrispvsbytes)
2641 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
2642 if (rtlight->static_numlighttrispvsbytes)
2643 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
2644 if (model->CompileShadowVolume && rtlight->shadow)
2645 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2646 // now we're done compiling the rtlight
2647 r_shadow_compilingrtlight = NULL;
2651 // use smallest available cullradius - box radius or light radius
2652 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2653 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2655 shadowzpasstris = 0;
2656 if (rtlight->static_meshchain_shadow_zpass)
2657 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
2658 shadowzpasstris += mesh->numtriangles;
2660 shadowzfailtris = 0;
2661 if (rtlight->static_meshchain_shadow_zfail)
2662 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
2663 shadowzfailtris += mesh->numtriangles;
2666 if (rtlight->static_numlighttrispvsbytes)
2667 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
2668 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
2672 if (rtlight->static_numlighttrispvsbytes)
2673 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
2674 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
2677 if (developer.integer >= 10)
2678 Con_Printf("static light built: %f %f %f : %f %f %f box, %i light triangles, %i shadow triangles, %i zpass/%i zfail compiled shadow volume triangles\n", rtlight->cullmins[0], rtlight->cullmins[1], rtlight->cullmins[2], rtlight->cullmaxs[0], rtlight->cullmaxs[1], rtlight->cullmaxs[2], lighttris, shadowtris, shadowzpasstris, shadowzfailtris);
2681 void R_RTLight_Uncompile(rtlight_t *rtlight)
2683 if (rtlight->compiled)
2685 if (rtlight->static_meshchain_shadow_zpass)
2686 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
2687 rtlight->static_meshchain_shadow_zpass = NULL;
2688 if (rtlight->static_meshchain_shadow_zfail)
2689 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
2690 rtlight->static_meshchain_shadow_zfail = NULL;
2691 // these allocations are grouped
2692 if (rtlight->static_surfacelist)
2693 Mem_Free(rtlight->static_surfacelist);
2694 rtlight->static_numleafs = 0;
2695 rtlight->static_numleafpvsbytes = 0;
2696 rtlight->static_leaflist = NULL;
2697 rtlight->static_leafpvs = NULL;
2698 rtlight->static_numsurfaces = 0;
2699 rtlight->static_surfacelist = NULL;
2700 rtlight->static_numshadowtrispvsbytes = 0;
2701 rtlight->static_shadowtrispvs = NULL;
2702 rtlight->static_numlighttrispvsbytes = 0;
2703 rtlight->static_lighttrispvs = NULL;
2704 rtlight->compiled = false;
2708 void R_Shadow_UncompileWorldLights(void)
2712 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2713 for (lightindex = 0;lightindex < range;lightindex++)
2715 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2718 R_RTLight_Uncompile(&light->rtlight);
2722 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
2726 // reset the count of frustum planes
2727 // see rsurface.rtlight_frustumplanes definition for how much this array
2729 rsurface.rtlight_numfrustumplanes = 0;
2731 // haven't implemented a culling path for ortho rendering
2732 if (!r_refdef.view.useperspective)
2734 // check if the light is on screen and copy the 4 planes if it is
2735 for (i = 0;i < 4;i++)
2736 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
2739 for (i = 0;i < 4;i++)
2740 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
2745 // generate a deformed frustum that includes the light origin, this is
2746 // used to cull shadow casting surfaces that can not possibly cast a
2747 // shadow onto the visible light-receiving surfaces, which can be a
2750 // if the light origin is onscreen the result will be 4 planes exactly
2751 // if the light origin is offscreen on only one axis the result will
2752 // be exactly 5 planes (split-side case)
2753 // if the light origin is offscreen on two axes the result will be
2754 // exactly 4 planes (stretched corner case)
2755 for (i = 0;i < 4;i++)
2757 // quickly reject standard frustum planes that put the light
2758 // origin outside the frustum
2759 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
2762 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
2764 // if all the standard frustum planes were accepted, the light is onscreen
2765 // otherwise we need to generate some more planes below...
2766 if (rsurface.rtlight_numfrustumplanes < 4)
2768 // at least one of the stock frustum planes failed, so we need to
2769 // create one or two custom planes to enclose the light origin
2770 for (i = 0;i < 4;i++)
2772 // create a plane using the view origin and light origin, and a
2773 // single point from the frustum corner set
2774 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
2775 VectorNormalize(plane.normal);
2776 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
2777 // see if this plane is backwards and flip it if so
2778 for (j = 0;j < 4;j++)
2779 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
2783 VectorNegate(plane.normal, plane.normal);
2785 // flipped plane, test again to see if it is now valid
2786 for (j = 0;j < 4;j++)
2787 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
2789 // if the plane is still not valid, then it is dividing the
2790 // frustum and has to be rejected
2794 // we have created a valid plane, compute extra info
2795 PlaneClassify(&plane);
2797 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
2799 // if we've found 5 frustum planes then we have constructed a
2800 // proper split-side case and do not need to keep searching for
2801 // planes to enclose the light origin
2802 if (rsurface.rtlight_numfrustumplanes == 5)
2810 for (i = 0;i < rsurface.rtlight_numfrustumplanes;i++)
2812 plane = rsurface.rtlight_frustumplanes[i];
2813 Con_Printf("light %p plane #%i %f %f %f : %f (%f %f %f %f %f)\n", rtlight, i, plane.normal[0], plane.normal[1], plane.normal[2], plane.dist, PlaneDiff(r_refdef.view.frustumcorner[0], &plane), PlaneDiff(r_refdef.view.frustumcorner[1], &plane), PlaneDiff(r_refdef.view.frustumcorner[2], &plane), PlaneDiff(r_refdef.view.frustumcorner[3], &plane), PlaneDiff(rtlight->shadoworigin, &plane));
2818 // now add the light-space box planes if the light box is rotated, as any
2819 // caster outside the oriented light box is irrelevant (even if it passed
2820 // the worldspace light box, which is axial)
2821 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
2823 for (i = 0;i < 6;i++)
2827 v[i >> 1] = (i & 1) ? -1 : 1;
2828 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
2829 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
2830 plane.dist = VectorNormalizeLength(plane.normal);
2831 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
2832 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
2838 // add the world-space reduced box planes
2839 for (i = 0;i < 6;i++)
2841 VectorClear(plane.normal);
2842 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
2843 plane.dist = (i & 1) ? -rsurface.rtlight_cullmaxs[i >> 1] : rsurface.rtlight_cullmins[i >> 1];
2844 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
2853 // reduce all plane distances to tightly fit the rtlight cull box, which
2855 VectorSet(points[0], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
2856 VectorSet(points[1], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
2857 VectorSet(points[2], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
2858 VectorSet(points[3], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
2859 VectorSet(points[4], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
2860 VectorSet(points[5], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
2861 VectorSet(points[6], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
2862 VectorSet(points[7], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
2863 oldnum = rsurface.rtlight_numfrustumplanes;
2864 rsurface.rtlight_numfrustumplanes = 0;
2865 for (j = 0;j < oldnum;j++)
2867 // find the nearest point on the box to this plane
2868 bestdist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[0]);
2869 for (i = 1;i < 8;i++)
2871 dist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[i]);
2872 if (bestdist > dist)
2875 Con_Printf("light %p %splane #%i %f %f %f : %f < %f\n", rtlight, rsurface.rtlight_frustumplanes[j].dist < bestdist + 0.03125 ? "^2" : "^1", j, rsurface.rtlight_frustumplanes[j].normal[0], rsurface.rtlight_frustumplanes[j].normal[1], rsurface.rtlight_frustumplanes[j].normal[2], rsurface.rtlight_frustumplanes[j].dist, bestdist);
2876 // if the nearest point is near or behind the plane, we want this
2877 // plane, otherwise the plane is useless as it won't cull anything
2878 if (rsurface.rtlight_frustumplanes[j].dist < bestdist + 0.03125)
2880 PlaneClassify(&rsurface.rtlight_frustumplanes[j]);
2881 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = rsurface.rtlight_frustumplanes[j];
2888 void R_Shadow_DrawWorldShadow(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
2892 int surfacelistindex;
2893 msurface_t *surface;
2895 RSurf_ActiveWorldEntity();
2896 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2899 mesh = rsurface.rtlight->static_meshchain_shadow_zfail;
2900 for (;mesh;mesh = mesh->next)
2902 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
2903 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
2904 GL_LockArrays(0, mesh->numverts);
2905 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
2907 // decrement stencil if backface is behind depthbuffer
2908 GL_CullFace(r_refdef.view.cullface_front);
2909 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2910 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
2911 // increment stencil if frontface is behind depthbuffer
2912 GL_CullFace(r_refdef.view.cullface_back);
2913 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2915 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
2916 GL_LockArrays(0, 0);
2920 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
2922 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
2923 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
2925 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
2926 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
2927 if (CHECKPVSBIT(trispvs, t))
2928 shadowmarklist[numshadowmark++] = t;
2930 R_Shadow_VolumeFromList(r_refdef.scene.worldmodel->brush.shadowmesh->numverts, r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles, r_refdef.scene.worldmodel->brush.shadowmesh->vertex3f, r_refdef.scene.worldmodel->brush.shadowmesh->element3i, r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius + r_refdef.scene.worldmodel->radius*2 + r_shadow_projectdistance.value, numshadowmark, shadowmarklist, r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
2932 else if (numsurfaces)
2933 r_refdef.scene.worldmodel->DrawShadowVolume(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
2936 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
2938 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
2939 vec_t relativeshadowradius;
2940 RSurf_ActiveModelEntity(ent, false, false);
2941 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
2942 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
2943 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
2944 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
2945 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
2946 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
2947 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
2948 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
2949 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2952 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
2954 // set up properties for rendering light onto this entity
2955 RSurf_ActiveModelEntity(ent, true, true);
2956 GL_AlphaTest(false);
2957 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
2958 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
2959 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
2960 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
2961 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2962 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
2965 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
2967 if (!r_refdef.scene.worldmodel->DrawLight)
2970 // set up properties for rendering light onto this entity
2971 RSurf_ActiveWorldEntity();
2972 GL_AlphaTest(false);
2973 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
2974 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
2975 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
2976 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
2977 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2978 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
2980 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, trispvs);
2983 void R_Shadow_DrawEntityLight(entity_render_t *ent)
2985 dp_model_t *model = ent->model;
2986 if (!model->DrawLight)
2989 R_Shadow_SetupEntityLight(ent);
2991 model->DrawLight(ent, model->nummodelsurfaces, model->surfacelist, NULL);
2994 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
2998 int numleafs, numsurfaces;
2999 int *leaflist, *surfacelist;
3000 unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs;
3001 int numlightentities;
3002 int numlightentities_noselfshadow;
3003 int numshadowentities;
3004 int numshadowentities_noselfshadow;
3005 static entity_render_t *lightentities[MAX_EDICTS];
3006 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3007 static entity_render_t *shadowentities[MAX_EDICTS];
3008 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3010 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3011 // skip lights that are basically invisible (color 0 0 0)
3012 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
3015 // loading is done before visibility checks because loading should happen
3016 // all at once at the start of a level, not when it stalls gameplay.
3017 // (especially important to benchmarks)
3019 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
3020 R_RTLight_Compile(rtlight);
3022 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
3024 // look up the light style value at this time
3025 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3026 VectorScale(rtlight->color, f, rtlight->currentcolor);
3028 if (rtlight->selected)
3030 f = 2 + sin(realtime * M_PI * 4.0);
3031 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3035 // if lightstyle is currently off, don't draw the light
3036 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3039 // if the light box is offscreen, skip it
3040 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3043 VectorCopy(rtlight->cullmins, rsurface.rtlight_cullmins);
3044 VectorCopy(rtlight->cullmaxs, rsurface.rtlight_cullmaxs);
3046 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3048 // compiled light, world available and can receive realtime lighting
3049 // retrieve leaf information
3050 numleafs = rtlight->static_numleafs;
3051 leaflist = rtlight->static_leaflist;
3052 leafpvs = rtlight->static_leafpvs;
3053 numsurfaces = rtlight->static_numsurfaces;
3054 surfacelist = rtlight->static_surfacelist;
3055 shadowtrispvs = rtlight->static_shadowtrispvs;
3056 lighttrispvs = rtlight->static_lighttrispvs;
3058 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3060 // dynamic light, world available and can receive realtime lighting
3061 // calculate lit surfaces and leafs
3062 R_Shadow_EnlargeLeafSurfaceTrisBuffer(r_refdef.scene.worldmodel->brush.num_leafs, r_refdef.scene.worldmodel->num_surfaces, r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles, r_refdef.scene.worldmodel->surfmesh.num_triangles);
3063 r_refdef.scene.worldmodel->GetLightInfo(r_refdef.scene.worldentity, rtlight->shadoworigin, rtlight->radius, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs, r_shadow_buffer_leaflist, r_shadow_buffer_leafpvs, &numleafs, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces, r_shadow_buffer_shadowtrispvs, r_shadow_buffer_lighttrispvs, r_shadow_buffer_visitingleafpvs);
3064 leaflist = r_shadow_buffer_leaflist;
3065 leafpvs = r_shadow_buffer_leafpvs;
3066 surfacelist = r_shadow_buffer_surfacelist;
3067 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3068 lighttrispvs = r_shadow_buffer_lighttrispvs;
3069 // if the reduced leaf bounds are offscreen, skip it
3070 if (R_CullBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3081 shadowtrispvs = NULL;
3082 lighttrispvs = NULL;
3084 // check if light is illuminating any visible leafs
3087 for (i = 0;i < numleafs;i++)
3088 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3093 // set up a scissor rectangle for this light
3094 if (R_Shadow_ScissorForBBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3097 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3099 // make a list of lit entities and shadow casting entities
3100 numlightentities = 0;
3101 numlightentities_noselfshadow = 0;
3102 numshadowentities = 0;
3103 numshadowentities_noselfshadow = 0;
3104 // add dynamic entities that are lit by the light
3105 if (r_drawentities.integer)
3107 for (i = 0;i < r_refdef.scene.numentities;i++)
3110 entity_render_t *ent = r_refdef.scene.entities[i];
3112 if (!BoxesOverlap(ent->mins, ent->maxs, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3114 // skip the object entirely if it is not within the valid
3115 // shadow-casting region (which includes the lit region)
3116 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rsurface.rtlight_numfrustumplanes, rsurface.rtlight_frustumplanes))
3118 if (!(model = ent->model))
3120 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3122 // this entity wants to receive light, is visible, and is
3123 // inside the light box
3124 // TODO: check if the surfaces in the model can receive light
3125 // so now check if it's in a leaf seen by the light
3126 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.scene.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.scene.worldmodel, leafpvs, ent->mins, ent->maxs))
3128 if (ent->flags & RENDER_NOSELFSHADOW)
3129 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3131 lightentities[numlightentities++] = ent;
3132 // since it is lit, it probably also casts a shadow...
3133 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3134 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3135 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3137 // note: exterior models without the RENDER_NOSELFSHADOW
3138 // flag still create a RENDER_NOSELFSHADOW shadow but
3139 // are lit normally, this means that they are
3140 // self-shadowing but do not shadow other
3141 // RENDER_NOSELFSHADOW entities such as the gun
3142 // (very weird, but keeps the player shadow off the gun)
3143 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3144 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3146 shadowentities[numshadowentities++] = ent;
3149 else if (ent->flags & RENDER_SHADOW)
3151 // this entity is not receiving light, but may still need to
3153 // TODO: check if the surfaces in the model can cast shadow
3154 // now check if it is in a leaf seen by the light
3155 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.scene.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.scene.worldmodel, leafpvs, ent->mins, ent->maxs))
3157 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3158 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3159 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3161 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3162 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3164 shadowentities[numshadowentities++] = ent;
3170 // return if there's nothing at all to light
3171 if (!numlightentities && !numsurfaces)
3174 // don't let sound skip if going slow
3175 if (r_refdef.scene.extraupdate)
3178 // make this the active rtlight for rendering purposes
3179 R_Shadow_RenderMode_ActiveLight(rtlight);
3180 // count this light in the r_speeds
3181 r_refdef.stats.lights++;
3183 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3185 // optionally draw visible shape of the shadow volumes
3186 // for performance analysis by level designers
3187 R_Shadow_RenderMode_VisibleShadowVolumes();
3189 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3190 for (i = 0;i < numshadowentities;i++)
3191 R_Shadow_DrawEntityShadow(shadowentities[i]);
3192 for (i = 0;i < numshadowentities_noselfshadow;i++)
3193 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3196 if (gl_stencil && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3198 // draw stencil shadow volumes to mask off pixels that are in shadow
3199 // so that they won't receive lighting
3200 R_Shadow_ClearStencil();
3201 R_Shadow_RenderMode_StencilShadowVolumes();
3203 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3204 for (i = 0;i < numshadowentities;i++)
3205 R_Shadow_DrawEntityShadow(shadowentities[i]);
3206 if (numlightentities_noselfshadow)
3208 // draw lighting in the unmasked areas
3209 R_Shadow_RenderMode_Lighting(true, false);
3210 for (i = 0;i < numlightentities_noselfshadow;i++)
3211 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3213 // optionally draw the illuminated areas
3214 // for performance analysis by level designers
3215 if (r_showlighting.integer && r_refdef.view.showdebug)
3217 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
3218 for (i = 0;i < numlightentities_noselfshadow;i++)
3219 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3222 R_Shadow_RenderMode_StencilShadowVolumes();
3224 for (i = 0;i < numshadowentities_noselfshadow;i++)
3225 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3227 if (numsurfaces + numlightentities)
3229 // draw lighting in the unmasked areas
3230 R_Shadow_RenderMode_Lighting(true, false);
3232 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3233 for (i = 0;i < numlightentities;i++)
3234 R_Shadow_DrawEntityLight(lightentities[i]);
3236 // optionally draw the illuminated areas
3237 // for performance analysis by level designers
3238 if (r_showlighting.integer && r_refdef.view.showdebug)
3240 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
3242 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3243 for (i = 0;i < numlightentities;i++)
3244 R_Shadow_DrawEntityLight(lightentities[i]);
3250 if (numsurfaces + numlightentities)
3252 // draw lighting in the unmasked areas
3253 R_Shadow_RenderMode_Lighting(false, false);
3255 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3256 for (i = 0;i < numlightentities;i++)
3257 R_Shadow_DrawEntityLight(lightentities[i]);
3258 for (i = 0;i < numlightentities_noselfshadow;i++)
3259 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3261 // optionally draw the illuminated areas
3262 // for performance analysis by level designers
3263 if (r_showlighting.integer && r_refdef.view.showdebug)
3265 R_Shadow_RenderMode_VisibleLighting(false, false);
3267 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3268 for (i = 0;i < numlightentities;i++)
3269 R_Shadow_DrawEntityLight(lightentities[i]);
3270 for (i = 0;i < numlightentities_noselfshadow;i++)
3271 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3277 void R_Shadow_DrawLightSprites(void);
3278 void R_ShadowVolumeLighting(qboolean visible)
3286 if (r_editlights.integer)
3287 R_Shadow_DrawLightSprites();
3289 R_Shadow_RenderMode_Begin();
3291 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3292 if (r_shadow_debuglight.integer >= 0)
3294 lightindex = r_shadow_debuglight.integer;
3295 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3296 if (light && (light->flags & flag))
3297 R_DrawRTLight(&light->rtlight, visible);
3301 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3302 for (lightindex = 0;lightindex < range;lightindex++)
3304 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3305 if (light && (light->flags & flag))
3306 R_DrawRTLight(&light->rtlight, visible);
3309 if (r_refdef.scene.rtdlight)
3310 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3311 R_DrawRTLight(r_refdef.scene.lights[lnum], visible);
3313 R_Shadow_RenderMode_End();
3316 extern void R_SetupView(qboolean allowwaterclippingplane);
3317 extern cvar_t r_shadows;
3318 extern cvar_t r_shadows_throwdistance;
3319 void R_DrawModelShadows(void)
3322 float relativethrowdistance;
3323 entity_render_t *ent;
3324 vec3_t relativelightorigin;
3325 vec3_t relativelightdirection;
3326 vec3_t relativeshadowmins, relativeshadowmaxs;
3330 if (!r_drawentities.integer || !gl_stencil)
3334 GL_Scissor(r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
3336 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
3338 if (gl_ext_separatestencil.integer)
3339 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
3340 else if (gl_ext_stenciltwoside.integer)
3341 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
3343 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
3345 R_Shadow_ClearStencil();
3346 R_Shadow_RenderMode_StencilShadowVolumes();
3348 for (i = 0;i < r_refdef.scene.numentities;i++)
3350 ent = r_refdef.scene.entities[i];
3351 // cast shadows from anything that is not a submodel of the map
3352 if (ent->model && ent->model->DrawShadowVolume != NULL && !ent->model->brush.submodel && (ent->flags & RENDER_SHADOW))
3354 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
3355 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
3356 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
3358 if(r_shadows.integer == 2)
3360 // 2: simpler mode, throw shadows always DOWN
3361 VectorSet(tmp, 0, 0, -1);
3362 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
3366 if(ent->entitynumber != 0)
3368 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
3369 int entnum, entnum2, recursion;
3370 entnum = entnum2 = ent->entitynumber;
3371 for(recursion = 32; recursion > 0; --recursion)
3373 entnum2 = cl.entities[entnum].state_current.tagentity;
3374 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
3379 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
3381 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
3382 // transform into modelspace of OUR entity
3383 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
3384 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
3387 VectorNegate(ent->modellight_lightdir, relativelightdirection);
3390 VectorNegate(ent->modellight_lightdir, relativelightdirection);
3393 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
3394 RSurf_ActiveModelEntity(ent, false, false);
3395 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
3399 // not really the right mode, but this will disable any silly stencil features
3400 R_Shadow_RenderMode_VisibleLighting(true, true);
3402 // vertex coordinates for a quad that covers the screen exactly
3403 vertex3f[0] = 0;vertex3f[1] = 0;vertex3f[2] = 0;
3404 vertex3f[3] = 1;vertex3f[4] = 0;vertex3f[5] = 0;
3405 vertex3f[6] = 1;vertex3f[7] = 1;vertex3f[8] = 0;
3406 vertex3f[9] = 0;vertex3f[10] = 1;vertex3f[11] = 0;
3408 // set up ortho view for rendering this pass
3409 GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
3410 GL_Scissor(r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
3411 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
3412 GL_ScissorTest(true);
3413 R_Mesh_Matrix(&identitymatrix);
3414 R_Mesh_ResetTextureState();
3415 R_Mesh_VertexPointer(vertex3f, 0, 0);
3416 R_Mesh_ColorPointer(NULL, 0, 0);
3418 // set up a 50% darkening blend on shadowed areas
3419 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3420 GL_DepthRange(0, 1);
3421 GL_DepthTest(false);
3422 GL_DepthMask(false);
3423 GL_PolygonOffset(0, 0);CHECKGLERROR
3424 GL_Color(0, 0, 0, 0.5);
3425 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
3426 qglDepthFunc(GL_ALWAYS);CHECKGLERROR
3427 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
3428 qglStencilMask(~0);CHECKGLERROR
3429 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
3430 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
3432 // apply the blend to the shadowed areas
3433 R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
3435 // restoring the perspective view is done by R_RenderScene
3436 //R_SetupView(true);
3438 // restore other state to normal
3439 R_Shadow_RenderMode_End();
3442 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
3444 // if it's too close, skip it
3445 if (VectorLength(rtlight->color) < (1.0f / 256.0f))
3447 if (VectorDistance2(rtlight->shadoworigin, r_refdef.view.origin) < 32.0f * 32.0f)
3449 if (usequery && r_numqueries + 2 <= r_maxqueries)
3451 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
3452 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
3454 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
3455 R_DrawSprite(GL_ONE, GL_ZERO, r_shadow_lightcorona, NULL, true, false, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale, 1, 1, 1, 1);
3456 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
3457 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
3458 R_DrawSprite(GL_ONE, GL_ZERO, r_shadow_lightcorona, NULL, false, false, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale, 1, 1, 1, 1);
3459 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
3462 rtlight->corona_visibility = 1;
3465 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
3468 GLint allpixels = 0, visiblepixels = 0;
3469 // now we have to check the query result
3470 if (rtlight->corona_queryindex_visiblepixels)
3473 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
3474 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
3476 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
3477 if (visiblepixels < 1 || allpixels < 1)
3479 rtlight->corona_visibility *= (float)visiblepixels / (float)allpixels;
3480 cscale *= rtlight->corona_visibility;
3484 // FIXME: these traces should scan all render entities instead of cl.world
3485 if (CL_Move(r_refdef.view.origin, vec3_origin, vec3_origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
3488 VectorScale(rtlight->color, cscale, color);
3489 if (VectorLength(color) > (1.0f / 256.0f))
3490 R_DrawSprite(GL_ONE, GL_ONE, r_shadow_lightcorona, NULL, true, false, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale, color[0], color[1], color[2], 1);
3493 void R_DrawCoronas(void)
3501 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
3503 if (r_waterstate.renderingscene)
3505 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3506 R_Mesh_Matrix(&identitymatrix);
3508 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3510 // check occlusion of coronas
3511 // use GL_ARB_occlusion_query if available
3512 // otherwise use raytraces
3514 usequery = gl_support_arb_occlusion_query && r_coronas_occlusionquery.integer;
3517 GL_ColorMask(0,0,0,0);
3518 if (r_maxqueries < range + r_refdef.scene.numlights)
3519 if (r_maxqueries < R_MAX_OCCLUSION_QUERIES)
3522 r_maxqueries = (range + r_refdef.scene.numlights) * 2;
3523 r_maxqueries = min(r_maxqueries, R_MAX_OCCLUSION_QUERIES);
3525 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
3529 for (lightindex = 0;lightindex < range;lightindex++)
3531 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3534 rtlight = &light->rtlight;
3535 rtlight->corona_visibility = 0;
3536 rtlight->corona_queryindex_visiblepixels = 0;
3537 rtlight->corona_queryindex_allpixels = 0;
3538 if (!(rtlight->flags & flag))
3540 if (rtlight->corona <= 0)
3542 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
3544 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
3546 for (i = 0;i < r_refdef.scene.numlights;i++)
3548 rtlight = r_refdef.scene.lights[i];
3549 rtlight->corona_visibility = 0;
3550 rtlight->corona_queryindex_visiblepixels = 0;
3551 rtlight->corona_queryindex_allpixels = 0;
3552 if (!(rtlight->flags & flag))
3554 if (rtlight->corona <= 0)
3556 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
3559 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
3561 // now draw the coronas using the query data for intensity info
3562 for (lightindex = 0;lightindex < range;lightindex++)
3564 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3567 rtlight = &light->rtlight;
3568 if (rtlight->corona_visibility <= 0)
3570 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
3572 for (i = 0;i < r_refdef.scene.numlights;i++)
3574 rtlight = r_refdef.scene.lights[i];
3575 if (rtlight->corona_visibility <= 0)
3577 if (gl_flashblend.integer)
3578 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
3580 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
3586 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
3587 typedef struct suffixinfo_s
3590 qboolean flipx, flipy, flipdiagonal;
3593 static suffixinfo_t suffix[3][6] =
3596 {"px", false, false, false},
3597 {"nx", false, false, false},
3598 {"py", false, false, false},
3599 {"ny", false, false, false},
3600 {"pz", false, false, false},
3601 {"nz", false, false, false}
3604 {"posx", false, false, false},
3605 {"negx", false, false, false},
3606 {"posy", false, false, false},
3607 {"negy", false, false, false},
3608 {"posz", false, false, false},
3609 {"negz", false, false, false}
3612 {"rt", true, false, true},
3613 {"lf", false, true, true},
3614 {"ft", true, true, false},
3615 {"bk", false, false, false},
3616 {"up", true, false, true},
3617 {"dn", true, false, true}
3621 static int componentorder[4] = {0, 1, 2, 3};
3623 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
3625 int i, j, cubemapsize;
3626 unsigned char *cubemappixels, *image_buffer;
3627 rtexture_t *cubemaptexture;
3629 // must start 0 so the first loadimagepixels has no requested width/height
3631 cubemappixels = NULL;
3632 cubemaptexture = NULL;
3633 // keep trying different suffix groups (posx, px, rt) until one loads
3634 for (j = 0;j < 3 && !cubemappixels;j++)
3636 // load the 6 images in the suffix group
3637 for (i = 0;i < 6;i++)
3639 // generate an image name based on the base and and suffix
3640 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
3642 if ((image_buffer = loadimagepixelsbgra(name, false, false)))
3644 // an image loaded, make sure width and height are equal
3645 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
3647 // if this is the first image to load successfully, allocate the cubemap memory
3648 if (!cubemappixels && image_width >= 1)
3650 cubemapsize = image_width;
3651 // note this clears to black, so unavailable sides are black
3652 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
3654 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
3656 Image_CopyMux(cubemappixels+i*cubemapsize*cubemapsize*4, image_buffer, cubemapsize, cubemapsize, suffix[j][i].flipx, suffix[j][i].flipy, suffix[j][i].flipdiagonal, 4, 4, componentorder);
3659 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
3661 Mem_Free(image_buffer);
3665 // if a cubemap loaded, upload it
3668 if (developer_loading.integer)
3669 Con_Printf("loading cubemap \"%s\"\n", basename);
3671 if (!r_shadow_filters_texturepool)
3672 r_shadow_filters_texturepool = R_AllocTexturePool();
3673 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, TEXF_PRECACHE | (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR, NULL);
3674 Mem_Free(cubemappixels);
3678 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
3679 if (developer_loading.integer)
3681 Con_Printf("(tried tried images ");
3682 for (j = 0;j < 3;j++)
3683 for (i = 0;i < 6;i++)
3684 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
3685 Con_Print(" and was unable to find any of them).\n");
3688 return cubemaptexture;
3691 rtexture_t *R_Shadow_Cubemap(const char *basename)
3694 for (i = 0;i < numcubemaps;i++)
3695 if (!strcasecmp(cubemaps[i].basename, basename))
3696 return cubemaps[i].texture ? cubemaps[i].texture : r_texture_whitecube;
3697 if (i >= MAX_CUBEMAPS)
3698 return r_texture_whitecube;
3700 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
3701 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
3702 return cubemaps[i].texture;
3705 void R_Shadow_FreeCubemaps(void)
3708 for (i = 0;i < numcubemaps;i++)
3710 if (developer_loading.integer)
3711 Con_Printf("unloading cubemap \"%s\"\n", cubemaps[i].basename);
3712 if (cubemaps[i].texture)
3713 R_FreeTexture(cubemaps[i].texture);
3717 R_FreeTexturePool(&r_shadow_filters_texturepool);
3720 dlight_t *R_Shadow_NewWorldLight(void)
3722 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
3725 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)
3728 // validate parameters
3729 if (style < 0 || style >= MAX_LIGHTSTYLES)
3731 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
3737 // copy to light properties
3738 VectorCopy(origin, light->origin);
3739 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
3740 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
3741 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
3742 light->color[0] = max(color[0], 0);
3743 light->color[1] = max(color[1], 0);
3744 light->color[2] = max(color[2], 0);
3745 light->radius = max(radius, 0);
3746 light->style = style;
3747 light->shadow = shadowenable;
3748 light->corona = corona;
3749 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
3750 light->coronasizescale = coronasizescale;
3751 light->ambientscale = ambientscale;
3752 light->diffusescale = diffusescale;
3753 light->specularscale = specularscale;
3754 light->flags = flags;
3756 // update renderable light data
3757 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
3758 R_RTLight_Update(&light->rtlight, true, &matrix, light->color, light->style, light->cubemapname[0] ? light->cubemapname : NULL, light->shadow, light->corona, light->coronasizescale, light->ambientscale, light->diffusescale, light->specularscale, light->flags);
3761 void R_Shadow_FreeWorldLight(dlight_t *light)
3763 if (r_shadow_selectedlight == light)
3764 r_shadow_selectedlight = NULL;
3765 R_RTLight_Uncompile(&light->rtlight);
3766 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
3769 void R_Shadow_ClearWorldLights(void)
3773 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3774 for (lightindex = 0;lightindex < range;lightindex++)
3776 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3778 R_Shadow_FreeWorldLight(light);
3780 r_shadow_selectedlight = NULL;
3781 R_Shadow_FreeCubemaps();
3784 void R_Shadow_SelectLight(dlight_t *light)
3786 if (r_shadow_selectedlight)
3787 r_shadow_selectedlight->selected = false;
3788 r_shadow_selectedlight = light;
3789 if (r_shadow_selectedlight)
3790 r_shadow_selectedlight->selected = true;
3793 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
3795 // this is never batched (there can be only one)
3796 R_DrawSprite(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, r_editlights_sprcursor->tex, r_editlights_sprcursor->tex, false, false, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE, 1, 1, 1, 1);
3799 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
3806 // this is never batched (due to the ent parameter changing every time)
3807 // so numsurfaces == 1 and surfacelist[0] == lightnumber
3808 const dlight_t *light = (dlight_t *)ent;
3811 VectorScale(light->color, intensity, spritecolor);
3812 if (VectorLength(spritecolor) < 0.1732f)
3813 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
3814 if (VectorLength(spritecolor) > 1.0f)
3815 VectorNormalize(spritecolor);
3817 // draw light sprite
3818 if (light->cubemapname[0] && !light->shadow)
3819 pic = r_editlights_sprcubemapnoshadowlight;
3820 else if (light->cubemapname[0])
3821 pic = r_editlights_sprcubemaplight;
3822 else if (!light->shadow)
3823 pic = r_editlights_sprnoshadowlight;
3825 pic = r_editlights_sprlight;
3826 R_DrawSprite(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, pic->tex, pic->tex, false, false, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s, spritecolor[0], spritecolor[1], spritecolor[2], 1);
3827 // draw selection sprite if light is selected
3828 if (light->selected)
3829 R_DrawSprite(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, r_editlights_sprselection->tex, r_editlights_sprselection->tex, false, false, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s, 1, 1, 1, 1);
3830 // VorteX todo: add normalmode/realtime mode light overlay sprites?
3833 void R_Shadow_DrawLightSprites(void)
3837 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3838 for (lightindex = 0;lightindex < range;lightindex++)
3840 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3842 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
3844 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
3847 void R_Shadow_SelectLightInView(void)
3849 float bestrating, rating, temp[3];
3853 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3856 for (lightindex = 0;lightindex < range;lightindex++)
3858 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3861 VectorSubtract(light->origin, r_refdef.view.origin, temp);
3862 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
3865 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
3866 if (bestrating < rating && CL_Move(light->origin, vec3_origin, vec3_origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
3868 bestrating = rating;
3873 R_Shadow_SelectLight(best);
3876 void R_Shadow_LoadWorldLights(void)
3878 int n, a, style, shadow, flags;
3879 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
3880 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
3881 if (cl.worldmodel == NULL)
3883 Con_Print("No map loaded.\n");
3886 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
3887 strlcat (name, ".rtlights", sizeof (name));
3888 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3898 for (;COM_Parse(t, true) && strcmp(
3899 if (COM_Parse(t, true))
3901 if (com_token[0] == '!')
3904 origin[0] = atof(com_token+1);
3907 origin[0] = atof(com_token);
3912 while (*s && *s != '\n' && *s != '\r')
3918 // check for modifier flags
3925 #if _MSC_VER >= 1400
3926 #define sscanf sscanf_s
3928 cubemapname[sizeof(cubemapname)-1] = 0;
3929 #if MAX_QPATH != 128
3930 #error update this code if MAX_QPATH changes
3932 a = sscanf(t, "%f %f %f %f %f %f %f %d %127s %f %f %f %f %f %f %f %f %i", &origin[0], &origin[1], &origin[2], &radius, &color[0], &color[1], &color[2], &style, cubemapname
3933 #if _MSC_VER >= 1400
3934 , sizeof(cubemapname)
3936 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
3939 flags = LIGHTFLAG_REALTIMEMODE;
3947 coronasizescale = 0.25f;
3949 VectorClear(angles);
3952 if (a < 9 || !strcmp(cubemapname, "\"\""))
3954 // remove quotes on cubemapname
3955 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
3958 namelen = strlen(cubemapname) - 2;
3959 memmove(cubemapname, cubemapname + 1, namelen);
3960 cubemapname[namelen] = '\0';
3964 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);
3967 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3975 Con_Printf("invalid rtlights file \"%s\"\n", name);
3976 Mem_Free(lightsstring);
3980 void R_Shadow_SaveWorldLights(void)
3984 size_t bufchars, bufmaxchars;
3986 char name[MAX_QPATH];
3987 char line[MAX_INPUTLINE];
3988 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
3989 // I hate lines which are 3 times my screen size :( --blub
3992 if (cl.worldmodel == NULL)
3994 Con_Print("No map loaded.\n");
3997 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
3998 strlcat (name, ".rtlights", sizeof (name));
3999 bufchars = bufmaxchars = 0;
4001 for (lightindex = 0;lightindex < range;lightindex++)
4003 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4006 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
4007 dpsnprintf(line, sizeof(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);
4008 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
4009 dpsnprintf(line, sizeof(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]);
4011 dpsnprintf(line, sizeof(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);
4012 if (bufchars + strlen(line) > bufmaxchars)
4014 bufmaxchars = bufchars + strlen(line) + 2048;
4016 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
4020 memcpy(buf, oldbuf, bufchars);
4026 memcpy(buf + bufchars, line, strlen(line));
4027 bufchars += strlen(line);
4031 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
4036 void R_Shadow_LoadLightsFile(void)
4039 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
4040 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
4041 if (cl.worldmodel == NULL)
4043 Con_Print("No map loaded.\n");
4046 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4047 strlcat (name, ".lights", sizeof (name));
4048 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4056 while (*s && *s != '\n' && *s != '\r')
4062 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);
4066 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);
4069 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
4070 radius = bound(15, radius, 4096);
4071 VectorScale(color, (2.0f / (8388608.0f)), color);
4072 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
4080 Con_Printf("invalid lights file \"%s\"\n", name);
4081 Mem_Free(lightsstring);
4085 // tyrlite/hmap2 light types in the delay field
4086 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
4088 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
4090 int entnum, style, islight, skin, pflags, effects, type, n;
4093 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
4094 char key[256], value[MAX_INPUTLINE];
4096 if (cl.worldmodel == NULL)
4098 Con_Print("No map loaded.\n");
4101 // try to load a .ent file first
4102 FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
4103 strlcat (key, ".ent", sizeof (key));
4104 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
4105 // and if that is not found, fall back to the bsp file entity string
4107 data = cl.worldmodel->brush.entities;
4110 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
4112 type = LIGHTTYPE_MINUSX;
4113 origin[0] = origin[1] = origin[2] = 0;
4114 originhack[0] = originhack[1] = originhack[2] = 0;
4115 angles[0] = angles[1] = angles[2] = 0;
4116 color[0] = color[1] = color[2] = 1;
4117 light[0] = light[1] = light[2] = 1;light[3] = 300;
4118 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
4128 if (!COM_ParseToken_Simple(&data, false, false))
4130 if (com_token[0] == '}')
4131 break; // end of entity
4132 if (com_token[0] == '_')
4133 strlcpy(key, com_token + 1, sizeof(key));
4135 strlcpy(key, com_token, sizeof(key));
4136 while (key[strlen(key)-1] == ' ') // remove trailing spaces
4137 key[strlen(key)-1] = 0;
4138 if (!COM_ParseToken_Simple(&data, false, false))
4140 strlcpy(value, com_token, sizeof(value));
4142 // now that we have the key pair worked out...
4143 if (!strcmp("light", key))
4145 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
4149 light[0] = vec[0] * (1.0f / 256.0f);
4150 light[1] = vec[0] * (1.0f / 256.0f);
4151 light[2] = vec[0] * (1.0f / 256.0f);
4157 light[0] = vec[0] * (1.0f / 255.0f);
4158 light[1] = vec[1] * (1.0f / 255.0f);
4159 light[2] = vec[2] * (1.0f / 255.0f);
4163 else if (!strcmp("delay", key))
4165 else if (!strcmp("origin", key))
4166 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
4167 else if (!strcmp("angle", key))
4168 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
4169 else if (!strcmp("angles", key))
4170 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
4171 else if (!strcmp("color", key))
4172 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
4173 else if (!strcmp("wait", key))
4174 fadescale = atof(value);
4175 else if (!strcmp("classname", key))
4177 if (!strncmp(value, "light", 5))
4180 if (!strcmp(value, "light_fluoro"))
4185 overridecolor[0] = 1;
4186 overridecolor[1] = 1;
4187 overridecolor[2] = 1;
4189 if (!strcmp(value, "light_fluorospark"))
4194 overridecolor[0] = 1;
4195 overridecolor[1] = 1;
4196 overridecolor[2] = 1;
4198 if (!strcmp(value, "light_globe"))
4203 overridecolor[0] = 1;
4204 overridecolor[1] = 0.8;
4205 overridecolor[2] = 0.4;
4207 if (!strcmp(value, "light_flame_large_yellow"))
4212 overridecolor[0] = 1;
4213 overridecolor[1] = 0.5;
4214 overridecolor[2] = 0.1;
4216 if (!strcmp(value, "light_flame_small_yellow"))
4221 overridecolor[0] = 1;
4222 overridecolor[1] = 0.5;
4223 overridecolor[2] = 0.1;
4225 if (!strcmp(value, "light_torch_small_white"))
4230 overridecolor[0] = 1;
4231 overridecolor[1] = 0.5;
4232 overridecolor[2] = 0.1;
4234 if (!strcmp(value, "light_torch_small_walltorch"))
4239 overridecolor[0] = 1;
4240 overridecolor[1] = 0.5;
4241 overridecolor[2] = 0.1;
4245 else if (!strcmp("style", key))
4246 style = atoi(value);
4247 else if (!strcmp("skin", key))
4248 skin = (int)atof(value);
4249 else if (!strcmp("pflags", key))
4250 pflags = (int)atof(value);
4251 else if (!strcmp("effects", key))
4252 effects = (int)atof(value);
4253 else if (cl.worldmodel->type == mod_brushq3)
4255 if (!strcmp("scale", key))
4256 lightscale = atof(value);
4257 if (!strcmp("fade", key))
4258 fadescale = atof(value);
4263 if (lightscale <= 0)
4267 if (color[0] == color[1] && color[0] == color[2])
4269 color[0] *= overridecolor[0];
4270 color[1] *= overridecolor[1];
4271 color[2] *= overridecolor[2];
4273 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
4274 color[0] = color[0] * light[0];
4275 color[1] = color[1] * light[1];
4276 color[2] = color[2] * light[2];
4279 case LIGHTTYPE_MINUSX:
4281 case LIGHTTYPE_RECIPX:
4283 VectorScale(color, (1.0f / 16.0f), color);
4285 case LIGHTTYPE_RECIPXX:
4287 VectorScale(color, (1.0f / 16.0f), color);
4290 case LIGHTTYPE_NONE:
4294 case LIGHTTYPE_MINUSXX:
4297 VectorAdd(origin, originhack, origin);
4299 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);
4302 Mem_Free(entfiledata);
4306 void R_Shadow_SetCursorLocationForView(void)
4309 vec3_t dest, endpos;
4311 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
4312 trace = CL_Move(r_refdef.view.origin, vec3_origin, vec3_origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
4313 if (trace.fraction < 1)
4315 dist = trace.fraction * r_editlights_cursordistance.value;
4316 push = r_editlights_cursorpushback.value;
4320 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
4321 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
4325 VectorClear( endpos );
4327 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4328 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4329 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4332 void R_Shadow_UpdateWorldLightSelection(void)
4334 if (r_editlights.integer)
4336 R_Shadow_SetCursorLocationForView();
4337 R_Shadow_SelectLightInView();
4340 R_Shadow_SelectLight(NULL);
4343 void R_Shadow_EditLights_Clear_f(void)
4345 R_Shadow_ClearWorldLights();
4348 void R_Shadow_EditLights_Reload_f(void)
4352 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
4353 R_Shadow_ClearWorldLights();
4354 R_Shadow_LoadWorldLights();
4355 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
4357 R_Shadow_LoadLightsFile();
4358 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
4359 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
4363 void R_Shadow_EditLights_Save_f(void)
4367 R_Shadow_SaveWorldLights();
4370 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
4372 R_Shadow_ClearWorldLights();
4373 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
4376 void R_Shadow_EditLights_ImportLightsFile_f(void)
4378 R_Shadow_ClearWorldLights();
4379 R_Shadow_LoadLightsFile();
4382 void R_Shadow_EditLights_Spawn_f(void)
4385 if (!r_editlights.integer)
4387 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4390 if (Cmd_Argc() != 1)
4392 Con_Print("r_editlights_spawn does not take parameters\n");
4395 color[0] = color[1] = color[2] = 1;
4396 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
4399 void R_Shadow_EditLights_Edit_f(void)
4401 vec3_t origin, angles, color;
4402 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
4403 int style, shadows, flags, normalmode, realtimemode;
4404 char cubemapname[MAX_INPUTLINE];
4405 if (!r_editlights.integer)
4407 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4410 if (!r_shadow_selectedlight)
4412 Con_Print("No selected light.\n");
4415 VectorCopy(r_shadow_selectedlight->origin, origin);
4416 VectorCopy(r_shadow_selectedlight->angles, angles);
4417 VectorCopy(r_shadow_selectedlight->color, color);
4418 radius = r_shadow_selectedlight->radius;
4419 style = r_shadow_selectedlight->style;
4420 if (r_shadow_selectedlight->cubemapname)
4421 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
4424 shadows = r_shadow_selectedlight->shadow;
4425 corona = r_shadow_selectedlight->corona;
4426 coronasizescale = r_shadow_selectedlight->coronasizescale;
4427 ambientscale = r_shadow_selectedlight->ambientscale;
4428 diffusescale = r_shadow_selectedlight->diffusescale;
4429 specularscale = r_shadow_selectedlight->specularscale;
4430 flags = r_shadow_selectedlight->flags;
4431 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
4432 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
4433 if (!strcmp(Cmd_Argv(1), "origin"))
4435 if (Cmd_Argc() != 5)
4437 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
4440 origin[0] = atof(Cmd_Argv(2));
4441 origin[1] = atof(Cmd_Argv(3));
4442 origin[2] = atof(Cmd_Argv(4));
4444 else if (!strcmp(Cmd_Argv(1), "originx"))
4446 if (Cmd_Argc() != 3)
4448 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4451 origin[0] = atof(Cmd_Argv(2));
4453 else if (!strcmp(Cmd_Argv(1), "originy"))
4455 if (Cmd_Argc() != 3)
4457 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4460 origin[1] = atof(Cmd_Argv(2));
4462 else if (!strcmp(Cmd_Argv(1), "originz"))
4464 if (Cmd_Argc() != 3)
4466 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4469 origin[2] = atof(Cmd_Argv(2));
4471 else if (!strcmp(Cmd_Argv(1), "move"))
4473 if (Cmd_Argc() != 5)
4475 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
4478 origin[0] += atof(Cmd_Argv(2));
4479 origin[1] += atof(Cmd_Argv(3));
4480 origin[2] += atof(Cmd_Argv(4));
4482 else if (!strcmp(Cmd_Argv(1), "movex"))
4484 if (Cmd_Argc() != 3)
4486 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4489 origin[0] += atof(Cmd_Argv(2));
4491 else if (!strcmp(Cmd_Argv(1), "movey"))
4493 if (Cmd_Argc() != 3)
4495 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4498 origin[1] += atof(Cmd_Argv(2));
4500 else if (!strcmp(Cmd_Argv(1), "movez"))
4502 if (Cmd_Argc() != 3)
4504 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4507 origin[2] += atof(Cmd_Argv(2));
4509 else if (!strcmp(Cmd_Argv(1), "angles"))
4511 if (Cmd_Argc() != 5)
4513 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
4516 angles[0] = atof(Cmd_Argv(2));
4517 angles[1] = atof(Cmd_Argv(3));
4518 angles[2] = atof(Cmd_Argv(4));
4520 else if (!strcmp(Cmd_Argv(1), "anglesx"))
4522 if (Cmd_Argc() != 3)
4524 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4527 angles[0] = atof(Cmd_Argv(2));
4529 else if (!strcmp(Cmd_Argv(1), "anglesy"))
4531 if (Cmd_Argc() != 3)
4533 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4536 angles[1] = atof(Cmd_Argv(2));
4538 else if (!strcmp(Cmd_Argv(1), "anglesz"))
4540 if (Cmd_Argc() != 3)
4542 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4545 angles[2] = atof(Cmd_Argv(2));
4547 else if (!strcmp(Cmd_Argv(1), "color"))
4549 if (Cmd_Argc() != 5)
4551 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
4554 color[0] = atof(Cmd_Argv(2));
4555 color[1] = atof(Cmd_Argv(3));
4556 color[2] = atof(Cmd_Argv(4));
4558 else if (!strcmp(Cmd_Argv(1), "radius"))
4560 if (Cmd_Argc() != 3)
4562 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4565 radius = atof(Cmd_Argv(2));
4567 else if (!strcmp(Cmd_Argv(1), "colorscale"))
4569 if (Cmd_Argc() == 3)
4571 double scale = atof(Cmd_Argv(2));
4578 if (Cmd_Argc() != 5)
4580 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
4583 color[0] *= atof(Cmd_Argv(2));
4584 color[1] *= atof(Cmd_Argv(3));
4585 color[2] *= atof(Cmd_Argv(4));
4588 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
4590 if (Cmd_Argc() != 3)
4592 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4595 radius *= atof(Cmd_Argv(2));
4597 else if (!strcmp(Cmd_Argv(1), "style"))
4599 if (Cmd_Argc() != 3)
4601 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4604 style = atoi(Cmd_Argv(2));
4606 else if (!strcmp(Cmd_Argv(1), "cubemap"))
4610 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4613 if (Cmd_Argc() == 3)
4614 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
4618 else if (!strcmp(Cmd_Argv(1), "shadows"))
4620 if (Cmd_Argc() != 3)
4622 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4625 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4627 else if (!strcmp(Cmd_Argv(1), "corona"))
4629 if (Cmd_Argc() != 3)
4631 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4634 corona = atof(Cmd_Argv(2));
4636 else if (!strcmp(Cmd_Argv(1), "coronasize"))
4638 if (Cmd_Argc() != 3)
4640 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4643 coronasizescale = atof(Cmd_Argv(2));
4645 else if (!strcmp(Cmd_Argv(1), "ambient"))
4647 if (Cmd_Argc() != 3)
4649 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4652 ambientscale = atof(Cmd_Argv(2));
4654 else if (!strcmp(Cmd_Argv(1), "diffuse"))
4656 if (Cmd_Argc() != 3)
4658 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4661 diffusescale = atof(Cmd_Argv(2));
4663 else if (!strcmp(Cmd_Argv(1), "specular"))
4665 if (Cmd_Argc() != 3)
4667 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4670 specularscale = atof(Cmd_Argv(2));
4672 else if (!strcmp(Cmd_Argv(1), "normalmode"))
4674 if (Cmd_Argc() != 3)
4676 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4679 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4681 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
4683 if (Cmd_Argc() != 3)
4685 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4688 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4692 Con_Print("usage: r_editlights_edit [property] [value]\n");
4693 Con_Print("Selected light's properties:\n");
4694 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
4695 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
4696 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
4697 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
4698 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
4699 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
4700 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
4701 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
4702 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
4703 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
4704 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
4705 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
4706 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
4707 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
4710 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
4711 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4714 void R_Shadow_EditLights_EditAll_f(void)
4720 if (!r_editlights.integer)
4722 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
4726 // EditLights doesn't seem to have a "remove" command or something so:
4727 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4728 for (lightindex = 0;lightindex < range;lightindex++)
4730 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4733 R_Shadow_SelectLight(light);
4734 R_Shadow_EditLights_Edit_f();
4738 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
4740 int lightnumber, lightcount;
4741 size_t lightindex, range;
4745 if (!r_editlights.integer)
4747 x = vid_conwidth.value - 240;
4749 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
4752 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4753 for (lightindex = 0;lightindex < range;lightindex++)
4755 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4758 if (light == r_shadow_selectedlight)
4759 lightnumber = lightindex;
4762 dpsnprintf(temp, sizeof(temp), "Cursor origin: %.0f %.0f %.0f", r_editlights_cursorlocation[0], r_editlights_cursorlocation[1], r_editlights_cursorlocation[2]); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, false);y += 8;
4763 dpsnprintf(temp, sizeof(temp), "Total lights : %i active (%i total)", lightcount, (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray)); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, false);y += 8;
4765 if (r_shadow_selectedlight == NULL)
4767 dpsnprintf(temp, sizeof(temp), "Light #%i properties:", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
4768 dpsnprintf(temp, sizeof(temp), "Origin : %.0f %.0f %.0f\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, NULL, true);y += 8;
4769 dpsnprintf(temp, sizeof(temp), "Angles : %.0f %.0f %.0f\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, NULL, true);y += 8;
4770 dpsnprintf(temp, sizeof(temp), "Color : %.2f %.2f %.2f\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, NULL, true);y += 8;
4771 dpsnprintf(temp, sizeof(temp), "Radius : %.0f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
4772 dpsnprintf(temp, sizeof(temp), "Corona : %.0f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
4773 dpsnprintf(temp, sizeof(temp), "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
4774 dpsnprintf(temp, sizeof(temp), "Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
4775 dpsnprintf(temp, sizeof(temp), "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
4776 dpsnprintf(temp, sizeof(temp), "CoronaSize : %.2f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
4777 dpsnprintf(temp, sizeof(temp), "Ambient : %.2f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
4778 dpsnprintf(temp, sizeof(temp), "Diffuse : %.2f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
4779 dpsnprintf(temp, sizeof(temp), "Specular : %.2f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
4780 dpsnprintf(temp, sizeof(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, NULL, true);y += 8;
4781 dpsnprintf(temp, sizeof(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, NULL, true);y += 8;
4784 void R_Shadow_EditLights_ToggleShadow_f(void)
4786 if (!r_editlights.integer)
4788 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4791 if (!r_shadow_selectedlight)
4793 Con_Print("No selected light.\n");
4796 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);
4799 void R_Shadow_EditLights_ToggleCorona_f(void)
4801 if (!r_editlights.integer)
4803 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4806 if (!r_shadow_selectedlight)
4808 Con_Print("No selected light.\n");
4811 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);
4814 void R_Shadow_EditLights_Remove_f(void)
4816 if (!r_editlights.integer)
4818 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
4821 if (!r_shadow_selectedlight)
4823 Con_Print("No selected light.\n");
4826 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
4827 r_shadow_selectedlight = NULL;
4830 void R_Shadow_EditLights_Help_f(void)
4833 "Documentation on r_editlights system:\n"
4835 "r_editlights : enable/disable editing mode\n"
4836 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
4837 "r_editlights_cursorpushback : push back cursor this far from surface\n"
4838 "r_editlights_cursorpushoff : push cursor off surface this far\n"
4839 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
4840 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
4842 "r_editlights_help : this help\n"
4843 "r_editlights_clear : remove all lights\n"
4844 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
4845 "r_editlights_save : save to .rtlights file\n"
4846 "r_editlights_spawn : create a light with default settings\n"
4847 "r_editlights_edit command : edit selected light - more documentation below\n"
4848 "r_editlights_remove : remove selected light\n"
4849 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
4850 "r_editlights_importlightentitiesfrommap : reload light entities\n"
4851 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
4853 "origin x y z : set light location\n"
4854 "originx x: set x component of light location\n"
4855 "originy y: set y component of light location\n"
4856 "originz z: set z component of light location\n"
4857 "move x y z : adjust light location\n"
4858 "movex x: adjust x component of light location\n"
4859 "movey y: adjust y component of light location\n"
4860 "movez z: adjust z component of light location\n"
4861 "angles x y z : set light angles\n"
4862 "anglesx x: set x component of light angles\n"
4863 "anglesy y: set y component of light angles\n"
4864 "anglesz z: set z component of light angles\n"
4865 "color r g b : set color of light (can be brighter than 1 1 1)\n"
4866 "radius radius : set radius (size) of light\n"
4867 "colorscale grey : multiply color of light (1 does nothing)\n"
4868 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
4869 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
4870 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
4871 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
4872 "cubemap basename : set filter cubemap of light (not yet supported)\n"
4873 "shadows 1/0 : turn on/off shadows\n"
4874 "corona n : set corona intensity\n"
4875 "coronasize n : set corona size (0-1)\n"
4876 "ambient n : set ambient intensity (0-1)\n"
4877 "diffuse n : set diffuse intensity (0-1)\n"
4878 "specular n : set specular intensity (0-1)\n"
4879 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
4880 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
4881 "<nothing> : print light properties to console\n"
4885 void R_Shadow_EditLights_CopyInfo_f(void)
4887 if (!r_editlights.integer)
4889 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
4892 if (!r_shadow_selectedlight)
4894 Con_Print("No selected light.\n");
4897 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
4898 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
4899 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
4900 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
4901 if (r_shadow_selectedlight->cubemapname)
4902 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
4904 r_shadow_bufferlight.cubemapname[0] = 0;
4905 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
4906 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
4907 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
4908 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
4909 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
4910 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
4911 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
4914 void R_Shadow_EditLights_PasteInfo_f(void)
4916 if (!r_editlights.integer)
4918 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
4921 if (!r_shadow_selectedlight)
4923 Con_Print("No selected light.\n");
4926 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);
4929 void R_Shadow_EditLights_Init(void)
4931 Cvar_RegisterVariable(&r_editlights);
4932 Cvar_RegisterVariable(&r_editlights_cursordistance);
4933 Cvar_RegisterVariable(&r_editlights_cursorpushback);
4934 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
4935 Cvar_RegisterVariable(&r_editlights_cursorgrid);
4936 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
4937 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
4938 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
4939 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)");
4940 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
4941 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
4942 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
4943 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)");
4944 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
4945 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
4946 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
4947 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
4948 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
4949 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
4950 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)");
4956 =============================================================================
4960 =============================================================================
4963 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
4965 VectorClear(diffusecolor);
4966 VectorClear(diffusenormal);
4968 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
4970 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient * (2.0f / 128.0f);
4971 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
4974 VectorSet(ambientcolor, 1, 1, 1);
4981 for (i = 0;i < r_refdef.scene.numlights;i++)
4983 light = r_refdef.scene.lights[i];
4984 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
4985 f = 1 - VectorLength2(v);
4986 if (f > 0 && CL_Move(p, vec3_origin, vec3_origin, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
4987 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);