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 (r_refdef.worldmodel && strncmp(r_refdef.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_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)
825 if (projectdistance < 0.1)
827 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
830 if (!numverts || !nummarktris)
832 // make sure shadowelements is big enough for this volume
833 if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
834 R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
835 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
836 r_refdef.stats.lights_dynamicshadowtriangles += tris;
837 R_Shadow_RenderVolume(outverts, tris, shadowvertex3f, shadowelements);
840 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)
846 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
848 tend = firsttriangle + numtris;
849 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
851 // surface box entirely inside light box, no box cull
852 if (projectdirection)
854 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
856 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
857 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
858 shadowmarklist[numshadowmark++] = t;
863 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
864 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
865 shadowmarklist[numshadowmark++] = t;
870 // surface box not entirely inside light box, cull each triangle
871 if (projectdirection)
873 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
875 v[0] = invertex3f + e[0] * 3;
876 v[1] = invertex3f + e[1] * 3;
877 v[2] = invertex3f + e[2] * 3;
878 TriangleNormal(v[0], v[1], v[2], normal);
879 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
880 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
881 shadowmarklist[numshadowmark++] = t;
886 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
888 v[0] = invertex3f + e[0] * 3;
889 v[1] = invertex3f + e[1] * 3;
890 v[2] = invertex3f + e[2] * 3;
891 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
892 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
893 shadowmarklist[numshadowmark++] = t;
899 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
901 if (r_shadow_compilingrtlight)
903 // if we're compiling an rtlight, capture the mesh
904 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
907 r_refdef.stats.lights_shadowtriangles += numtriangles;
909 R_Mesh_VertexPointer(vertex3f, 0, 0);
910 GL_LockArrays(0, numvertices);
911 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
913 // decrement stencil if backface is behind depthbuffer
914 GL_CullFace(r_refdef.view.cullface_front);
915 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
916 R_Mesh_Draw(0, numvertices, numtriangles, element3i, 0, 0);
917 // increment stencil if frontface is behind depthbuffer
918 GL_CullFace(r_refdef.view.cullface_back);
919 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
921 R_Mesh_Draw(0, numvertices, numtriangles, element3i, 0, 0);
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", true);
999 r_editlights_sprlight = Draw_CachePic("gfx/editlights/light", true);
1000 r_editlights_sprnoshadowlight = Draw_CachePic("gfx/editlights/noshadow", true);
1001 r_editlights_sprcubemaplight = Draw_CachePic("gfx/editlights/cubemaplight", true);
1002 r_editlights_sprcubemapnoshadowlight = Draw_CachePic("gfx/editlights/cubemapnoshadowlight", true);
1003 r_editlights_sprselection = Draw_CachePic("gfx/editlights/selection", true);
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(rtlight_t *rtlight)
1056 rsurface.rtlight = rtlight;
1059 void R_Shadow_RenderMode_Reset(void)
1062 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1064 qglUseProgramObjectARB(0);CHECKGLERROR
1066 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
1068 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1070 R_Mesh_ColorPointer(NULL, 0, 0);
1071 R_Mesh_ResetTextureState();
1072 GL_DepthRange(0, 1);
1074 GL_DepthMask(false);
1075 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1076 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1077 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1078 qglStencilMask(~0);CHECKGLERROR
1079 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1080 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1081 GL_CullFace(r_refdef.view.cullface_back);
1082 GL_Color(1, 1, 1, 1);
1083 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1084 GL_BlendFunc(GL_ONE, GL_ZERO);
1087 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean clearstencil)
1090 R_Shadow_RenderMode_Reset();
1091 GL_ColorMask(0, 0, 0, 0);
1092 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1093 qglDepthFunc(GL_LESS);CHECKGLERROR
1094 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1095 r_shadow_rendermode = r_shadow_shadowingrendermode;
1096 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SEPARATESTENCIL)
1098 GL_CullFace(GL_NONE);
1099 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1100 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1102 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
1104 GL_CullFace(GL_NONE);
1105 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1106 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1107 qglStencilMask(~0);CHECKGLERROR
1108 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1109 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1110 qglStencilMask(~0);CHECKGLERROR
1111 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1114 GL_Clear(GL_STENCIL_BUFFER_BIT);
1115 r_refdef.stats.lights_clears++;
1118 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent)
1121 R_Shadow_RenderMode_Reset();
1122 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1125 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1129 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1130 // only draw light where this geometry was already rendered AND the
1131 // stencil is 128 (values other than this mean shadow)
1132 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1134 r_shadow_rendermode = r_shadow_lightingrendermode;
1135 // do global setup needed for the chosen lighting mode
1136 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1138 R_Mesh_TexBind(0, R_GetTexture(r_texture_blanknormalmap)); // normal
1139 R_Mesh_TexBind(1, R_GetTexture(r_texture_white)); // diffuse
1140 R_Mesh_TexBind(2, R_GetTexture(r_texture_white)); // gloss
1141 R_Mesh_TexBindCubeMap(3, R_GetTexture(rsurface.rtlight->currentcubemap)); // light filter
1142 R_Mesh_TexBind(4, R_GetTexture(r_texture_fogattenuation)); // fog
1143 R_Mesh_TexBind(5, R_GetTexture(r_texture_white)); // pants
1144 R_Mesh_TexBind(6, R_GetTexture(r_texture_white)); // shirt
1145 R_Mesh_TexBind(7, R_GetTexture(r_texture_white)); // lightmap
1146 R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap)); // deluxemap
1147 R_Mesh_TexBind(9, R_GetTexture(r_texture_black)); // glow
1148 //R_Mesh_TexMatrix(3, rsurface.entitytolight); // light filter matrix
1149 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1150 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
1155 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
1158 R_Shadow_RenderMode_Reset();
1159 GL_BlendFunc(GL_ONE, GL_ONE);
1160 GL_DepthRange(0, 1);
1161 GL_DepthTest(r_showshadowvolumes.integer < 2);
1162 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
1163 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1164 GL_CullFace(GL_NONE);
1165 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
1168 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
1171 R_Shadow_RenderMode_Reset();
1172 GL_BlendFunc(GL_ONE, GL_ONE);
1173 GL_DepthRange(0, 1);
1174 GL_DepthTest(r_showlighting.integer < 2);
1175 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
1178 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1182 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1183 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1185 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
1188 void R_Shadow_RenderMode_End(void)
1191 R_Shadow_RenderMode_Reset();
1192 R_Shadow_RenderMode_ActiveLight(NULL);
1194 GL_Scissor(r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
1195 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1198 int bboxedges[12][2] =
1217 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1219 int i, ix1, iy1, ix2, iy2;
1220 float x1, y1, x2, y2;
1222 float vertex[20][3];
1231 if (!r_shadow_scissor.integer)
1234 // if view is inside the light box, just say yes it's visible
1235 if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
1237 GL_Scissor(r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
1241 x1 = y1 = x2 = y2 = 0;
1243 // transform all corners that are infront of the nearclip plane
1244 VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
1245 plane4f[3] = r_refdef.view.frustum[4].dist;
1247 for (i = 0;i < 8;i++)
1249 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
1250 dist[i] = DotProduct4(corner[i], plane4f);
1251 sign[i] = dist[i] > 0;
1254 VectorCopy(corner[i], vertex[numvertices]);
1258 // if some points are behind the nearclip, add clipped edge points to make
1259 // sure that the scissor boundary is complete
1260 if (numvertices > 0 && numvertices < 8)
1262 // add clipped edge points
1263 for (i = 0;i < 12;i++)
1265 j = bboxedges[i][0];
1266 k = bboxedges[i][1];
1267 if (sign[j] != sign[k])
1269 f = dist[j] / (dist[j] - dist[k]);
1270 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
1276 // if we have no points to check, the light is behind the view plane
1280 // if we have some points to transform, check what screen area is covered
1281 x1 = y1 = x2 = y2 = 0;
1283 //Con_Printf("%i vertices to transform...\n", numvertices);
1284 for (i = 0;i < numvertices;i++)
1286 VectorCopy(vertex[i], v);
1287 GL_TransformToScreen(v, v2);
1288 //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]);
1291 if (x1 > v2[0]) x1 = v2[0];
1292 if (x2 < v2[0]) x2 = v2[0];
1293 if (y1 > v2[1]) y1 = v2[1];
1294 if (y2 < v2[1]) y2 = v2[1];
1303 // now convert the scissor rectangle to integer screen coordinates
1304 ix1 = (int)(x1 - 1.0f);
1305 iy1 = (int)(y1 - 1.0f);
1306 ix2 = (int)(x2 + 1.0f);
1307 iy2 = (int)(y2 + 1.0f);
1308 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1310 // clamp it to the screen
1311 if (ix1 < r_refdef.view.x) ix1 = r_refdef.view.x;
1312 if (iy1 < r_refdef.view.y) iy1 = r_refdef.view.y;
1313 if (ix2 > r_refdef.view.x + r_refdef.view.width) ix2 = r_refdef.view.x + r_refdef.view.width;
1314 if (iy2 > r_refdef.view.y + r_refdef.view.height) iy2 = r_refdef.view.y + r_refdef.view.height;
1316 // if it is inside out, it's not visible
1317 if (ix2 <= ix1 || iy2 <= iy1)
1320 // the light area is visible, set up the scissor rectangle
1321 GL_Scissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1322 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);CHECKGLERROR
1323 //qglEnable(GL_SCISSOR_TEST);CHECKGLERROR
1324 r_refdef.stats.lights_scissored++;
1328 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
1330 float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1331 float *normal3f = rsurface.normal3f + 3 * firstvertex;
1332 float *color4f = rsurface.array_color4f + 4 * firstvertex;
1333 float dist, dot, distintensity, shadeintensity, v[3], n[3];
1334 if (r_textureunits.integer >= 3)
1336 if (VectorLength2(diffusecolor) > 0)
1338 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1340 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1341 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1342 if ((dot = DotProduct(n, v)) < 0)
1344 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1345 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
1348 VectorCopy(ambientcolor, color4f);
1349 if (r_refdef.fogenabled)
1352 f = FogPoint_Model(vertex3f);
1353 VectorScale(color4f, f, color4f);
1360 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1362 VectorCopy(ambientcolor, color4f);
1363 if (r_refdef.fogenabled)
1366 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1367 f = FogPoint_Model(vertex3f);
1368 VectorScale(color4f, f, color4f);
1374 else if (r_textureunits.integer >= 2)
1376 if (VectorLength2(diffusecolor) > 0)
1378 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1380 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1381 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1383 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1384 if ((dot = DotProduct(n, v)) < 0)
1386 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1387 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1388 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1389 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1393 color4f[0] = ambientcolor[0] * distintensity;
1394 color4f[1] = ambientcolor[1] * distintensity;
1395 color4f[2] = ambientcolor[2] * distintensity;
1397 if (r_refdef.fogenabled)
1400 f = FogPoint_Model(vertex3f);
1401 VectorScale(color4f, f, color4f);
1405 VectorClear(color4f);
1411 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1413 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1414 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1416 color4f[0] = ambientcolor[0] * distintensity;
1417 color4f[1] = ambientcolor[1] * distintensity;
1418 color4f[2] = ambientcolor[2] * distintensity;
1419 if (r_refdef.fogenabled)
1422 f = FogPoint_Model(vertex3f);
1423 VectorScale(color4f, f, color4f);
1427 VectorClear(color4f);
1434 if (VectorLength2(diffusecolor) > 0)
1436 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1438 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1439 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1441 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
1442 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1443 if ((dot = DotProduct(n, v)) < 0)
1445 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1446 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1447 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1448 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1452 color4f[0] = ambientcolor[0] * distintensity;
1453 color4f[1] = ambientcolor[1] * distintensity;
1454 color4f[2] = ambientcolor[2] * distintensity;
1456 if (r_refdef.fogenabled)
1459 f = FogPoint_Model(vertex3f);
1460 VectorScale(color4f, f, color4f);
1464 VectorClear(color4f);
1470 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1472 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1473 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1475 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
1476 color4f[0] = ambientcolor[0] * distintensity;
1477 color4f[1] = ambientcolor[1] * distintensity;
1478 color4f[2] = ambientcolor[2] * distintensity;
1479 if (r_refdef.fogenabled)
1482 f = FogPoint_Model(vertex3f);
1483 VectorScale(color4f, f, color4f);
1487 VectorClear(color4f);
1494 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1496 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
1499 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
1500 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1501 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
1502 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
1503 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
1505 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1507 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
1508 // the cubemap normalizes this for us
1509 out3f[0] = DotProduct(svector3f, lightdir);
1510 out3f[1] = DotProduct(tvector3f, lightdir);
1511 out3f[2] = DotProduct(normal3f, lightdir);
1515 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
1518 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
1519 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1520 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
1521 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
1522 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
1523 float lightdir[3], eyedir[3], halfdir[3];
1524 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1526 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
1527 VectorNormalize(lightdir);
1528 VectorSubtract(rsurface.modelorg, vertex3f, eyedir);
1529 VectorNormalize(eyedir);
1530 VectorAdd(lightdir, eyedir, halfdir);
1531 // the cubemap normalizes this for us
1532 out3f[0] = DotProduct(svector3f, halfdir);
1533 out3f[1] = DotProduct(tvector3f, halfdir);
1534 out3f[2] = DotProduct(normal3f, halfdir);
1538 static void R_Shadow_RenderLighting_VisibleLighting(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset, 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)
1540 // used to display how many times a surface is lit for level design purposes
1541 GL_Color(0.1 * r_refdef.view.colorscale, 0.025 * r_refdef.view.colorscale, 0, 1);
1542 R_Mesh_ColorPointer(NULL, 0, 0);
1543 R_Mesh_ResetTextureState();
1544 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1547 static void R_Shadow_RenderLighting_Light_GLSL(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset, 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)
1549 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
1550 R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
1551 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
1552 R_Mesh_TexBind(0, R_GetTexture(rsurface.texture->currentskinframe->nmap));
1553 R_Mesh_TexBind(1, R_GetTexture(rsurface.texture->basetexture));
1554 R_Mesh_TexBind(2, R_GetTexture(rsurface.texture->glosstexture));
1555 R_Mesh_TexBindCubeMap(3, R_GetTexture(rsurface.rtlight->currentcubemap));
1556 R_Mesh_TexBind(4, R_GetTexture(r_texture_fogattenuation));
1557 R_Mesh_TexBind(5, R_GetTexture(rsurface.texture->currentskinframe->pants));
1558 R_Mesh_TexBind(6, R_GetTexture(rsurface.texture->currentskinframe->shirt));
1559 R_Mesh_TexBind(10, R_GetTexture(r_shadow_attenuationgradienttexture));
1560 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
1561 R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
1562 R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
1563 R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
1564 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1566 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1568 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1569 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1571 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1575 static void R_Shadow_RenderLighting_Light_Dot3_Finalize(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset, float r, float g, float b)
1577 // shared final code for all the dot3 layers
1579 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
1580 for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
1582 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
1583 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1587 static void R_Shadow_RenderLighting_Light_Dot3_AmbientPass(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset, const vec3_t lightcolorbase, rtexture_t *basetexture, float colorscale)
1590 // colorscale accounts for how much we multiply the brightness
1593 // mult is how many times the final pass of the lighting will be
1594 // performed to get more brightness than otherwise possible.
1596 // Limit mult to 64 for sanity sake.
1598 if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1600 // 3 3D combine path (Geforce3, Radeon 8500)
1601 memset(&m, 0, sizeof(m));
1602 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1603 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1604 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1605 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1606 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1607 m.tex[1] = R_GetTexture(basetexture);
1608 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
1609 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
1610 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
1611 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
1612 m.texcubemap[2] = R_GetTexture(rsurface.rtlight->currentcubemap);
1613 m.pointer_texcoord3f[2] = rsurface.vertex3f;
1614 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
1615 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
1616 m.texmatrix[2] = rsurface.entitytolight;
1617 GL_BlendFunc(GL_ONE, GL_ONE);
1619 else if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1621 // 2 3D combine path (Geforce3, original Radeon)
1622 memset(&m, 0, sizeof(m));
1623 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1624 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1625 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1626 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1627 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1628 m.tex[1] = R_GetTexture(basetexture);
1629 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
1630 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
1631 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
1632 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
1633 GL_BlendFunc(GL_ONE, GL_ONE);
1635 else if (r_textureunits.integer >= 4 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
1637 // 4 2D combine path (Geforce3, Radeon 8500)
1638 memset(&m, 0, sizeof(m));
1639 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1640 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1641 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1642 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1643 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1644 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1645 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1646 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1647 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1648 m.texmatrix[1] = rsurface.entitytoattenuationz;
1649 m.tex[2] = R_GetTexture(basetexture);
1650 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
1651 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
1652 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
1653 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
1654 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1656 m.texcubemap[3] = R_GetTexture(rsurface.rtlight->currentcubemap);
1657 m.pointer_texcoord3f[3] = rsurface.vertex3f;
1658 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
1659 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
1660 m.texmatrix[3] = rsurface.entitytolight;
1662 GL_BlendFunc(GL_ONE, GL_ONE);
1664 else if (r_textureunits.integer >= 3 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
1666 // 3 2D combine path (Geforce3, original Radeon)
1667 memset(&m, 0, sizeof(m));
1668 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1669 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1670 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1671 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1672 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1673 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1674 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1675 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1676 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1677 m.texmatrix[1] = rsurface.entitytoattenuationz;
1678 m.tex[2] = R_GetTexture(basetexture);
1679 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
1680 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
1681 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
1682 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
1683 GL_BlendFunc(GL_ONE, GL_ONE);
1687 // 2/2/2 2D combine path (any dot3 card)
1688 memset(&m, 0, sizeof(m));
1689 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1690 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1691 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1692 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1693 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1694 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1695 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1696 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1697 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1698 m.texmatrix[1] = rsurface.entitytoattenuationz;
1699 R_Mesh_TextureState(&m);
1700 GL_ColorMask(0,0,0,1);
1701 GL_BlendFunc(GL_ONE, GL_ZERO);
1702 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1705 memset(&m, 0, sizeof(m));
1706 m.tex[0] = R_GetTexture(basetexture);
1707 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1708 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1709 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1710 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1711 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1713 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1714 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1715 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1716 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1717 m.texmatrix[1] = rsurface.entitytolight;
1719 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1721 // this final code is shared
1722 R_Mesh_TextureState(&m);
1723 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1726 static void R_Shadow_RenderLighting_Light_Dot3_DiffusePass(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset, const vec3_t lightcolorbase, rtexture_t *basetexture, rtexture_t *normalmaptexture, float colorscale)
1729 // colorscale accounts for how much we multiply the brightness
1732 // mult is how many times the final pass of the lighting will be
1733 // performed to get more brightness than otherwise possible.
1735 // Limit mult to 64 for sanity sake.
1737 // generate normalization cubemap texcoords
1738 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
1739 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1741 // 3/2 3D combine path (Geforce3, Radeon 8500)
1742 memset(&m, 0, sizeof(m));
1743 m.tex[0] = R_GetTexture(normalmaptexture);
1744 m.texcombinergb[0] = GL_REPLACE;
1745 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1746 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1747 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1748 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1749 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1750 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1751 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1752 m.pointer_texcoord_bufferobject[1] = 0;
1753 m.pointer_texcoord_bufferoffset[1] = 0;
1754 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1755 m.pointer_texcoord3f[2] = rsurface.vertex3f;
1756 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
1757 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
1758 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
1759 R_Mesh_TextureState(&m);
1760 GL_ColorMask(0,0,0,1);
1761 GL_BlendFunc(GL_ONE, GL_ZERO);
1762 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1765 memset(&m, 0, sizeof(m));
1766 m.tex[0] = R_GetTexture(basetexture);
1767 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1768 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1769 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1770 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1771 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1773 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1774 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1775 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1776 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1777 m.texmatrix[1] = rsurface.entitytolight;
1779 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1781 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
1783 // 1/2/2 3D combine path (original Radeon)
1784 memset(&m, 0, sizeof(m));
1785 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1786 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1787 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1788 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1789 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1790 R_Mesh_TextureState(&m);
1791 GL_ColorMask(0,0,0,1);
1792 GL_BlendFunc(GL_ONE, GL_ZERO);
1793 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1796 memset(&m, 0, sizeof(m));
1797 m.tex[0] = R_GetTexture(normalmaptexture);
1798 m.texcombinergb[0] = GL_REPLACE;
1799 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1800 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1801 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1802 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1803 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1804 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1805 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1806 m.pointer_texcoord_bufferobject[1] = 0;
1807 m.pointer_texcoord_bufferoffset[1] = 0;
1808 R_Mesh_TextureState(&m);
1809 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1810 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1813 memset(&m, 0, sizeof(m));
1814 m.tex[0] = R_GetTexture(basetexture);
1815 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1816 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1817 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1818 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1819 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1821 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1822 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1823 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1824 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1825 m.texmatrix[1] = rsurface.entitytolight;
1827 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1829 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
1831 // 2/2 3D combine path (original Radeon)
1832 memset(&m, 0, sizeof(m));
1833 m.tex[0] = R_GetTexture(normalmaptexture);
1834 m.texcombinergb[0] = GL_REPLACE;
1835 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1836 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1837 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1838 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1839 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1840 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1841 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1842 m.pointer_texcoord_bufferobject[1] = 0;
1843 m.pointer_texcoord_bufferoffset[1] = 0;
1844 R_Mesh_TextureState(&m);
1845 GL_ColorMask(0,0,0,1);
1846 GL_BlendFunc(GL_ONE, GL_ZERO);
1847 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1850 memset(&m, 0, sizeof(m));
1851 m.tex[0] = R_GetTexture(basetexture);
1852 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1853 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1854 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1855 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1856 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1857 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1858 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1859 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1860 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
1861 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1863 else if (r_textureunits.integer >= 4)
1865 // 4/2 2D combine path (Geforce3, Radeon 8500)
1866 memset(&m, 0, sizeof(m));
1867 m.tex[0] = R_GetTexture(normalmaptexture);
1868 m.texcombinergb[0] = GL_REPLACE;
1869 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1870 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1871 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1872 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1873 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1874 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1875 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1876 m.pointer_texcoord_bufferobject[1] = 0;
1877 m.pointer_texcoord_bufferoffset[1] = 0;
1878 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1879 m.pointer_texcoord3f[2] = rsurface.vertex3f;
1880 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
1881 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
1882 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
1883 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1884 m.pointer_texcoord3f[3] = rsurface.vertex3f;
1885 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
1886 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
1887 m.texmatrix[3] = rsurface.entitytoattenuationz;
1888 R_Mesh_TextureState(&m);
1889 GL_ColorMask(0,0,0,1);
1890 GL_BlendFunc(GL_ONE, GL_ZERO);
1891 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1894 memset(&m, 0, sizeof(m));
1895 m.tex[0] = R_GetTexture(basetexture);
1896 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1897 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1898 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1899 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1900 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1902 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1903 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1904 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1905 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1906 m.texmatrix[1] = rsurface.entitytolight;
1908 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1912 // 2/2/2 2D combine path (any dot3 card)
1913 memset(&m, 0, sizeof(m));
1914 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1915 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1916 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1917 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1918 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1919 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1920 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1921 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1922 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1923 m.texmatrix[1] = rsurface.entitytoattenuationz;
1924 R_Mesh_TextureState(&m);
1925 GL_ColorMask(0,0,0,1);
1926 GL_BlendFunc(GL_ONE, GL_ZERO);
1927 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1930 memset(&m, 0, sizeof(m));
1931 m.tex[0] = R_GetTexture(normalmaptexture);
1932 m.texcombinergb[0] = GL_REPLACE;
1933 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1934 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1935 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1936 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1937 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1938 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1939 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1940 m.pointer_texcoord_bufferobject[1] = 0;
1941 m.pointer_texcoord_bufferoffset[1] = 0;
1942 R_Mesh_TextureState(&m);
1943 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1944 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1947 memset(&m, 0, sizeof(m));
1948 m.tex[0] = R_GetTexture(basetexture);
1949 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1950 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1951 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1952 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1953 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1955 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1956 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1957 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1958 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1959 m.texmatrix[1] = rsurface.entitytolight;
1961 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1963 // this final code is shared
1964 R_Mesh_TextureState(&m);
1965 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1968 static void R_Shadow_RenderLighting_Light_Dot3_SpecularPass(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset, const vec3_t lightcolorbase, rtexture_t *glosstexture, rtexture_t *normalmaptexture, float colorscale)
1970 float glossexponent;
1972 // FIXME: detect blendsquare!
1973 //if (!gl_support_blendsquare)
1976 // generate normalization cubemap texcoords
1977 R_Shadow_GenTexCoords_Specular_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
1978 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
1980 // 2/0/0/1/2 3D combine blendsquare path
1981 memset(&m, 0, sizeof(m));
1982 m.tex[0] = R_GetTexture(normalmaptexture);
1983 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1984 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1985 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1986 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1987 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1988 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1989 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1990 m.pointer_texcoord_bufferobject[1] = 0;
1991 m.pointer_texcoord_bufferoffset[1] = 0;
1992 R_Mesh_TextureState(&m);
1993 GL_ColorMask(0,0,0,1);
1994 // this squares the result
1995 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1996 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1998 // second and third pass
1999 R_Mesh_ResetTextureState();
2000 // square alpha in framebuffer a few times to make it shiny
2001 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2002 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2003 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2006 memset(&m, 0, sizeof(m));
2007 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2008 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2009 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2010 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2011 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2012 R_Mesh_TextureState(&m);
2013 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2014 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2017 memset(&m, 0, sizeof(m));
2018 m.tex[0] = R_GetTexture(glosstexture);
2019 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2020 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2021 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2022 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2023 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2025 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2026 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2027 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2028 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2029 m.texmatrix[1] = rsurface.entitytolight;
2031 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2033 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
2035 // 2/0/0/2 3D combine blendsquare path
2036 memset(&m, 0, sizeof(m));
2037 m.tex[0] = R_GetTexture(normalmaptexture);
2038 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2039 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2040 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2041 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2042 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2043 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2044 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2045 m.pointer_texcoord_bufferobject[1] = 0;
2046 m.pointer_texcoord_bufferoffset[1] = 0;
2047 R_Mesh_TextureState(&m);
2048 GL_ColorMask(0,0,0,1);
2049 // this squares the result
2050 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2051 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2053 // second and third pass
2054 R_Mesh_ResetTextureState();
2055 // square alpha in framebuffer a few times to make it shiny
2056 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2057 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2058 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2061 memset(&m, 0, sizeof(m));
2062 m.tex[0] = R_GetTexture(glosstexture);
2063 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2064 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2065 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2066 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2067 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2068 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2069 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2070 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2071 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2072 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2076 // 2/0/0/2/2 2D combine blendsquare path
2077 memset(&m, 0, sizeof(m));
2078 m.tex[0] = R_GetTexture(normalmaptexture);
2079 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2080 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2081 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2082 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2083 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2084 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2085 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2086 m.pointer_texcoord_bufferobject[1] = 0;
2087 m.pointer_texcoord_bufferoffset[1] = 0;
2088 R_Mesh_TextureState(&m);
2089 GL_ColorMask(0,0,0,1);
2090 // this squares the result
2091 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2092 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2094 // second and third pass
2095 R_Mesh_ResetTextureState();
2096 // square alpha in framebuffer a few times to make it shiny
2097 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2098 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2099 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2102 memset(&m, 0, sizeof(m));
2103 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2104 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2105 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2106 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2107 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2108 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2109 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2110 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2111 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2112 m.texmatrix[1] = rsurface.entitytoattenuationz;
2113 R_Mesh_TextureState(&m);
2114 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2115 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2118 memset(&m, 0, sizeof(m));
2119 m.tex[0] = R_GetTexture(glosstexture);
2120 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2121 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2122 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2123 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2124 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2126 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2127 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2128 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2129 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2130 m.texmatrix[1] = rsurface.entitytolight;
2132 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2134 // this final code is shared
2135 R_Mesh_TextureState(&m);
2136 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
2139 static void R_Shadow_RenderLighting_Light_Dot3(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset, 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)
2141 // ARB path (any Geforce, any Radeon)
2142 qboolean doambient = ambientscale > 0;
2143 qboolean dodiffuse = diffusescale > 0;
2144 qboolean dospecular = specularscale > 0;
2145 if (!doambient && !dodiffuse && !dospecular)
2147 R_Mesh_ColorPointer(NULL, 0, 0);
2149 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, basetexture, ambientscale * r_refdef.view.colorscale);
2151 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, basetexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2155 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorpants, pantstexture, ambientscale * r_refdef.view.colorscale);
2157 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorpants, pantstexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2162 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorshirt, shirttexture, ambientscale * r_refdef.view.colorscale);
2164 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorshirt, shirttexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2167 R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_refdef.view.colorscale);
2170 void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset, vec3_t diffusecolor2, vec3_t ambientcolor2)
2177 int newnumtriangles;
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 >= (int)(sizeof(newelements)/sizeof(float[3])))
2220 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, newnumtriangles, newelements, 0, 0);
2221 newnumtriangles = 0;
2227 if (newnumtriangles >= 1)
2229 // if all triangles are included, use the original array to take advantage of the bufferobject if possible
2230 if (newnumtriangles == numtriangles)
2231 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2233 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, newnumtriangles, newelements, 0, 0);
2236 // if we couldn't find any lit triangles, exit early
2239 // now reduce the intensity for the next overbright pass
2240 // we have to clamp to 0 here incase the drivers have improper
2241 // handling of negative colors
2242 // (some old drivers even have improper handling of >1 color)
2244 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2246 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2248 c[0] = max(0, c[0] - 1);
2249 c[1] = max(0, c[1] - 1);
2250 c[2] = max(0, c[2] - 1);
2262 static void R_Shadow_RenderLighting_Light_Vertex(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset, 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)
2264 // OpenGL 1.1 path (anything)
2265 float ambientcolorbase[3], diffusecolorbase[3];
2266 float ambientcolorpants[3], diffusecolorpants[3];
2267 float ambientcolorshirt[3], diffusecolorshirt[3];
2269 VectorScale(lightcolorbase, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorbase);
2270 VectorScale(lightcolorbase, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorbase);
2271 VectorScale(lightcolorpants, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorpants);
2272 VectorScale(lightcolorpants, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorpants);
2273 VectorScale(lightcolorshirt, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorshirt);
2274 VectorScale(lightcolorshirt, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorshirt);
2275 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2276 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
2277 memset(&m, 0, sizeof(m));
2278 m.tex[0] = R_GetTexture(basetexture);
2279 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2280 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2281 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2282 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2283 if (r_textureunits.integer >= 2)
2286 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2287 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2288 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2289 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2290 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2291 if (r_textureunits.integer >= 3)
2293 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
2294 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2295 m.texmatrix[2] = rsurface.entitytoattenuationz;
2296 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2297 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2298 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2301 R_Mesh_TextureState(&m);
2302 //R_Mesh_TexBind(0, R_GetTexture(basetexture));
2303 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, diffusecolorbase, ambientcolorbase);
2306 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
2307 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, diffusecolorpants, ambientcolorpants);
2311 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
2312 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, diffusecolorshirt, ambientcolorshirt);
2316 extern cvar_t gl_lightmaps;
2317 void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset)
2319 float ambientscale, diffusescale, specularscale;
2320 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
2322 // calculate colors to render this texture with
2323 lightcolorbase[0] = rsurface.rtlight->currentcolor[0] * rsurface.texture->dlightcolor[0];
2324 lightcolorbase[1] = rsurface.rtlight->currentcolor[1] * rsurface.texture->dlightcolor[1];
2325 lightcolorbase[2] = rsurface.rtlight->currentcolor[2] * rsurface.texture->dlightcolor[2];
2326 ambientscale = rsurface.rtlight->ambientscale;
2327 diffusescale = rsurface.rtlight->diffusescale;
2328 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2329 if (!r_shadow_usenormalmap.integer)
2331 ambientscale += 1.0f * diffusescale;
2335 if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
2337 RSurf_SetupDepthAndCulling();
2338 nmap = rsurface.texture->currentskinframe->nmap;
2339 if (gl_lightmaps.integer)
2340 nmap = r_texture_blanknormalmap;
2341 if (rsurface.texture->colormapping && !gl_lightmaps.integer)
2343 qboolean dopants = rsurface.texture->currentskinframe->pants != NULL && VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f);
2344 qboolean doshirt = rsurface.texture->currentskinframe->shirt != NULL && VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f);
2347 lightcolorpants[0] = lightcolorbase[0] * rsurface.colormap_pantscolor[0];
2348 lightcolorpants[1] = lightcolorbase[1] * rsurface.colormap_pantscolor[1];
2349 lightcolorpants[2] = lightcolorbase[2] * rsurface.colormap_pantscolor[2];
2352 VectorClear(lightcolorpants);
2355 lightcolorshirt[0] = lightcolorbase[0] * rsurface.colormap_shirtcolor[0];
2356 lightcolorshirt[1] = lightcolorbase[1] * rsurface.colormap_shirtcolor[1];
2357 lightcolorshirt[2] = lightcolorbase[2] * rsurface.colormap_shirtcolor[2];
2360 VectorClear(lightcolorshirt);
2361 switch (r_shadow_rendermode)
2363 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2364 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2365 R_Shadow_RenderLighting_VisibleLighting(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, 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_GLSL:
2368 R_Shadow_RenderLighting_Light_GLSL(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface.texture->basetexture, rsurface.texture->currentskinframe->pants, rsurface.texture->currentskinframe->shirt, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, dopants, doshirt);
2370 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2371 R_Shadow_RenderLighting_Light_Dot3(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface.texture->basetexture, rsurface.texture->currentskinframe->pants, rsurface.texture->currentskinframe->shirt, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, dopants, doshirt);
2373 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2374 R_Shadow_RenderLighting_Light_Vertex(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface.texture->basetexture, rsurface.texture->currentskinframe->pants, rsurface.texture->currentskinframe->shirt, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, dopants, doshirt);
2377 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2383 switch (r_shadow_rendermode)
2385 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2386 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2387 R_Shadow_RenderLighting_VisibleLighting(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, 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_GLSL:
2390 R_Shadow_RenderLighting_Light_GLSL(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, vec3_origin, vec3_origin, rsurface.texture->basetexture, r_texture_black, r_texture_black, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, false, false);
2392 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2393 R_Shadow_RenderLighting_Light_Dot3(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, vec3_origin, vec3_origin, rsurface.texture->basetexture, r_texture_black, r_texture_black, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, false, false);
2395 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2396 R_Shadow_RenderLighting_Light_Vertex(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, vec3_origin, vec3_origin, rsurface.texture->basetexture, r_texture_black, r_texture_black, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, false, false);
2399 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2405 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)
2407 matrix4x4_t tempmatrix = *matrix;
2408 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2410 // if this light has been compiled before, free the associated data
2411 R_RTLight_Uncompile(rtlight);
2413 // clear it completely to avoid any lingering data
2414 memset(rtlight, 0, sizeof(*rtlight));
2416 // copy the properties
2417 rtlight->matrix_lighttoworld = tempmatrix;
2418 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2419 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2420 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2421 VectorCopy(color, rtlight->color);
2422 rtlight->cubemapname[0] = 0;
2423 if (cubemapname && cubemapname[0])
2424 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2425 rtlight->shadow = shadow;
2426 rtlight->corona = corona;
2427 rtlight->style = style;
2428 rtlight->isstatic = isstatic;
2429 rtlight->coronasizescale = coronasizescale;
2430 rtlight->ambientscale = ambientscale;
2431 rtlight->diffusescale = diffusescale;
2432 rtlight->specularscale = specularscale;
2433 rtlight->flags = flags;
2435 // compute derived data
2436 //rtlight->cullradius = rtlight->radius;
2437 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2438 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2439 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2440 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2441 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2442 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2443 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2446 // compiles rtlight geometry
2447 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2448 void R_RTLight_Compile(rtlight_t *rtlight)
2451 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2452 int lighttris, shadowtris, shadowmeshes, shadowmeshtris;
2453 entity_render_t *ent = r_refdef.worldentity;
2454 model_t *model = r_refdef.worldmodel;
2455 unsigned char *data;
2457 // compile the light
2458 rtlight->compiled = true;
2459 rtlight->static_numleafs = 0;
2460 rtlight->static_numleafpvsbytes = 0;
2461 rtlight->static_leaflist = NULL;
2462 rtlight->static_leafpvs = NULL;
2463 rtlight->static_numsurfaces = 0;
2464 rtlight->static_surfacelist = NULL;
2465 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2466 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2467 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2468 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2469 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2470 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2472 if (model && model->GetLightInfo)
2474 // this variable must be set for the CompileShadowVolume code
2475 r_shadow_compilingrtlight = rtlight;
2476 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);
2477 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);
2478 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2479 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
2480 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
2481 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
2482 rtlight->static_numsurfaces = numsurfaces;
2483 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2484 rtlight->static_numleafs = numleafs;
2485 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2486 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2487 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2488 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
2489 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
2490 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
2491 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
2492 if (rtlight->static_numsurfaces)
2493 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2494 if (rtlight->static_numleafs)
2495 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2496 if (rtlight->static_numleafpvsbytes)
2497 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2498 if (rtlight->static_numshadowtrispvsbytes)
2499 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
2500 if (rtlight->static_numlighttrispvsbytes)
2501 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
2502 if (model->CompileShadowVolume && rtlight->shadow)
2503 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2504 // now we're done compiling the rtlight
2505 r_shadow_compilingrtlight = NULL;
2509 // use smallest available cullradius - box radius or light radius
2510 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2511 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2515 if (rtlight->static_meshchain_shadow)
2518 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2521 shadowmeshtris += mesh->numtriangles;
2526 if (rtlight->static_numlighttrispvsbytes)
2527 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
2528 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
2532 if (rtlight->static_numlighttrispvsbytes)
2533 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
2534 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
2537 if (developer.integer >= 10)
2538 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);
2541 void R_RTLight_Uncompile(rtlight_t *rtlight)
2543 if (rtlight->compiled)
2545 if (rtlight->static_meshchain_shadow)
2546 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2547 rtlight->static_meshchain_shadow = NULL;
2548 // these allocations are grouped
2549 if (rtlight->static_surfacelist)
2550 Mem_Free(rtlight->static_surfacelist);
2551 rtlight->static_numleafs = 0;
2552 rtlight->static_numleafpvsbytes = 0;
2553 rtlight->static_leaflist = NULL;
2554 rtlight->static_leafpvs = NULL;
2555 rtlight->static_numsurfaces = 0;
2556 rtlight->static_surfacelist = NULL;
2557 rtlight->static_numshadowtrispvsbytes = 0;
2558 rtlight->static_shadowtrispvs = NULL;
2559 rtlight->static_numlighttrispvsbytes = 0;
2560 rtlight->static_lighttrispvs = NULL;
2561 rtlight->compiled = false;
2565 void R_Shadow_UncompileWorldLights(void)
2569 for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
2571 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2574 R_RTLight_Uncompile(&light->rtlight);
2578 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
2582 // reset the count of frustum planes
2583 // see rsurface.rtlight_frustumplanes definition for how much this array
2585 rsurface.rtlight_numfrustumplanes = 0;
2587 // haven't implemented a culling path for ortho rendering
2588 if (!r_refdef.view.useperspective)
2590 // check if the light is on screen and copy the 4 planes if it is
2591 for (i = 0;i < 4;i++)
2592 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
2595 for (i = 0;i < 4;i++)
2596 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
2601 // generate a deformed frustum that includes the light origin, this is
2602 // used to cull shadow casting surfaces that can not possibly cast a
2603 // shadow onto the visible light-receiving surfaces, which can be a
2606 // if the light origin is onscreen the result will be 4 planes exactly
2607 // if the light origin is offscreen on only one axis the result will
2608 // be exactly 5 planes (split-side case)
2609 // if the light origin is offscreen on two axes the result will be
2610 // exactly 4 planes (stretched corner case)
2611 for (i = 0;i < 4;i++)
2613 // quickly reject standard frustum planes that put the light
2614 // origin outside the frustum
2615 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
2618 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
2620 // if all the standard frustum planes were accepted, the light is onscreen
2621 // otherwise we need to generate some more planes below...
2622 if (rsurface.rtlight_numfrustumplanes < 4)
2624 // at least one of the stock frustum planes failed, so we need to
2625 // create one or two custom planes to enclose the light origin
2626 for (i = 0;i < 4;i++)
2628 // create a plane using the view origin and light origin, and a
2629 // single point from the frustum corner set
2630 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
2631 VectorNormalize(plane.normal);
2632 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
2633 // see if this plane is backwards and flip it if so
2634 for (j = 0;j < 4;j++)
2635 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
2639 VectorNegate(plane.normal, plane.normal);
2641 // flipped plane, test again to see if it is now valid
2642 for (j = 0;j < 4;j++)
2643 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
2645 // if the plane is still not valid, then it is dividing the
2646 // frustum and has to be rejected
2650 // we have created a valid plane, compute extra info
2651 PlaneClassify(&plane);
2653 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
2655 // if we've found 5 frustum planes then we have constructed a
2656 // proper split-side case and do not need to keep searching for
2657 // planes to enclose the light origin
2658 if (rsurface.rtlight_numfrustumplanes == 5)
2666 for (i = 0;i < rsurface.rtlight_numfrustumplanes;i++)
2668 plane = rsurface.rtlight_frustumplanes[i];
2669 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));
2674 // now add the light-space box planes if the light box is rotated, as any
2675 // caster outside the oriented light box is irrelevant (even if it passed
2676 // the worldspace light box, which is axial)
2677 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
2679 for (i = 0;i < 6;i++)
2683 v[i >> 1] = (i & 1) ? -1 : 1;
2684 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
2685 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
2686 plane.dist = VectorNormalizeLength(plane.normal);
2687 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
2688 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
2694 // add the world-space reduced box planes
2695 for (i = 0;i < 6;i++)
2697 VectorClear(plane.normal);
2698 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
2699 plane.dist = (i & 1) ? -rsurface.rtlight_cullmaxs[i >> 1] : rsurface.rtlight_cullmins[i >> 1];
2700 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
2709 // reduce all plane distances to tightly fit the rtlight cull box, which
2711 VectorSet(points[0], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
2712 VectorSet(points[1], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
2713 VectorSet(points[2], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
2714 VectorSet(points[3], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
2715 VectorSet(points[4], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
2716 VectorSet(points[5], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
2717 VectorSet(points[6], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
2718 VectorSet(points[7], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
2719 oldnum = rsurface.rtlight_numfrustumplanes;
2720 rsurface.rtlight_numfrustumplanes = 0;
2721 for (j = 0;j < oldnum;j++)
2723 // find the nearest point on the box to this plane
2724 bestdist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[0]);
2725 for (i = 1;i < 8;i++)
2727 dist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[i]);
2728 if (bestdist > dist)
2731 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);
2732 // if the nearest point is near or behind the plane, we want this
2733 // plane, otherwise the plane is useless as it won't cull anything
2734 if (rsurface.rtlight_frustumplanes[j].dist < bestdist + 0.03125)
2736 PlaneClassify(&rsurface.rtlight_frustumplanes[j]);
2737 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = rsurface.rtlight_frustumplanes[j];
2744 void R_Shadow_DrawWorldShadow(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
2746 RSurf_ActiveWorldEntity();
2747 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2751 for (mesh = rsurface.rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2753 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
2754 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
2755 GL_LockArrays(0, mesh->numverts);
2756 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
2758 // decrement stencil if backface is behind depthbuffer
2759 GL_CullFace(r_refdef.view.cullface_front);
2760 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2761 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->ebo, 0);
2762 // increment stencil if frontface is behind depthbuffer
2763 GL_CullFace(r_refdef.view.cullface_back);
2764 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2766 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->ebo, 0);
2767 GL_LockArrays(0, 0);
2771 else if (numsurfaces && r_refdef.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
2774 int surfacelistindex;
2775 msurface_t *surface;
2776 R_Shadow_PrepareShadowMark(r_refdef.worldmodel->brush.shadowmesh->numtriangles);
2777 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
2779 surface = r_refdef.worldmodel->data_surfaces + surfacelist[surfacelistindex];
2780 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
2781 if (CHECKPVSBIT(trispvs, t))
2782 shadowmarklist[numshadowmark++] = t;
2784 R_Shadow_VolumeFromList(r_refdef.worldmodel->brush.shadowmesh->numverts, r_refdef.worldmodel->brush.shadowmesh->numtriangles, r_refdef.worldmodel->brush.shadowmesh->vertex3f, r_refdef.worldmodel->brush.shadowmesh->element3i, r_refdef.worldmodel->brush.shadowmesh->neighbor3i, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius + r_refdef.worldmodel->radius*2 + r_shadow_projectdistance.value, numshadowmark, shadowmarklist);
2786 else if (numsurfaces)
2787 r_refdef.worldmodel->DrawShadowVolume(r_refdef.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
2790 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
2792 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
2793 vec_t relativeshadowradius;
2794 RSurf_ActiveModelEntity(ent, false, false);
2795 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
2796 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
2797 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
2798 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
2799 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
2800 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
2801 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
2802 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
2803 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2806 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
2808 // set up properties for rendering light onto this entity
2809 RSurf_ActiveModelEntity(ent, true, true);
2810 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
2811 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
2812 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
2813 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
2814 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2815 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
2818 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
2820 if (!r_refdef.worldmodel->DrawLight)
2823 // set up properties for rendering light onto this entity
2824 RSurf_ActiveWorldEntity();
2825 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
2826 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
2827 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
2828 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
2829 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2830 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
2832 r_refdef.worldmodel->DrawLight(r_refdef.worldentity, numsurfaces, surfacelist, trispvs);
2835 void R_Shadow_DrawEntityLight(entity_render_t *ent)
2837 model_t *model = ent->model;
2838 if (!model->DrawLight)
2841 R_Shadow_SetupEntityLight(ent);
2843 model->DrawLight(ent, model->nummodelsurfaces, model->surfacelist, NULL);
2846 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
2850 int numleafs, numsurfaces;
2851 int *leaflist, *surfacelist;
2852 unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs;
2853 int numlightentities;
2854 int numlightentities_noselfshadow;
2855 int numshadowentities;
2856 int numshadowentities_noselfshadow;
2857 entity_render_t *lightentities[MAX_EDICTS];
2858 entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
2859 entity_render_t *shadowentities[MAX_EDICTS];
2860 entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
2862 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
2863 // skip lights that are basically invisible (color 0 0 0)
2864 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
2867 // loading is done before visibility checks because loading should happen
2868 // all at once at the start of a level, not when it stalls gameplay.
2869 // (especially important to benchmarks)
2871 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2872 R_RTLight_Compile(rtlight);
2874 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
2876 // look up the light style value at this time
2877 f = (rtlight->style >= 0 ? r_refdef.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
2878 VectorScale(rtlight->color, f, rtlight->currentcolor);
2880 if (rtlight->selected)
2882 f = 2 + sin(realtime * M_PI * 4.0);
2883 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
2887 // if lightstyle is currently off, don't draw the light
2888 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
2891 // if the light box is offscreen, skip it
2892 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2895 VectorCopy(rtlight->cullmins, rsurface.rtlight_cullmins);
2896 VectorCopy(rtlight->cullmaxs, rsurface.rtlight_cullmaxs);
2898 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2900 // compiled light, world available and can receive realtime lighting
2901 // retrieve leaf information
2902 numleafs = rtlight->static_numleafs;
2903 leaflist = rtlight->static_leaflist;
2904 leafpvs = rtlight->static_leafpvs;
2905 numsurfaces = rtlight->static_numsurfaces;
2906 surfacelist = rtlight->static_surfacelist;
2907 shadowtrispvs = rtlight->static_shadowtrispvs;
2908 lighttrispvs = rtlight->static_lighttrispvs;
2910 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2912 // dynamic light, world available and can receive realtime lighting
2913 // calculate lit surfaces and leafs
2914 R_Shadow_EnlargeLeafSurfaceTrisBuffer(r_refdef.worldmodel->brush.num_leafs, r_refdef.worldmodel->num_surfaces, r_refdef.worldmodel->brush.shadowmesh ? r_refdef.worldmodel->brush.shadowmesh->numtriangles : r_refdef.worldmodel->surfmesh.num_triangles, r_refdef.worldmodel->surfmesh.num_triangles);
2915 r_refdef.worldmodel->GetLightInfo(r_refdef.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);
2916 leaflist = r_shadow_buffer_leaflist;
2917 leafpvs = r_shadow_buffer_leafpvs;
2918 surfacelist = r_shadow_buffer_surfacelist;
2919 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
2920 lighttrispvs = r_shadow_buffer_lighttrispvs;
2921 // if the reduced leaf bounds are offscreen, skip it
2922 if (R_CullBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
2933 shadowtrispvs = NULL;
2934 lighttrispvs = NULL;
2936 // check if light is illuminating any visible leafs
2939 for (i = 0;i < numleafs;i++)
2940 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
2945 // set up a scissor rectangle for this light
2946 if (R_Shadow_ScissorForBBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
2949 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
2951 // make a list of lit entities and shadow casting entities
2952 numlightentities = 0;
2953 numlightentities_noselfshadow = 0;
2954 numshadowentities = 0;
2955 numshadowentities_noselfshadow = 0;
2956 // add dynamic entities that are lit by the light
2957 if (r_drawentities.integer)
2959 for (i = 0;i < r_refdef.numentities;i++)
2962 entity_render_t *ent = r_refdef.entities[i];
2964 if (!BoxesOverlap(ent->mins, ent->maxs, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
2966 // skip the object entirely if it is not within the valid
2967 // shadow-casting region (which includes the lit region)
2968 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rsurface.rtlight_numfrustumplanes, rsurface.rtlight_frustumplanes))
2970 if (!(model = ent->model))
2972 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
2974 // this entity wants to receive light, is visible, and is
2975 // inside the light box
2976 // TODO: check if the surfaces in the model can receive light
2977 // so now check if it's in a leaf seen by the light
2978 if (r_refdef.worldmodel && r_refdef.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs))
2980 if (ent->flags & RENDER_NOSELFSHADOW)
2981 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
2983 lightentities[numlightentities++] = ent;
2984 // since it is lit, it probably also casts a shadow...
2985 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2986 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
2987 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
2989 // note: exterior models without the RENDER_NOSELFSHADOW
2990 // flag still create a RENDER_NOSELFSHADOW shadow but
2991 // are lit normally, this means that they are
2992 // self-shadowing but do not shadow other
2993 // RENDER_NOSELFSHADOW entities such as the gun
2994 // (very weird, but keeps the player shadow off the gun)
2995 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
2996 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
2998 shadowentities[numshadowentities++] = ent;
3001 else if (ent->flags & RENDER_SHADOW)
3003 // this entity is not receiving light, but may still need to
3005 // TODO: check if the surfaces in the model can cast shadow
3006 // now check if it is in a leaf seen by the light
3007 if (r_refdef.worldmodel && r_refdef.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs))
3009 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3010 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3011 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3013 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3014 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3016 shadowentities[numshadowentities++] = ent;
3022 // return if there's nothing at all to light
3023 if (!numlightentities && !numsurfaces)
3026 // don't let sound skip if going slow
3027 if (r_refdef.extraupdate)
3030 // make this the active rtlight for rendering purposes
3031 R_Shadow_RenderMode_ActiveLight(rtlight);
3032 // count this light in the r_speeds
3033 r_refdef.stats.lights++;
3035 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.rtworldshadows : r_refdef.rtdlightshadows))
3037 // optionally draw visible shape of the shadow volumes
3038 // for performance analysis by level designers
3039 R_Shadow_RenderMode_VisibleShadowVolumes();
3041 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3042 for (i = 0;i < numshadowentities;i++)
3043 R_Shadow_DrawEntityShadow(shadowentities[i]);
3044 for (i = 0;i < numshadowentities_noselfshadow;i++)
3045 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3048 if (gl_stencil && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.rtworldshadows : r_refdef.rtdlightshadows))
3050 // draw stencil shadow volumes to mask off pixels that are in shadow
3051 // so that they won't receive lighting
3052 R_Shadow_RenderMode_StencilShadowVolumes(true);
3054 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3055 for (i = 0;i < numshadowentities;i++)
3056 R_Shadow_DrawEntityShadow(shadowentities[i]);
3057 if (numlightentities_noselfshadow)
3059 // draw lighting in the unmasked areas
3060 R_Shadow_RenderMode_Lighting(true, false);
3061 for (i = 0;i < numlightentities_noselfshadow;i++)
3062 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3064 // optionally draw the illuminated areas
3065 // for performance analysis by level designers
3066 if (r_showlighting.integer && r_refdef.view.showdebug)
3068 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
3069 for (i = 0;i < numlightentities_noselfshadow;i++)
3070 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3073 R_Shadow_RenderMode_StencilShadowVolumes(false);
3075 for (i = 0;i < numshadowentities_noselfshadow;i++)
3076 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3078 if (numsurfaces + numlightentities)
3080 // draw lighting in the unmasked areas
3081 R_Shadow_RenderMode_Lighting(true, false);
3083 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3084 for (i = 0;i < numlightentities;i++)
3085 R_Shadow_DrawEntityLight(lightentities[i]);
3087 // optionally draw the illuminated areas
3088 // for performance analysis by level designers
3089 if (r_showlighting.integer && r_refdef.view.showdebug)
3091 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
3093 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3094 for (i = 0;i < numlightentities;i++)
3095 R_Shadow_DrawEntityLight(lightentities[i]);
3101 if (numsurfaces + numlightentities)
3103 // draw lighting in the unmasked areas
3104 R_Shadow_RenderMode_Lighting(false, false);
3106 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3107 for (i = 0;i < numlightentities;i++)
3108 R_Shadow_DrawEntityLight(lightentities[i]);
3109 for (i = 0;i < numlightentities_noselfshadow;i++)
3110 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3112 // optionally draw the illuminated areas
3113 // for performance analysis by level designers
3114 if (r_showlighting.integer && r_refdef.view.showdebug)
3116 R_Shadow_RenderMode_VisibleLighting(false, false);
3118 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3119 for (i = 0;i < numlightentities;i++)
3120 R_Shadow_DrawEntityLight(lightentities[i]);
3121 for (i = 0;i < numlightentities_noselfshadow;i++)
3122 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3128 void R_Shadow_DrawLightSprites(void);
3129 void R_ShadowVolumeLighting(qboolean visible)
3136 if (r_editlights.integer)
3137 R_Shadow_DrawLightSprites();
3139 R_Shadow_RenderMode_Begin();
3141 flag = r_refdef.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3142 if (r_shadow_debuglight.integer >= 0)
3144 lightindex = r_shadow_debuglight.integer;
3145 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3146 if (light && (light->flags & flag))
3147 R_DrawRTLight(&light->rtlight, visible);
3151 for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
3153 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3154 if (light && (light->flags & flag))
3155 R_DrawRTLight(&light->rtlight, visible);
3158 if (r_refdef.rtdlight)
3159 for (lnum = 0;lnum < r_refdef.numlights;lnum++)
3160 R_DrawRTLight(&r_refdef.lights[lnum], visible);
3162 R_Shadow_RenderMode_End();
3165 extern void R_SetupView(void);
3166 extern cvar_t r_shadows_throwdistance;
3167 void R_DrawModelShadows(void)
3170 float relativethrowdistance;
3171 entity_render_t *ent;
3172 vec3_t relativelightorigin;
3173 vec3_t relativelightdirection;
3174 vec3_t relativeshadowmins, relativeshadowmaxs;
3177 if (!r_drawentities.integer || !gl_stencil)
3181 GL_Scissor(r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
3183 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
3185 if (gl_ext_separatestencil.integer)
3186 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
3187 else if (gl_ext_stenciltwoside.integer)
3188 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
3190 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
3192 R_Shadow_RenderMode_StencilShadowVolumes(true);
3194 for (i = 0;i < r_refdef.numentities;i++)
3196 ent = r_refdef.entities[i];
3197 // cast shadows from anything that is not a submodel of the map
3198 if (ent->model && ent->model->DrawShadowVolume != NULL && !ent->model->brush.submodel && (ent->flags & RENDER_SHADOW))
3200 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
3201 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
3202 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
3203 VectorNegate(ent->modellight_lightdir, relativelightdirection);
3204 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
3205 RSurf_ActiveModelEntity(ent, false, false);
3206 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
3210 // not really the right mode, but this will disable any silly stencil features
3211 R_Shadow_RenderMode_VisibleLighting(true, true);
3213 // vertex coordinates for a quad that covers the screen exactly
3214 vertex3f[0] = 0;vertex3f[1] = 0;vertex3f[2] = 0;
3215 vertex3f[3] = 1;vertex3f[4] = 0;vertex3f[5] = 0;
3216 vertex3f[6] = 1;vertex3f[7] = 1;vertex3f[8] = 0;
3217 vertex3f[9] = 0;vertex3f[10] = 1;vertex3f[11] = 0;
3219 // set up ortho view for rendering this pass
3220 GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
3221 GL_Scissor(r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
3222 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
3223 GL_ScissorTest(true);
3224 R_Mesh_Matrix(&identitymatrix);
3225 R_Mesh_ResetTextureState();
3226 R_Mesh_VertexPointer(vertex3f, 0, 0);
3227 R_Mesh_ColorPointer(NULL, 0, 0);
3229 // set up a 50% darkening blend on shadowed areas
3230 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3231 GL_DepthRange(0, 1);
3232 GL_DepthTest(false);
3233 GL_DepthMask(false);
3234 GL_PolygonOffset(0, 0);CHECKGLERROR
3235 GL_Color(0, 0, 0, 0.5);
3236 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
3237 qglDepthFunc(GL_ALWAYS);CHECKGLERROR
3238 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
3239 qglStencilMask(~0);CHECKGLERROR
3240 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
3241 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
3243 // apply the blend to the shadowed areas
3244 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3246 // restoring the perspective view is done by R_RenderScene
3249 // restore other state to normal
3250 R_Shadow_RenderMode_End();
3253 void R_DrawCoronas(void)
3256 float cscale, scale;
3260 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
3262 R_Mesh_Matrix(&identitymatrix);
3263 flag = r_refdef.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3264 // FIXME: these traces should scan all render entities instead of cl.world
3265 for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
3267 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3270 rtlight = &light->rtlight;
3271 if (!(rtlight->flags & flag))
3273 if (rtlight->corona * r_coronas.value <= 0)
3275 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
3277 cscale = rtlight->corona * r_coronas.value* 0.25f;
3278 scale = rtlight->radius * rtlight->coronasizescale;
3279 if (VectorDistance2(rtlight->shadoworigin, r_refdef.view.origin) < 16.0f * 16.0f)
3281 if (CL_Move(r_refdef.view.origin, vec3_origin, vec3_origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
3283 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);
3285 for (i = 0;i < r_refdef.numlights;i++)
3287 rtlight = &r_refdef.lights[i];
3288 if (!(rtlight->flags & flag))
3290 if (rtlight->corona <= 0)
3292 if (VectorDistance2(rtlight->shadoworigin, r_refdef.view.origin) < 32.0f * 32.0f)
3294 if (gl_flashblend.integer)
3296 cscale = rtlight->corona * 1.0f;
3297 scale = rtlight->radius * rtlight->coronasizescale * 2.0f;
3301 cscale = rtlight->corona * r_coronas.value* 0.25f;
3302 scale = rtlight->radius * rtlight->coronasizescale;
3304 if (VectorLength(rtlight->color) * cscale < (1.0f / 256.0f))
3306 if (CL_Move(r_refdef.view.origin, vec3_origin, vec3_origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
3308 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);
3314 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
3315 typedef struct suffixinfo_s
3318 qboolean flipx, flipy, flipdiagonal;
3321 static suffixinfo_t suffix[3][6] =
3324 {"px", false, false, false},
3325 {"nx", false, false, false},
3326 {"py", false, false, false},
3327 {"ny", false, false, false},
3328 {"pz", false, false, false},
3329 {"nz", false, false, false}
3332 {"posx", false, false, false},
3333 {"negx", false, false, false},
3334 {"posy", false, false, false},
3335 {"negy", false, false, false},
3336 {"posz", false, false, false},
3337 {"negz", false, false, false}
3340 {"rt", true, false, true},
3341 {"lf", false, true, true},
3342 {"ft", true, true, false},
3343 {"bk", false, false, false},
3344 {"up", true, false, true},
3345 {"dn", true, false, true}
3349 static int componentorder[4] = {0, 1, 2, 3};
3351 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
3353 int i, j, cubemapsize;
3354 unsigned char *cubemappixels, *image_buffer;
3355 rtexture_t *cubemaptexture;
3357 // must start 0 so the first loadimagepixels has no requested width/height
3359 cubemappixels = NULL;
3360 cubemaptexture = NULL;
3361 // keep trying different suffix groups (posx, px, rt) until one loads
3362 for (j = 0;j < 3 && !cubemappixels;j++)
3364 // load the 6 images in the suffix group
3365 for (i = 0;i < 6;i++)
3367 // generate an image name based on the base and and suffix
3368 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
3370 if ((image_buffer = loadimagepixelsbgra(name, false, false)))
3372 // an image loaded, make sure width and height are equal
3373 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
3375 // if this is the first image to load successfully, allocate the cubemap memory
3376 if (!cubemappixels && image_width >= 1)
3378 cubemapsize = image_width;
3379 // note this clears to black, so unavailable sides are black
3380 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
3382 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
3384 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);
3387 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
3389 Mem_Free(image_buffer);
3393 // if a cubemap loaded, upload it
3396 if (!r_shadow_filters_texturepool)
3397 r_shadow_filters_texturepool = R_AllocTexturePool();
3398 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, TEXF_PRECACHE | (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0), NULL);
3399 Mem_Free(cubemappixels);
3403 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
3404 for (j = 0;j < 3;j++)
3405 for (i = 0;i < 6;i++)
3406 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
3407 Con_Print(" and was unable to find any of them.\n");
3409 return cubemaptexture;
3412 rtexture_t *R_Shadow_Cubemap(const char *basename)
3415 for (i = 0;i < numcubemaps;i++)
3416 if (!strcasecmp(cubemaps[i].basename, basename))
3417 return cubemaps[i].texture;
3418 if (i >= MAX_CUBEMAPS)
3419 return r_texture_whitecube;
3421 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
3422 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
3423 if (!cubemaps[i].texture)
3424 cubemaps[i].texture = r_texture_whitecube;
3425 return cubemaps[i].texture;
3428 void R_Shadow_FreeCubemaps(void)
3431 R_FreeTexturePool(&r_shadow_filters_texturepool);
3434 dlight_t *R_Shadow_NewWorldLight(void)
3436 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
3439 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)
3442 // validate parameters
3443 if (style < 0 || style >= MAX_LIGHTSTYLES)
3445 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
3451 // copy to light properties
3452 VectorCopy(origin, light->origin);
3453 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
3454 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
3455 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
3456 light->color[0] = max(color[0], 0);
3457 light->color[1] = max(color[1], 0);
3458 light->color[2] = max(color[2], 0);
3459 light->radius = max(radius, 0);
3460 light->style = style;
3461 light->shadow = shadowenable;
3462 light->corona = corona;
3463 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
3464 light->coronasizescale = coronasizescale;
3465 light->ambientscale = ambientscale;
3466 light->diffusescale = diffusescale;
3467 light->specularscale = specularscale;
3468 light->flags = flags;
3470 // update renderable light data
3471 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
3472 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);
3475 void R_Shadow_FreeWorldLight(dlight_t *light)
3477 if (r_shadow_selectedlight == light)
3478 r_shadow_selectedlight = NULL;
3479 R_RTLight_Uncompile(&light->rtlight);
3480 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
3483 void R_Shadow_ClearWorldLights(void)
3487 for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
3489 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3491 R_Shadow_FreeWorldLight(light);
3493 r_shadow_selectedlight = NULL;
3494 R_Shadow_FreeCubemaps();
3497 void R_Shadow_SelectLight(dlight_t *light)
3499 if (r_shadow_selectedlight)
3500 r_shadow_selectedlight->selected = false;
3501 r_shadow_selectedlight = light;
3502 if (r_shadow_selectedlight)
3503 r_shadow_selectedlight->selected = true;
3506 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
3508 // this is never batched (there can be only one)
3509 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);
3512 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
3519 // this is never batched (due to the ent parameter changing every time)
3520 // so numsurfaces == 1 and surfacelist[0] == lightnumber
3521 const dlight_t *light = (dlight_t *)ent;
3524 VectorScale(light->color, intensity, spritecolor);
3525 if (VectorLength(spritecolor) < 0.1732f)
3526 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
3527 if (VectorLength(spritecolor) > 1.0f)
3528 VectorNormalize(spritecolor);
3530 // draw light sprite
3531 if (light->cubemapname[0] && !light->shadow)
3532 pic = r_editlights_sprcubemapnoshadowlight;
3533 else if (light->cubemapname[0])
3534 pic = r_editlights_sprcubemaplight;
3535 else if (!light->shadow)
3536 pic = r_editlights_sprnoshadowlight;
3538 pic = r_editlights_sprlight;
3539 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);
3540 // draw selection sprite if light is selected
3541 if (light->selected)
3542 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);
3543 // VorteX todo: add normalmode/realtime mode light overlay sprites?
3546 void R_Shadow_DrawLightSprites(void)
3550 for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
3552 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3554 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
3556 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
3559 void R_Shadow_SelectLightInView(void)
3561 float bestrating, rating, temp[3];
3567 for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
3569 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3572 VectorSubtract(light->origin, r_refdef.view.origin, temp);
3573 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
3576 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
3577 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)
3579 bestrating = rating;
3584 R_Shadow_SelectLight(best);
3587 void R_Shadow_LoadWorldLights(void)
3589 int n, a, style, shadow, flags;
3590 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
3591 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
3592 if (r_refdef.worldmodel == NULL)
3594 Con_Print("No map loaded.\n");
3597 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3598 strlcat (name, ".rtlights", sizeof (name));
3599 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3609 for (;COM_Parse(t, true) && strcmp(
3610 if (COM_Parse(t, true))
3612 if (com_token[0] == '!')
3615 origin[0] = atof(com_token+1);
3618 origin[0] = atof(com_token);
3623 while (*s && *s != '\n' && *s != '\r')
3629 // check for modifier flags
3636 a = sscanf(t, "%f %f %f %f %f %f %f %d %s %f %f %f %f %f %f %f %f %i", &origin[0], &origin[1], &origin[2], &radius, &color[0], &color[1], &color[2], &style, cubemapname, &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
3639 flags = LIGHTFLAG_REALTIMEMODE;
3647 coronasizescale = 0.25f;
3649 VectorClear(angles);
3652 if (a < 9 || !strcmp(cubemapname, "\"\""))
3654 // remove quotes on cubemapname
3655 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
3658 namelen = strlen(cubemapname) - 2;
3659 memmove(cubemapname, cubemapname + 1, namelen);
3660 cubemapname[namelen] = '\0';
3664 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);
3667 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3675 Con_Printf("invalid rtlights file \"%s\"\n", name);
3676 Mem_Free(lightsstring);
3680 void R_Shadow_SaveWorldLights(void)
3684 size_t bufchars, bufmaxchars;
3686 char name[MAX_QPATH];
3687 char line[MAX_INPUTLINE];
3688 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
3690 if (r_refdef.worldmodel == NULL)
3692 Con_Print("No map loaded.\n");
3695 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3696 strlcat (name, ".rtlights", sizeof (name));
3697 bufchars = bufmaxchars = 0;
3699 for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
3701 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3704 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3705 sprintf(line, "%s%f %f %f %f %f %f %f %d \"%s\" %f %f %f %f %f %f %f %f %i\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius, light->color[0], light->color[1], light->color[2], light->style, light->cubemapname, light->corona, light->angles[0], light->angles[1], light->angles[2], light->coronasizescale, light->ambientscale, light->diffusescale, light->specularscale, light->flags);
3706 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3707 sprintf(line, "%s%f %f %f %f %f %f %f %d \"%s\" %f %f %f %f\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius, light->color[0], light->color[1], light->color[2], light->style, light->cubemapname, light->corona, light->angles[0], light->angles[1], light->angles[2]);
3709 sprintf(line, "%s%f %f %f %f %f %f %f %d\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius, light->color[0], light->color[1], light->color[2], light->style);
3710 if (bufchars + strlen(line) > bufmaxchars)
3712 bufmaxchars = bufchars + strlen(line) + 2048;
3714 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
3718 memcpy(buf, oldbuf, bufchars);
3724 memcpy(buf + bufchars, line, strlen(line));
3725 bufchars += strlen(line);
3729 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
3734 void R_Shadow_LoadLightsFile(void)
3737 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3738 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3739 if (r_refdef.worldmodel == NULL)
3741 Con_Print("No map loaded.\n");
3744 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3745 strlcat (name, ".lights", sizeof (name));
3746 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3754 while (*s && *s != '\n' && *s != '\r')
3760 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);
3764 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);
3767 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3768 radius = bound(15, radius, 4096);
3769 VectorScale(color, (2.0f / (8388608.0f)), color);
3770 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3778 Con_Printf("invalid lights file \"%s\"\n", name);
3779 Mem_Free(lightsstring);
3783 // tyrlite/hmap2 light types in the delay field
3784 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3786 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3788 int entnum, style, islight, skin, pflags, effects, type, n;
3791 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3792 char key[256], value[MAX_INPUTLINE];
3794 if (r_refdef.worldmodel == NULL)
3796 Con_Print("No map loaded.\n");
3799 // try to load a .ent file first
3800 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3801 strlcat (key, ".ent", sizeof (key));
3802 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
3803 // and if that is not found, fall back to the bsp file entity string
3805 data = r_refdef.worldmodel->brush.entities;
3808 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
3810 type = LIGHTTYPE_MINUSX;
3811 origin[0] = origin[1] = origin[2] = 0;
3812 originhack[0] = originhack[1] = originhack[2] = 0;
3813 angles[0] = angles[1] = angles[2] = 0;
3814 color[0] = color[1] = color[2] = 1;
3815 light[0] = light[1] = light[2] = 1;light[3] = 300;
3816 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3826 if (!COM_ParseToken_Simple(&data, false, false))
3828 if (com_token[0] == '}')
3829 break; // end of entity
3830 if (com_token[0] == '_')
3831 strlcpy(key, com_token + 1, sizeof(key));
3833 strlcpy(key, com_token, sizeof(key));
3834 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3835 key[strlen(key)-1] = 0;
3836 if (!COM_ParseToken_Simple(&data, false, false))
3838 strlcpy(value, com_token, sizeof(value));
3840 // now that we have the key pair worked out...
3841 if (!strcmp("light", key))
3843 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3847 light[0] = vec[0] * (1.0f / 256.0f);
3848 light[1] = vec[0] * (1.0f / 256.0f);
3849 light[2] = vec[0] * (1.0f / 256.0f);
3855 light[0] = vec[0] * (1.0f / 255.0f);
3856 light[1] = vec[1] * (1.0f / 255.0f);
3857 light[2] = vec[2] * (1.0f / 255.0f);
3861 else if (!strcmp("delay", key))
3863 else if (!strcmp("origin", key))
3864 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3865 else if (!strcmp("angle", key))
3866 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3867 else if (!strcmp("angles", key))
3868 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3869 else if (!strcmp("color", key))
3870 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3871 else if (!strcmp("wait", key))
3872 fadescale = atof(value);
3873 else if (!strcmp("classname", key))
3875 if (!strncmp(value, "light", 5))
3878 if (!strcmp(value, "light_fluoro"))
3883 overridecolor[0] = 1;
3884 overridecolor[1] = 1;
3885 overridecolor[2] = 1;
3887 if (!strcmp(value, "light_fluorospark"))
3892 overridecolor[0] = 1;
3893 overridecolor[1] = 1;
3894 overridecolor[2] = 1;
3896 if (!strcmp(value, "light_globe"))
3901 overridecolor[0] = 1;
3902 overridecolor[1] = 0.8;
3903 overridecolor[2] = 0.4;
3905 if (!strcmp(value, "light_flame_large_yellow"))
3910 overridecolor[0] = 1;
3911 overridecolor[1] = 0.5;
3912 overridecolor[2] = 0.1;
3914 if (!strcmp(value, "light_flame_small_yellow"))
3919 overridecolor[0] = 1;
3920 overridecolor[1] = 0.5;
3921 overridecolor[2] = 0.1;
3923 if (!strcmp(value, "light_torch_small_white"))
3928 overridecolor[0] = 1;
3929 overridecolor[1] = 0.5;
3930 overridecolor[2] = 0.1;
3932 if (!strcmp(value, "light_torch_small_walltorch"))
3937 overridecolor[0] = 1;
3938 overridecolor[1] = 0.5;
3939 overridecolor[2] = 0.1;
3943 else if (!strcmp("style", key))
3944 style = atoi(value);
3945 else if (!strcmp("skin", key))
3946 skin = (int)atof(value);
3947 else if (!strcmp("pflags", key))
3948 pflags = (int)atof(value);
3949 else if (!strcmp("effects", key))
3950 effects = (int)atof(value);
3951 else if (r_refdef.worldmodel->type == mod_brushq3)
3953 if (!strcmp("scale", key))
3954 lightscale = atof(value);
3955 if (!strcmp("fade", key))
3956 fadescale = atof(value);
3961 if (lightscale <= 0)
3965 if (color[0] == color[1] && color[0] == color[2])
3967 color[0] *= overridecolor[0];
3968 color[1] *= overridecolor[1];
3969 color[2] *= overridecolor[2];
3971 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3972 color[0] = color[0] * light[0];
3973 color[1] = color[1] * light[1];
3974 color[2] = color[2] * light[2];
3977 case LIGHTTYPE_MINUSX:
3979 case LIGHTTYPE_RECIPX:
3981 VectorScale(color, (1.0f / 16.0f), color);
3983 case LIGHTTYPE_RECIPXX:
3985 VectorScale(color, (1.0f / 16.0f), color);
3988 case LIGHTTYPE_NONE:
3992 case LIGHTTYPE_MINUSXX:
3995 VectorAdd(origin, originhack, origin);
3997 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);
4000 Mem_Free(entfiledata);
4004 void R_Shadow_SetCursorLocationForView(void)
4007 vec3_t dest, endpos;
4009 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
4010 trace = CL_Move(r_refdef.view.origin, vec3_origin, vec3_origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
4011 if (trace.fraction < 1)
4013 dist = trace.fraction * r_editlights_cursordistance.value;
4014 push = r_editlights_cursorpushback.value;
4018 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
4019 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
4023 VectorClear( endpos );
4025 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4026 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4027 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4030 void R_Shadow_UpdateWorldLightSelection(void)
4032 if (r_editlights.integer)
4034 R_Shadow_SetCursorLocationForView();
4035 R_Shadow_SelectLightInView();
4038 R_Shadow_SelectLight(NULL);
4041 void R_Shadow_EditLights_Clear_f(void)
4043 R_Shadow_ClearWorldLights();
4046 void R_Shadow_EditLights_Reload_f(void)
4048 if (!r_refdef.worldmodel)
4050 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
4051 R_Shadow_ClearWorldLights();
4052 R_Shadow_LoadWorldLights();
4053 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
4055 R_Shadow_LoadLightsFile();
4056 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
4057 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
4061 void R_Shadow_EditLights_Save_f(void)
4063 if (!r_refdef.worldmodel)
4065 R_Shadow_SaveWorldLights();
4068 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
4070 R_Shadow_ClearWorldLights();
4071 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
4074 void R_Shadow_EditLights_ImportLightsFile_f(void)
4076 R_Shadow_ClearWorldLights();
4077 R_Shadow_LoadLightsFile();
4080 void R_Shadow_EditLights_Spawn_f(void)
4083 if (!r_editlights.integer)
4085 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4088 if (Cmd_Argc() != 1)
4090 Con_Print("r_editlights_spawn does not take parameters\n");
4093 color[0] = color[1] = color[2] = 1;
4094 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
4097 void R_Shadow_EditLights_Edit_f(void)
4099 vec3_t origin, angles, color;
4100 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
4101 int style, shadows, flags, normalmode, realtimemode;
4102 char cubemapname[MAX_INPUTLINE];
4103 if (!r_editlights.integer)
4105 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4108 if (!r_shadow_selectedlight)
4110 Con_Print("No selected light.\n");
4113 VectorCopy(r_shadow_selectedlight->origin, origin);
4114 VectorCopy(r_shadow_selectedlight->angles, angles);
4115 VectorCopy(r_shadow_selectedlight->color, color);
4116 radius = r_shadow_selectedlight->radius;
4117 style = r_shadow_selectedlight->style;
4118 if (r_shadow_selectedlight->cubemapname)
4119 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
4122 shadows = r_shadow_selectedlight->shadow;
4123 corona = r_shadow_selectedlight->corona;
4124 coronasizescale = r_shadow_selectedlight->coronasizescale;
4125 ambientscale = r_shadow_selectedlight->ambientscale;
4126 diffusescale = r_shadow_selectedlight->diffusescale;
4127 specularscale = r_shadow_selectedlight->specularscale;
4128 flags = r_shadow_selectedlight->flags;
4129 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
4130 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
4131 if (!strcmp(Cmd_Argv(1), "origin"))
4133 if (Cmd_Argc() != 5)
4135 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
4138 origin[0] = atof(Cmd_Argv(2));
4139 origin[1] = atof(Cmd_Argv(3));
4140 origin[2] = atof(Cmd_Argv(4));
4142 else if (!strcmp(Cmd_Argv(1), "originx"))
4144 if (Cmd_Argc() != 3)
4146 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4149 origin[0] = atof(Cmd_Argv(2));
4151 else if (!strcmp(Cmd_Argv(1), "originy"))
4153 if (Cmd_Argc() != 3)
4155 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4158 origin[1] = atof(Cmd_Argv(2));
4160 else if (!strcmp(Cmd_Argv(1), "originz"))
4162 if (Cmd_Argc() != 3)
4164 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4167 origin[2] = atof(Cmd_Argv(2));
4169 else if (!strcmp(Cmd_Argv(1), "move"))
4171 if (Cmd_Argc() != 5)
4173 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
4176 origin[0] += atof(Cmd_Argv(2));
4177 origin[1] += atof(Cmd_Argv(3));
4178 origin[2] += atof(Cmd_Argv(4));
4180 else if (!strcmp(Cmd_Argv(1), "movex"))
4182 if (Cmd_Argc() != 3)
4184 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4187 origin[0] += atof(Cmd_Argv(2));
4189 else if (!strcmp(Cmd_Argv(1), "movey"))
4191 if (Cmd_Argc() != 3)
4193 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4196 origin[1] += atof(Cmd_Argv(2));
4198 else if (!strcmp(Cmd_Argv(1), "movez"))
4200 if (Cmd_Argc() != 3)
4202 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4205 origin[2] += atof(Cmd_Argv(2));
4207 else if (!strcmp(Cmd_Argv(1), "angles"))
4209 if (Cmd_Argc() != 5)
4211 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
4214 angles[0] = atof(Cmd_Argv(2));
4215 angles[1] = atof(Cmd_Argv(3));
4216 angles[2] = atof(Cmd_Argv(4));
4218 else if (!strcmp(Cmd_Argv(1), "anglesx"))
4220 if (Cmd_Argc() != 3)
4222 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4225 angles[0] = atof(Cmd_Argv(2));
4227 else if (!strcmp(Cmd_Argv(1), "anglesy"))
4229 if (Cmd_Argc() != 3)
4231 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4234 angles[1] = atof(Cmd_Argv(2));
4236 else if (!strcmp(Cmd_Argv(1), "anglesz"))
4238 if (Cmd_Argc() != 3)
4240 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4243 angles[2] = atof(Cmd_Argv(2));
4245 else if (!strcmp(Cmd_Argv(1), "color"))
4247 if (Cmd_Argc() != 5)
4249 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
4252 color[0] = atof(Cmd_Argv(2));
4253 color[1] = atof(Cmd_Argv(3));
4254 color[2] = atof(Cmd_Argv(4));
4256 else if (!strcmp(Cmd_Argv(1), "radius"))
4258 if (Cmd_Argc() != 3)
4260 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4263 radius = atof(Cmd_Argv(2));
4265 else if (!strcmp(Cmd_Argv(1), "colorscale"))
4267 if (Cmd_Argc() == 3)
4269 double scale = atof(Cmd_Argv(2));
4276 if (Cmd_Argc() != 5)
4278 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
4281 color[0] *= atof(Cmd_Argv(2));
4282 color[1] *= atof(Cmd_Argv(3));
4283 color[2] *= atof(Cmd_Argv(4));
4286 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
4288 if (Cmd_Argc() != 3)
4290 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4293 radius *= atof(Cmd_Argv(2));
4295 else if (!strcmp(Cmd_Argv(1), "style"))
4297 if (Cmd_Argc() != 3)
4299 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4302 style = atoi(Cmd_Argv(2));
4304 else if (!strcmp(Cmd_Argv(1), "cubemap"))
4308 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4311 if (Cmd_Argc() == 3)
4312 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
4316 else if (!strcmp(Cmd_Argv(1), "shadows"))
4318 if (Cmd_Argc() != 3)
4320 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4323 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4325 else if (!strcmp(Cmd_Argv(1), "corona"))
4327 if (Cmd_Argc() != 3)
4329 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4332 corona = atof(Cmd_Argv(2));
4334 else if (!strcmp(Cmd_Argv(1), "coronasize"))
4336 if (Cmd_Argc() != 3)
4338 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4341 coronasizescale = atof(Cmd_Argv(2));
4343 else if (!strcmp(Cmd_Argv(1), "ambient"))
4345 if (Cmd_Argc() != 3)
4347 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4350 ambientscale = atof(Cmd_Argv(2));
4352 else if (!strcmp(Cmd_Argv(1), "diffuse"))
4354 if (Cmd_Argc() != 3)
4356 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4359 diffusescale = atof(Cmd_Argv(2));
4361 else if (!strcmp(Cmd_Argv(1), "specular"))
4363 if (Cmd_Argc() != 3)
4365 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4368 specularscale = atof(Cmd_Argv(2));
4370 else if (!strcmp(Cmd_Argv(1), "normalmode"))
4372 if (Cmd_Argc() != 3)
4374 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4377 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4379 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
4381 if (Cmd_Argc() != 3)
4383 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4386 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4390 Con_Print("usage: r_editlights_edit [property] [value]\n");
4391 Con_Print("Selected light's properties:\n");
4392 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
4393 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
4394 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
4395 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
4396 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
4397 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
4398 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
4399 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
4400 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
4401 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
4402 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
4403 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
4404 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
4405 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
4408 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
4409 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4412 void R_Shadow_EditLights_EditAll_f(void)
4417 if (!r_editlights.integer)
4419 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
4423 for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
4425 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4428 R_Shadow_SelectLight(light);
4429 R_Shadow_EditLights_Edit_f();
4433 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
4435 int lightnumber, lightcount;
4440 if (!r_editlights.integer)
4442 x = vid_conwidth.value - 240;
4444 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
4447 for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
4449 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4452 if (light == r_shadow_selectedlight)
4453 lightnumber = lightindex;
4456 sprintf(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;
4457 sprintf(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;
4459 if (r_shadow_selectedlight == NULL)
4461 sprintf(temp, "Light #%i properties:", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
4462 sprintf(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;
4463 sprintf(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;
4464 sprintf(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;
4465 sprintf(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;
4466 sprintf(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;
4467 sprintf(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;
4468 sprintf(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;
4469 sprintf(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;
4470 sprintf(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;
4471 sprintf(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;
4472 sprintf(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;
4473 sprintf(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;
4474 sprintf(temp, "NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
4475 sprintf(temp, "RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
4478 void R_Shadow_EditLights_ToggleShadow_f(void)
4480 if (!r_editlights.integer)
4482 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4485 if (!r_shadow_selectedlight)
4487 Con_Print("No selected light.\n");
4490 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);
4493 void R_Shadow_EditLights_ToggleCorona_f(void)
4495 if (!r_editlights.integer)
4497 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4500 if (!r_shadow_selectedlight)
4502 Con_Print("No selected light.\n");
4505 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);
4508 void R_Shadow_EditLights_Remove_f(void)
4510 if (!r_editlights.integer)
4512 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
4515 if (!r_shadow_selectedlight)
4517 Con_Print("No selected light.\n");
4520 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
4521 r_shadow_selectedlight = NULL;
4524 void R_Shadow_EditLights_Help_f(void)
4527 "Documentation on r_editlights system:\n"
4529 "r_editlights : enable/disable editing mode\n"
4530 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
4531 "r_editlights_cursorpushback : push back cursor this far from surface\n"
4532 "r_editlights_cursorpushoff : push cursor off surface this far\n"
4533 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
4534 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
4536 "r_editlights_help : this help\n"
4537 "r_editlights_clear : remove all lights\n"
4538 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
4539 "r_editlights_save : save to .rtlights file\n"
4540 "r_editlights_spawn : create a light with default settings\n"
4541 "r_editlights_edit command : edit selected light - more documentation below\n"
4542 "r_editlights_remove : remove selected light\n"
4543 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
4544 "r_editlights_importlightentitiesfrommap : reload light entities\n"
4545 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
4547 "origin x y z : set light location\n"
4548 "originx x: set x component of light location\n"
4549 "originy y: set y component of light location\n"
4550 "originz z: set z component of light location\n"
4551 "move x y z : adjust light location\n"
4552 "movex x: adjust x component of light location\n"
4553 "movey y: adjust y component of light location\n"
4554 "movez z: adjust z component of light location\n"
4555 "angles x y z : set light angles\n"
4556 "anglesx x: set x component of light angles\n"
4557 "anglesy y: set y component of light angles\n"
4558 "anglesz z: set z component of light angles\n"
4559 "color r g b : set color of light (can be brighter than 1 1 1)\n"
4560 "radius radius : set radius (size) of light\n"
4561 "colorscale grey : multiply color of light (1 does nothing)\n"
4562 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
4563 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
4564 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
4565 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
4566 "cubemap basename : set filter cubemap of light (not yet supported)\n"
4567 "shadows 1/0 : turn on/off shadows\n"
4568 "corona n : set corona intensity\n"
4569 "coronasize n : set corona size (0-1)\n"
4570 "ambient n : set ambient intensity (0-1)\n"
4571 "diffuse n : set diffuse intensity (0-1)\n"
4572 "specular n : set specular intensity (0-1)\n"
4573 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
4574 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
4575 "<nothing> : print light properties to console\n"
4579 void R_Shadow_EditLights_CopyInfo_f(void)
4581 if (!r_editlights.integer)
4583 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
4586 if (!r_shadow_selectedlight)
4588 Con_Print("No selected light.\n");
4591 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
4592 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
4593 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
4594 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
4595 if (r_shadow_selectedlight->cubemapname)
4596 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
4598 r_shadow_bufferlight.cubemapname[0] = 0;
4599 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
4600 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
4601 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
4602 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
4603 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
4604 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
4605 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
4608 void R_Shadow_EditLights_PasteInfo_f(void)
4610 if (!r_editlights.integer)
4612 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
4615 if (!r_shadow_selectedlight)
4617 Con_Print("No selected light.\n");
4620 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);
4623 void R_Shadow_EditLights_Init(void)
4625 Cvar_RegisterVariable(&r_editlights);
4626 Cvar_RegisterVariable(&r_editlights_cursordistance);
4627 Cvar_RegisterVariable(&r_editlights_cursorpushback);
4628 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
4629 Cvar_RegisterVariable(&r_editlights_cursorgrid);
4630 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
4631 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
4632 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
4633 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)");
4634 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
4635 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
4636 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
4637 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)");
4638 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
4639 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
4640 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
4641 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
4642 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
4643 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
4644 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)");
4650 =============================================================================
4654 =============================================================================
4657 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
4659 VectorClear(diffusecolor);
4660 VectorClear(diffusenormal);
4662 if (!r_fullbright.integer && r_refdef.worldmodel && r_refdef.worldmodel->brush.LightPoint)
4664 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_ambient.value * (2.0f / 128.0f);
4665 r_refdef.worldmodel->brush.LightPoint(r_refdef.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
4668 VectorSet(ambientcolor, 1, 1, 1);
4675 for (i = 0;i < r_refdef.numlights;i++)
4677 light = &r_refdef.lights[i];
4678 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
4679 f = 1 - VectorLength2(v);
4680 if (f > 0 && CL_Move(p, vec3_origin, vec3_origin, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
4681 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);