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_leafpvs;
182 int *r_shadow_buffer_leaflist;
184 int r_shadow_buffer_numsurfacepvsbytes;
185 unsigned char *r_shadow_buffer_surfacepvs;
186 int *r_shadow_buffer_surfacelist;
188 int r_shadow_buffer_numshadowtrispvsbytes;
189 unsigned char *r_shadow_buffer_shadowtrispvs;
190 int r_shadow_buffer_numlighttrispvsbytes;
191 unsigned char *r_shadow_buffer_lighttrispvs;
193 rtexturepool_t *r_shadow_texturepool;
194 rtexture_t *r_shadow_attenuationgradienttexture;
195 rtexture_t *r_shadow_attenuation2dtexture;
196 rtexture_t *r_shadow_attenuation3dtexture;
197 rtexture_t *r_shadow_lightcorona;
199 // lights are reloaded when this changes
200 char r_shadow_mapname[MAX_QPATH];
202 // used only for light filters (cubemaps)
203 rtexturepool_t *r_shadow_filters_texturepool;
205 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"};
206 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"};
207 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
208 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
209 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)"};
210 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"};
211 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
212 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
213 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
214 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
215 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
216 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
217 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"};
218 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000", "how far to cast shadows"};
219 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)"};
220 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
221 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
222 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
223 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
224 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)"};
225 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"};
226 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
227 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
228 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"};
229 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation"};
230 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation"};
231 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)"};
232 cvar_t r_shadow_culltriangles = {0, "r_shadow_culltriangles", "1", "performs more expensive tests to remove unnecessary triangles of lit surfaces"};
233 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
234 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)"};
235 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)"};
236 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
237 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
238 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
239 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
240 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
241 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
242 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
243 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
244 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
245 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
247 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
248 #define ATTENTABLESIZE 256
249 // 1D gradient, 2D circle and 3D sphere attenuation textures
250 #define ATTEN1DSIZE 32
251 #define ATTEN2DSIZE 64
252 #define ATTEN3DSIZE 32
254 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
255 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
256 static float r_shadow_attentable[ATTENTABLESIZE+1];
258 rtlight_t *r_shadow_compilingrtlight;
259 static memexpandablearray_t r_shadow_worldlightsarray;
260 dlight_t *r_shadow_selectedlight;
261 dlight_t r_shadow_bufferlight;
262 vec3_t r_editlights_cursorlocation;
264 extern int con_vislines;
266 typedef struct cubemapinfo_s
273 #define MAX_CUBEMAPS 256
274 static int numcubemaps;
275 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
277 void R_Shadow_UncompileWorldLights(void);
278 void R_Shadow_ClearWorldLights(void);
279 void R_Shadow_SaveWorldLights(void);
280 void R_Shadow_LoadWorldLights(void);
281 void R_Shadow_LoadLightsFile(void);
282 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
283 void R_Shadow_EditLights_Reload_f(void);
284 void R_Shadow_ValidateCvars(void);
285 static void R_Shadow_MakeTextures(void);
287 // VorteX: custom editor light sprites
288 #define EDLIGHTSPRSIZE 8
289 cachepic_t *r_editlights_sprcursor;
290 cachepic_t *r_editlights_sprlight;
291 cachepic_t *r_editlights_sprnoshadowlight;
292 cachepic_t *r_editlights_sprcubemaplight;
293 cachepic_t *r_editlights_sprcubemapnoshadowlight;
294 cachepic_t *r_editlights_sprselection;
296 void r_shadow_start(void)
298 // allocate vertex processing arrays
300 r_shadow_attenuationgradienttexture = NULL;
301 r_shadow_attenuation2dtexture = NULL;
302 r_shadow_attenuation3dtexture = NULL;
303 r_shadow_texturepool = NULL;
304 r_shadow_filters_texturepool = NULL;
305 R_Shadow_ValidateCvars();
306 R_Shadow_MakeTextures();
307 maxshadowtriangles = 0;
308 shadowelements = NULL;
309 maxshadowvertices = 0;
310 shadowvertex3f = NULL;
318 shadowmarklist = NULL;
320 r_shadow_buffer_numleafpvsbytes = 0;
321 r_shadow_buffer_leafpvs = NULL;
322 r_shadow_buffer_leaflist = NULL;
323 r_shadow_buffer_numsurfacepvsbytes = 0;
324 r_shadow_buffer_surfacepvs = NULL;
325 r_shadow_buffer_surfacelist = NULL;
326 r_shadow_buffer_numshadowtrispvsbytes = 0;
327 r_shadow_buffer_shadowtrispvs = NULL;
328 r_shadow_buffer_numlighttrispvsbytes = 0;
329 r_shadow_buffer_lighttrispvs = NULL;
332 void r_shadow_shutdown(void)
334 R_Shadow_UncompileWorldLights();
336 r_shadow_attenuationgradienttexture = NULL;
337 r_shadow_attenuation2dtexture = NULL;
338 r_shadow_attenuation3dtexture = NULL;
339 R_FreeTexturePool(&r_shadow_texturepool);
340 R_FreeTexturePool(&r_shadow_filters_texturepool);
341 maxshadowtriangles = 0;
343 Mem_Free(shadowelements);
344 shadowelements = NULL;
346 Mem_Free(shadowvertex3f);
347 shadowvertex3f = NULL;
350 Mem_Free(vertexupdate);
353 Mem_Free(vertexremap);
359 Mem_Free(shadowmark);
362 Mem_Free(shadowmarklist);
363 shadowmarklist = NULL;
365 r_shadow_buffer_numleafpvsbytes = 0;
366 if (r_shadow_buffer_leafpvs)
367 Mem_Free(r_shadow_buffer_leafpvs);
368 r_shadow_buffer_leafpvs = NULL;
369 if (r_shadow_buffer_leaflist)
370 Mem_Free(r_shadow_buffer_leaflist);
371 r_shadow_buffer_leaflist = NULL;
372 r_shadow_buffer_numsurfacepvsbytes = 0;
373 if (r_shadow_buffer_surfacepvs)
374 Mem_Free(r_shadow_buffer_surfacepvs);
375 r_shadow_buffer_surfacepvs = NULL;
376 if (r_shadow_buffer_surfacelist)
377 Mem_Free(r_shadow_buffer_surfacelist);
378 r_shadow_buffer_surfacelist = NULL;
379 r_shadow_buffer_numshadowtrispvsbytes = 0;
380 if (r_shadow_buffer_shadowtrispvs)
381 Mem_Free(r_shadow_buffer_shadowtrispvs);
382 r_shadow_buffer_numlighttrispvsbytes = 0;
383 if (r_shadow_buffer_lighttrispvs)
384 Mem_Free(r_shadow_buffer_lighttrispvs);
387 void r_shadow_newmap(void)
389 if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
390 R_Shadow_EditLights_Reload_f();
393 void R_Shadow_Help_f(void)
396 "Documentation on r_shadow system:\n"
398 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
399 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
400 "r_shadow_debuglight : render only this light number (-1 = all)\n"
401 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
402 "r_shadow_gloss2intensity : brightness of forced gloss\n"
403 "r_shadow_glossintensity : brightness of textured gloss\n"
404 "r_shadow_lightattenuationlinearscale : used to generate attenuation texture\n"
405 "r_shadow_lightattenuationdividebias : used to generate attenuation texture\n"
406 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
407 "r_shadow_lightradiusscale : scale rendering radius of all lights\n"
408 "r_shadow_portallight : use portal visibility for static light precomputation\n"
409 "r_shadow_projectdistance : shadow volume projection distance\n"
410 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
411 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
412 "r_shadow_realtime_world : use high quality world lighting mode\n"
413 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
414 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
415 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
416 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
417 "r_shadow_scissor : use scissor optimization\n"
418 "r_shadow_polygonfactor : nudge shadow volumes closer/further\n"
419 "r_shadow_polygonoffset : nudge shadow volumes closer/further\n"
420 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
421 "r_showlighting : useful for performance testing; bright = slow!\n"
422 "r_showshadowvolumes : useful for performance testing; bright = slow!\n"
424 "r_shadow_help : this help\n"
428 void R_Shadow_Init(void)
430 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
431 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
432 Cvar_RegisterVariable(&r_shadow_usenormalmap);
433 Cvar_RegisterVariable(&r_shadow_debuglight);
434 Cvar_RegisterVariable(&r_shadow_gloss);
435 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
436 Cvar_RegisterVariable(&r_shadow_glossintensity);
437 Cvar_RegisterVariable(&r_shadow_glossexponent);
438 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
439 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
440 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
441 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
442 Cvar_RegisterVariable(&r_shadow_portallight);
443 Cvar_RegisterVariable(&r_shadow_projectdistance);
444 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
445 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
446 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
447 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
448 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
449 Cvar_RegisterVariable(&r_shadow_realtime_world);
450 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
451 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
452 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
453 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
454 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
455 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
456 Cvar_RegisterVariable(&r_shadow_scissor);
457 Cvar_RegisterVariable(&r_shadow_culltriangles);
458 Cvar_RegisterVariable(&r_shadow_polygonfactor);
459 Cvar_RegisterVariable(&r_shadow_polygonoffset);
460 Cvar_RegisterVariable(&r_shadow_texture3d);
461 Cvar_RegisterVariable(&r_coronas);
462 Cvar_RegisterVariable(&gl_flashblend);
463 Cvar_RegisterVariable(&gl_ext_separatestencil);
464 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
465 if (gamemode == GAME_TENEBRAE)
467 Cvar_SetValue("r_shadow_gloss", 2);
468 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
470 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f, "prints documentation on console commands and variables used by realtime lighting and shadowing system");
471 R_Shadow_EditLights_Init();
472 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
473 maxshadowtriangles = 0;
474 shadowelements = NULL;
475 maxshadowvertices = 0;
476 shadowvertex3f = NULL;
484 shadowmarklist = NULL;
486 r_shadow_buffer_numleafpvsbytes = 0;
487 r_shadow_buffer_leafpvs = NULL;
488 r_shadow_buffer_leaflist = NULL;
489 r_shadow_buffer_numsurfacepvsbytes = 0;
490 r_shadow_buffer_surfacepvs = NULL;
491 r_shadow_buffer_surfacelist = NULL;
492 r_shadow_buffer_shadowtrispvs = NULL;
493 r_shadow_buffer_lighttrispvs = NULL;
494 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
497 matrix4x4_t matrix_attenuationxyz =
500 {0.5, 0.0, 0.0, 0.5},
501 {0.0, 0.5, 0.0, 0.5},
502 {0.0, 0.0, 0.5, 0.5},
507 matrix4x4_t matrix_attenuationz =
510 {0.0, 0.0, 0.5, 0.5},
511 {0.0, 0.0, 0.0, 0.5},
512 {0.0, 0.0, 0.0, 0.5},
517 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles)
519 // make sure shadowelements is big enough for this volume
520 if (maxshadowtriangles < numtriangles)
522 maxshadowtriangles = numtriangles;
524 Mem_Free(shadowelements);
525 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[24]));
527 // make sure shadowvertex3f is big enough for this volume
528 if (maxshadowvertices < numvertices)
530 maxshadowvertices = numvertices;
532 Mem_Free(shadowvertex3f);
533 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[6]));
537 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
539 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
540 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
541 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
542 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
543 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
545 if (r_shadow_buffer_leafpvs)
546 Mem_Free(r_shadow_buffer_leafpvs);
547 if (r_shadow_buffer_leaflist)
548 Mem_Free(r_shadow_buffer_leaflist);
549 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
550 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
551 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
553 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
555 if (r_shadow_buffer_surfacepvs)
556 Mem_Free(r_shadow_buffer_surfacepvs);
557 if (r_shadow_buffer_surfacelist)
558 Mem_Free(r_shadow_buffer_surfacelist);
559 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
560 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
561 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
563 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
565 if (r_shadow_buffer_shadowtrispvs)
566 Mem_Free(r_shadow_buffer_shadowtrispvs);
567 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
568 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
570 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
572 if (r_shadow_buffer_lighttrispvs)
573 Mem_Free(r_shadow_buffer_lighttrispvs);
574 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
575 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
579 void R_Shadow_PrepareShadowMark(int numtris)
581 // make sure shadowmark is big enough for this volume
582 if (maxshadowmark < numtris)
584 maxshadowmark = numtris;
586 Mem_Free(shadowmark);
588 Mem_Free(shadowmarklist);
589 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
590 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
594 // if shadowmarkcount wrapped we clear the array and adjust accordingly
595 if (shadowmarkcount == 0)
598 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
603 int R_Shadow_ConstructShadowVolume(int innumvertices, int innumtris, const int *inelement3i, const int *inneighbor3i, const float *invertex3f, int *outnumvertices, int *outelement3i, float *outvertex3f, const float *projectorigin, const float *projectdirection, float projectdistance, int numshadowmarktris, const int *shadowmarktris)
606 int outtriangles = 0, outvertices = 0;
609 float ratio, direction[3], projectvector[3];
611 if (projectdirection)
612 VectorScale(projectdirection, projectdistance, projectvector);
614 VectorClear(projectvector);
616 if (maxvertexupdate < innumvertices)
618 maxvertexupdate = innumvertices;
620 Mem_Free(vertexupdate);
622 Mem_Free(vertexremap);
623 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
624 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
628 if (vertexupdatenum == 0)
631 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
632 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
635 for (i = 0;i < numshadowmarktris;i++)
636 shadowmark[shadowmarktris[i]] = shadowmarkcount;
638 // create the vertices
639 if (projectdirection)
641 for (i = 0;i < numshadowmarktris;i++)
643 element = inelement3i + shadowmarktris[i] * 3;
644 for (j = 0;j < 3;j++)
646 if (vertexupdate[element[j]] != vertexupdatenum)
648 vertexupdate[element[j]] = vertexupdatenum;
649 vertexremap[element[j]] = outvertices;
650 vertex = invertex3f + element[j] * 3;
651 // project one copy of the vertex according to projectvector
652 VectorCopy(vertex, outvertex3f);
653 VectorAdd(vertex, projectvector, (outvertex3f + 3));
662 for (i = 0;i < numshadowmarktris;i++)
664 element = inelement3i + shadowmarktris[i] * 3;
665 for (j = 0;j < 3;j++)
667 if (vertexupdate[element[j]] != vertexupdatenum)
669 vertexupdate[element[j]] = vertexupdatenum;
670 vertexremap[element[j]] = outvertices;
671 vertex = invertex3f + element[j] * 3;
672 // project one copy of the vertex to the sphere radius of the light
673 // (FIXME: would projecting it to the light box be better?)
674 VectorSubtract(vertex, projectorigin, direction);
675 ratio = projectdistance / VectorLength(direction);
676 VectorCopy(vertex, outvertex3f);
677 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
685 if (r_shadow_frontsidecasting.integer)
687 for (i = 0;i < numshadowmarktris;i++)
689 int remappedelement[3];
691 const int *neighbortriangle;
693 markindex = shadowmarktris[i] * 3;
694 element = inelement3i + markindex;
695 neighbortriangle = inneighbor3i + markindex;
696 // output the front and back triangles
697 outelement3i[0] = vertexremap[element[0]];
698 outelement3i[1] = vertexremap[element[1]];
699 outelement3i[2] = vertexremap[element[2]];
700 outelement3i[3] = vertexremap[element[2]] + 1;
701 outelement3i[4] = vertexremap[element[1]] + 1;
702 outelement3i[5] = vertexremap[element[0]] + 1;
706 // output the sides (facing outward from this triangle)
707 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
709 remappedelement[0] = vertexremap[element[0]];
710 remappedelement[1] = vertexremap[element[1]];
711 outelement3i[0] = remappedelement[1];
712 outelement3i[1] = remappedelement[0];
713 outelement3i[2] = remappedelement[0] + 1;
714 outelement3i[3] = remappedelement[1];
715 outelement3i[4] = remappedelement[0] + 1;
716 outelement3i[5] = remappedelement[1] + 1;
721 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
723 remappedelement[1] = vertexremap[element[1]];
724 remappedelement[2] = vertexremap[element[2]];
725 outelement3i[0] = remappedelement[2];
726 outelement3i[1] = remappedelement[1];
727 outelement3i[2] = remappedelement[1] + 1;
728 outelement3i[3] = remappedelement[2];
729 outelement3i[4] = remappedelement[1] + 1;
730 outelement3i[5] = remappedelement[2] + 1;
735 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
737 remappedelement[0] = vertexremap[element[0]];
738 remappedelement[2] = vertexremap[element[2]];
739 outelement3i[0] = remappedelement[0];
740 outelement3i[1] = remappedelement[2];
741 outelement3i[2] = remappedelement[2] + 1;
742 outelement3i[3] = remappedelement[0];
743 outelement3i[4] = remappedelement[2] + 1;
744 outelement3i[5] = remappedelement[0] + 1;
753 for (i = 0;i < numshadowmarktris;i++)
755 int remappedelement[3];
757 const int *neighbortriangle;
759 markindex = shadowmarktris[i] * 3;
760 element = inelement3i + markindex;
761 neighbortriangle = inneighbor3i + markindex;
762 // output the front and back triangles
763 outelement3i[0] = vertexremap[element[2]];
764 outelement3i[1] = vertexremap[element[1]];
765 outelement3i[2] = vertexremap[element[0]];
766 outelement3i[3] = vertexremap[element[0]] + 1;
767 outelement3i[4] = vertexremap[element[1]] + 1;
768 outelement3i[5] = vertexremap[element[2]] + 1;
772 // output the sides (facing outward from this triangle)
773 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
775 remappedelement[0] = vertexremap[element[0]];
776 remappedelement[1] = vertexremap[element[1]];
777 outelement3i[0] = remappedelement[0];
778 outelement3i[1] = remappedelement[1];
779 outelement3i[2] = remappedelement[1] + 1;
780 outelement3i[3] = remappedelement[0];
781 outelement3i[4] = remappedelement[1] + 1;
782 outelement3i[5] = remappedelement[0] + 1;
787 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
789 remappedelement[1] = vertexremap[element[1]];
790 remappedelement[2] = vertexremap[element[2]];
791 outelement3i[0] = remappedelement[1];
792 outelement3i[1] = remappedelement[2];
793 outelement3i[2] = remappedelement[2] + 1;
794 outelement3i[3] = remappedelement[1];
795 outelement3i[4] = remappedelement[2] + 1;
796 outelement3i[5] = remappedelement[1] + 1;
801 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
803 remappedelement[0] = vertexremap[element[0]];
804 remappedelement[2] = vertexremap[element[2]];
805 outelement3i[0] = remappedelement[2];
806 outelement3i[1] = remappedelement[0];
807 outelement3i[2] = remappedelement[0] + 1;
808 outelement3i[3] = remappedelement[2];
809 outelement3i[4] = remappedelement[0] + 1;
810 outelement3i[5] = remappedelement[2] + 1;
818 *outnumvertices = outvertices;
822 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)
828 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
830 tend = firsttriangle + numtris;
831 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
833 // surface box entirely inside light box, no box cull
834 if (projectdirection)
836 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
838 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
839 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
840 shadowmarklist[numshadowmark++] = t;
845 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
846 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
847 shadowmarklist[numshadowmark++] = t;
852 // surface box not entirely inside light box, cull each triangle
853 if (projectdirection)
855 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
857 v[0] = invertex3f + e[0] * 3;
858 v[1] = invertex3f + e[1] * 3;
859 v[2] = invertex3f + e[2] * 3;
860 TriangleNormal(v[0], v[1], v[2], normal);
861 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
862 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
863 shadowmarklist[numshadowmark++] = t;
868 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
870 v[0] = invertex3f + e[0] * 3;
871 v[1] = invertex3f + e[1] * 3;
872 v[2] = invertex3f + e[2] * 3;
873 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
874 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
875 shadowmarklist[numshadowmark++] = t;
881 static void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
883 if (r_shadow_compilingrtlight)
885 // if we're compiling an rtlight, capture the mesh
886 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
889 r_refdef.stats.lights_shadowtriangles += numtriangles;
891 R_Mesh_VertexPointer(vertex3f, 0, 0);
892 GL_LockArrays(0, numvertices);
893 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
895 // decrement stencil if backface is behind depthbuffer
896 GL_CullFace(r_refdef.view.cullface_front);
897 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
898 R_Mesh_Draw(0, numvertices, 0, numtriangles, element3i, NULL, 0, 0);
899 // increment stencil if frontface is behind depthbuffer
900 GL_CullFace(r_refdef.view.cullface_back);
901 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
903 R_Mesh_Draw(0, numvertices, 0, numtriangles, element3i, NULL, 0, 0);
908 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)
911 if (projectdistance < 0.1)
913 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
916 if (!numverts || !nummarktris)
918 // make sure shadowelements is big enough for this volume
919 if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
920 R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
921 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
922 r_refdef.stats.lights_dynamicshadowtriangles += tris;
923 R_Shadow_RenderVolume(outverts, tris, shadowvertex3f, shadowelements);
926 static void R_Shadow_MakeTextures_MakeCorona(void)
930 unsigned char pixels[32][32][4];
931 for (y = 0;y < 32;y++)
933 dy = (y - 15.5f) * (1.0f / 16.0f);
934 for (x = 0;x < 32;x++)
936 dx = (x - 15.5f) * (1.0f / 16.0f);
937 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
938 a = bound(0, a, 255);
942 pixels[y][x][3] = 255;
945 r_shadow_lightcorona = R_LoadTexture2D(r_shadow_texturepool, "lightcorona", 32, 32, &pixels[0][0][0], TEXTYPE_BGRA, TEXF_PRECACHE, NULL);
948 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
950 float dist = sqrt(x*x+y*y+z*z);
951 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
952 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
953 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
956 static void R_Shadow_MakeTextures(void)
959 float intensity, dist;
961 R_FreeTexturePool(&r_shadow_texturepool);
962 r_shadow_texturepool = R_AllocTexturePool();
963 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
964 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
965 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
966 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
967 for (x = 0;x <= ATTENTABLESIZE;x++)
969 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
970 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
971 r_shadow_attentable[x] = bound(0, intensity, 1);
973 // 1D gradient texture
974 for (x = 0;x < ATTEN1DSIZE;x++)
975 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
976 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
978 for (y = 0;y < ATTEN2DSIZE;y++)
979 for (x = 0;x < ATTEN2DSIZE;x++)
980 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);
981 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
983 if (r_shadow_texture3d.integer && gl_texture3d)
985 for (z = 0;z < ATTEN3DSIZE;z++)
986 for (y = 0;y < ATTEN3DSIZE;y++)
987 for (x = 0;x < ATTEN3DSIZE;x++)
988 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));
989 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
992 r_shadow_attenuation3dtexture = NULL;
995 R_Shadow_MakeTextures_MakeCorona();
997 // Editor light sprites
998 r_editlights_sprcursor = Draw_CachePic ("gfx/editlights/cursor");
999 r_editlights_sprlight = Draw_CachePic ("gfx/editlights/light");
1000 r_editlights_sprnoshadowlight = Draw_CachePic ("gfx/editlights/noshadow");
1001 r_editlights_sprcubemaplight = Draw_CachePic ("gfx/editlights/cubemaplight");
1002 r_editlights_sprcubemapnoshadowlight = Draw_CachePic ("gfx/editlights/cubemapnoshadowlight");
1003 r_editlights_sprselection = Draw_CachePic ("gfx/editlights/selection");
1006 void R_Shadow_ValidateCvars(void)
1008 if (r_shadow_texture3d.integer && !gl_texture3d)
1009 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1010 if (gl_ext_separatestencil.integer && !gl_support_separatestencil)
1011 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1012 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1013 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1016 void R_Shadow_RenderMode_Begin(void)
1018 R_Shadow_ValidateCvars();
1020 if (!r_shadow_attenuation2dtexture
1021 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1022 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1023 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1024 R_Shadow_MakeTextures();
1027 R_Mesh_ColorPointer(NULL, 0, 0);
1028 R_Mesh_ResetTextureState();
1029 GL_BlendFunc(GL_ONE, GL_ZERO);
1030 GL_DepthRange(0, 1);
1031 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1033 GL_DepthMask(false);
1034 GL_Color(0, 0, 0, 1);
1035 GL_Scissor(r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
1037 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1039 if (gl_ext_separatestencil.integer)
1040 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
1041 else if (gl_ext_stenciltwoside.integer)
1042 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
1044 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
1046 if (r_glsl.integer && gl_support_fragment_shader)
1047 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1048 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
1049 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
1051 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1054 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1056 rsurface.rtlight = rtlight;
1059 void R_Shadow_RenderMode_Reset(void)
1062 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
1064 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1066 R_Mesh_ColorPointer(NULL, 0, 0);
1067 R_Mesh_ResetTextureState();
1068 GL_DepthRange(0, 1);
1070 GL_DepthMask(false);
1071 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1072 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1073 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1074 qglStencilMask(~0);CHECKGLERROR
1075 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1076 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1077 GL_CullFace(r_refdef.view.cullface_back);
1078 GL_Color(1, 1, 1, 1);
1079 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1080 GL_BlendFunc(GL_ONE, GL_ZERO);
1081 R_SetupGenericShader(false);
1084 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean clearstencil)
1087 R_Shadow_RenderMode_Reset();
1088 GL_ColorMask(0, 0, 0, 0);
1089 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1090 R_SetupDepthOrShadowShader();
1091 qglDepthFunc(GL_LESS);CHECKGLERROR
1092 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1093 r_shadow_rendermode = r_shadow_shadowingrendermode;
1094 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SEPARATESTENCIL)
1096 GL_CullFace(GL_NONE);
1097 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1098 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1100 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
1102 GL_CullFace(GL_NONE);
1103 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1104 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1105 qglStencilMask(~0);CHECKGLERROR
1106 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1107 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1108 qglStencilMask(~0);CHECKGLERROR
1109 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1112 GL_Clear(GL_STENCIL_BUFFER_BIT);
1113 r_refdef.stats.lights_clears++;
1116 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent)
1119 R_Shadow_RenderMode_Reset();
1120 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1123 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1127 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1128 // only draw light where this geometry was already rendered AND the
1129 // stencil is 128 (values other than this mean shadow)
1130 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1132 r_shadow_rendermode = r_shadow_lightingrendermode;
1133 // do global setup needed for the chosen lighting mode
1134 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1136 R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap)); // light filter
1137 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
1139 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_VERTEX)
1140 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
1141 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1144 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
1147 R_Shadow_RenderMode_Reset();
1148 GL_BlendFunc(GL_ONE, GL_ONE);
1149 GL_DepthRange(0, 1);
1150 GL_DepthTest(r_showshadowvolumes.integer < 2);
1151 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
1152 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1153 GL_CullFace(GL_NONE);
1154 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
1157 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
1160 R_Shadow_RenderMode_Reset();
1161 GL_BlendFunc(GL_ONE, GL_ONE);
1162 GL_DepthRange(0, 1);
1163 GL_DepthTest(r_showlighting.integer < 2);
1164 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
1167 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1171 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1172 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1174 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
1177 void R_Shadow_RenderMode_End(void)
1180 R_Shadow_RenderMode_Reset();
1181 R_Shadow_RenderMode_ActiveLight(NULL);
1183 GL_Scissor(r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
1184 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1187 int bboxedges[12][2] =
1206 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1208 int i, ix1, iy1, ix2, iy2;
1209 float x1, y1, x2, y2;
1211 float vertex[20][3];
1220 if (!r_shadow_scissor.integer)
1223 // if view is inside the light box, just say yes it's visible
1224 if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
1226 GL_Scissor(r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
1230 x1 = y1 = x2 = y2 = 0;
1232 // transform all corners that are infront of the nearclip plane
1233 VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
1234 plane4f[3] = r_refdef.view.frustum[4].dist;
1236 for (i = 0;i < 8;i++)
1238 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
1239 dist[i] = DotProduct4(corner[i], plane4f);
1240 sign[i] = dist[i] > 0;
1243 VectorCopy(corner[i], vertex[numvertices]);
1247 // if some points are behind the nearclip, add clipped edge points to make
1248 // sure that the scissor boundary is complete
1249 if (numvertices > 0 && numvertices < 8)
1251 // add clipped edge points
1252 for (i = 0;i < 12;i++)
1254 j = bboxedges[i][0];
1255 k = bboxedges[i][1];
1256 if (sign[j] != sign[k])
1258 f = dist[j] / (dist[j] - dist[k]);
1259 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
1265 // if we have no points to check, the light is behind the view plane
1269 // if we have some points to transform, check what screen area is covered
1270 x1 = y1 = x2 = y2 = 0;
1272 //Con_Printf("%i vertices to transform...\n", numvertices);
1273 for (i = 0;i < numvertices;i++)
1275 VectorCopy(vertex[i], v);
1276 GL_TransformToScreen(v, v2);
1277 //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]);
1280 if (x1 > v2[0]) x1 = v2[0];
1281 if (x2 < v2[0]) x2 = v2[0];
1282 if (y1 > v2[1]) y1 = v2[1];
1283 if (y2 < v2[1]) y2 = v2[1];
1292 // now convert the scissor rectangle to integer screen coordinates
1293 ix1 = (int)(x1 - 1.0f);
1294 iy1 = (int)(y1 - 1.0f);
1295 ix2 = (int)(x2 + 1.0f);
1296 iy2 = (int)(y2 + 1.0f);
1297 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1299 // clamp it to the screen
1300 if (ix1 < r_refdef.view.x) ix1 = r_refdef.view.x;
1301 if (iy1 < r_refdef.view.y) iy1 = r_refdef.view.y;
1302 if (ix2 > r_refdef.view.x + r_refdef.view.width) ix2 = r_refdef.view.x + r_refdef.view.width;
1303 if (iy2 > r_refdef.view.y + r_refdef.view.height) iy2 = r_refdef.view.y + r_refdef.view.height;
1305 // if it is inside out, it's not visible
1306 if (ix2 <= ix1 || iy2 <= iy1)
1309 // the light area is visible, set up the scissor rectangle
1310 GL_Scissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1311 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);CHECKGLERROR
1312 //qglEnable(GL_SCISSOR_TEST);CHECKGLERROR
1313 r_refdef.stats.lights_scissored++;
1317 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
1319 float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1320 float *normal3f = rsurface.normal3f + 3 * firstvertex;
1321 float *color4f = rsurface.array_color4f + 4 * firstvertex;
1322 float dist, dot, distintensity, shadeintensity, v[3], n[3];
1323 if (r_textureunits.integer >= 3)
1325 if (VectorLength2(diffusecolor) > 0)
1327 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1329 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1330 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1331 if ((dot = DotProduct(n, v)) < 0)
1333 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1334 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
1337 VectorCopy(ambientcolor, color4f);
1338 if (r_refdef.fogenabled)
1341 f = FogPoint_Model(vertex3f);
1342 VectorScale(color4f, f, color4f);
1349 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1351 VectorCopy(ambientcolor, color4f);
1352 if (r_refdef.fogenabled)
1355 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1356 f = FogPoint_Model(vertex3f);
1357 VectorScale(color4f, f, color4f);
1363 else if (r_textureunits.integer >= 2)
1365 if (VectorLength2(diffusecolor) > 0)
1367 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1369 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1370 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1372 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1373 if ((dot = DotProduct(n, v)) < 0)
1375 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1376 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1377 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1378 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1382 color4f[0] = ambientcolor[0] * distintensity;
1383 color4f[1] = ambientcolor[1] * distintensity;
1384 color4f[2] = ambientcolor[2] * distintensity;
1386 if (r_refdef.fogenabled)
1389 f = FogPoint_Model(vertex3f);
1390 VectorScale(color4f, f, color4f);
1394 VectorClear(color4f);
1400 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1402 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1403 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1405 color4f[0] = ambientcolor[0] * distintensity;
1406 color4f[1] = ambientcolor[1] * distintensity;
1407 color4f[2] = ambientcolor[2] * distintensity;
1408 if (r_refdef.fogenabled)
1411 f = FogPoint_Model(vertex3f);
1412 VectorScale(color4f, f, color4f);
1416 VectorClear(color4f);
1423 if (VectorLength2(diffusecolor) > 0)
1425 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1427 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1428 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1430 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
1431 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1432 if ((dot = DotProduct(n, v)) < 0)
1434 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1435 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1436 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1437 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1441 color4f[0] = ambientcolor[0] * distintensity;
1442 color4f[1] = ambientcolor[1] * distintensity;
1443 color4f[2] = ambientcolor[2] * distintensity;
1445 if (r_refdef.fogenabled)
1448 f = FogPoint_Model(vertex3f);
1449 VectorScale(color4f, f, color4f);
1453 VectorClear(color4f);
1459 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1461 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1462 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1464 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
1465 color4f[0] = ambientcolor[0] * distintensity;
1466 color4f[1] = ambientcolor[1] * distintensity;
1467 color4f[2] = ambientcolor[2] * distintensity;
1468 if (r_refdef.fogenabled)
1471 f = FogPoint_Model(vertex3f);
1472 VectorScale(color4f, f, color4f);
1476 VectorClear(color4f);
1483 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1485 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
1488 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
1489 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1490 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
1491 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
1492 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
1494 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1496 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
1497 // the cubemap normalizes this for us
1498 out3f[0] = DotProduct(svector3f, lightdir);
1499 out3f[1] = DotProduct(tvector3f, lightdir);
1500 out3f[2] = DotProduct(normal3f, lightdir);
1504 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
1507 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
1508 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1509 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
1510 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
1511 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
1512 float lightdir[3], eyedir[3], halfdir[3];
1513 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1515 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
1516 VectorNormalize(lightdir);
1517 VectorSubtract(rsurface.modelorg, vertex3f, eyedir);
1518 VectorNormalize(eyedir);
1519 VectorAdd(lightdir, eyedir, halfdir);
1520 // the cubemap normalizes this for us
1521 out3f[0] = DotProduct(svector3f, halfdir);
1522 out3f[1] = DotProduct(tvector3f, halfdir);
1523 out3f[2] = DotProduct(normal3f, halfdir);
1527 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)
1529 // used to display how many times a surface is lit for level design purposes
1530 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
1533 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)
1535 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
1536 R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
1537 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND))
1538 R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
1540 R_Mesh_ColorPointer(NULL, 0, 0);
1541 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
1542 R_Mesh_TexBind(GL20TU_NORMAL, R_GetTexture(rsurface.texture->currentskinframe->nmap));
1543 R_Mesh_TexBind(GL20TU_COLOR, R_GetTexture(rsurface.texture->basetexture));
1544 R_Mesh_TexBind(GL20TU_GLOSS, R_GetTexture(rsurface.texture->glosstexture));
1545 if (rsurface.texture->backgroundcurrentskinframe)
1547 R_Mesh_TexBind(GL20TU_SECONDARY_NORMAL, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->nmap));
1548 R_Mesh_TexBind(GL20TU_SECONDARY_COLOR, R_GetTexture(rsurface.texture->backgroundbasetexture));
1549 R_Mesh_TexBind(GL20TU_SECONDARY_GLOSS, R_GetTexture(rsurface.texture->backgroundglosstexture));
1551 //R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap));
1552 R_Mesh_TexBind(GL20TU_FOGMASK, R_GetTexture(r_texture_fogattenuation));
1553 if(rsurface.texture->colormapping)
1555 R_Mesh_TexBind(GL20TU_PANTS, R_GetTexture(rsurface.texture->currentskinframe->pants));
1556 R_Mesh_TexBind(GL20TU_SHIRT, R_GetTexture(rsurface.texture->currentskinframe->shirt));
1558 R_Mesh_TexBind(GL20TU_ATTENUATION, R_GetTexture(r_shadow_attenuationgradienttexture));
1559 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
1560 R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
1561 R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
1562 R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
1563 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1565 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1567 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
1568 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1570 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1574 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)
1576 // shared final code for all the dot3 layers
1578 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
1579 for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
1581 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
1582 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
1586 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)
1589 // colorscale accounts for how much we multiply the brightness
1592 // mult is how many times the final pass of the lighting will be
1593 // performed to get more brightness than otherwise possible.
1595 // Limit mult to 64 for sanity sake.
1597 if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1599 // 3 3D combine path (Geforce3, Radeon 8500)
1600 memset(&m, 0, sizeof(m));
1601 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1602 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1603 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1604 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1605 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1606 m.tex[1] = R_GetTexture(basetexture);
1607 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
1608 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
1609 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
1610 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
1611 m.texcubemap[2] = R_GetTexture(rsurface.rtlight->currentcubemap);
1612 m.pointer_texcoord3f[2] = rsurface.vertex3f;
1613 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
1614 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
1615 m.texmatrix[2] = rsurface.entitytolight;
1616 GL_BlendFunc(GL_ONE, GL_ONE);
1618 else if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1620 // 2 3D combine path (Geforce3, original Radeon)
1621 memset(&m, 0, sizeof(m));
1622 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1623 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1624 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1625 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1626 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1627 m.tex[1] = R_GetTexture(basetexture);
1628 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
1629 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
1630 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
1631 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
1632 GL_BlendFunc(GL_ONE, GL_ONE);
1634 else if (r_textureunits.integer >= 4 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
1636 // 4 2D combine path (Geforce3, Radeon 8500)
1637 memset(&m, 0, sizeof(m));
1638 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1639 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1640 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1641 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1642 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1643 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1644 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1645 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1646 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1647 m.texmatrix[1] = rsurface.entitytoattenuationz;
1648 m.tex[2] = R_GetTexture(basetexture);
1649 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
1650 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
1651 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
1652 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
1653 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1655 m.texcubemap[3] = R_GetTexture(rsurface.rtlight->currentcubemap);
1656 m.pointer_texcoord3f[3] = rsurface.vertex3f;
1657 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
1658 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
1659 m.texmatrix[3] = rsurface.entitytolight;
1661 GL_BlendFunc(GL_ONE, GL_ONE);
1663 else if (r_textureunits.integer >= 3 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
1665 // 3 2D combine path (Geforce3, original Radeon)
1666 memset(&m, 0, sizeof(m));
1667 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1668 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1669 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1670 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1671 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1672 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1673 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1674 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1675 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1676 m.texmatrix[1] = rsurface.entitytoattenuationz;
1677 m.tex[2] = R_GetTexture(basetexture);
1678 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
1679 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
1680 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
1681 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
1682 GL_BlendFunc(GL_ONE, GL_ONE);
1686 // 2/2/2 2D combine path (any dot3 card)
1687 memset(&m, 0, sizeof(m));
1688 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1689 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1690 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1691 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1692 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1693 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1694 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1695 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1696 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1697 m.texmatrix[1] = rsurface.entitytoattenuationz;
1698 R_Mesh_TextureState(&m);
1699 GL_ColorMask(0,0,0,1);
1700 GL_BlendFunc(GL_ONE, GL_ZERO);
1701 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
1704 memset(&m, 0, sizeof(m));
1705 m.tex[0] = R_GetTexture(basetexture);
1706 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1707 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1708 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1709 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1710 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1712 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1713 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1714 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1715 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1716 m.texmatrix[1] = rsurface.entitytolight;
1718 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1720 // this final code is shared
1721 R_Mesh_TextureState(&m);
1722 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);
1725 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)
1728 // colorscale accounts for how much we multiply the brightness
1731 // mult is how many times the final pass of the lighting will be
1732 // performed to get more brightness than otherwise possible.
1734 // Limit mult to 64 for sanity sake.
1736 // generate normalization cubemap texcoords
1737 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
1738 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1740 // 3/2 3D combine path (Geforce3, Radeon 8500)
1741 memset(&m, 0, sizeof(m));
1742 m.tex[0] = R_GetTexture(normalmaptexture);
1743 m.texcombinergb[0] = GL_REPLACE;
1744 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1745 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1746 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1747 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1748 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1749 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1750 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1751 m.pointer_texcoord_bufferobject[1] = 0;
1752 m.pointer_texcoord_bufferoffset[1] = 0;
1753 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1754 m.pointer_texcoord3f[2] = rsurface.vertex3f;
1755 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
1756 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
1757 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
1758 R_Mesh_TextureState(&m);
1759 GL_ColorMask(0,0,0,1);
1760 GL_BlendFunc(GL_ONE, GL_ZERO);
1761 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
1764 memset(&m, 0, sizeof(m));
1765 m.tex[0] = R_GetTexture(basetexture);
1766 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1767 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1768 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1769 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1770 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1772 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1773 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1774 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1775 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1776 m.texmatrix[1] = rsurface.entitytolight;
1778 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1780 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
1782 // 1/2/2 3D combine path (original Radeon)
1783 memset(&m, 0, sizeof(m));
1784 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1785 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1786 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1787 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1788 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1789 R_Mesh_TextureState(&m);
1790 GL_ColorMask(0,0,0,1);
1791 GL_BlendFunc(GL_ONE, GL_ZERO);
1792 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
1795 memset(&m, 0, sizeof(m));
1796 m.tex[0] = R_GetTexture(normalmaptexture);
1797 m.texcombinergb[0] = GL_REPLACE;
1798 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1799 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1800 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1801 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1802 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1803 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1804 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1805 m.pointer_texcoord_bufferobject[1] = 0;
1806 m.pointer_texcoord_bufferoffset[1] = 0;
1807 R_Mesh_TextureState(&m);
1808 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1809 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
1812 memset(&m, 0, sizeof(m));
1813 m.tex[0] = R_GetTexture(basetexture);
1814 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1815 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1816 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1817 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1818 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1820 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1821 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1822 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1823 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1824 m.texmatrix[1] = rsurface.entitytolight;
1826 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1828 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
1830 // 2/2 3D combine path (original Radeon)
1831 memset(&m, 0, sizeof(m));
1832 m.tex[0] = R_GetTexture(normalmaptexture);
1833 m.texcombinergb[0] = GL_REPLACE;
1834 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1835 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1836 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1837 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1838 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1839 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1840 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1841 m.pointer_texcoord_bufferobject[1] = 0;
1842 m.pointer_texcoord_bufferoffset[1] = 0;
1843 R_Mesh_TextureState(&m);
1844 GL_ColorMask(0,0,0,1);
1845 GL_BlendFunc(GL_ONE, GL_ZERO);
1846 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
1849 memset(&m, 0, sizeof(m));
1850 m.tex[0] = R_GetTexture(basetexture);
1851 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1852 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1853 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1854 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1855 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1856 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1857 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1858 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1859 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
1860 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1862 else if (r_textureunits.integer >= 4)
1864 // 4/2 2D combine path (Geforce3, Radeon 8500)
1865 memset(&m, 0, sizeof(m));
1866 m.tex[0] = R_GetTexture(normalmaptexture);
1867 m.texcombinergb[0] = GL_REPLACE;
1868 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1869 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1870 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1871 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1872 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1873 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1874 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1875 m.pointer_texcoord_bufferobject[1] = 0;
1876 m.pointer_texcoord_bufferoffset[1] = 0;
1877 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1878 m.pointer_texcoord3f[2] = rsurface.vertex3f;
1879 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
1880 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
1881 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
1882 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1883 m.pointer_texcoord3f[3] = rsurface.vertex3f;
1884 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
1885 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
1886 m.texmatrix[3] = rsurface.entitytoattenuationz;
1887 R_Mesh_TextureState(&m);
1888 GL_ColorMask(0,0,0,1);
1889 GL_BlendFunc(GL_ONE, GL_ZERO);
1890 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
1893 memset(&m, 0, sizeof(m));
1894 m.tex[0] = R_GetTexture(basetexture);
1895 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1896 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1897 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1898 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1899 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1901 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1902 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1903 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1904 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1905 m.texmatrix[1] = rsurface.entitytolight;
1907 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1911 // 2/2/2 2D combine path (any dot3 card)
1912 memset(&m, 0, sizeof(m));
1913 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1914 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1915 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1916 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1917 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1918 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1919 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1920 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1921 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1922 m.texmatrix[1] = rsurface.entitytoattenuationz;
1923 R_Mesh_TextureState(&m);
1924 GL_ColorMask(0,0,0,1);
1925 GL_BlendFunc(GL_ONE, GL_ZERO);
1926 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
1929 memset(&m, 0, sizeof(m));
1930 m.tex[0] = R_GetTexture(normalmaptexture);
1931 m.texcombinergb[0] = GL_REPLACE;
1932 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1933 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1934 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1935 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1936 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1937 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1938 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1939 m.pointer_texcoord_bufferobject[1] = 0;
1940 m.pointer_texcoord_bufferoffset[1] = 0;
1941 R_Mesh_TextureState(&m);
1942 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1943 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
1946 memset(&m, 0, sizeof(m));
1947 m.tex[0] = R_GetTexture(basetexture);
1948 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1949 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1950 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1951 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1952 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1954 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1955 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1956 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1957 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1958 m.texmatrix[1] = rsurface.entitytolight;
1960 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1962 // this final code is shared
1963 R_Mesh_TextureState(&m);
1964 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);
1967 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)
1969 float glossexponent;
1971 // FIXME: detect blendsquare!
1972 //if (!gl_support_blendsquare)
1975 // generate normalization cubemap texcoords
1976 R_Shadow_GenTexCoords_Specular_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
1977 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
1979 // 2/0/0/1/2 3D combine blendsquare path
1980 memset(&m, 0, sizeof(m));
1981 m.tex[0] = R_GetTexture(normalmaptexture);
1982 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1983 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1984 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1985 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1986 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1987 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1988 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1989 m.pointer_texcoord_bufferobject[1] = 0;
1990 m.pointer_texcoord_bufferoffset[1] = 0;
1991 R_Mesh_TextureState(&m);
1992 GL_ColorMask(0,0,0,1);
1993 // this squares the result
1994 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1995 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
1997 // second and third pass
1998 R_Mesh_ResetTextureState();
1999 // square alpha in framebuffer a few times to make it shiny
2000 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2001 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2002 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2005 memset(&m, 0, sizeof(m));
2006 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2007 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2008 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2009 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2010 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2011 R_Mesh_TextureState(&m);
2012 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2013 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2016 memset(&m, 0, sizeof(m));
2017 m.tex[0] = R_GetTexture(glosstexture);
2018 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2019 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2020 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2021 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2022 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2024 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2025 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2026 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2027 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2028 m.texmatrix[1] = rsurface.entitytolight;
2030 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2032 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
2034 // 2/0/0/2 3D combine blendsquare path
2035 memset(&m, 0, sizeof(m));
2036 m.tex[0] = R_GetTexture(normalmaptexture);
2037 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2038 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2039 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2040 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2041 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2042 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2043 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2044 m.pointer_texcoord_bufferobject[1] = 0;
2045 m.pointer_texcoord_bufferoffset[1] = 0;
2046 R_Mesh_TextureState(&m);
2047 GL_ColorMask(0,0,0,1);
2048 // this squares the result
2049 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2050 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2052 // second and third pass
2053 R_Mesh_ResetTextureState();
2054 // square alpha in framebuffer a few times to make it shiny
2055 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2056 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2057 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2060 memset(&m, 0, sizeof(m));
2061 m.tex[0] = R_GetTexture(glosstexture);
2062 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2063 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2064 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2065 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2066 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2067 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2068 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2069 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2070 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2071 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2075 // 2/0/0/2/2 2D combine blendsquare path
2076 memset(&m, 0, sizeof(m));
2077 m.tex[0] = R_GetTexture(normalmaptexture);
2078 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2079 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2080 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2081 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2082 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2083 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2084 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2085 m.pointer_texcoord_bufferobject[1] = 0;
2086 m.pointer_texcoord_bufferoffset[1] = 0;
2087 R_Mesh_TextureState(&m);
2088 GL_ColorMask(0,0,0,1);
2089 // this squares the result
2090 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2091 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2093 // second and third pass
2094 R_Mesh_ResetTextureState();
2095 // square alpha in framebuffer a few times to make it shiny
2096 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2097 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2098 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2101 memset(&m, 0, sizeof(m));
2102 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2103 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2104 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2105 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2106 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2107 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2108 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2109 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2110 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2111 m.texmatrix[1] = rsurface.entitytoattenuationz;
2112 R_Mesh_TextureState(&m);
2113 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2114 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2117 memset(&m, 0, sizeof(m));
2118 m.tex[0] = R_GetTexture(glosstexture);
2119 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2120 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2121 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2122 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2123 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2125 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2126 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2127 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2128 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2129 m.texmatrix[1] = rsurface.entitytolight;
2131 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2133 // this final code is shared
2134 R_Mesh_TextureState(&m);
2135 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);
2138 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)
2140 // ARB path (any Geforce, any Radeon)
2141 qboolean doambient = ambientscale > 0;
2142 qboolean dodiffuse = diffusescale > 0;
2143 qboolean dospecular = specularscale > 0;
2144 if (!doambient && !dodiffuse && !dospecular)
2146 R_Mesh_ColorPointer(NULL, 0, 0);
2148 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, ambientscale * r_refdef.view.colorscale);
2150 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2154 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, ambientscale * r_refdef.view.colorscale);
2156 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2161 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, ambientscale * r_refdef.view.colorscale);
2163 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2166 R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_refdef.view.colorscale);
2169 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2176 int newnumtriangles;
2180 int maxtriangles = 4096;
2181 int newelements[4096*3];
2182 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
2183 for (renders = 0;renders < 64;renders++)
2188 newnumtriangles = 0;
2190 // due to low fillrate on the cards this vertex lighting path is
2191 // designed for, we manually cull all triangles that do not
2192 // contain a lit vertex
2193 // this builds batches of triangles from multiple surfaces and
2194 // renders them at once
2195 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2197 if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
2199 if (newnumtriangles)
2201 newfirstvertex = min(newfirstvertex, e[0]);
2202 newlastvertex = max(newlastvertex, e[0]);
2206 newfirstvertex = e[0];
2207 newlastvertex = e[0];
2209 newfirstvertex = min(newfirstvertex, e[1]);
2210 newlastvertex = max(newlastvertex, e[1]);
2211 newfirstvertex = min(newfirstvertex, e[2]);
2212 newlastvertex = max(newlastvertex, e[2]);
2218 if (newnumtriangles >= maxtriangles)
2220 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2221 newnumtriangles = 0;
2227 if (newnumtriangles >= 1)
2229 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2232 // if we couldn't find any lit triangles, exit early
2235 // now reduce the intensity for the next overbright pass
2236 // we have to clamp to 0 here incase the drivers have improper
2237 // handling of negative colors
2238 // (some old drivers even have improper handling of >1 color)
2240 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2242 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2244 c[0] = max(0, c[0] - 1);
2245 c[1] = max(0, c[1] - 1);
2246 c[2] = max(0, c[2] - 1);
2258 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)
2260 // OpenGL 1.1 path (anything)
2261 float ambientcolorbase[3], diffusecolorbase[3];
2262 float ambientcolorpants[3], diffusecolorpants[3];
2263 float ambientcolorshirt[3], diffusecolorshirt[3];
2265 VectorScale(lightcolorbase, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorbase);
2266 VectorScale(lightcolorbase, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorbase);
2267 VectorScale(lightcolorpants, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorpants);
2268 VectorScale(lightcolorpants, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorpants);
2269 VectorScale(lightcolorshirt, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorshirt);
2270 VectorScale(lightcolorshirt, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorshirt);
2271 memset(&m, 0, sizeof(m));
2272 m.tex[0] = R_GetTexture(basetexture);
2273 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2274 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2275 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2276 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2277 if (r_textureunits.integer >= 2)
2280 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2281 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2282 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2283 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2284 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2285 if (r_textureunits.integer >= 3)
2287 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
2288 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2289 m.texmatrix[2] = rsurface.entitytoattenuationz;
2290 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2291 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2292 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2295 R_Mesh_TextureState(&m);
2296 //R_Mesh_TexBind(0, R_GetTexture(basetexture));
2297 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
2300 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
2301 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
2305 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
2306 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
2310 extern cvar_t gl_lightmaps;
2311 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)
2313 float ambientscale, diffusescale, specularscale;
2314 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
2316 // calculate colors to render this texture with
2317 lightcolorbase[0] = rsurface.rtlight->currentcolor[0] * rsurface.texture->dlightcolor[0];
2318 lightcolorbase[1] = rsurface.rtlight->currentcolor[1] * rsurface.texture->dlightcolor[1];
2319 lightcolorbase[2] = rsurface.rtlight->currentcolor[2] * rsurface.texture->dlightcolor[2];
2320 ambientscale = rsurface.rtlight->ambientscale;
2321 diffusescale = rsurface.rtlight->diffusescale;
2322 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2323 if (!r_shadow_usenormalmap.integer)
2325 ambientscale += 1.0f * diffusescale;
2329 if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
2331 RSurf_SetupDepthAndCulling();
2332 nmap = rsurface.texture->currentskinframe->nmap;
2333 if (gl_lightmaps.integer)
2334 nmap = r_texture_blanknormalmap;
2335 if (rsurface.texture->colormapping && !gl_lightmaps.integer)
2337 qboolean dopants = rsurface.texture->currentskinframe->pants != NULL && VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f);
2338 qboolean doshirt = rsurface.texture->currentskinframe->shirt != NULL && VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f);
2341 lightcolorpants[0] = lightcolorbase[0] * rsurface.colormap_pantscolor[0];
2342 lightcolorpants[1] = lightcolorbase[1] * rsurface.colormap_pantscolor[1];
2343 lightcolorpants[2] = lightcolorbase[2] * rsurface.colormap_pantscolor[2];
2346 VectorClear(lightcolorpants);
2349 lightcolorshirt[0] = lightcolorbase[0] * rsurface.colormap_shirtcolor[0];
2350 lightcolorshirt[1] = lightcolorbase[1] * rsurface.colormap_shirtcolor[1];
2351 lightcolorshirt[2] = lightcolorbase[2] * rsurface.colormap_shirtcolor[2];
2354 VectorClear(lightcolorshirt);
2355 switch (r_shadow_rendermode)
2357 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2358 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2359 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);
2361 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2362 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);
2364 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2365 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);
2367 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2368 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);
2371 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2377 switch (r_shadow_rendermode)
2379 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2380 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2381 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);
2383 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2384 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);
2386 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2387 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);
2389 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2390 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);
2393 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2399 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)
2401 matrix4x4_t tempmatrix = *matrix;
2402 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2404 // if this light has been compiled before, free the associated data
2405 R_RTLight_Uncompile(rtlight);
2407 // clear it completely to avoid any lingering data
2408 memset(rtlight, 0, sizeof(*rtlight));
2410 // copy the properties
2411 rtlight->matrix_lighttoworld = tempmatrix;
2412 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2413 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2414 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2415 VectorCopy(color, rtlight->color);
2416 rtlight->cubemapname[0] = 0;
2417 if (cubemapname && cubemapname[0])
2418 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2419 rtlight->shadow = shadow;
2420 rtlight->corona = corona;
2421 rtlight->style = style;
2422 rtlight->isstatic = isstatic;
2423 rtlight->coronasizescale = coronasizescale;
2424 rtlight->ambientscale = ambientscale;
2425 rtlight->diffusescale = diffusescale;
2426 rtlight->specularscale = specularscale;
2427 rtlight->flags = flags;
2429 // compute derived data
2430 //rtlight->cullradius = rtlight->radius;
2431 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2432 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2433 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2434 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2435 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2436 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2437 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2440 // compiles rtlight geometry
2441 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2442 void R_RTLight_Compile(rtlight_t *rtlight)
2445 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2446 int lighttris, shadowtris, shadowmeshes, shadowmeshtris;
2447 entity_render_t *ent = r_refdef.scene.worldentity;
2448 dp_model_t *model = r_refdef.scene.worldmodel;
2449 unsigned char *data;
2451 // compile the light
2452 rtlight->compiled = true;
2453 rtlight->static_numleafs = 0;
2454 rtlight->static_numleafpvsbytes = 0;
2455 rtlight->static_leaflist = NULL;
2456 rtlight->static_leafpvs = NULL;
2457 rtlight->static_numsurfaces = 0;
2458 rtlight->static_surfacelist = NULL;
2459 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2460 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2461 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2462 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2463 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2464 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2466 if (model && model->GetLightInfo)
2468 // this variable must be set for the CompileShadowVolume code
2469 r_shadow_compilingrtlight = rtlight;
2470 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);
2471 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);
2472 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2473 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
2474 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
2475 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
2476 rtlight->static_numsurfaces = numsurfaces;
2477 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2478 rtlight->static_numleafs = numleafs;
2479 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2480 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2481 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2482 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
2483 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
2484 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
2485 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
2486 if (rtlight->static_numsurfaces)
2487 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2488 if (rtlight->static_numleafs)
2489 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2490 if (rtlight->static_numleafpvsbytes)
2491 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2492 if (rtlight->static_numshadowtrispvsbytes)
2493 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
2494 if (rtlight->static_numlighttrispvsbytes)
2495 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
2496 if (model->CompileShadowVolume && rtlight->shadow)
2497 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2498 // now we're done compiling the rtlight
2499 r_shadow_compilingrtlight = NULL;
2503 // use smallest available cullradius - box radius or light radius
2504 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2505 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2509 if (rtlight->static_meshchain_shadow)
2512 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2515 shadowmeshtris += mesh->numtriangles;
2520 if (rtlight->static_numlighttrispvsbytes)
2521 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
2522 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
2526 if (rtlight->static_numlighttrispvsbytes)
2527 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
2528 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
2531 if (developer.integer >= 10)
2532 Con_Printf("static light built: %f %f %f : %f %f %f box, %i light triangles, %i shadow triangles, %i compiled shadow volume triangles (in %i meshes)\n", rtlight->cullmins[0], rtlight->cullmins[1], rtlight->cullmins[2], rtlight->cullmaxs[0], rtlight->cullmaxs[1], rtlight->cullmaxs[2], lighttris, shadowtris, shadowmeshtris, shadowmeshes);
2535 void R_RTLight_Uncompile(rtlight_t *rtlight)
2537 if (rtlight->compiled)
2539 if (rtlight->static_meshchain_shadow)
2540 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2541 rtlight->static_meshchain_shadow = NULL;
2542 // these allocations are grouped
2543 if (rtlight->static_surfacelist)
2544 Mem_Free(rtlight->static_surfacelist);
2545 rtlight->static_numleafs = 0;
2546 rtlight->static_numleafpvsbytes = 0;
2547 rtlight->static_leaflist = NULL;
2548 rtlight->static_leafpvs = NULL;
2549 rtlight->static_numsurfaces = 0;
2550 rtlight->static_surfacelist = NULL;
2551 rtlight->static_numshadowtrispvsbytes = 0;
2552 rtlight->static_shadowtrispvs = NULL;
2553 rtlight->static_numlighttrispvsbytes = 0;
2554 rtlight->static_lighttrispvs = NULL;
2555 rtlight->compiled = false;
2559 void R_Shadow_UncompileWorldLights(void)
2563 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2564 for (lightindex = 0;lightindex < range;lightindex++)
2566 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2569 R_RTLight_Uncompile(&light->rtlight);
2573 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
2577 // reset the count of frustum planes
2578 // see rsurface.rtlight_frustumplanes definition for how much this array
2580 rsurface.rtlight_numfrustumplanes = 0;
2582 // haven't implemented a culling path for ortho rendering
2583 if (!r_refdef.view.useperspective)
2585 // check if the light is on screen and copy the 4 planes if it is
2586 for (i = 0;i < 4;i++)
2587 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
2590 for (i = 0;i < 4;i++)
2591 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
2596 // generate a deformed frustum that includes the light origin, this is
2597 // used to cull shadow casting surfaces that can not possibly cast a
2598 // shadow onto the visible light-receiving surfaces, which can be a
2601 // if the light origin is onscreen the result will be 4 planes exactly
2602 // if the light origin is offscreen on only one axis the result will
2603 // be exactly 5 planes (split-side case)
2604 // if the light origin is offscreen on two axes the result will be
2605 // exactly 4 planes (stretched corner case)
2606 for (i = 0;i < 4;i++)
2608 // quickly reject standard frustum planes that put the light
2609 // origin outside the frustum
2610 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
2613 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
2615 // if all the standard frustum planes were accepted, the light is onscreen
2616 // otherwise we need to generate some more planes below...
2617 if (rsurface.rtlight_numfrustumplanes < 4)
2619 // at least one of the stock frustum planes failed, so we need to
2620 // create one or two custom planes to enclose the light origin
2621 for (i = 0;i < 4;i++)
2623 // create a plane using the view origin and light origin, and a
2624 // single point from the frustum corner set
2625 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
2626 VectorNormalize(plane.normal);
2627 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
2628 // see if this plane is backwards and flip it if so
2629 for (j = 0;j < 4;j++)
2630 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
2634 VectorNegate(plane.normal, plane.normal);
2636 // flipped plane, test again to see if it is now valid
2637 for (j = 0;j < 4;j++)
2638 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
2640 // if the plane is still not valid, then it is dividing the
2641 // frustum and has to be rejected
2645 // we have created a valid plane, compute extra info
2646 PlaneClassify(&plane);
2648 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
2650 // if we've found 5 frustum planes then we have constructed a
2651 // proper split-side case and do not need to keep searching for
2652 // planes to enclose the light origin
2653 if (rsurface.rtlight_numfrustumplanes == 5)
2661 for (i = 0;i < rsurface.rtlight_numfrustumplanes;i++)
2663 plane = rsurface.rtlight_frustumplanes[i];
2664 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));
2669 // now add the light-space box planes if the light box is rotated, as any
2670 // caster outside the oriented light box is irrelevant (even if it passed
2671 // the worldspace light box, which is axial)
2672 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
2674 for (i = 0;i < 6;i++)
2678 v[i >> 1] = (i & 1) ? -1 : 1;
2679 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
2680 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
2681 plane.dist = VectorNormalizeLength(plane.normal);
2682 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
2683 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
2689 // add the world-space reduced box planes
2690 for (i = 0;i < 6;i++)
2692 VectorClear(plane.normal);
2693 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
2694 plane.dist = (i & 1) ? -rsurface.rtlight_cullmaxs[i >> 1] : rsurface.rtlight_cullmins[i >> 1];
2695 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
2704 // reduce all plane distances to tightly fit the rtlight cull box, which
2706 VectorSet(points[0], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
2707 VectorSet(points[1], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
2708 VectorSet(points[2], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
2709 VectorSet(points[3], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
2710 VectorSet(points[4], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
2711 VectorSet(points[5], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
2712 VectorSet(points[6], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
2713 VectorSet(points[7], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
2714 oldnum = rsurface.rtlight_numfrustumplanes;
2715 rsurface.rtlight_numfrustumplanes = 0;
2716 for (j = 0;j < oldnum;j++)
2718 // find the nearest point on the box to this plane
2719 bestdist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[0]);
2720 for (i = 1;i < 8;i++)
2722 dist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[i]);
2723 if (bestdist > dist)
2726 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);
2727 // if the nearest point is near or behind the plane, we want this
2728 // plane, otherwise the plane is useless as it won't cull anything
2729 if (rsurface.rtlight_frustumplanes[j].dist < bestdist + 0.03125)
2731 PlaneClassify(&rsurface.rtlight_frustumplanes[j]);
2732 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = rsurface.rtlight_frustumplanes[j];
2739 void R_Shadow_DrawWorldShadow(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
2741 RSurf_ActiveWorldEntity();
2742 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2746 for (mesh = rsurface.rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2748 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
2749 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
2750 GL_LockArrays(0, mesh->numverts);
2751 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
2753 // decrement stencil if backface is behind depthbuffer
2754 GL_CullFace(r_refdef.view.cullface_front);
2755 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2756 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
2757 // increment stencil if frontface is behind depthbuffer
2758 GL_CullFace(r_refdef.view.cullface_back);
2759 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2761 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
2762 GL_LockArrays(0, 0);
2766 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
2769 int surfacelistindex;
2770 msurface_t *surface;
2771 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
2772 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
2774 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
2775 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
2776 if (CHECKPVSBIT(trispvs, t))
2777 shadowmarklist[numshadowmark++] = t;
2779 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);
2781 else if (numsurfaces)
2782 r_refdef.scene.worldmodel->DrawShadowVolume(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
2785 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
2787 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
2788 vec_t relativeshadowradius;
2789 RSurf_ActiveModelEntity(ent, false, false);
2790 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
2791 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
2792 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
2793 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
2794 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
2795 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
2796 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
2797 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
2798 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2801 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
2803 // set up properties for rendering light onto this entity
2804 RSurf_ActiveModelEntity(ent, true, true);
2805 GL_AlphaTest(false);
2806 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
2807 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
2808 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
2809 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
2810 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2811 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
2814 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
2816 if (!r_refdef.scene.worldmodel->DrawLight)
2819 // set up properties for rendering light onto this entity
2820 RSurf_ActiveWorldEntity();
2821 GL_AlphaTest(false);
2822 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
2823 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
2824 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
2825 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
2826 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2827 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
2829 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, trispvs);
2832 void R_Shadow_DrawEntityLight(entity_render_t *ent)
2834 dp_model_t *model = ent->model;
2835 if (!model->DrawLight)
2838 R_Shadow_SetupEntityLight(ent);
2840 model->DrawLight(ent, model->nummodelsurfaces, model->surfacelist, NULL);
2843 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
2847 int numleafs, numsurfaces;
2848 int *leaflist, *surfacelist;
2849 unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs;
2850 int numlightentities;
2851 int numlightentities_noselfshadow;
2852 int numshadowentities;
2853 int numshadowentities_noselfshadow;
2854 entity_render_t *lightentities[MAX_EDICTS];
2855 entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
2856 entity_render_t *shadowentities[MAX_EDICTS];
2857 entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
2859 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
2860 // skip lights that are basically invisible (color 0 0 0)
2861 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
2864 // loading is done before visibility checks because loading should happen
2865 // all at once at the start of a level, not when it stalls gameplay.
2866 // (especially important to benchmarks)
2868 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2869 R_RTLight_Compile(rtlight);
2871 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
2873 // look up the light style value at this time
2874 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
2875 VectorScale(rtlight->color, f, rtlight->currentcolor);
2877 if (rtlight->selected)
2879 f = 2 + sin(realtime * M_PI * 4.0);
2880 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
2884 // if lightstyle is currently off, don't draw the light
2885 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
2888 // if the light box is offscreen, skip it
2889 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2892 VectorCopy(rtlight->cullmins, rsurface.rtlight_cullmins);
2893 VectorCopy(rtlight->cullmaxs, rsurface.rtlight_cullmaxs);
2895 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2897 // compiled light, world available and can receive realtime lighting
2898 // retrieve leaf information
2899 numleafs = rtlight->static_numleafs;
2900 leaflist = rtlight->static_leaflist;
2901 leafpvs = rtlight->static_leafpvs;
2902 numsurfaces = rtlight->static_numsurfaces;
2903 surfacelist = rtlight->static_surfacelist;
2904 shadowtrispvs = rtlight->static_shadowtrispvs;
2905 lighttrispvs = rtlight->static_lighttrispvs;
2907 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
2909 // dynamic light, world available and can receive realtime lighting
2910 // calculate lit surfaces and leafs
2911 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);
2912 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);
2913 leaflist = r_shadow_buffer_leaflist;
2914 leafpvs = r_shadow_buffer_leafpvs;
2915 surfacelist = r_shadow_buffer_surfacelist;
2916 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
2917 lighttrispvs = r_shadow_buffer_lighttrispvs;
2918 // if the reduced leaf bounds are offscreen, skip it
2919 if (R_CullBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
2930 shadowtrispvs = NULL;
2931 lighttrispvs = NULL;
2933 // check if light is illuminating any visible leafs
2936 for (i = 0;i < numleafs;i++)
2937 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
2942 // set up a scissor rectangle for this light
2943 if (R_Shadow_ScissorForBBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
2946 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
2948 // make a list of lit entities and shadow casting entities
2949 numlightentities = 0;
2950 numlightentities_noselfshadow = 0;
2951 numshadowentities = 0;
2952 numshadowentities_noselfshadow = 0;
2953 // add dynamic entities that are lit by the light
2954 if (r_drawentities.integer)
2956 for (i = 0;i < r_refdef.scene.numentities;i++)
2959 entity_render_t *ent = r_refdef.scene.entities[i];
2961 if (!BoxesOverlap(ent->mins, ent->maxs, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
2963 // skip the object entirely if it is not within the valid
2964 // shadow-casting region (which includes the lit region)
2965 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rsurface.rtlight_numfrustumplanes, rsurface.rtlight_frustumplanes))
2967 if (!(model = ent->model))
2969 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
2971 // this entity wants to receive light, is visible, and is
2972 // inside the light box
2973 // TODO: check if the surfaces in the model can receive light
2974 // so now check if it's in a leaf seen by the light
2975 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))
2977 if (ent->flags & RENDER_NOSELFSHADOW)
2978 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
2980 lightentities[numlightentities++] = ent;
2981 // since it is lit, it probably also casts a shadow...
2982 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2983 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
2984 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
2986 // note: exterior models without the RENDER_NOSELFSHADOW
2987 // flag still create a RENDER_NOSELFSHADOW shadow but
2988 // are lit normally, this means that they are
2989 // self-shadowing but do not shadow other
2990 // RENDER_NOSELFSHADOW entities such as the gun
2991 // (very weird, but keeps the player shadow off the gun)
2992 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
2993 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
2995 shadowentities[numshadowentities++] = ent;
2998 else if (ent->flags & RENDER_SHADOW)
3000 // this entity is not receiving light, but may still need to
3002 // TODO: check if the surfaces in the model can cast shadow
3003 // now check if it is in a leaf seen by the light
3004 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))
3006 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3007 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3008 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3010 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3011 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3013 shadowentities[numshadowentities++] = ent;
3019 // return if there's nothing at all to light
3020 if (!numlightentities && !numsurfaces)
3023 // don't let sound skip if going slow
3024 if (r_refdef.scene.extraupdate)
3027 // make this the active rtlight for rendering purposes
3028 R_Shadow_RenderMode_ActiveLight(rtlight);
3029 // count this light in the r_speeds
3030 r_refdef.stats.lights++;
3032 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3034 // optionally draw visible shape of the shadow volumes
3035 // for performance analysis by level designers
3036 R_Shadow_RenderMode_VisibleShadowVolumes();
3038 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3039 for (i = 0;i < numshadowentities;i++)
3040 R_Shadow_DrawEntityShadow(shadowentities[i]);
3041 for (i = 0;i < numshadowentities_noselfshadow;i++)
3042 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3045 if (gl_stencil && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3047 // draw stencil shadow volumes to mask off pixels that are in shadow
3048 // so that they won't receive lighting
3049 R_Shadow_RenderMode_StencilShadowVolumes(true);
3051 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3052 for (i = 0;i < numshadowentities;i++)
3053 R_Shadow_DrawEntityShadow(shadowentities[i]);
3054 if (numlightentities_noselfshadow)
3056 // draw lighting in the unmasked areas
3057 R_Shadow_RenderMode_Lighting(true, false);
3058 for (i = 0;i < numlightentities_noselfshadow;i++)
3059 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3061 // optionally draw the illuminated areas
3062 // for performance analysis by level designers
3063 if (r_showlighting.integer && r_refdef.view.showdebug)
3065 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
3066 for (i = 0;i < numlightentities_noselfshadow;i++)
3067 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3070 R_Shadow_RenderMode_StencilShadowVolumes(false);
3072 for (i = 0;i < numshadowentities_noselfshadow;i++)
3073 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3075 if (numsurfaces + numlightentities)
3077 // draw lighting in the unmasked areas
3078 R_Shadow_RenderMode_Lighting(true, false);
3080 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3081 for (i = 0;i < numlightentities;i++)
3082 R_Shadow_DrawEntityLight(lightentities[i]);
3084 // optionally draw the illuminated areas
3085 // for performance analysis by level designers
3086 if (r_showlighting.integer && r_refdef.view.showdebug)
3088 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
3090 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3091 for (i = 0;i < numlightentities;i++)
3092 R_Shadow_DrawEntityLight(lightentities[i]);
3098 if (numsurfaces + numlightentities)
3100 // draw lighting in the unmasked areas
3101 R_Shadow_RenderMode_Lighting(false, false);
3103 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3104 for (i = 0;i < numlightentities;i++)
3105 R_Shadow_DrawEntityLight(lightentities[i]);
3106 for (i = 0;i < numlightentities_noselfshadow;i++)
3107 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3109 // optionally draw the illuminated areas
3110 // for performance analysis by level designers
3111 if (r_showlighting.integer && r_refdef.view.showdebug)
3113 R_Shadow_RenderMode_VisibleLighting(false, false);
3115 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3116 for (i = 0;i < numlightentities;i++)
3117 R_Shadow_DrawEntityLight(lightentities[i]);
3118 for (i = 0;i < numlightentities_noselfshadow;i++)
3119 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3125 void R_Shadow_DrawLightSprites(void);
3126 void R_ShadowVolumeLighting(qboolean visible)
3134 if (r_editlights.integer)
3135 R_Shadow_DrawLightSprites();
3137 R_Shadow_RenderMode_Begin();
3139 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3140 if (r_shadow_debuglight.integer >= 0)
3142 lightindex = r_shadow_debuglight.integer;
3143 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3144 if (light && (light->flags & flag))
3145 R_DrawRTLight(&light->rtlight, visible);
3149 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3150 for (lightindex = 0;lightindex < range;lightindex++)
3152 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3153 if (light && (light->flags & flag))
3154 R_DrawRTLight(&light->rtlight, visible);
3157 if (r_refdef.scene.rtdlight)
3158 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3159 R_DrawRTLight(&r_refdef.scene.lights[lnum], visible);
3161 R_Shadow_RenderMode_End();
3164 extern void R_SetupView(qboolean allowwaterclippingplane);
3165 extern cvar_t r_shadows_throwdistance;
3166 void R_DrawModelShadows(void)
3169 float relativethrowdistance;
3170 entity_render_t *ent;
3171 vec3_t relativelightorigin;
3172 vec3_t relativelightdirection;
3173 vec3_t relativeshadowmins, relativeshadowmaxs;
3176 if (!r_drawentities.integer || !gl_stencil)
3180 GL_Scissor(r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
3182 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
3184 if (gl_ext_separatestencil.integer)
3185 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
3186 else if (gl_ext_stenciltwoside.integer)
3187 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
3189 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
3191 R_Shadow_RenderMode_StencilShadowVolumes(true);
3193 for (i = 0;i < r_refdef.scene.numentities;i++)
3195 ent = r_refdef.scene.entities[i];
3196 // cast shadows from anything that is not a submodel of the map
3197 if (ent->model && ent->model->DrawShadowVolume != NULL && !ent->model->brush.submodel && (ent->flags & RENDER_SHADOW))
3199 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
3200 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
3201 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
3202 VectorNegate(ent->modellight_lightdir, relativelightdirection);
3203 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
3204 RSurf_ActiveModelEntity(ent, false, false);
3205 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
3209 // not really the right mode, but this will disable any silly stencil features
3210 R_Shadow_RenderMode_VisibleLighting(true, true);
3212 // vertex coordinates for a quad that covers the screen exactly
3213 vertex3f[0] = 0;vertex3f[1] = 0;vertex3f[2] = 0;
3214 vertex3f[3] = 1;vertex3f[4] = 0;vertex3f[5] = 0;
3215 vertex3f[6] = 1;vertex3f[7] = 1;vertex3f[8] = 0;
3216 vertex3f[9] = 0;vertex3f[10] = 1;vertex3f[11] = 0;
3218 // set up ortho view for rendering this pass
3219 GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
3220 GL_Scissor(r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
3221 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
3222 GL_ScissorTest(true);
3223 R_Mesh_Matrix(&identitymatrix);
3224 R_Mesh_ResetTextureState();
3225 R_Mesh_VertexPointer(vertex3f, 0, 0);
3226 R_Mesh_ColorPointer(NULL, 0, 0);
3228 // set up a 50% darkening blend on shadowed areas
3229 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3230 GL_DepthRange(0, 1);
3231 GL_DepthTest(false);
3232 GL_DepthMask(false);
3233 GL_PolygonOffset(0, 0);CHECKGLERROR
3234 GL_Color(0, 0, 0, 0.5);
3235 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
3236 qglDepthFunc(GL_ALWAYS);CHECKGLERROR
3237 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
3238 qglStencilMask(~0);CHECKGLERROR
3239 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
3240 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
3242 // apply the blend to the shadowed areas
3243 R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
3245 // restoring the perspective view is done by R_RenderScene
3246 //R_SetupView(true);
3248 // restore other state to normal
3249 R_Shadow_RenderMode_End();
3252 void R_DrawCoronas(void)
3255 float cscale, scale;
3260 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
3262 R_Mesh_Matrix(&identitymatrix);
3263 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3264 // FIXME: these traces should scan all render entities instead of cl.world
3265 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3266 for (lightindex = 0;lightindex < range;lightindex++)
3268 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3271 rtlight = &light->rtlight;
3272 if (!(rtlight->flags & flag))
3274 if (rtlight->corona * r_coronas.value <= 0)
3276 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
3278 cscale = rtlight->corona * r_coronas.value* 0.25f;
3279 scale = rtlight->radius * rtlight->coronasizescale;
3280 if (VectorDistance2(rtlight->shadoworigin, r_refdef.view.origin) < 16.0f * 16.0f)
3282 if (CL_Move(r_refdef.view.origin, vec3_origin, vec3_origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
3284 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, rtlight->color[0] * cscale, rtlight->color[1] * cscale, rtlight->color[2] * cscale, 1);
3286 for (i = 0;i < r_refdef.scene.numlights;i++)
3288 rtlight = &r_refdef.scene.lights[i];
3289 if (!(rtlight->flags & flag))
3291 if (rtlight->corona <= 0)
3293 if (VectorDistance2(rtlight->shadoworigin, r_refdef.view.origin) < 32.0f * 32.0f)
3295 if (gl_flashblend.integer)
3297 cscale = rtlight->corona * 1.0f;
3298 scale = rtlight->radius * rtlight->coronasizescale * 2.0f;
3302 cscale = rtlight->corona * r_coronas.value* 0.25f;
3303 scale = rtlight->radius * rtlight->coronasizescale;
3305 if (VectorLength(rtlight->color) * cscale < (1.0f / 256.0f))
3307 if (CL_Move(r_refdef.view.origin, vec3_origin, vec3_origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
3309 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, rtlight->color[0] * cscale, rtlight->color[1] * cscale, rtlight->color[2] * cscale, 1);
3315 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
3316 typedef struct suffixinfo_s
3319 qboolean flipx, flipy, flipdiagonal;
3322 static suffixinfo_t suffix[3][6] =
3325 {"px", false, false, false},
3326 {"nx", false, false, false},
3327 {"py", false, false, false},
3328 {"ny", false, false, false},
3329 {"pz", false, false, false},
3330 {"nz", false, false, false}
3333 {"posx", false, false, false},
3334 {"negx", false, false, false},
3335 {"posy", false, false, false},
3336 {"negy", false, false, false},
3337 {"posz", false, false, false},
3338 {"negz", false, false, false}
3341 {"rt", true, false, true},
3342 {"lf", false, true, true},
3343 {"ft", true, true, false},
3344 {"bk", false, false, false},
3345 {"up", true, false, true},
3346 {"dn", true, false, true}
3350 static int componentorder[4] = {0, 1, 2, 3};
3352 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
3354 int i, j, cubemapsize;
3355 unsigned char *cubemappixels, *image_buffer;
3356 rtexture_t *cubemaptexture;
3358 // must start 0 so the first loadimagepixels has no requested width/height
3360 cubemappixels = NULL;
3361 cubemaptexture = NULL;
3362 // keep trying different suffix groups (posx, px, rt) until one loads
3363 for (j = 0;j < 3 && !cubemappixels;j++)
3365 // load the 6 images in the suffix group
3366 for (i = 0;i < 6;i++)
3368 // generate an image name based on the base and and suffix
3369 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
3371 if ((image_buffer = loadimagepixelsbgra(name, false, false)))
3373 // an image loaded, make sure width and height are equal
3374 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
3376 // if this is the first image to load successfully, allocate the cubemap memory
3377 if (!cubemappixels && image_width >= 1)
3379 cubemapsize = image_width;
3380 // note this clears to black, so unavailable sides are black
3381 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
3383 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
3385 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);
3388 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
3390 Mem_Free(image_buffer);
3394 // if a cubemap loaded, upload it
3397 if (developer_loading.integer)
3398 Con_Printf("loading cubemap \"%s\"\n", basename);
3400 if (!r_shadow_filters_texturepool)
3401 r_shadow_filters_texturepool = R_AllocTexturePool();
3402 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, TEXF_PRECACHE | (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0), NULL);
3403 Mem_Free(cubemappixels);
3407 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
3408 if (developer_loading.integer)
3410 Con_Printf("(tried tried images ");
3411 for (j = 0;j < 3;j++)
3412 for (i = 0;i < 6;i++)
3413 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
3414 Con_Print(" and was unable to find any of them).\n");
3417 return cubemaptexture;
3420 rtexture_t *R_Shadow_Cubemap(const char *basename)
3423 for (i = 0;i < numcubemaps;i++)
3424 if (!strcasecmp(cubemaps[i].basename, basename))
3425 return cubemaps[i].texture ? cubemaps[i].texture : r_texture_whitecube;
3426 if (i >= MAX_CUBEMAPS)
3427 return r_texture_whitecube;
3429 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
3430 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
3431 return cubemaps[i].texture;
3434 void R_Shadow_FreeCubemaps(void)
3437 for (i = 0;i < numcubemaps;i++)
3439 if (developer_loading.integer)
3440 Con_Printf("unloading cubemap \"%s\"\n", cubemaps[i].basename);
3441 if (cubemaps[i].texture)
3442 R_FreeTexture(cubemaps[i].texture);
3446 R_FreeTexturePool(&r_shadow_filters_texturepool);
3449 dlight_t *R_Shadow_NewWorldLight(void)
3451 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
3454 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)
3457 // validate parameters
3458 if (style < 0 || style >= MAX_LIGHTSTYLES)
3460 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
3466 // copy to light properties
3467 VectorCopy(origin, light->origin);
3468 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
3469 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
3470 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
3471 light->color[0] = max(color[0], 0);
3472 light->color[1] = max(color[1], 0);
3473 light->color[2] = max(color[2], 0);
3474 light->radius = max(radius, 0);
3475 light->style = style;
3476 light->shadow = shadowenable;
3477 light->corona = corona;
3478 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
3479 light->coronasizescale = coronasizescale;
3480 light->ambientscale = ambientscale;
3481 light->diffusescale = diffusescale;
3482 light->specularscale = specularscale;
3483 light->flags = flags;
3485 // update renderable light data
3486 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
3487 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);
3490 void R_Shadow_FreeWorldLight(dlight_t *light)
3492 if (r_shadow_selectedlight == light)
3493 r_shadow_selectedlight = NULL;
3494 R_RTLight_Uncompile(&light->rtlight);
3495 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
3498 void R_Shadow_ClearWorldLights(void)
3502 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3503 for (lightindex = 0;lightindex < range;lightindex++)
3505 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3507 R_Shadow_FreeWorldLight(light);
3509 r_shadow_selectedlight = NULL;
3510 R_Shadow_FreeCubemaps();
3513 void R_Shadow_SelectLight(dlight_t *light)
3515 if (r_shadow_selectedlight)
3516 r_shadow_selectedlight->selected = false;
3517 r_shadow_selectedlight = light;
3518 if (r_shadow_selectedlight)
3519 r_shadow_selectedlight->selected = true;
3522 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
3524 // this is never batched (there can be only one)
3525 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);
3528 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
3535 // this is never batched (due to the ent parameter changing every time)
3536 // so numsurfaces == 1 and surfacelist[0] == lightnumber
3537 const dlight_t *light = (dlight_t *)ent;
3540 VectorScale(light->color, intensity, spritecolor);
3541 if (VectorLength(spritecolor) < 0.1732f)
3542 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
3543 if (VectorLength(spritecolor) > 1.0f)
3544 VectorNormalize(spritecolor);
3546 // draw light sprite
3547 if (light->cubemapname[0] && !light->shadow)
3548 pic = r_editlights_sprcubemapnoshadowlight;
3549 else if (light->cubemapname[0])
3550 pic = r_editlights_sprcubemaplight;
3551 else if (!light->shadow)
3552 pic = r_editlights_sprnoshadowlight;
3554 pic = r_editlights_sprlight;
3555 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);
3556 // draw selection sprite if light is selected
3557 if (light->selected)
3558 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);
3559 // VorteX todo: add normalmode/realtime mode light overlay sprites?
3562 void R_Shadow_DrawLightSprites(void)
3566 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3567 for (lightindex = 0;lightindex < range;lightindex++)
3569 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3571 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
3573 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
3576 void R_Shadow_SelectLightInView(void)
3578 float bestrating, rating, temp[3];
3582 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3585 for (lightindex = 0;lightindex < range;lightindex++)
3587 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3590 VectorSubtract(light->origin, r_refdef.view.origin, temp);
3591 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
3594 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
3595 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)
3597 bestrating = rating;
3602 R_Shadow_SelectLight(best);
3605 void R_Shadow_LoadWorldLights(void)
3607 int n, a, style, shadow, flags;
3608 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
3609 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
3610 if (cl.worldmodel == NULL)
3612 Con_Print("No map loaded.\n");
3615 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
3616 strlcat (name, ".rtlights", sizeof (name));
3617 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3627 for (;COM_Parse(t, true) && strcmp(
3628 if (COM_Parse(t, true))
3630 if (com_token[0] == '!')
3633 origin[0] = atof(com_token+1);
3636 origin[0] = atof(com_token);
3641 while (*s && *s != '\n' && *s != '\r')
3647 // check for modifier flags
3654 #if _MSC_VER >= 1400
3655 #define sscanf sscanf_s
3657 cubemapname[sizeof(cubemapname)-1] = 0;
3658 #if MAX_QPATH != 128
3659 #error update this code if MAX_QPATH changes
3661 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
3662 #if _MSC_VER >= 1400
3663 , sizeof(cubemapname)
3665 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
3668 flags = LIGHTFLAG_REALTIMEMODE;
3676 coronasizescale = 0.25f;
3678 VectorClear(angles);
3681 if (a < 9 || !strcmp(cubemapname, "\"\""))
3683 // remove quotes on cubemapname
3684 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
3687 namelen = strlen(cubemapname) - 2;
3688 memmove(cubemapname, cubemapname + 1, namelen);
3689 cubemapname[namelen] = '\0';
3693 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);
3696 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3704 Con_Printf("invalid rtlights file \"%s\"\n", name);
3705 Mem_Free(lightsstring);
3709 void R_Shadow_SaveWorldLights(void)
3713 size_t bufchars, bufmaxchars;
3715 char name[MAX_QPATH];
3716 char line[MAX_INPUTLINE];
3717 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
3718 // I hate lines which are 3 times my screen size :( --blub
3721 if (cl.worldmodel == NULL)
3723 Con_Print("No map loaded.\n");
3726 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
3727 strlcat (name, ".rtlights", sizeof (name));
3728 bufchars = bufmaxchars = 0;
3730 for (lightindex = 0;lightindex < range;lightindex++)
3732 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3735 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3736 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);
3737 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3738 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]);
3740 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);
3741 if (bufchars + strlen(line) > bufmaxchars)
3743 bufmaxchars = bufchars + strlen(line) + 2048;
3745 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
3749 memcpy(buf, oldbuf, bufchars);
3755 memcpy(buf + bufchars, line, strlen(line));
3756 bufchars += strlen(line);
3760 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
3765 void R_Shadow_LoadLightsFile(void)
3768 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3769 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3770 if (cl.worldmodel == NULL)
3772 Con_Print("No map loaded.\n");
3775 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
3776 strlcat (name, ".lights", sizeof (name));
3777 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3785 while (*s && *s != '\n' && *s != '\r')
3791 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);
3795 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);
3798 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3799 radius = bound(15, radius, 4096);
3800 VectorScale(color, (2.0f / (8388608.0f)), color);
3801 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3809 Con_Printf("invalid lights file \"%s\"\n", name);
3810 Mem_Free(lightsstring);
3814 // tyrlite/hmap2 light types in the delay field
3815 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3817 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3819 int entnum, style, islight, skin, pflags, effects, type, n;
3822 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3823 char key[256], value[MAX_INPUTLINE];
3825 if (cl.worldmodel == NULL)
3827 Con_Print("No map loaded.\n");
3830 // try to load a .ent file first
3831 FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
3832 strlcat (key, ".ent", sizeof (key));
3833 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
3834 // and if that is not found, fall back to the bsp file entity string
3836 data = cl.worldmodel->brush.entities;
3839 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
3841 type = LIGHTTYPE_MINUSX;
3842 origin[0] = origin[1] = origin[2] = 0;
3843 originhack[0] = originhack[1] = originhack[2] = 0;
3844 angles[0] = angles[1] = angles[2] = 0;
3845 color[0] = color[1] = color[2] = 1;
3846 light[0] = light[1] = light[2] = 1;light[3] = 300;
3847 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3857 if (!COM_ParseToken_Simple(&data, false, false))
3859 if (com_token[0] == '}')
3860 break; // end of entity
3861 if (com_token[0] == '_')
3862 strlcpy(key, com_token + 1, sizeof(key));
3864 strlcpy(key, com_token, sizeof(key));
3865 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3866 key[strlen(key)-1] = 0;
3867 if (!COM_ParseToken_Simple(&data, false, false))
3869 strlcpy(value, com_token, sizeof(value));
3871 // now that we have the key pair worked out...
3872 if (!strcmp("light", key))
3874 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3878 light[0] = vec[0] * (1.0f / 256.0f);
3879 light[1] = vec[0] * (1.0f / 256.0f);
3880 light[2] = vec[0] * (1.0f / 256.0f);
3886 light[0] = vec[0] * (1.0f / 255.0f);
3887 light[1] = vec[1] * (1.0f / 255.0f);
3888 light[2] = vec[2] * (1.0f / 255.0f);
3892 else if (!strcmp("delay", key))
3894 else if (!strcmp("origin", key))
3895 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3896 else if (!strcmp("angle", key))
3897 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3898 else if (!strcmp("angles", key))
3899 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3900 else if (!strcmp("color", key))
3901 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3902 else if (!strcmp("wait", key))
3903 fadescale = atof(value);
3904 else if (!strcmp("classname", key))
3906 if (!strncmp(value, "light", 5))
3909 if (!strcmp(value, "light_fluoro"))
3914 overridecolor[0] = 1;
3915 overridecolor[1] = 1;
3916 overridecolor[2] = 1;
3918 if (!strcmp(value, "light_fluorospark"))
3923 overridecolor[0] = 1;
3924 overridecolor[1] = 1;
3925 overridecolor[2] = 1;
3927 if (!strcmp(value, "light_globe"))
3932 overridecolor[0] = 1;
3933 overridecolor[1] = 0.8;
3934 overridecolor[2] = 0.4;
3936 if (!strcmp(value, "light_flame_large_yellow"))
3941 overridecolor[0] = 1;
3942 overridecolor[1] = 0.5;
3943 overridecolor[2] = 0.1;
3945 if (!strcmp(value, "light_flame_small_yellow"))
3950 overridecolor[0] = 1;
3951 overridecolor[1] = 0.5;
3952 overridecolor[2] = 0.1;
3954 if (!strcmp(value, "light_torch_small_white"))
3959 overridecolor[0] = 1;
3960 overridecolor[1] = 0.5;
3961 overridecolor[2] = 0.1;
3963 if (!strcmp(value, "light_torch_small_walltorch"))
3968 overridecolor[0] = 1;
3969 overridecolor[1] = 0.5;
3970 overridecolor[2] = 0.1;
3974 else if (!strcmp("style", key))
3975 style = atoi(value);
3976 else if (!strcmp("skin", key))
3977 skin = (int)atof(value);
3978 else if (!strcmp("pflags", key))
3979 pflags = (int)atof(value);
3980 else if (!strcmp("effects", key))
3981 effects = (int)atof(value);
3982 else if (cl.worldmodel->type == mod_brushq3)
3984 if (!strcmp("scale", key))
3985 lightscale = atof(value);
3986 if (!strcmp("fade", key))
3987 fadescale = atof(value);
3992 if (lightscale <= 0)
3996 if (color[0] == color[1] && color[0] == color[2])
3998 color[0] *= overridecolor[0];
3999 color[1] *= overridecolor[1];
4000 color[2] *= overridecolor[2];
4002 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
4003 color[0] = color[0] * light[0];
4004 color[1] = color[1] * light[1];
4005 color[2] = color[2] * light[2];
4008 case LIGHTTYPE_MINUSX:
4010 case LIGHTTYPE_RECIPX:
4012 VectorScale(color, (1.0f / 16.0f), color);
4014 case LIGHTTYPE_RECIPXX:
4016 VectorScale(color, (1.0f / 16.0f), color);
4019 case LIGHTTYPE_NONE:
4023 case LIGHTTYPE_MINUSXX:
4026 VectorAdd(origin, originhack, origin);
4028 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);
4031 Mem_Free(entfiledata);
4035 void R_Shadow_SetCursorLocationForView(void)
4038 vec3_t dest, endpos;
4040 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
4041 trace = CL_Move(r_refdef.view.origin, vec3_origin, vec3_origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
4042 if (trace.fraction < 1)
4044 dist = trace.fraction * r_editlights_cursordistance.value;
4045 push = r_editlights_cursorpushback.value;
4049 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
4050 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
4054 VectorClear( endpos );
4056 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4057 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4058 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4061 void R_Shadow_UpdateWorldLightSelection(void)
4063 if (r_editlights.integer)
4065 R_Shadow_SetCursorLocationForView();
4066 R_Shadow_SelectLightInView();
4069 R_Shadow_SelectLight(NULL);
4072 void R_Shadow_EditLights_Clear_f(void)
4074 R_Shadow_ClearWorldLights();
4077 void R_Shadow_EditLights_Reload_f(void)
4081 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
4082 R_Shadow_ClearWorldLights();
4083 R_Shadow_LoadWorldLights();
4084 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
4086 R_Shadow_LoadLightsFile();
4087 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
4088 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
4092 void R_Shadow_EditLights_Save_f(void)
4096 R_Shadow_SaveWorldLights();
4099 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
4101 R_Shadow_ClearWorldLights();
4102 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
4105 void R_Shadow_EditLights_ImportLightsFile_f(void)
4107 R_Shadow_ClearWorldLights();
4108 R_Shadow_LoadLightsFile();
4111 void R_Shadow_EditLights_Spawn_f(void)
4114 if (!r_editlights.integer)
4116 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4119 if (Cmd_Argc() != 1)
4121 Con_Print("r_editlights_spawn does not take parameters\n");
4124 color[0] = color[1] = color[2] = 1;
4125 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
4128 void R_Shadow_EditLights_Edit_f(void)
4130 vec3_t origin, angles, color;
4131 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
4132 int style, shadows, flags, normalmode, realtimemode;
4133 char cubemapname[MAX_INPUTLINE];
4134 if (!r_editlights.integer)
4136 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4139 if (!r_shadow_selectedlight)
4141 Con_Print("No selected light.\n");
4144 VectorCopy(r_shadow_selectedlight->origin, origin);
4145 VectorCopy(r_shadow_selectedlight->angles, angles);
4146 VectorCopy(r_shadow_selectedlight->color, color);
4147 radius = r_shadow_selectedlight->radius;
4148 style = r_shadow_selectedlight->style;
4149 if (r_shadow_selectedlight->cubemapname)
4150 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
4153 shadows = r_shadow_selectedlight->shadow;
4154 corona = r_shadow_selectedlight->corona;
4155 coronasizescale = r_shadow_selectedlight->coronasizescale;
4156 ambientscale = r_shadow_selectedlight->ambientscale;
4157 diffusescale = r_shadow_selectedlight->diffusescale;
4158 specularscale = r_shadow_selectedlight->specularscale;
4159 flags = r_shadow_selectedlight->flags;
4160 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
4161 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
4162 if (!strcmp(Cmd_Argv(1), "origin"))
4164 if (Cmd_Argc() != 5)
4166 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
4169 origin[0] = atof(Cmd_Argv(2));
4170 origin[1] = atof(Cmd_Argv(3));
4171 origin[2] = atof(Cmd_Argv(4));
4173 else if (!strcmp(Cmd_Argv(1), "originx"))
4175 if (Cmd_Argc() != 3)
4177 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4180 origin[0] = atof(Cmd_Argv(2));
4182 else if (!strcmp(Cmd_Argv(1), "originy"))
4184 if (Cmd_Argc() != 3)
4186 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4189 origin[1] = atof(Cmd_Argv(2));
4191 else if (!strcmp(Cmd_Argv(1), "originz"))
4193 if (Cmd_Argc() != 3)
4195 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4198 origin[2] = atof(Cmd_Argv(2));
4200 else if (!strcmp(Cmd_Argv(1), "move"))
4202 if (Cmd_Argc() != 5)
4204 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
4207 origin[0] += atof(Cmd_Argv(2));
4208 origin[1] += atof(Cmd_Argv(3));
4209 origin[2] += atof(Cmd_Argv(4));
4211 else if (!strcmp(Cmd_Argv(1), "movex"))
4213 if (Cmd_Argc() != 3)
4215 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4218 origin[0] += atof(Cmd_Argv(2));
4220 else if (!strcmp(Cmd_Argv(1), "movey"))
4222 if (Cmd_Argc() != 3)
4224 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4227 origin[1] += atof(Cmd_Argv(2));
4229 else if (!strcmp(Cmd_Argv(1), "movez"))
4231 if (Cmd_Argc() != 3)
4233 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4236 origin[2] += atof(Cmd_Argv(2));
4238 else if (!strcmp(Cmd_Argv(1), "angles"))
4240 if (Cmd_Argc() != 5)
4242 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
4245 angles[0] = atof(Cmd_Argv(2));
4246 angles[1] = atof(Cmd_Argv(3));
4247 angles[2] = atof(Cmd_Argv(4));
4249 else if (!strcmp(Cmd_Argv(1), "anglesx"))
4251 if (Cmd_Argc() != 3)
4253 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4256 angles[0] = atof(Cmd_Argv(2));
4258 else if (!strcmp(Cmd_Argv(1), "anglesy"))
4260 if (Cmd_Argc() != 3)
4262 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4265 angles[1] = atof(Cmd_Argv(2));
4267 else if (!strcmp(Cmd_Argv(1), "anglesz"))
4269 if (Cmd_Argc() != 3)
4271 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4274 angles[2] = atof(Cmd_Argv(2));
4276 else if (!strcmp(Cmd_Argv(1), "color"))
4278 if (Cmd_Argc() != 5)
4280 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
4283 color[0] = atof(Cmd_Argv(2));
4284 color[1] = atof(Cmd_Argv(3));
4285 color[2] = atof(Cmd_Argv(4));
4287 else if (!strcmp(Cmd_Argv(1), "radius"))
4289 if (Cmd_Argc() != 3)
4291 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4294 radius = atof(Cmd_Argv(2));
4296 else if (!strcmp(Cmd_Argv(1), "colorscale"))
4298 if (Cmd_Argc() == 3)
4300 double scale = atof(Cmd_Argv(2));
4307 if (Cmd_Argc() != 5)
4309 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
4312 color[0] *= atof(Cmd_Argv(2));
4313 color[1] *= atof(Cmd_Argv(3));
4314 color[2] *= atof(Cmd_Argv(4));
4317 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
4319 if (Cmd_Argc() != 3)
4321 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4324 radius *= atof(Cmd_Argv(2));
4326 else if (!strcmp(Cmd_Argv(1), "style"))
4328 if (Cmd_Argc() != 3)
4330 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4333 style = atoi(Cmd_Argv(2));
4335 else if (!strcmp(Cmd_Argv(1), "cubemap"))
4339 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4342 if (Cmd_Argc() == 3)
4343 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
4347 else if (!strcmp(Cmd_Argv(1), "shadows"))
4349 if (Cmd_Argc() != 3)
4351 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4354 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4356 else if (!strcmp(Cmd_Argv(1), "corona"))
4358 if (Cmd_Argc() != 3)
4360 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4363 corona = atof(Cmd_Argv(2));
4365 else if (!strcmp(Cmd_Argv(1), "coronasize"))
4367 if (Cmd_Argc() != 3)
4369 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4372 coronasizescale = atof(Cmd_Argv(2));
4374 else if (!strcmp(Cmd_Argv(1), "ambient"))
4376 if (Cmd_Argc() != 3)
4378 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4381 ambientscale = atof(Cmd_Argv(2));
4383 else if (!strcmp(Cmd_Argv(1), "diffuse"))
4385 if (Cmd_Argc() != 3)
4387 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4390 diffusescale = atof(Cmd_Argv(2));
4392 else if (!strcmp(Cmd_Argv(1), "specular"))
4394 if (Cmd_Argc() != 3)
4396 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4399 specularscale = atof(Cmd_Argv(2));
4401 else if (!strcmp(Cmd_Argv(1), "normalmode"))
4403 if (Cmd_Argc() != 3)
4405 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4408 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4410 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
4412 if (Cmd_Argc() != 3)
4414 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4417 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4421 Con_Print("usage: r_editlights_edit [property] [value]\n");
4422 Con_Print("Selected light's properties:\n");
4423 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
4424 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
4425 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
4426 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
4427 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
4428 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
4429 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
4430 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
4431 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
4432 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
4433 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
4434 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
4435 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
4436 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
4439 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
4440 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4443 void R_Shadow_EditLights_EditAll_f(void)
4449 if (!r_editlights.integer)
4451 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
4455 // EditLights doesn't seem to have a "remove" command or something so:
4456 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4457 for (lightindex = 0;lightindex < range;lightindex++)
4459 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4462 R_Shadow_SelectLight(light);
4463 R_Shadow_EditLights_Edit_f();
4467 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
4469 int lightnumber, lightcount;
4470 size_t lightindex, range;
4474 if (!r_editlights.integer)
4476 x = vid_conwidth.value - 240;
4478 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
4481 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4482 for (lightindex = 0;lightindex < range;lightindex++)
4484 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4487 if (light == r_shadow_selectedlight)
4488 lightnumber = lightindex;
4491 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;
4492 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;
4494 if (r_shadow_selectedlight == NULL)
4496 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;
4497 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;
4498 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;
4499 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;
4500 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;
4501 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;
4502 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;
4503 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;
4504 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;
4505 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;
4506 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;
4507 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;
4508 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;
4509 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;
4510 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;
4513 void R_Shadow_EditLights_ToggleShadow_f(void)
4515 if (!r_editlights.integer)
4517 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4520 if (!r_shadow_selectedlight)
4522 Con_Print("No selected light.\n");
4525 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);
4528 void R_Shadow_EditLights_ToggleCorona_f(void)
4530 if (!r_editlights.integer)
4532 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4535 if (!r_shadow_selectedlight)
4537 Con_Print("No selected light.\n");
4540 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);
4543 void R_Shadow_EditLights_Remove_f(void)
4545 if (!r_editlights.integer)
4547 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
4550 if (!r_shadow_selectedlight)
4552 Con_Print("No selected light.\n");
4555 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
4556 r_shadow_selectedlight = NULL;
4559 void R_Shadow_EditLights_Help_f(void)
4562 "Documentation on r_editlights system:\n"
4564 "r_editlights : enable/disable editing mode\n"
4565 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
4566 "r_editlights_cursorpushback : push back cursor this far from surface\n"
4567 "r_editlights_cursorpushoff : push cursor off surface this far\n"
4568 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
4569 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
4571 "r_editlights_help : this help\n"
4572 "r_editlights_clear : remove all lights\n"
4573 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
4574 "r_editlights_save : save to .rtlights file\n"
4575 "r_editlights_spawn : create a light with default settings\n"
4576 "r_editlights_edit command : edit selected light - more documentation below\n"
4577 "r_editlights_remove : remove selected light\n"
4578 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
4579 "r_editlights_importlightentitiesfrommap : reload light entities\n"
4580 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
4582 "origin x y z : set light location\n"
4583 "originx x: set x component of light location\n"
4584 "originy y: set y component of light location\n"
4585 "originz z: set z component of light location\n"
4586 "move x y z : adjust light location\n"
4587 "movex x: adjust x component of light location\n"
4588 "movey y: adjust y component of light location\n"
4589 "movez z: adjust z component of light location\n"
4590 "angles x y z : set light angles\n"
4591 "anglesx x: set x component of light angles\n"
4592 "anglesy y: set y component of light angles\n"
4593 "anglesz z: set z component of light angles\n"
4594 "color r g b : set color of light (can be brighter than 1 1 1)\n"
4595 "radius radius : set radius (size) of light\n"
4596 "colorscale grey : multiply color of light (1 does nothing)\n"
4597 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
4598 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
4599 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
4600 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
4601 "cubemap basename : set filter cubemap of light (not yet supported)\n"
4602 "shadows 1/0 : turn on/off shadows\n"
4603 "corona n : set corona intensity\n"
4604 "coronasize n : set corona size (0-1)\n"
4605 "ambient n : set ambient intensity (0-1)\n"
4606 "diffuse n : set diffuse intensity (0-1)\n"
4607 "specular n : set specular intensity (0-1)\n"
4608 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
4609 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
4610 "<nothing> : print light properties to console\n"
4614 void R_Shadow_EditLights_CopyInfo_f(void)
4616 if (!r_editlights.integer)
4618 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
4621 if (!r_shadow_selectedlight)
4623 Con_Print("No selected light.\n");
4626 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
4627 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
4628 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
4629 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
4630 if (r_shadow_selectedlight->cubemapname)
4631 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
4633 r_shadow_bufferlight.cubemapname[0] = 0;
4634 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
4635 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
4636 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
4637 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
4638 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
4639 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
4640 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
4643 void R_Shadow_EditLights_PasteInfo_f(void)
4645 if (!r_editlights.integer)
4647 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
4650 if (!r_shadow_selectedlight)
4652 Con_Print("No selected light.\n");
4655 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);
4658 void R_Shadow_EditLights_Init(void)
4660 Cvar_RegisterVariable(&r_editlights);
4661 Cvar_RegisterVariable(&r_editlights_cursordistance);
4662 Cvar_RegisterVariable(&r_editlights_cursorpushback);
4663 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
4664 Cvar_RegisterVariable(&r_editlights_cursorgrid);
4665 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
4666 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
4667 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
4668 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)");
4669 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
4670 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
4671 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
4672 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)");
4673 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
4674 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
4675 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
4676 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
4677 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
4678 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
4679 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)");
4685 =============================================================================
4689 =============================================================================
4692 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
4694 VectorClear(diffusecolor);
4695 VectorClear(diffusenormal);
4697 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
4699 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient * (2.0f / 128.0f);
4700 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
4703 VectorSet(ambientcolor, 1, 1, 1);
4710 for (i = 0;i < r_refdef.scene.numlights;i++)
4712 light = &r_refdef.scene.lights[i];
4713 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
4714 f = 1 - VectorLength2(v);
4715 if (f > 0 && CL_Move(p, vec3_origin, vec3_origin, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
4716 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);