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)
391 void R_Shadow_Help_f(void)
394 "Documentation on r_shadow system:\n"
396 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
397 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
398 "r_shadow_debuglight : render only this light number (-1 = all)\n"
399 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
400 "r_shadow_gloss2intensity : brightness of forced gloss\n"
401 "r_shadow_glossintensity : brightness of textured gloss\n"
402 "r_shadow_lightattenuationlinearscale : used to generate attenuation texture\n"
403 "r_shadow_lightattenuationdividebias : used to generate attenuation texture\n"
404 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
405 "r_shadow_lightradiusscale : scale rendering radius of all lights\n"
406 "r_shadow_portallight : use portal visibility for static light precomputation\n"
407 "r_shadow_projectdistance : shadow volume projection distance\n"
408 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
409 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
410 "r_shadow_realtime_world : use high quality world lighting mode\n"
411 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
412 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
413 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
414 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
415 "r_shadow_scissor : use scissor optimization\n"
416 "r_shadow_polygonfactor : nudge shadow volumes closer/further\n"
417 "r_shadow_polygonoffset : nudge shadow volumes closer/further\n"
418 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
419 "r_showlighting : useful for performance testing; bright = slow!\n"
420 "r_showshadowvolumes : useful for performance testing; bright = slow!\n"
422 "r_shadow_help : this help\n"
426 void R_Shadow_Init(void)
428 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
429 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
430 Cvar_RegisterVariable(&r_shadow_usenormalmap);
431 Cvar_RegisterVariable(&r_shadow_debuglight);
432 Cvar_RegisterVariable(&r_shadow_gloss);
433 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
434 Cvar_RegisterVariable(&r_shadow_glossintensity);
435 Cvar_RegisterVariable(&r_shadow_glossexponent);
436 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
437 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
438 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
439 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
440 Cvar_RegisterVariable(&r_shadow_portallight);
441 Cvar_RegisterVariable(&r_shadow_projectdistance);
442 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
443 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
444 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
445 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
446 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
447 Cvar_RegisterVariable(&r_shadow_realtime_world);
448 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
449 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
450 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
451 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
452 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
453 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
454 Cvar_RegisterVariable(&r_shadow_scissor);
455 Cvar_RegisterVariable(&r_shadow_culltriangles);
456 Cvar_RegisterVariable(&r_shadow_polygonfactor);
457 Cvar_RegisterVariable(&r_shadow_polygonoffset);
458 Cvar_RegisterVariable(&r_shadow_texture3d);
459 Cvar_RegisterVariable(&r_coronas);
460 Cvar_RegisterVariable(&gl_flashblend);
461 Cvar_RegisterVariable(&gl_ext_separatestencil);
462 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
463 if (gamemode == GAME_TENEBRAE)
465 Cvar_SetValue("r_shadow_gloss", 2);
466 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
468 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f, "prints documentation on console commands and variables used by realtime lighting and shadowing system");
469 R_Shadow_EditLights_Init();
470 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
471 maxshadowtriangles = 0;
472 shadowelements = NULL;
473 maxshadowvertices = 0;
474 shadowvertex3f = NULL;
482 shadowmarklist = NULL;
484 r_shadow_buffer_numleafpvsbytes = 0;
485 r_shadow_buffer_leafpvs = NULL;
486 r_shadow_buffer_leaflist = NULL;
487 r_shadow_buffer_numsurfacepvsbytes = 0;
488 r_shadow_buffer_surfacepvs = NULL;
489 r_shadow_buffer_surfacelist = NULL;
490 r_shadow_buffer_shadowtrispvs = NULL;
491 r_shadow_buffer_lighttrispvs = NULL;
492 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
495 matrix4x4_t matrix_attenuationxyz =
498 {0.5, 0.0, 0.0, 0.5},
499 {0.0, 0.5, 0.0, 0.5},
500 {0.0, 0.0, 0.5, 0.5},
505 matrix4x4_t matrix_attenuationz =
508 {0.0, 0.0, 0.5, 0.5},
509 {0.0, 0.0, 0.0, 0.5},
510 {0.0, 0.0, 0.0, 0.5},
515 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles)
517 // make sure shadowelements is big enough for this volume
518 if (maxshadowtriangles < numtriangles)
520 maxshadowtriangles = numtriangles;
522 Mem_Free(shadowelements);
523 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[24]));
525 // make sure shadowvertex3f is big enough for this volume
526 if (maxshadowvertices < numvertices)
528 maxshadowvertices = numvertices;
530 Mem_Free(shadowvertex3f);
531 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[6]));
535 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
537 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
538 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
539 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
540 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
541 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
543 if (r_shadow_buffer_leafpvs)
544 Mem_Free(r_shadow_buffer_leafpvs);
545 if (r_shadow_buffer_leaflist)
546 Mem_Free(r_shadow_buffer_leaflist);
547 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
548 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
549 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
551 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
553 if (r_shadow_buffer_surfacepvs)
554 Mem_Free(r_shadow_buffer_surfacepvs);
555 if (r_shadow_buffer_surfacelist)
556 Mem_Free(r_shadow_buffer_surfacelist);
557 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
558 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
559 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
561 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
563 if (r_shadow_buffer_shadowtrispvs)
564 Mem_Free(r_shadow_buffer_shadowtrispvs);
565 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
566 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
568 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
570 if (r_shadow_buffer_lighttrispvs)
571 Mem_Free(r_shadow_buffer_lighttrispvs);
572 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
573 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
577 void R_Shadow_PrepareShadowMark(int numtris)
579 // make sure shadowmark is big enough for this volume
580 if (maxshadowmark < numtris)
582 maxshadowmark = numtris;
584 Mem_Free(shadowmark);
586 Mem_Free(shadowmarklist);
587 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
588 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
592 // if shadowmarkcount wrapped we clear the array and adjust accordingly
593 if (shadowmarkcount == 0)
596 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
601 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)
604 int outtriangles = 0, outvertices = 0;
607 float ratio, direction[3], projectvector[3];
609 if (projectdirection)
610 VectorScale(projectdirection, projectdistance, projectvector);
612 VectorClear(projectvector);
614 if (maxvertexupdate < innumvertices)
616 maxvertexupdate = innumvertices;
618 Mem_Free(vertexupdate);
620 Mem_Free(vertexremap);
621 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
622 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
626 if (vertexupdatenum == 0)
629 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
630 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
633 for (i = 0;i < numshadowmarktris;i++)
634 shadowmark[shadowmarktris[i]] = shadowmarkcount;
636 // create the vertices
637 if (projectdirection)
639 for (i = 0;i < numshadowmarktris;i++)
641 element = inelement3i + shadowmarktris[i] * 3;
642 for (j = 0;j < 3;j++)
644 if (vertexupdate[element[j]] != vertexupdatenum)
646 vertexupdate[element[j]] = vertexupdatenum;
647 vertexremap[element[j]] = outvertices;
648 vertex = invertex3f + element[j] * 3;
649 // project one copy of the vertex according to projectvector
650 VectorCopy(vertex, outvertex3f);
651 VectorAdd(vertex, projectvector, (outvertex3f + 3));
660 for (i = 0;i < numshadowmarktris;i++)
662 element = inelement3i + shadowmarktris[i] * 3;
663 for (j = 0;j < 3;j++)
665 if (vertexupdate[element[j]] != vertexupdatenum)
667 vertexupdate[element[j]] = vertexupdatenum;
668 vertexremap[element[j]] = outvertices;
669 vertex = invertex3f + element[j] * 3;
670 // project one copy of the vertex to the sphere radius of the light
671 // (FIXME: would projecting it to the light box be better?)
672 VectorSubtract(vertex, projectorigin, direction);
673 ratio = projectdistance / VectorLength(direction);
674 VectorCopy(vertex, outvertex3f);
675 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
683 if (r_shadow_frontsidecasting.integer)
685 for (i = 0;i < numshadowmarktris;i++)
687 int remappedelement[3];
689 const int *neighbortriangle;
691 markindex = shadowmarktris[i] * 3;
692 element = inelement3i + markindex;
693 neighbortriangle = inneighbor3i + markindex;
694 // output the front and back triangles
695 outelement3i[0] = vertexremap[element[0]];
696 outelement3i[1] = vertexremap[element[1]];
697 outelement3i[2] = vertexremap[element[2]];
698 outelement3i[3] = vertexremap[element[2]] + 1;
699 outelement3i[4] = vertexremap[element[1]] + 1;
700 outelement3i[5] = vertexremap[element[0]] + 1;
704 // output the sides (facing outward from this triangle)
705 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
707 remappedelement[0] = vertexremap[element[0]];
708 remappedelement[1] = vertexremap[element[1]];
709 outelement3i[0] = remappedelement[1];
710 outelement3i[1] = remappedelement[0];
711 outelement3i[2] = remappedelement[0] + 1;
712 outelement3i[3] = remappedelement[1];
713 outelement3i[4] = remappedelement[0] + 1;
714 outelement3i[5] = remappedelement[1] + 1;
719 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
721 remappedelement[1] = vertexremap[element[1]];
722 remappedelement[2] = vertexremap[element[2]];
723 outelement3i[0] = remappedelement[2];
724 outelement3i[1] = remappedelement[1];
725 outelement3i[2] = remappedelement[1] + 1;
726 outelement3i[3] = remappedelement[2];
727 outelement3i[4] = remappedelement[1] + 1;
728 outelement3i[5] = remappedelement[2] + 1;
733 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
735 remappedelement[0] = vertexremap[element[0]];
736 remappedelement[2] = vertexremap[element[2]];
737 outelement3i[0] = remappedelement[0];
738 outelement3i[1] = remappedelement[2];
739 outelement3i[2] = remappedelement[2] + 1;
740 outelement3i[3] = remappedelement[0];
741 outelement3i[4] = remappedelement[2] + 1;
742 outelement3i[5] = remappedelement[0] + 1;
751 for (i = 0;i < numshadowmarktris;i++)
753 int remappedelement[3];
755 const int *neighbortriangle;
757 markindex = shadowmarktris[i] * 3;
758 element = inelement3i + markindex;
759 neighbortriangle = inneighbor3i + markindex;
760 // output the front and back triangles
761 outelement3i[0] = vertexremap[element[2]];
762 outelement3i[1] = vertexremap[element[1]];
763 outelement3i[2] = vertexremap[element[0]];
764 outelement3i[3] = vertexremap[element[0]] + 1;
765 outelement3i[4] = vertexremap[element[1]] + 1;
766 outelement3i[5] = vertexremap[element[2]] + 1;
770 // output the sides (facing outward from this triangle)
771 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
773 remappedelement[0] = vertexremap[element[0]];
774 remappedelement[1] = vertexremap[element[1]];
775 outelement3i[0] = remappedelement[0];
776 outelement3i[1] = remappedelement[1];
777 outelement3i[2] = remappedelement[1] + 1;
778 outelement3i[3] = remappedelement[0];
779 outelement3i[4] = remappedelement[1] + 1;
780 outelement3i[5] = remappedelement[0] + 1;
785 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
787 remappedelement[1] = vertexremap[element[1]];
788 remappedelement[2] = vertexremap[element[2]];
789 outelement3i[0] = remappedelement[1];
790 outelement3i[1] = remappedelement[2];
791 outelement3i[2] = remappedelement[2] + 1;
792 outelement3i[3] = remappedelement[1];
793 outelement3i[4] = remappedelement[2] + 1;
794 outelement3i[5] = remappedelement[1] + 1;
799 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
801 remappedelement[0] = vertexremap[element[0]];
802 remappedelement[2] = vertexremap[element[2]];
803 outelement3i[0] = remappedelement[2];
804 outelement3i[1] = remappedelement[0];
805 outelement3i[2] = remappedelement[0] + 1;
806 outelement3i[3] = remappedelement[2];
807 outelement3i[4] = remappedelement[0] + 1;
808 outelement3i[5] = remappedelement[2] + 1;
816 *outnumvertices = outvertices;
820 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)
823 if (projectdistance < 0.1)
825 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
828 if (!numverts || !nummarktris)
830 // make sure shadowelements is big enough for this volume
831 if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
832 R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
833 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
834 r_refdef.stats.lights_dynamicshadowtriangles += tris;
835 R_Shadow_RenderVolume(outverts, tris, shadowvertex3f, shadowelements);
838 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)
844 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
846 tend = firsttriangle + numtris;
847 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
849 // surface box entirely inside light box, no box cull
850 if (projectdirection)
852 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
854 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
855 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
856 shadowmarklist[numshadowmark++] = t;
861 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
862 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
863 shadowmarklist[numshadowmark++] = t;
868 // surface box not entirely inside light box, cull each triangle
869 if (projectdirection)
871 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
873 v[0] = invertex3f + e[0] * 3;
874 v[1] = invertex3f + e[1] * 3;
875 v[2] = invertex3f + e[2] * 3;
876 TriangleNormal(v[0], v[1], v[2], normal);
877 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
878 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
879 shadowmarklist[numshadowmark++] = t;
884 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
886 v[0] = invertex3f + e[0] * 3;
887 v[1] = invertex3f + e[1] * 3;
888 v[2] = invertex3f + e[2] * 3;
889 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
890 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
891 shadowmarklist[numshadowmark++] = t;
897 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
899 if (r_shadow_compilingrtlight)
901 // if we're compiling an rtlight, capture the mesh
902 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
905 r_refdef.stats.lights_shadowtriangles += numtriangles;
907 R_Mesh_VertexPointer(vertex3f, 0, 0);
908 GL_LockArrays(0, numvertices);
909 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
911 // decrement stencil if backface is behind depthbuffer
912 GL_CullFace(r_view.cullface_front);
913 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
914 R_Mesh_Draw(0, numvertices, numtriangles, element3i, 0, 0);
915 // increment stencil if frontface is behind depthbuffer
916 GL_CullFace(r_view.cullface_back);
917 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
919 R_Mesh_Draw(0, numvertices, numtriangles, element3i, 0, 0);
924 static void R_Shadow_MakeTextures_MakeCorona(void)
928 unsigned char pixels[32][32][4];
929 for (y = 0;y < 32;y++)
931 dy = (y - 15.5f) * (1.0f / 16.0f);
932 for (x = 0;x < 32;x++)
934 dx = (x - 15.5f) * (1.0f / 16.0f);
935 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
936 a = bound(0, a, 255);
940 pixels[y][x][3] = 255;
943 r_shadow_lightcorona = R_LoadTexture2D(r_shadow_texturepool, "lightcorona", 32, 32, &pixels[0][0][0], TEXTYPE_BGRA, TEXF_PRECACHE, NULL);
946 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
948 float dist = sqrt(x*x+y*y+z*z);
949 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
950 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
951 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
954 static void R_Shadow_MakeTextures(void)
957 float intensity, dist;
959 R_FreeTexturePool(&r_shadow_texturepool);
960 r_shadow_texturepool = R_AllocTexturePool();
961 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
962 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
963 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
964 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
965 for (x = 0;x <= ATTENTABLESIZE;x++)
967 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
968 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
969 r_shadow_attentable[x] = bound(0, intensity, 1);
971 // 1D gradient texture
972 for (x = 0;x < ATTEN1DSIZE;x++)
973 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
974 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
976 for (y = 0;y < ATTEN2DSIZE;y++)
977 for (x = 0;x < ATTEN2DSIZE;x++)
978 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);
979 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
981 if (r_shadow_texture3d.integer && gl_texture3d)
983 for (z = 0;z < ATTEN3DSIZE;z++)
984 for (y = 0;y < ATTEN3DSIZE;y++)
985 for (x = 0;x < ATTEN3DSIZE;x++)
986 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));
987 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
990 r_shadow_attenuation3dtexture = NULL;
993 R_Shadow_MakeTextures_MakeCorona();
995 // Editor light sprites
996 r_editlights_sprcursor = Draw_CachePic("gfx/editlights/cursor", true);
997 r_editlights_sprlight = Draw_CachePic("gfx/editlights/light", true);
998 r_editlights_sprnoshadowlight = Draw_CachePic("gfx/editlights/noshadow", true);
999 r_editlights_sprcubemaplight = Draw_CachePic("gfx/editlights/cubemaplight", true);
1000 r_editlights_sprcubemapnoshadowlight = Draw_CachePic("gfx/editlights/cubemapnoshadowlight", true);
1001 r_editlights_sprselection = Draw_CachePic("gfx/editlights/selection", true);
1004 void R_Shadow_ValidateCvars(void)
1006 if (r_shadow_texture3d.integer && !gl_texture3d)
1007 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1008 if (gl_ext_separatestencil.integer && !gl_support_separatestencil)
1009 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1010 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1011 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1014 void R_Shadow_RenderMode_Begin(void)
1016 R_Shadow_ValidateCvars();
1018 if (!r_shadow_attenuation2dtexture
1019 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1020 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1021 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1022 R_Shadow_MakeTextures();
1025 R_Mesh_ColorPointer(NULL, 0, 0);
1026 R_Mesh_ResetTextureState();
1027 GL_BlendFunc(GL_ONE, GL_ZERO);
1028 GL_DepthRange(0, 1);
1029 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1031 GL_DepthMask(false);
1032 GL_Color(0, 0, 0, 1);
1033 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
1035 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1037 if (gl_ext_separatestencil.integer)
1038 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
1039 else if (gl_ext_stenciltwoside.integer)
1040 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
1042 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
1044 if (r_glsl.integer && gl_support_fragment_shader)
1045 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1046 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
1047 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
1049 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1052 void R_Shadow_RenderMode_ActiveLight(rtlight_t *rtlight)
1054 rsurface.rtlight = rtlight;
1057 void R_Shadow_RenderMode_Reset(void)
1060 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1062 qglUseProgramObjectARB(0);CHECKGLERROR
1064 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
1066 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1068 R_Mesh_ColorPointer(NULL, 0, 0);
1069 R_Mesh_ResetTextureState();
1070 GL_DepthRange(0, 1);
1072 GL_DepthMask(false);
1073 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1074 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1075 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1076 qglStencilMask(~0);CHECKGLERROR
1077 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1078 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1079 GL_CullFace(r_view.cullface_back);
1080 GL_Color(1, 1, 1, 1);
1081 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
1082 GL_BlendFunc(GL_ONE, GL_ZERO);
1085 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean clearstencil)
1088 R_Shadow_RenderMode_Reset();
1089 GL_ColorMask(0, 0, 0, 0);
1090 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1091 qglDepthFunc(GL_LESS);CHECKGLERROR
1092 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1093 r_shadow_rendermode = r_shadow_shadowingrendermode;
1094 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SEPARATESTENCIL)
1096 GL_CullFace(GL_NONE);
1097 qglStencilOpSeparate(r_view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1098 qglStencilOpSeparate(r_view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1100 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
1102 GL_CullFace(GL_NONE);
1103 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1104 qglActiveStencilFaceEXT(r_view.cullface_front);CHECKGLERROR
1105 qglStencilMask(~0);CHECKGLERROR
1106 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1107 qglActiveStencilFaceEXT(r_view.cullface_back);CHECKGLERROR
1108 qglStencilMask(~0);CHECKGLERROR
1109 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1112 GL_Clear(GL_STENCIL_BUFFER_BIT);
1113 r_refdef.stats.lights_clears++;
1116 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent)
1119 R_Shadow_RenderMode_Reset();
1120 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1123 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1127 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1128 // only draw light where this geometry was already rendered AND the
1129 // stencil is 128 (values other than this mean shadow)
1130 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1132 r_shadow_rendermode = r_shadow_lightingrendermode;
1133 // do global setup needed for the chosen lighting mode
1134 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1136 R_Mesh_TexBind(0, R_GetTexture(r_texture_blanknormalmap)); // normal
1137 R_Mesh_TexBind(1, R_GetTexture(r_texture_white)); // diffuse
1138 R_Mesh_TexBind(2, R_GetTexture(r_texture_white)); // gloss
1139 R_Mesh_TexBindCubeMap(3, R_GetTexture(rsurface.rtlight->currentcubemap)); // light filter
1140 R_Mesh_TexBind(4, R_GetTexture(r_texture_fogattenuation)); // fog
1141 R_Mesh_TexBind(5, R_GetTexture(r_texture_white)); // pants
1142 R_Mesh_TexBind(6, R_GetTexture(r_texture_white)); // shirt
1143 R_Mesh_TexBind(7, R_GetTexture(r_texture_white)); // lightmap
1144 R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap)); // deluxemap
1145 R_Mesh_TexBind(9, R_GetTexture(r_texture_black)); // glow
1146 //R_Mesh_TexMatrix(3, rsurface.entitytolight); // light filter matrix
1147 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1148 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 0);
1153 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
1156 R_Shadow_RenderMode_Reset();
1157 GL_BlendFunc(GL_ONE, GL_ONE);
1158 GL_DepthRange(0, 1);
1159 GL_DepthTest(r_showshadowvolumes.integer < 2);
1160 GL_Color(0.0, 0.0125 * r_view.colorscale, 0.1 * r_view.colorscale, 1);
1161 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1162 GL_CullFace(GL_NONE);
1163 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
1166 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
1169 R_Shadow_RenderMode_Reset();
1170 GL_BlendFunc(GL_ONE, GL_ONE);
1171 GL_DepthRange(0, 1);
1172 GL_DepthTest(r_showlighting.integer < 2);
1173 GL_Color(0.1 * r_view.colorscale, 0.0125 * r_view.colorscale, 0, 1);
1176 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1180 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1181 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1183 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
1186 void R_Shadow_RenderMode_End(void)
1189 R_Shadow_RenderMode_Reset();
1190 R_Shadow_RenderMode_ActiveLight(NULL);
1192 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
1193 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1196 int bboxedges[12][2] =
1215 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1217 int i, ix1, iy1, ix2, iy2;
1218 float x1, y1, x2, y2;
1220 float vertex[20][3];
1229 if (!r_shadow_scissor.integer)
1232 // if view is inside the light box, just say yes it's visible
1233 if (BoxesOverlap(r_view.origin, r_view.origin, mins, maxs))
1235 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
1239 x1 = y1 = x2 = y2 = 0;
1241 // transform all corners that are infront of the nearclip plane
1242 VectorNegate(r_view.frustum[4].normal, plane4f);
1243 plane4f[3] = r_view.frustum[4].dist;
1245 for (i = 0;i < 8;i++)
1247 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
1248 dist[i] = DotProduct4(corner[i], plane4f);
1249 sign[i] = dist[i] > 0;
1252 VectorCopy(corner[i], vertex[numvertices]);
1256 // if some points are behind the nearclip, add clipped edge points to make
1257 // sure that the scissor boundary is complete
1258 if (numvertices > 0 && numvertices < 8)
1260 // add clipped edge points
1261 for (i = 0;i < 12;i++)
1263 j = bboxedges[i][0];
1264 k = bboxedges[i][1];
1265 if (sign[j] != sign[k])
1267 f = dist[j] / (dist[j] - dist[k]);
1268 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
1274 // if we have no points to check, the light is behind the view plane
1278 // if we have some points to transform, check what screen area is covered
1279 x1 = y1 = x2 = y2 = 0;
1281 //Con_Printf("%i vertices to transform...\n", numvertices);
1282 for (i = 0;i < numvertices;i++)
1284 VectorCopy(vertex[i], v);
1285 GL_TransformToScreen(v, v2);
1286 //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]);
1289 if (x1 > v2[0]) x1 = v2[0];
1290 if (x2 < v2[0]) x2 = v2[0];
1291 if (y1 > v2[1]) y1 = v2[1];
1292 if (y2 < v2[1]) y2 = v2[1];
1301 // now convert the scissor rectangle to integer screen coordinates
1302 ix1 = (int)(x1 - 1.0f);
1303 iy1 = (int)(y1 - 1.0f);
1304 ix2 = (int)(x2 + 1.0f);
1305 iy2 = (int)(y2 + 1.0f);
1306 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1308 // clamp it to the screen
1309 if (ix1 < r_view.x) ix1 = r_view.x;
1310 if (iy1 < r_view.y) iy1 = r_view.y;
1311 if (ix2 > r_view.x + r_view.width) ix2 = r_view.x + r_view.width;
1312 if (iy2 > r_view.y + r_view.height) iy2 = r_view.y + r_view.height;
1314 // if it is inside out, it's not visible
1315 if (ix2 <= ix1 || iy2 <= iy1)
1318 // the light area is visible, set up the scissor rectangle
1319 GL_Scissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1320 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);CHECKGLERROR
1321 //qglEnable(GL_SCISSOR_TEST);CHECKGLERROR
1322 r_refdef.stats.lights_scissored++;
1326 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
1328 float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1329 float *normal3f = rsurface.normal3f + 3 * firstvertex;
1330 float *color4f = rsurface.array_color4f + 4 * firstvertex;
1331 float dist, dot, distintensity, shadeintensity, v[3], n[3];
1332 if (r_textureunits.integer >= 3)
1334 if (VectorLength2(diffusecolor) > 0)
1336 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1338 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1339 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1340 if ((dot = DotProduct(n, v)) < 0)
1342 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1343 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
1346 VectorCopy(ambientcolor, color4f);
1347 if (r_refdef.fogenabled)
1350 f = FogPoint_Model(vertex3f);
1351 VectorScale(color4f, f, color4f);
1358 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1360 VectorCopy(ambientcolor, color4f);
1361 if (r_refdef.fogenabled)
1364 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1365 f = FogPoint_Model(vertex3f);
1366 VectorScale(color4f, f, color4f);
1372 else if (r_textureunits.integer >= 2)
1374 if (VectorLength2(diffusecolor) > 0)
1376 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1378 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1379 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1381 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1382 if ((dot = DotProduct(n, v)) < 0)
1384 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1385 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1386 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1387 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1391 color4f[0] = ambientcolor[0] * distintensity;
1392 color4f[1] = ambientcolor[1] * distintensity;
1393 color4f[2] = ambientcolor[2] * distintensity;
1395 if (r_refdef.fogenabled)
1398 f = FogPoint_Model(vertex3f);
1399 VectorScale(color4f, f, color4f);
1403 VectorClear(color4f);
1409 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1411 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1412 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1414 color4f[0] = ambientcolor[0] * distintensity;
1415 color4f[1] = ambientcolor[1] * distintensity;
1416 color4f[2] = ambientcolor[2] * distintensity;
1417 if (r_refdef.fogenabled)
1420 f = FogPoint_Model(vertex3f);
1421 VectorScale(color4f, f, color4f);
1425 VectorClear(color4f);
1432 if (VectorLength2(diffusecolor) > 0)
1434 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1436 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1437 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1439 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
1440 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1441 if ((dot = DotProduct(n, v)) < 0)
1443 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1444 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1445 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1446 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1450 color4f[0] = ambientcolor[0] * distintensity;
1451 color4f[1] = ambientcolor[1] * distintensity;
1452 color4f[2] = ambientcolor[2] * distintensity;
1454 if (r_refdef.fogenabled)
1457 f = FogPoint_Model(vertex3f);
1458 VectorScale(color4f, f, color4f);
1462 VectorClear(color4f);
1468 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1470 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1471 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1473 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
1474 color4f[0] = ambientcolor[0] * distintensity;
1475 color4f[1] = ambientcolor[1] * distintensity;
1476 color4f[2] = ambientcolor[2] * distintensity;
1477 if (r_refdef.fogenabled)
1480 f = FogPoint_Model(vertex3f);
1481 VectorScale(color4f, f, color4f);
1485 VectorClear(color4f);
1492 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1494 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
1497 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
1498 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1499 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
1500 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
1501 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
1503 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1505 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
1506 // the cubemap normalizes this for us
1507 out3f[0] = DotProduct(svector3f, lightdir);
1508 out3f[1] = DotProduct(tvector3f, lightdir);
1509 out3f[2] = DotProduct(normal3f, lightdir);
1513 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
1516 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
1517 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1518 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
1519 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
1520 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
1521 float lightdir[3], eyedir[3], halfdir[3];
1522 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1524 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
1525 VectorNormalize(lightdir);
1526 VectorSubtract(rsurface.modelorg, vertex3f, eyedir);
1527 VectorNormalize(eyedir);
1528 VectorAdd(lightdir, eyedir, halfdir);
1529 // the cubemap normalizes this for us
1530 out3f[0] = DotProduct(svector3f, halfdir);
1531 out3f[1] = DotProduct(tvector3f, halfdir);
1532 out3f[2] = DotProduct(normal3f, halfdir);
1536 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)
1538 // used to display how many times a surface is lit for level design purposes
1539 GL_Color(0.1 * r_view.colorscale, 0.025 * r_view.colorscale, 0, 1);
1540 R_Mesh_ColorPointer(NULL, 0, 0);
1541 R_Mesh_ResetTextureState();
1542 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1545 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)
1547 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
1548 R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
1549 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
1550 R_Mesh_TexBind(0, R_GetTexture(rsurface.texture->currentskinframe->nmap));
1551 R_Mesh_TexBind(1, R_GetTexture(rsurface.texture->basetexture));
1552 R_Mesh_TexBind(2, R_GetTexture(rsurface.texture->glosstexture));
1553 R_Mesh_TexBindCubeMap(3, R_GetTexture(rsurface.rtlight->currentcubemap));
1554 R_Mesh_TexBind(4, R_GetTexture(r_texture_fogattenuation));
1555 R_Mesh_TexBind(5, R_GetTexture(rsurface.texture->currentskinframe->pants));
1556 R_Mesh_TexBind(6, R_GetTexture(rsurface.texture->currentskinframe->shirt));
1557 R_Mesh_TexBind(10, R_GetTexture(r_shadow_attenuationgradienttexture));
1558 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
1559 R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
1560 R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
1561 R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
1562 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1564 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1566 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1567 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1569 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1573 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)
1575 // shared final code for all the dot3 layers
1577 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 0);
1578 for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
1580 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
1581 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1585 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)
1588 // colorscale accounts for how much we multiply the brightness
1591 // mult is how many times the final pass of the lighting will be
1592 // performed to get more brightness than otherwise possible.
1594 // Limit mult to 64 for sanity sake.
1596 if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1598 // 3 3D combine path (Geforce3, Radeon 8500)
1599 memset(&m, 0, sizeof(m));
1600 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1601 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1602 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1603 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1604 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1605 m.tex[1] = R_GetTexture(basetexture);
1606 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
1607 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
1608 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
1609 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
1610 m.texcubemap[2] = R_GetTexture(rsurface.rtlight->currentcubemap);
1611 m.pointer_texcoord3f[2] = rsurface.vertex3f;
1612 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
1613 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
1614 m.texmatrix[2] = rsurface.entitytolight;
1615 GL_BlendFunc(GL_ONE, GL_ONE);
1617 else if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1619 // 2 3D combine path (Geforce3, original Radeon)
1620 memset(&m, 0, sizeof(m));
1621 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1622 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1623 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1624 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1625 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1626 m.tex[1] = R_GetTexture(basetexture);
1627 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
1628 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
1629 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
1630 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
1631 GL_BlendFunc(GL_ONE, GL_ONE);
1633 else if (r_textureunits.integer >= 4 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
1635 // 4 2D combine path (Geforce3, Radeon 8500)
1636 memset(&m, 0, sizeof(m));
1637 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1638 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1639 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1640 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1641 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1642 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1643 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1644 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1645 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1646 m.texmatrix[1] = rsurface.entitytoattenuationz;
1647 m.tex[2] = R_GetTexture(basetexture);
1648 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
1649 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
1650 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
1651 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
1652 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1654 m.texcubemap[3] = R_GetTexture(rsurface.rtlight->currentcubemap);
1655 m.pointer_texcoord3f[3] = rsurface.vertex3f;
1656 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
1657 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
1658 m.texmatrix[3] = rsurface.entitytolight;
1660 GL_BlendFunc(GL_ONE, GL_ONE);
1662 else if (r_textureunits.integer >= 3 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
1664 // 3 2D combine path (Geforce3, original Radeon)
1665 memset(&m, 0, sizeof(m));
1666 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1667 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1668 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1669 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1670 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1671 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1672 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1673 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1674 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1675 m.texmatrix[1] = rsurface.entitytoattenuationz;
1676 m.tex[2] = R_GetTexture(basetexture);
1677 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
1678 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
1679 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
1680 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
1681 GL_BlendFunc(GL_ONE, GL_ONE);
1685 // 2/2/2 2D combine path (any dot3 card)
1686 memset(&m, 0, sizeof(m));
1687 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1688 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1689 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1690 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1691 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1692 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1693 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1694 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1695 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1696 m.texmatrix[1] = rsurface.entitytoattenuationz;
1697 R_Mesh_TextureState(&m);
1698 GL_ColorMask(0,0,0,1);
1699 GL_BlendFunc(GL_ONE, GL_ZERO);
1700 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1703 memset(&m, 0, sizeof(m));
1704 m.tex[0] = R_GetTexture(basetexture);
1705 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1706 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1707 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1708 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1709 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1711 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1712 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1713 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1714 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1715 m.texmatrix[1] = rsurface.entitytolight;
1717 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1719 // this final code is shared
1720 R_Mesh_TextureState(&m);
1721 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1724 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)
1727 // colorscale accounts for how much we multiply the brightness
1730 // mult is how many times the final pass of the lighting will be
1731 // performed to get more brightness than otherwise possible.
1733 // Limit mult to 64 for sanity sake.
1735 // generate normalization cubemap texcoords
1736 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
1737 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1739 // 3/2 3D combine path (Geforce3, Radeon 8500)
1740 memset(&m, 0, sizeof(m));
1741 m.tex[0] = R_GetTexture(normalmaptexture);
1742 m.texcombinergb[0] = GL_REPLACE;
1743 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1744 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1745 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1746 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1747 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1748 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1749 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1750 m.pointer_texcoord_bufferobject[1] = 0;
1751 m.pointer_texcoord_bufferoffset[1] = 0;
1752 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1753 m.pointer_texcoord3f[2] = rsurface.vertex3f;
1754 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
1755 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
1756 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
1757 R_Mesh_TextureState(&m);
1758 GL_ColorMask(0,0,0,1);
1759 GL_BlendFunc(GL_ONE, GL_ZERO);
1760 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1763 memset(&m, 0, sizeof(m));
1764 m.tex[0] = R_GetTexture(basetexture);
1765 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1766 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1767 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1768 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1769 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1771 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1772 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1773 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1774 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1775 m.texmatrix[1] = rsurface.entitytolight;
1777 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1779 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
1781 // 1/2/2 3D combine path (original Radeon)
1782 memset(&m, 0, sizeof(m));
1783 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1784 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1785 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1786 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1787 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1788 R_Mesh_TextureState(&m);
1789 GL_ColorMask(0,0,0,1);
1790 GL_BlendFunc(GL_ONE, GL_ZERO);
1791 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1794 memset(&m, 0, sizeof(m));
1795 m.tex[0] = R_GetTexture(normalmaptexture);
1796 m.texcombinergb[0] = GL_REPLACE;
1797 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1798 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1799 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1800 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1801 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1802 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1803 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1804 m.pointer_texcoord_bufferobject[1] = 0;
1805 m.pointer_texcoord_bufferoffset[1] = 0;
1806 R_Mesh_TextureState(&m);
1807 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1808 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1811 memset(&m, 0, sizeof(m));
1812 m.tex[0] = R_GetTexture(basetexture);
1813 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1814 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1815 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1816 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1817 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1819 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1820 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1821 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1822 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1823 m.texmatrix[1] = rsurface.entitytolight;
1825 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1827 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
1829 // 2/2 3D combine path (original Radeon)
1830 memset(&m, 0, sizeof(m));
1831 m.tex[0] = R_GetTexture(normalmaptexture);
1832 m.texcombinergb[0] = GL_REPLACE;
1833 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1834 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1835 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1836 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1837 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1838 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1839 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1840 m.pointer_texcoord_bufferobject[1] = 0;
1841 m.pointer_texcoord_bufferoffset[1] = 0;
1842 R_Mesh_TextureState(&m);
1843 GL_ColorMask(0,0,0,1);
1844 GL_BlendFunc(GL_ONE, GL_ZERO);
1845 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1848 memset(&m, 0, sizeof(m));
1849 m.tex[0] = R_GetTexture(basetexture);
1850 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1851 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1852 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1853 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1854 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1855 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1856 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1857 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1858 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
1859 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1861 else if (r_textureunits.integer >= 4)
1863 // 4/2 2D combine path (Geforce3, Radeon 8500)
1864 memset(&m, 0, sizeof(m));
1865 m.tex[0] = R_GetTexture(normalmaptexture);
1866 m.texcombinergb[0] = GL_REPLACE;
1867 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1868 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1869 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1870 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1871 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1872 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1873 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1874 m.pointer_texcoord_bufferobject[1] = 0;
1875 m.pointer_texcoord_bufferoffset[1] = 0;
1876 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1877 m.pointer_texcoord3f[2] = rsurface.vertex3f;
1878 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
1879 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
1880 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
1881 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1882 m.pointer_texcoord3f[3] = rsurface.vertex3f;
1883 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
1884 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
1885 m.texmatrix[3] = rsurface.entitytoattenuationz;
1886 R_Mesh_TextureState(&m);
1887 GL_ColorMask(0,0,0,1);
1888 GL_BlendFunc(GL_ONE, GL_ZERO);
1889 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1892 memset(&m, 0, sizeof(m));
1893 m.tex[0] = R_GetTexture(basetexture);
1894 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1895 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1896 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1897 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1898 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1900 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1901 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1902 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1903 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1904 m.texmatrix[1] = rsurface.entitytolight;
1906 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1910 // 2/2/2 2D combine path (any dot3 card)
1911 memset(&m, 0, sizeof(m));
1912 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1913 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1914 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1915 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1916 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1917 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1918 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1919 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1920 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1921 m.texmatrix[1] = rsurface.entitytoattenuationz;
1922 R_Mesh_TextureState(&m);
1923 GL_ColorMask(0,0,0,1);
1924 GL_BlendFunc(GL_ONE, GL_ZERO);
1925 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1928 memset(&m, 0, sizeof(m));
1929 m.tex[0] = R_GetTexture(normalmaptexture);
1930 m.texcombinergb[0] = GL_REPLACE;
1931 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1932 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1933 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1934 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1935 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1936 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1937 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1938 m.pointer_texcoord_bufferobject[1] = 0;
1939 m.pointer_texcoord_bufferoffset[1] = 0;
1940 R_Mesh_TextureState(&m);
1941 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1942 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1945 memset(&m, 0, sizeof(m));
1946 m.tex[0] = R_GetTexture(basetexture);
1947 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1948 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1949 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1950 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1951 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1953 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1954 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1955 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1956 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1957 m.texmatrix[1] = rsurface.entitytolight;
1959 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1961 // this final code is shared
1962 R_Mesh_TextureState(&m);
1963 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1966 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)
1968 float glossexponent;
1970 // FIXME: detect blendsquare!
1971 //if (!gl_support_blendsquare)
1974 // generate normalization cubemap texcoords
1975 R_Shadow_GenTexCoords_Specular_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
1976 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
1978 // 2/0/0/1/2 3D combine blendsquare path
1979 memset(&m, 0, sizeof(m));
1980 m.tex[0] = R_GetTexture(normalmaptexture);
1981 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1982 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1983 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1984 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1985 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1986 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1987 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1988 m.pointer_texcoord_bufferobject[1] = 0;
1989 m.pointer_texcoord_bufferoffset[1] = 0;
1990 R_Mesh_TextureState(&m);
1991 GL_ColorMask(0,0,0,1);
1992 // this squares the result
1993 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1994 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1996 // second and third pass
1997 R_Mesh_ResetTextureState();
1998 // square alpha in framebuffer a few times to make it shiny
1999 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2000 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2001 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2004 memset(&m, 0, sizeof(m));
2005 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2006 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2007 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2008 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2009 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2010 R_Mesh_TextureState(&m);
2011 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2012 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2015 memset(&m, 0, sizeof(m));
2016 m.tex[0] = R_GetTexture(glosstexture);
2017 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2018 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2019 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2020 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2021 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2023 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2024 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2025 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2026 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2027 m.texmatrix[1] = rsurface.entitytolight;
2029 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2031 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
2033 // 2/0/0/2 3D combine blendsquare path
2034 memset(&m, 0, sizeof(m));
2035 m.tex[0] = R_GetTexture(normalmaptexture);
2036 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2037 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2038 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2039 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2040 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2041 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2042 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2043 m.pointer_texcoord_bufferobject[1] = 0;
2044 m.pointer_texcoord_bufferoffset[1] = 0;
2045 R_Mesh_TextureState(&m);
2046 GL_ColorMask(0,0,0,1);
2047 // this squares the result
2048 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2049 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2051 // second and third pass
2052 R_Mesh_ResetTextureState();
2053 // square alpha in framebuffer a few times to make it shiny
2054 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2055 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2056 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2059 memset(&m, 0, sizeof(m));
2060 m.tex[0] = R_GetTexture(glosstexture);
2061 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2062 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2063 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2064 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2065 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2066 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2067 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2068 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2069 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2070 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2074 // 2/0/0/2/2 2D combine blendsquare path
2075 memset(&m, 0, sizeof(m));
2076 m.tex[0] = R_GetTexture(normalmaptexture);
2077 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2078 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2079 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2080 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2081 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2082 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2083 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2084 m.pointer_texcoord_bufferobject[1] = 0;
2085 m.pointer_texcoord_bufferoffset[1] = 0;
2086 R_Mesh_TextureState(&m);
2087 GL_ColorMask(0,0,0,1);
2088 // this squares the result
2089 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2090 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2092 // second and third pass
2093 R_Mesh_ResetTextureState();
2094 // square alpha in framebuffer a few times to make it shiny
2095 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2096 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2097 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2100 memset(&m, 0, sizeof(m));
2101 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2102 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2103 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2104 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2105 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2106 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2107 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2108 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2109 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2110 m.texmatrix[1] = rsurface.entitytoattenuationz;
2111 R_Mesh_TextureState(&m);
2112 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2113 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2116 memset(&m, 0, sizeof(m));
2117 m.tex[0] = R_GetTexture(glosstexture);
2118 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2119 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2120 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2121 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2122 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2124 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2125 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2126 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2127 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2128 m.texmatrix[1] = rsurface.entitytolight;
2130 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2132 // this final code is shared
2133 R_Mesh_TextureState(&m);
2134 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
2137 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)
2139 // ARB path (any Geforce, any Radeon)
2140 qboolean doambient = ambientscale > 0;
2141 qboolean dodiffuse = diffusescale > 0;
2142 qboolean dospecular = specularscale > 0;
2143 if (!doambient && !dodiffuse && !dospecular)
2145 R_Mesh_ColorPointer(NULL, 0, 0);
2147 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, basetexture, ambientscale * r_view.colorscale);
2149 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, basetexture, normalmaptexture, diffusescale * r_view.colorscale);
2153 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorpants, pantstexture, ambientscale * r_view.colorscale);
2155 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorpants, pantstexture, normalmaptexture, diffusescale * r_view.colorscale);
2160 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorshirt, shirttexture, ambientscale * r_view.colorscale);
2162 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorshirt, shirttexture, normalmaptexture, diffusescale * r_view.colorscale);
2165 R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_view.colorscale);
2168 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)
2175 int newnumtriangles;
2179 int newelements[4096*3];
2180 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
2181 for (renders = 0;renders < 64;renders++)
2186 newnumtriangles = 0;
2188 // due to low fillrate on the cards this vertex lighting path is
2189 // designed for, we manually cull all triangles that do not
2190 // contain a lit vertex
2191 // this builds batches of triangles from multiple surfaces and
2192 // renders them at once
2193 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2195 if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
2197 if (newnumtriangles)
2199 newfirstvertex = min(newfirstvertex, e[0]);
2200 newlastvertex = max(newlastvertex, e[0]);
2204 newfirstvertex = e[0];
2205 newlastvertex = e[0];
2207 newfirstvertex = min(newfirstvertex, e[1]);
2208 newlastvertex = max(newlastvertex, e[1]);
2209 newfirstvertex = min(newfirstvertex, e[2]);
2210 newlastvertex = max(newlastvertex, e[2]);
2216 if (newnumtriangles >= (int)(sizeof(newelements)/sizeof(float[3])))
2218 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, newnumtriangles, newelements, 0, 0);
2219 newnumtriangles = 0;
2225 if (newnumtriangles >= 1)
2227 // if all triangles are included, use the original array to take advantage of the bufferobject if possible
2228 if (newnumtriangles == numtriangles)
2229 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2231 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, newnumtriangles, newelements, 0, 0);
2234 // if we couldn't find any lit triangles, exit early
2237 // now reduce the intensity for the next overbright pass
2238 // we have to clamp to 0 here incase the drivers have improper
2239 // handling of negative colors
2240 // (some old drivers even have improper handling of >1 color)
2242 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2244 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2246 c[0] = max(0, c[0] - 1);
2247 c[1] = max(0, c[1] - 1);
2248 c[2] = max(0, c[2] - 1);
2260 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)
2262 // OpenGL 1.1 path (anything)
2263 float ambientcolorbase[3], diffusecolorbase[3];
2264 float ambientcolorpants[3], diffusecolorpants[3];
2265 float ambientcolorshirt[3], diffusecolorshirt[3];
2267 VectorScale(lightcolorbase, ambientscale * 2 * r_view.colorscale, ambientcolorbase);
2268 VectorScale(lightcolorbase, diffusescale * 2 * r_view.colorscale, diffusecolorbase);
2269 VectorScale(lightcolorpants, ambientscale * 2 * r_view.colorscale, ambientcolorpants);
2270 VectorScale(lightcolorpants, diffusescale * 2 * r_view.colorscale, diffusecolorpants);
2271 VectorScale(lightcolorshirt, ambientscale * 2 * r_view.colorscale, ambientcolorshirt);
2272 VectorScale(lightcolorshirt, diffusescale * 2 * r_view.colorscale, diffusecolorshirt);
2273 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2274 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
2275 memset(&m, 0, sizeof(m));
2276 m.tex[0] = R_GetTexture(basetexture);
2277 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2278 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2279 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2280 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2281 if (r_textureunits.integer >= 2)
2284 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2285 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2286 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2287 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2288 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2289 if (r_textureunits.integer >= 3)
2291 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
2292 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2293 m.texmatrix[2] = rsurface.entitytoattenuationz;
2294 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2295 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2296 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2299 R_Mesh_TextureState(&m);
2300 //R_Mesh_TexBind(0, R_GetTexture(basetexture));
2301 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, diffusecolorbase, ambientcolorbase);
2304 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
2305 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, diffusecolorpants, ambientcolorpants);
2309 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
2310 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, diffusecolorshirt, ambientcolorshirt);
2314 extern cvar_t gl_lightmaps;
2315 void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset)
2317 float ambientscale, diffusescale, specularscale;
2318 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
2320 // calculate colors to render this texture with
2321 lightcolorbase[0] = rsurface.rtlight->currentcolor[0] * rsurface.texture->dlightcolor[0];
2322 lightcolorbase[1] = rsurface.rtlight->currentcolor[1] * rsurface.texture->dlightcolor[1];
2323 lightcolorbase[2] = rsurface.rtlight->currentcolor[2] * rsurface.texture->dlightcolor[2];
2324 ambientscale = rsurface.rtlight->ambientscale;
2325 diffusescale = rsurface.rtlight->diffusescale;
2326 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2327 if (!r_shadow_usenormalmap.integer)
2329 ambientscale += 1.0f * diffusescale;
2333 if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
2335 GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
2336 GL_PolygonOffset(rsurface.texture->currentpolygonfactor, rsurface.texture->currentpolygonoffset);
2337 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
2338 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_view.cullface_back);
2339 nmap = rsurface.texture->currentskinframe->nmap;
2340 if (gl_lightmaps.integer)
2341 nmap = r_texture_blanknormalmap;
2342 if (rsurface.texture->colormapping && !gl_lightmaps.integer)
2344 qboolean dopants = rsurface.texture->currentskinframe->pants != NULL && VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f);
2345 qboolean doshirt = rsurface.texture->currentskinframe->shirt != NULL && VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f);
2348 lightcolorpants[0] = lightcolorbase[0] * rsurface.colormap_pantscolor[0];
2349 lightcolorpants[1] = lightcolorbase[1] * rsurface.colormap_pantscolor[1];
2350 lightcolorpants[2] = lightcolorbase[2] * rsurface.colormap_pantscolor[2];
2353 VectorClear(lightcolorpants);
2356 lightcolorshirt[0] = lightcolorbase[0] * rsurface.colormap_shirtcolor[0];
2357 lightcolorshirt[1] = lightcolorbase[1] * rsurface.colormap_shirtcolor[1];
2358 lightcolorshirt[2] = lightcolorbase[2] * rsurface.colormap_shirtcolor[2];
2361 VectorClear(lightcolorshirt);
2362 switch (r_shadow_rendermode)
2364 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2365 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2366 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);
2368 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2369 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);
2371 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2372 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);
2374 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2375 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);
2378 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2384 switch (r_shadow_rendermode)
2386 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2387 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2388 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);
2390 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2391 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);
2393 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2394 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);
2396 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2397 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);
2400 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2406 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)
2408 matrix4x4_t tempmatrix = *matrix;
2409 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2411 // if this light has been compiled before, free the associated data
2412 R_RTLight_Uncompile(rtlight);
2414 // clear it completely to avoid any lingering data
2415 memset(rtlight, 0, sizeof(*rtlight));
2417 // copy the properties
2418 rtlight->matrix_lighttoworld = tempmatrix;
2419 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2420 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2421 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2422 VectorCopy(color, rtlight->color);
2423 rtlight->cubemapname[0] = 0;
2424 if (cubemapname && cubemapname[0])
2425 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2426 rtlight->shadow = shadow;
2427 rtlight->corona = corona;
2428 rtlight->style = style;
2429 rtlight->isstatic = isstatic;
2430 rtlight->coronasizescale = coronasizescale;
2431 rtlight->ambientscale = ambientscale;
2432 rtlight->diffusescale = diffusescale;
2433 rtlight->specularscale = specularscale;
2434 rtlight->flags = flags;
2436 // compute derived data
2437 //rtlight->cullradius = rtlight->radius;
2438 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2439 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2440 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2441 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2442 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2443 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2444 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2447 // compiles rtlight geometry
2448 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2449 void R_RTLight_Compile(rtlight_t *rtlight)
2452 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2453 int lighttris, shadowtris, shadowmeshes, shadowmeshtris;
2454 entity_render_t *ent = r_refdef.worldentity;
2455 model_t *model = r_refdef.worldmodel;
2456 unsigned char *data;
2458 // compile the light
2459 rtlight->compiled = true;
2460 rtlight->static_numleafs = 0;
2461 rtlight->static_numleafpvsbytes = 0;
2462 rtlight->static_leaflist = NULL;
2463 rtlight->static_leafpvs = NULL;
2464 rtlight->static_numsurfaces = 0;
2465 rtlight->static_surfacelist = NULL;
2466 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2467 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2468 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2469 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2470 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2471 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2473 if (model && model->GetLightInfo)
2475 // this variable must be set for the CompileShadowVolume code
2476 r_shadow_compilingrtlight = rtlight;
2477 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);
2478 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);
2479 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2480 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
2481 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
2482 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
2483 rtlight->static_numsurfaces = numsurfaces;
2484 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2485 rtlight->static_numleafs = numleafs;
2486 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2487 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2488 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2489 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
2490 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
2491 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
2492 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
2493 if (rtlight->static_numsurfaces)
2494 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2495 if (rtlight->static_numleafs)
2496 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2497 if (rtlight->static_numleafpvsbytes)
2498 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2499 if (rtlight->static_numshadowtrispvsbytes)
2500 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
2501 if (rtlight->static_numlighttrispvsbytes)
2502 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
2503 if (model->CompileShadowVolume && rtlight->shadow)
2504 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2505 // now we're done compiling the rtlight
2506 r_shadow_compilingrtlight = NULL;
2510 // use smallest available cullradius - box radius or light radius
2511 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2512 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2516 if (rtlight->static_meshchain_shadow)
2519 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2522 shadowmeshtris += mesh->numtriangles;
2527 if (rtlight->static_numlighttrispvsbytes)
2528 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
2529 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
2533 if (rtlight->static_numlighttrispvsbytes)
2534 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
2535 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
2538 if (developer.integer >= 10)
2539 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);
2542 void R_RTLight_Uncompile(rtlight_t *rtlight)
2544 if (rtlight->compiled)
2546 if (rtlight->static_meshchain_shadow)
2547 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2548 rtlight->static_meshchain_shadow = NULL;
2549 // these allocations are grouped
2550 if (rtlight->static_surfacelist)
2551 Mem_Free(rtlight->static_surfacelist);
2552 rtlight->static_numleafs = 0;
2553 rtlight->static_numleafpvsbytes = 0;
2554 rtlight->static_leaflist = NULL;
2555 rtlight->static_leafpvs = NULL;
2556 rtlight->static_numsurfaces = 0;
2557 rtlight->static_surfacelist = NULL;
2558 rtlight->static_numshadowtrispvsbytes = 0;
2559 rtlight->static_shadowtrispvs = NULL;
2560 rtlight->static_numlighttrispvsbytes = 0;
2561 rtlight->static_lighttrispvs = NULL;
2562 rtlight->compiled = false;
2566 void R_Shadow_UncompileWorldLights(void)
2570 for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
2572 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2575 R_RTLight_Uncompile(&light->rtlight);
2579 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
2583 // reset the count of frustum planes
2584 // see rsurface.rtlight_frustumplanes definition for how much this array
2586 rsurface.rtlight_numfrustumplanes = 0;
2588 // haven't implemented a culling path for ortho rendering
2589 if (!r_view.useperspective)
2591 // check if the light is on screen and copy the 4 planes if it is
2592 for (i = 0;i < 4;i++)
2593 if (PlaneDiff(rtlight->shadoworigin, &r_view.frustum[i]) < -0.03125)
2596 for (i = 0;i < 4;i++)
2597 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_view.frustum[i];
2602 // generate a deformed frustum that includes the light origin, this is
2603 // used to cull shadow casting surfaces that can not possibly cast a
2604 // shadow onto the visible light-receiving surfaces, which can be a
2607 // if the light origin is onscreen the result will be 4 planes exactly
2608 // if the light origin is offscreen on only one axis the result will
2609 // be exactly 5 planes (split-side case)
2610 // if the light origin is offscreen on two axes the result will be
2611 // exactly 4 planes (stretched corner case)
2612 for (i = 0;i < 4;i++)
2614 // quickly reject standard frustum planes that put the light
2615 // origin outside the frustum
2616 if (PlaneDiff(rtlight->shadoworigin, &r_view.frustum[i]) < -0.03125)
2619 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_view.frustum[i];
2621 // if all the standard frustum planes were accepted, the light is onscreen
2622 // otherwise we need to generate some more planes below...
2623 if (rsurface.rtlight_numfrustumplanes < 4)
2625 // at least one of the stock frustum planes failed, so we need to
2626 // create one or two custom planes to enclose the light origin
2627 for (i = 0;i < 4;i++)
2629 // create a plane using the view origin and light origin, and a
2630 // single point from the frustum corner set
2631 TriangleNormal(r_view.origin, r_view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
2632 VectorNormalize(plane.normal);
2633 plane.dist = DotProduct(r_view.origin, plane.normal);
2634 // see if this plane is backwards and flip it if so
2635 for (j = 0;j < 4;j++)
2636 if (j != i && DotProduct(r_view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
2640 VectorNegate(plane.normal, plane.normal);
2642 // flipped plane, test again to see if it is now valid
2643 for (j = 0;j < 4;j++)
2644 if (j != i && DotProduct(r_view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
2646 // if the plane is still not valid, then it is dividing the
2647 // frustum and has to be rejected
2651 // we have created a valid plane, compute extra info
2652 PlaneClassify(&plane);
2654 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
2656 // if we've found 5 frustum planes then we have constructed a
2657 // proper split-side case and do not need to keep searching for
2658 // planes to enclose the light origin
2659 if (rsurface.rtlight_numfrustumplanes == 5)
2667 for (i = 0;i < rsurface.rtlight_numfrustumplanes;i++)
2669 plane = rsurface.rtlight_frustumplanes[i];
2670 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_view.frustumcorner[0], &plane), PlaneDiff(r_view.frustumcorner[1], &plane), PlaneDiff(r_view.frustumcorner[2], &plane), PlaneDiff(r_view.frustumcorner[3], &plane), PlaneDiff(rtlight->shadoworigin, &plane));
2675 // now add the light-space box planes if the light box is rotated, as any
2676 // caster outside the oriented light box is irrelevant (even if it passed
2677 // the worldspace light box, which is axial)
2678 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
2680 for (i = 0;i < 6;i++)
2684 v[i >> 1] = (i & 1) ? -1 : 1;
2685 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
2686 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
2687 plane.dist = VectorNormalizeLength(plane.normal);
2688 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
2689 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
2695 // add the world-space reduced box planes
2696 for (i = 0;i < 6;i++)
2698 VectorClear(plane.normal);
2699 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
2700 plane.dist = (i & 1) ? -rsurface.rtlight_cullmaxs[i >> 1] : rsurface.rtlight_cullmins[i >> 1];
2701 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
2710 // reduce all plane distances to tightly fit the rtlight cull box, which
2712 VectorSet(points[0], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
2713 VectorSet(points[1], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
2714 VectorSet(points[2], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
2715 VectorSet(points[3], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
2716 VectorSet(points[4], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
2717 VectorSet(points[5], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
2718 VectorSet(points[6], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
2719 VectorSet(points[7], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
2720 oldnum = rsurface.rtlight_numfrustumplanes;
2721 rsurface.rtlight_numfrustumplanes = 0;
2722 for (j = 0;j < oldnum;j++)
2724 // find the nearest point on the box to this plane
2725 bestdist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[0]);
2726 for (i = 1;i < 8;i++)
2728 dist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[i]);
2729 if (bestdist > dist)
2732 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);
2733 // if the nearest point is near or behind the plane, we want this
2734 // plane, otherwise the plane is useless as it won't cull anything
2735 if (rsurface.rtlight_frustumplanes[j].dist < bestdist + 0.03125)
2737 PlaneClassify(&rsurface.rtlight_frustumplanes[j]);
2738 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = rsurface.rtlight_frustumplanes[j];
2745 void R_Shadow_DrawWorldShadow(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
2747 RSurf_ActiveWorldEntity();
2748 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2752 for (mesh = rsurface.rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2754 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
2755 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
2756 GL_LockArrays(0, mesh->numverts);
2757 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
2759 // decrement stencil if backface is behind depthbuffer
2760 GL_CullFace(r_view.cullface_front);
2761 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2762 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->ebo, 0);
2763 // increment stencil if frontface is behind depthbuffer
2764 GL_CullFace(r_view.cullface_back);
2765 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2767 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->ebo, 0);
2768 GL_LockArrays(0, 0);
2772 else if (numsurfaces && r_refdef.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
2775 int surfacelistindex;
2776 msurface_t *surface;
2777 R_Shadow_PrepareShadowMark(r_refdef.worldmodel->brush.shadowmesh->numtriangles);
2778 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
2780 surface = r_refdef.worldmodel->data_surfaces + surfacelist[surfacelistindex];
2781 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
2782 if (CHECKPVSBIT(trispvs, t))
2783 shadowmarklist[numshadowmark++] = t;
2785 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);
2787 else if (numsurfaces)
2788 r_refdef.worldmodel->DrawShadowVolume(r_refdef.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
2791 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
2793 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
2794 vec_t relativeshadowradius;
2795 RSurf_ActiveModelEntity(ent, false, false);
2796 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
2797 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
2798 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
2799 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
2800 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
2801 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
2802 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
2803 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
2804 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2807 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
2809 // set up properties for rendering light onto this entity
2810 RSurf_ActiveModelEntity(ent, true, true);
2811 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
2812 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
2813 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
2814 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
2815 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2816 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
2819 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
2821 if (!r_refdef.worldmodel->DrawLight)
2824 // set up properties for rendering light onto this entity
2825 RSurf_ActiveWorldEntity();
2826 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
2827 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
2828 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
2829 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
2830 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2831 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
2833 r_refdef.worldmodel->DrawLight(r_refdef.worldentity, numsurfaces, surfacelist, trispvs);
2836 void R_Shadow_DrawEntityLight(entity_render_t *ent, int numsurfaces, int *surfacelist)
2838 model_t *model = ent->model;
2839 if (!model->DrawLight)
2842 R_Shadow_SetupEntityLight(ent);
2844 model->DrawLight(ent, model->nummodelsurfaces, model->surfacelist, NULL);
2847 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
2851 int numleafs, numsurfaces;
2852 int *leaflist, *surfacelist;
2853 unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs;
2854 int numlightentities;
2855 int numlightentities_noselfshadow;
2856 int numshadowentities;
2857 int numshadowentities_noselfshadow;
2858 entity_render_t *lightentities[MAX_EDICTS];
2859 entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
2860 entity_render_t *shadowentities[MAX_EDICTS];
2861 entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
2863 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
2864 // skip lights that are basically invisible (color 0 0 0)
2865 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
2868 // loading is done before visibility checks because loading should happen
2869 // all at once at the start of a level, not when it stalls gameplay.
2870 // (especially important to benchmarks)
2872 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2873 R_RTLight_Compile(rtlight);
2875 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
2877 // look up the light style value at this time
2878 f = (rtlight->style >= 0 ? r_refdef.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
2879 VectorScale(rtlight->color, f, rtlight->currentcolor);
2881 if (rtlight->selected)
2883 f = 2 + sin(realtime * M_PI * 4.0);
2884 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
2888 // if lightstyle is currently off, don't draw the light
2889 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
2892 // if the light box is offscreen, skip it
2893 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2896 VectorCopy(rtlight->cullmins, rsurface.rtlight_cullmins);
2897 VectorCopy(rtlight->cullmaxs, rsurface.rtlight_cullmaxs);
2899 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2901 // compiled light, world available and can receive realtime lighting
2902 // retrieve leaf information
2903 numleafs = rtlight->static_numleafs;
2904 leaflist = rtlight->static_leaflist;
2905 leafpvs = rtlight->static_leafpvs;
2906 numsurfaces = rtlight->static_numsurfaces;
2907 surfacelist = rtlight->static_surfacelist;
2908 shadowtrispvs = rtlight->static_shadowtrispvs;
2909 lighttrispvs = rtlight->static_lighttrispvs;
2911 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2913 // dynamic light, world available and can receive realtime lighting
2914 // calculate lit surfaces and leafs
2915 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);
2916 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);
2917 leaflist = r_shadow_buffer_leaflist;
2918 leafpvs = r_shadow_buffer_leafpvs;
2919 surfacelist = r_shadow_buffer_surfacelist;
2920 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
2921 lighttrispvs = r_shadow_buffer_lighttrispvs;
2922 // if the reduced leaf bounds are offscreen, skip it
2923 if (R_CullBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
2934 shadowtrispvs = NULL;
2935 lighttrispvs = NULL;
2937 // check if light is illuminating any visible leafs
2940 for (i = 0;i < numleafs;i++)
2941 if (r_viewcache.world_leafvisible[leaflist[i]])
2946 // set up a scissor rectangle for this light
2947 if (R_Shadow_ScissorForBBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
2950 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
2952 // make a list of lit entities and shadow casting entities
2953 numlightentities = 0;
2954 numlightentities_noselfshadow = 0;
2955 numshadowentities = 0;
2956 numshadowentities_noselfshadow = 0;
2957 // add dynamic entities that are lit by the light
2958 if (r_drawentities.integer)
2960 for (i = 0;i < r_refdef.numentities;i++)
2963 entity_render_t *ent = r_refdef.entities[i];
2965 if (!BoxesOverlap(ent->mins, ent->maxs, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
2967 // skip the object entirely if it is not within the valid
2968 // shadow-casting region (which includes the lit region)
2969 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rsurface.rtlight_numfrustumplanes, rsurface.rtlight_frustumplanes))
2971 if (!(model = ent->model))
2973 if (r_viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
2975 // this entity wants to receive light, is visible, and is
2976 // inside the light box
2977 // TODO: check if the surfaces in the model can receive light
2978 // so now check if it's in a leaf seen by the light
2979 if (r_refdef.worldmodel && r_refdef.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs))
2981 if (ent->flags & RENDER_NOSELFSHADOW)
2982 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
2984 lightentities[numlightentities++] = ent;
2985 // since it is lit, it probably also casts a shadow...
2986 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2987 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
2988 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
2990 // note: exterior models without the RENDER_NOSELFSHADOW
2991 // flag still create a RENDER_NOSELFSHADOW shadow but
2992 // are lit normally, this means that they are
2993 // self-shadowing but do not shadow other
2994 // RENDER_NOSELFSHADOW entities such as the gun
2995 // (very weird, but keeps the player shadow off the gun)
2996 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
2997 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
2999 shadowentities[numshadowentities++] = ent;
3002 else if (ent->flags & RENDER_SHADOW)
3004 // this entity is not receiving light, but may still need to
3006 // TODO: check if the surfaces in the model can cast shadow
3007 // now check if it is in a leaf seen by the light
3008 if (r_refdef.worldmodel && r_refdef.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs))
3010 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3011 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3012 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3014 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3015 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3017 shadowentities[numshadowentities++] = ent;
3023 // return if there's nothing at all to light
3024 if (!numlightentities && !numsurfaces)
3027 // don't let sound skip if going slow
3028 if (r_refdef.extraupdate)
3031 // make this the active rtlight for rendering purposes
3032 R_Shadow_RenderMode_ActiveLight(rtlight);
3033 // count this light in the r_speeds
3034 r_refdef.stats.lights++;
3036 if (r_showshadowvolumes.integer && r_view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.rtworldshadows : r_refdef.rtdlightshadows))
3038 // optionally draw visible shape of the shadow volumes
3039 // for performance analysis by level designers
3040 R_Shadow_RenderMode_VisibleShadowVolumes();
3042 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3043 for (i = 0;i < numshadowentities;i++)
3044 R_Shadow_DrawEntityShadow(shadowentities[i]);
3045 for (i = 0;i < numshadowentities_noselfshadow;i++)
3046 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3049 if (gl_stencil && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.rtworldshadows : r_refdef.rtdlightshadows))
3051 // draw stencil shadow volumes to mask off pixels that are in shadow
3052 // so that they won't receive lighting
3053 R_Shadow_RenderMode_StencilShadowVolumes(true);
3055 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3056 for (i = 0;i < numshadowentities;i++)
3057 R_Shadow_DrawEntityShadow(shadowentities[i]);
3058 if (numlightentities_noselfshadow)
3060 // draw lighting in the unmasked areas
3061 R_Shadow_RenderMode_Lighting(true, false);
3062 for (i = 0;i < numlightentities_noselfshadow;i++)
3063 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i], numsurfaces, surfacelist);
3065 // optionally draw the illuminated areas
3066 // for performance analysis by level designers
3067 if (r_showlighting.integer && r_view.showdebug)
3069 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
3070 for (i = 0;i < numlightentities_noselfshadow;i++)
3071 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i], numsurfaces, surfacelist);
3074 R_Shadow_RenderMode_StencilShadowVolumes(false);
3076 for (i = 0;i < numshadowentities_noselfshadow;i++)
3077 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3079 if (numsurfaces + numlightentities)
3081 // draw lighting in the unmasked areas
3082 R_Shadow_RenderMode_Lighting(true, false);
3084 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3085 for (i = 0;i < numlightentities;i++)
3086 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
3088 // optionally draw the illuminated areas
3089 // for performance analysis by level designers
3090 if (r_showlighting.integer && r_view.showdebug)
3092 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
3094 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3095 for (i = 0;i < numlightentities;i++)
3096 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
3102 if (numsurfaces + numlightentities)
3104 // draw lighting in the unmasked areas
3105 R_Shadow_RenderMode_Lighting(false, false);
3107 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3108 for (i = 0;i < numlightentities;i++)
3109 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
3110 for (i = 0;i < numlightentities_noselfshadow;i++)
3111 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i], numsurfaces, surfacelist);
3113 // optionally draw the illuminated areas
3114 // for performance analysis by level designers
3115 if (r_showlighting.integer && r_view.showdebug)
3117 R_Shadow_RenderMode_VisibleLighting(false, false);
3119 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3120 for (i = 0;i < numlightentities;i++)
3121 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
3122 for (i = 0;i < numlightentities_noselfshadow;i++)
3123 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i], numsurfaces, surfacelist);
3129 void R_Shadow_DrawLightSprites(void);
3130 void R_ShadowVolumeLighting(qboolean visible)
3137 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
3138 R_Shadow_EditLights_Reload_f();
3140 if (r_editlights.integer)
3141 R_Shadow_DrawLightSprites();
3143 R_Shadow_RenderMode_Begin();
3145 flag = r_refdef.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3146 if (r_shadow_debuglight.integer >= 0)
3148 lightindex = r_shadow_debuglight.integer;
3149 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3150 if (light && (light->flags & flag))
3151 R_DrawRTLight(&light->rtlight, visible);
3155 for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
3157 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3158 if (light && (light->flags & flag))
3159 R_DrawRTLight(&light->rtlight, visible);
3162 if (r_refdef.rtdlight)
3163 for (lnum = 0;lnum < r_refdef.numlights;lnum++)
3164 R_DrawRTLight(&r_refdef.lights[lnum], visible);
3166 R_Shadow_RenderMode_End();
3169 extern void R_SetupView(void);
3170 extern cvar_t r_shadows_throwdistance;
3171 void R_DrawModelShadows(void)
3174 float relativethrowdistance;
3175 entity_render_t *ent;
3176 vec3_t relativelightorigin;
3177 vec3_t relativelightdirection;
3178 vec3_t relativeshadowmins, relativeshadowmaxs;
3181 if (!r_drawentities.integer || !gl_stencil)
3185 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
3187 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
3189 if (gl_ext_separatestencil.integer)
3190 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
3191 else if (gl_ext_stenciltwoside.integer)
3192 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
3194 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
3196 R_Shadow_RenderMode_StencilShadowVolumes(true);
3198 for (i = 0;i < r_refdef.numentities;i++)
3200 ent = r_refdef.entities[i];
3201 // cast shadows from anything that is not a submodel of the map
3202 if (ent->model && ent->model->DrawShadowVolume != NULL && !ent->model->brush.submodel && (ent->flags & RENDER_SHADOW))
3204 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
3205 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
3206 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
3207 VectorNegate(ent->modellight_lightdir, relativelightdirection);
3208 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
3209 RSurf_ActiveModelEntity(ent, false, false);
3210 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
3214 // not really the right mode, but this will disable any silly stencil features
3215 R_Shadow_RenderMode_VisibleLighting(true, true);
3217 // vertex coordinates for a quad that covers the screen exactly
3218 vertex3f[0] = 0;vertex3f[1] = 0;vertex3f[2] = 0;
3219 vertex3f[3] = 1;vertex3f[4] = 0;vertex3f[5] = 0;
3220 vertex3f[6] = 1;vertex3f[7] = 1;vertex3f[8] = 0;
3221 vertex3f[9] = 0;vertex3f[10] = 1;vertex3f[11] = 0;
3223 // set up ortho view for rendering this pass
3224 GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
3225 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
3226 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
3227 GL_ScissorTest(true);
3228 R_Mesh_Matrix(&identitymatrix);
3229 R_Mesh_ResetTextureState();
3230 R_Mesh_VertexPointer(vertex3f, 0, 0);
3231 R_Mesh_ColorPointer(NULL, 0, 0);
3233 // set up a 50% darkening blend on shadowed areas
3234 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3235 GL_DepthRange(0, 1);
3236 GL_DepthTest(false);
3237 GL_DepthMask(false);
3238 GL_PolygonOffset(0, 0);CHECKGLERROR
3239 GL_Color(0, 0, 0, 0.5);
3240 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
3241 qglDepthFunc(GL_ALWAYS);CHECKGLERROR
3242 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
3243 qglStencilMask(~0);CHECKGLERROR
3244 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
3245 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
3247 // apply the blend to the shadowed areas
3248 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3250 // restoring the perspective view is done by R_RenderScene
3253 // restore other state to normal
3254 R_Shadow_RenderMode_End();
3257 void R_DrawCoronas(void)
3260 float cscale, scale;
3264 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
3266 R_Mesh_Matrix(&identitymatrix);
3267 flag = r_refdef.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3268 // FIXME: these traces should scan all render entities instead of cl.world
3269 for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
3271 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3274 rtlight = &light->rtlight;
3275 if (!(rtlight->flags & flag))
3277 if (rtlight->corona * r_coronas.value <= 0)
3279 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
3281 cscale = rtlight->corona * r_coronas.value* 0.25f;
3282 scale = rtlight->radius * rtlight->coronasizescale;
3283 if (VectorDistance2(rtlight->shadoworigin, r_view.origin) < 16.0f * 16.0f)
3285 if (CL_Move(r_view.origin, vec3_origin, vec3_origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
3287 R_DrawSprite(GL_ONE, GL_ONE, r_shadow_lightcorona, NULL, true, false, rtlight->shadoworigin, r_view.right, r_view.up, scale, -scale, -scale, scale, rtlight->color[0] * cscale, rtlight->color[1] * cscale, rtlight->color[2] * cscale, 1);
3289 for (i = 0;i < r_refdef.numlights;i++)
3291 rtlight = &r_refdef.lights[i];
3292 if (!(rtlight->flags & flag))
3294 if (rtlight->corona <= 0)
3296 if (VectorDistance2(rtlight->shadoworigin, r_view.origin) < 32.0f * 32.0f)
3298 if (gl_flashblend.integer)
3300 cscale = rtlight->corona * 1.0f;
3301 scale = rtlight->radius * rtlight->coronasizescale * 2.0f;
3305 cscale = rtlight->corona * r_coronas.value* 0.25f;
3306 scale = rtlight->radius * rtlight->coronasizescale;
3308 if (VectorLength(rtlight->color) * cscale < (1.0f / 256.0f))
3310 if (CL_Move(r_view.origin, vec3_origin, vec3_origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
3312 R_DrawSprite(GL_ONE, GL_ONE, r_shadow_lightcorona, NULL, true, false, rtlight->shadoworigin, r_view.right, r_view.up, scale, -scale, -scale, scale, rtlight->color[0] * cscale, rtlight->color[1] * cscale, rtlight->color[2] * cscale, 1);
3318 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
3319 typedef struct suffixinfo_s
3322 qboolean flipx, flipy, flipdiagonal;
3325 static suffixinfo_t suffix[3][6] =
3328 {"px", false, false, false},
3329 {"nx", false, false, false},
3330 {"py", false, false, false},
3331 {"ny", false, false, false},
3332 {"pz", false, false, false},
3333 {"nz", false, false, false}
3336 {"posx", false, false, false},
3337 {"negx", false, false, false},
3338 {"posy", false, false, false},
3339 {"negy", false, false, false},
3340 {"posz", false, false, false},
3341 {"negz", false, false, false}
3344 {"rt", true, false, true},
3345 {"lf", false, true, true},
3346 {"ft", true, true, false},
3347 {"bk", false, false, false},
3348 {"up", true, false, true},
3349 {"dn", true, false, true}
3353 static int componentorder[4] = {0, 1, 2, 3};
3355 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
3357 int i, j, cubemapsize;
3358 unsigned char *cubemappixels, *image_buffer;
3359 rtexture_t *cubemaptexture;
3361 // must start 0 so the first loadimagepixels has no requested width/height
3363 cubemappixels = NULL;
3364 cubemaptexture = NULL;
3365 // keep trying different suffix groups (posx, px, rt) until one loads
3366 for (j = 0;j < 3 && !cubemappixels;j++)
3368 // load the 6 images in the suffix group
3369 for (i = 0;i < 6;i++)
3371 // generate an image name based on the base and and suffix
3372 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
3374 if ((image_buffer = loadimagepixelsbgra(name, false, false)))
3376 // an image loaded, make sure width and height are equal
3377 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
3379 // if this is the first image to load successfully, allocate the cubemap memory
3380 if (!cubemappixels && image_width >= 1)
3382 cubemapsize = image_width;
3383 // note this clears to black, so unavailable sides are black
3384 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
3386 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
3388 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);
3391 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
3393 Mem_Free(image_buffer);
3397 // if a cubemap loaded, upload it
3400 if (!r_shadow_filters_texturepool)
3401 r_shadow_filters_texturepool = R_AllocTexturePool();
3402 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, TEXF_PRECACHE | (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0), NULL);
3403 Mem_Free(cubemappixels);
3407 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
3408 for (j = 0;j < 3;j++)
3409 for (i = 0;i < 6;i++)
3410 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
3411 Con_Print(" and was unable to find any of them.\n");
3413 return cubemaptexture;
3416 rtexture_t *R_Shadow_Cubemap(const char *basename)
3419 for (i = 0;i < numcubemaps;i++)
3420 if (!strcasecmp(cubemaps[i].basename, basename))
3421 return cubemaps[i].texture;
3422 if (i >= MAX_CUBEMAPS)
3423 return r_texture_whitecube;
3425 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
3426 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
3427 if (!cubemaps[i].texture)
3428 cubemaps[i].texture = r_texture_whitecube;
3429 return cubemaps[i].texture;
3432 void R_Shadow_FreeCubemaps(void)
3435 R_FreeTexturePool(&r_shadow_filters_texturepool);
3438 dlight_t *R_Shadow_NewWorldLight(void)
3440 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
3443 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)
3446 // validate parameters
3447 if (style < 0 || style >= MAX_LIGHTSTYLES)
3449 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
3455 // copy to light properties
3456 VectorCopy(origin, light->origin);
3457 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
3458 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
3459 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
3460 light->color[0] = max(color[0], 0);
3461 light->color[1] = max(color[1], 0);
3462 light->color[2] = max(color[2], 0);
3463 light->radius = max(radius, 0);
3464 light->style = style;
3465 light->shadow = shadowenable;
3466 light->corona = corona;
3467 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
3468 light->coronasizescale = coronasizescale;
3469 light->ambientscale = ambientscale;
3470 light->diffusescale = diffusescale;
3471 light->specularscale = specularscale;
3472 light->flags = flags;
3474 // update renderable light data
3475 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
3476 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);
3479 void R_Shadow_FreeWorldLight(dlight_t *light)
3481 if (r_shadow_selectedlight == light)
3482 r_shadow_selectedlight = NULL;
3483 R_RTLight_Uncompile(&light->rtlight);
3484 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
3487 void R_Shadow_ClearWorldLights(void)
3491 for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
3493 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3495 R_Shadow_FreeWorldLight(light);
3497 r_shadow_selectedlight = NULL;
3498 R_Shadow_FreeCubemaps();
3501 void R_Shadow_SelectLight(dlight_t *light)
3503 if (r_shadow_selectedlight)
3504 r_shadow_selectedlight->selected = false;
3505 r_shadow_selectedlight = light;
3506 if (r_shadow_selectedlight)
3507 r_shadow_selectedlight->selected = true;
3510 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
3512 // this is never batched (there can be only one)
3513 R_DrawSprite(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, r_editlights_sprcursor->tex, r_editlights_sprcursor->tex, false, false, r_editlights_cursorlocation, r_view.right, r_view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE, 1, 1, 1, 1);
3516 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
3523 // this is never batched (due to the ent parameter changing every time)
3524 // so numsurfaces == 1 and surfacelist[0] == lightnumber
3525 const dlight_t *light = (dlight_t *)ent;
3528 VectorScale(light->color, intensity, spritecolor);
3529 if (VectorLength(spritecolor) < 0.1732f)
3530 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
3531 if (VectorLength(spritecolor) > 1.0f)
3532 VectorNormalize(spritecolor);
3534 // draw light sprite
3535 if (light->cubemapname[0] && !light->shadow)
3536 pic = r_editlights_sprcubemapnoshadowlight;
3537 else if (light->cubemapname[0])
3538 pic = r_editlights_sprcubemaplight;
3539 else if (!light->shadow)
3540 pic = r_editlights_sprnoshadowlight;
3542 pic = r_editlights_sprlight;
3543 R_DrawSprite(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, pic->tex, pic->tex, false, false, light->origin, r_view.right, r_view.up, s, -s, -s, s, spritecolor[0], spritecolor[1], spritecolor[2], 1);
3544 // draw selection sprite if light is selected
3545 if (light->selected)
3546 R_DrawSprite(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, r_editlights_sprselection->tex, r_editlights_sprselection->tex, false, false, light->origin, r_view.right, r_view.up, s, -s, -s, s, 1, 1, 1, 1);
3547 // VorteX todo: add normalmode/realtime mode light overlay sprites?
3550 void R_Shadow_DrawLightSprites(void)
3554 for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
3556 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3558 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
3560 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
3563 void R_Shadow_SelectLightInView(void)
3565 float bestrating, rating, temp[3];
3571 for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
3573 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3576 VectorSubtract(light->origin, r_view.origin, temp);
3577 rating = (DotProduct(temp, r_view.forward) / sqrt(DotProduct(temp, temp)));
3580 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
3581 if (bestrating < rating && CL_Move(light->origin, vec3_origin, vec3_origin, r_view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
3583 bestrating = rating;
3588 R_Shadow_SelectLight(best);
3591 void R_Shadow_LoadWorldLights(void)
3593 int n, a, style, shadow, flags;
3594 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
3595 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
3596 if (r_refdef.worldmodel == NULL)
3598 Con_Print("No map loaded.\n");
3601 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3602 strlcat (name, ".rtlights", sizeof (name));
3603 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3613 for (;COM_Parse(t, true) && strcmp(
3614 if (COM_Parse(t, true))
3616 if (com_token[0] == '!')
3619 origin[0] = atof(com_token+1);
3622 origin[0] = atof(com_token);
3627 while (*s && *s != '\n' && *s != '\r')
3633 // check for modifier flags
3640 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);
3643 flags = LIGHTFLAG_REALTIMEMODE;
3651 coronasizescale = 0.25f;
3653 VectorClear(angles);
3656 if (a < 9 || !strcmp(cubemapname, "\"\""))
3658 // remove quotes on cubemapname
3659 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
3662 namelen = strlen(cubemapname) - 2;
3663 memmove(cubemapname, cubemapname + 1, namelen);
3664 cubemapname[namelen] = '\0';
3668 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);
3671 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3679 Con_Printf("invalid rtlights file \"%s\"\n", name);
3680 Mem_Free(lightsstring);
3684 void R_Shadow_SaveWorldLights(void)
3688 size_t bufchars, bufmaxchars;
3690 char name[MAX_QPATH];
3691 char line[MAX_INPUTLINE];
3692 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
3694 if (r_refdef.worldmodel == NULL)
3696 Con_Print("No map loaded.\n");
3699 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3700 strlcat (name, ".rtlights", sizeof (name));
3701 bufchars = bufmaxchars = 0;
3703 for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
3705 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3708 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3709 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);
3710 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3711 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]);
3713 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);
3714 if (bufchars + strlen(line) > bufmaxchars)
3716 bufmaxchars = bufchars + strlen(line) + 2048;
3718 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
3722 memcpy(buf, oldbuf, bufchars);
3728 memcpy(buf + bufchars, line, strlen(line));
3729 bufchars += strlen(line);
3733 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
3738 void R_Shadow_LoadLightsFile(void)
3741 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3742 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3743 if (r_refdef.worldmodel == NULL)
3745 Con_Print("No map loaded.\n");
3748 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3749 strlcat (name, ".lights", sizeof (name));
3750 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3758 while (*s && *s != '\n' && *s != '\r')
3764 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);
3768 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);
3771 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3772 radius = bound(15, radius, 4096);
3773 VectorScale(color, (2.0f / (8388608.0f)), color);
3774 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3782 Con_Printf("invalid lights file \"%s\"\n", name);
3783 Mem_Free(lightsstring);
3787 // tyrlite/hmap2 light types in the delay field
3788 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3790 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3792 int entnum, style, islight, skin, pflags, effects, type, n;
3795 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3796 char key[256], value[MAX_INPUTLINE];
3798 if (r_refdef.worldmodel == NULL)
3800 Con_Print("No map loaded.\n");
3803 // try to load a .ent file first
3804 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3805 strlcat (key, ".ent", sizeof (key));
3806 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
3807 // and if that is not found, fall back to the bsp file entity string
3809 data = r_refdef.worldmodel->brush.entities;
3812 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
3814 type = LIGHTTYPE_MINUSX;
3815 origin[0] = origin[1] = origin[2] = 0;
3816 originhack[0] = originhack[1] = originhack[2] = 0;
3817 angles[0] = angles[1] = angles[2] = 0;
3818 color[0] = color[1] = color[2] = 1;
3819 light[0] = light[1] = light[2] = 1;light[3] = 300;
3820 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3830 if (!COM_ParseToken_Simple(&data, false, false))
3832 if (com_token[0] == '}')
3833 break; // end of entity
3834 if (com_token[0] == '_')
3835 strlcpy(key, com_token + 1, sizeof(key));
3837 strlcpy(key, com_token, sizeof(key));
3838 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3839 key[strlen(key)-1] = 0;
3840 if (!COM_ParseToken_Simple(&data, false, false))
3842 strlcpy(value, com_token, sizeof(value));
3844 // now that we have the key pair worked out...
3845 if (!strcmp("light", key))
3847 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3851 light[0] = vec[0] * (1.0f / 256.0f);
3852 light[1] = vec[0] * (1.0f / 256.0f);
3853 light[2] = vec[0] * (1.0f / 256.0f);
3859 light[0] = vec[0] * (1.0f / 255.0f);
3860 light[1] = vec[1] * (1.0f / 255.0f);
3861 light[2] = vec[2] * (1.0f / 255.0f);
3865 else if (!strcmp("delay", key))
3867 else if (!strcmp("origin", key))
3868 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3869 else if (!strcmp("angle", key))
3870 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3871 else if (!strcmp("angles", key))
3872 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3873 else if (!strcmp("color", key))
3874 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3875 else if (!strcmp("wait", key))
3876 fadescale = atof(value);
3877 else if (!strcmp("classname", key))
3879 if (!strncmp(value, "light", 5))
3882 if (!strcmp(value, "light_fluoro"))
3887 overridecolor[0] = 1;
3888 overridecolor[1] = 1;
3889 overridecolor[2] = 1;
3891 if (!strcmp(value, "light_fluorospark"))
3896 overridecolor[0] = 1;
3897 overridecolor[1] = 1;
3898 overridecolor[2] = 1;
3900 if (!strcmp(value, "light_globe"))
3905 overridecolor[0] = 1;
3906 overridecolor[1] = 0.8;
3907 overridecolor[2] = 0.4;
3909 if (!strcmp(value, "light_flame_large_yellow"))
3914 overridecolor[0] = 1;
3915 overridecolor[1] = 0.5;
3916 overridecolor[2] = 0.1;
3918 if (!strcmp(value, "light_flame_small_yellow"))
3923 overridecolor[0] = 1;
3924 overridecolor[1] = 0.5;
3925 overridecolor[2] = 0.1;
3927 if (!strcmp(value, "light_torch_small_white"))
3932 overridecolor[0] = 1;
3933 overridecolor[1] = 0.5;
3934 overridecolor[2] = 0.1;
3936 if (!strcmp(value, "light_torch_small_walltorch"))
3941 overridecolor[0] = 1;
3942 overridecolor[1] = 0.5;
3943 overridecolor[2] = 0.1;
3947 else if (!strcmp("style", key))
3948 style = atoi(value);
3949 else if (!strcmp("skin", key))
3950 skin = (int)atof(value);
3951 else if (!strcmp("pflags", key))
3952 pflags = (int)atof(value);
3953 else if (!strcmp("effects", key))
3954 effects = (int)atof(value);
3955 else if (r_refdef.worldmodel->type == mod_brushq3)
3957 if (!strcmp("scale", key))
3958 lightscale = atof(value);
3959 if (!strcmp("fade", key))
3960 fadescale = atof(value);
3965 if (lightscale <= 0)
3969 if (color[0] == color[1] && color[0] == color[2])
3971 color[0] *= overridecolor[0];
3972 color[1] *= overridecolor[1];
3973 color[2] *= overridecolor[2];
3975 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3976 color[0] = color[0] * light[0];
3977 color[1] = color[1] * light[1];
3978 color[2] = color[2] * light[2];
3981 case LIGHTTYPE_MINUSX:
3983 case LIGHTTYPE_RECIPX:
3985 VectorScale(color, (1.0f / 16.0f), color);
3987 case LIGHTTYPE_RECIPXX:
3989 VectorScale(color, (1.0f / 16.0f), color);
3992 case LIGHTTYPE_NONE:
3996 case LIGHTTYPE_MINUSXX:
3999 VectorAdd(origin, originhack, origin);
4001 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);
4004 Mem_Free(entfiledata);
4008 void R_Shadow_SetCursorLocationForView(void)
4011 vec3_t dest, endpos;
4013 VectorMA(r_view.origin, r_editlights_cursordistance.value, r_view.forward, dest);
4014 trace = CL_Move(r_view.origin, vec3_origin, vec3_origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
4015 if (trace.fraction < 1)
4017 dist = trace.fraction * r_editlights_cursordistance.value;
4018 push = r_editlights_cursorpushback.value;
4022 VectorMA(trace.endpos, push, r_view.forward, endpos);
4023 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
4027 VectorClear( endpos );
4029 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4030 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4031 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4034 void R_Shadow_UpdateWorldLightSelection(void)
4036 if (r_editlights.integer)
4038 R_Shadow_SetCursorLocationForView();
4039 R_Shadow_SelectLightInView();
4042 R_Shadow_SelectLight(NULL);
4045 void R_Shadow_EditLights_Clear_f(void)
4047 R_Shadow_ClearWorldLights();
4050 void R_Shadow_EditLights_Reload_f(void)
4052 if (!r_refdef.worldmodel)
4054 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
4055 R_Shadow_ClearWorldLights();
4056 R_Shadow_LoadWorldLights();
4057 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
4059 R_Shadow_LoadLightsFile();
4060 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
4061 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
4065 void R_Shadow_EditLights_Save_f(void)
4067 if (!r_refdef.worldmodel)
4069 R_Shadow_SaveWorldLights();
4072 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
4074 R_Shadow_ClearWorldLights();
4075 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
4078 void R_Shadow_EditLights_ImportLightsFile_f(void)
4080 R_Shadow_ClearWorldLights();
4081 R_Shadow_LoadLightsFile();
4084 void R_Shadow_EditLights_Spawn_f(void)
4087 if (!r_editlights.integer)
4089 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4092 if (Cmd_Argc() != 1)
4094 Con_Print("r_editlights_spawn does not take parameters\n");
4097 color[0] = color[1] = color[2] = 1;
4098 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
4101 void R_Shadow_EditLights_Edit_f(void)
4103 vec3_t origin, angles, color;
4104 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
4105 int style, shadows, flags, normalmode, realtimemode;
4106 char cubemapname[MAX_INPUTLINE];
4107 if (!r_editlights.integer)
4109 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4112 if (!r_shadow_selectedlight)
4114 Con_Print("No selected light.\n");
4117 VectorCopy(r_shadow_selectedlight->origin, origin);
4118 VectorCopy(r_shadow_selectedlight->angles, angles);
4119 VectorCopy(r_shadow_selectedlight->color, color);
4120 radius = r_shadow_selectedlight->radius;
4121 style = r_shadow_selectedlight->style;
4122 if (r_shadow_selectedlight->cubemapname)
4123 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
4126 shadows = r_shadow_selectedlight->shadow;
4127 corona = r_shadow_selectedlight->corona;
4128 coronasizescale = r_shadow_selectedlight->coronasizescale;
4129 ambientscale = r_shadow_selectedlight->ambientscale;
4130 diffusescale = r_shadow_selectedlight->diffusescale;
4131 specularscale = r_shadow_selectedlight->specularscale;
4132 flags = r_shadow_selectedlight->flags;
4133 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
4134 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
4135 if (!strcmp(Cmd_Argv(1), "origin"))
4137 if (Cmd_Argc() != 5)
4139 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
4142 origin[0] = atof(Cmd_Argv(2));
4143 origin[1] = atof(Cmd_Argv(3));
4144 origin[2] = atof(Cmd_Argv(4));
4146 else if (!strcmp(Cmd_Argv(1), "originx"))
4148 if (Cmd_Argc() != 3)
4150 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4153 origin[0] = atof(Cmd_Argv(2));
4155 else if (!strcmp(Cmd_Argv(1), "originy"))
4157 if (Cmd_Argc() != 3)
4159 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4162 origin[1] = atof(Cmd_Argv(2));
4164 else if (!strcmp(Cmd_Argv(1), "originz"))
4166 if (Cmd_Argc() != 3)
4168 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4171 origin[2] = atof(Cmd_Argv(2));
4173 else if (!strcmp(Cmd_Argv(1), "move"))
4175 if (Cmd_Argc() != 5)
4177 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
4180 origin[0] += atof(Cmd_Argv(2));
4181 origin[1] += atof(Cmd_Argv(3));
4182 origin[2] += atof(Cmd_Argv(4));
4184 else if (!strcmp(Cmd_Argv(1), "movex"))
4186 if (Cmd_Argc() != 3)
4188 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4191 origin[0] += atof(Cmd_Argv(2));
4193 else if (!strcmp(Cmd_Argv(1), "movey"))
4195 if (Cmd_Argc() != 3)
4197 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4200 origin[1] += atof(Cmd_Argv(2));
4202 else if (!strcmp(Cmd_Argv(1), "movez"))
4204 if (Cmd_Argc() != 3)
4206 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4209 origin[2] += atof(Cmd_Argv(2));
4211 else if (!strcmp(Cmd_Argv(1), "angles"))
4213 if (Cmd_Argc() != 5)
4215 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
4218 angles[0] = atof(Cmd_Argv(2));
4219 angles[1] = atof(Cmd_Argv(3));
4220 angles[2] = atof(Cmd_Argv(4));
4222 else if (!strcmp(Cmd_Argv(1), "anglesx"))
4224 if (Cmd_Argc() != 3)
4226 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4229 angles[0] = atof(Cmd_Argv(2));
4231 else if (!strcmp(Cmd_Argv(1), "anglesy"))
4233 if (Cmd_Argc() != 3)
4235 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4238 angles[1] = atof(Cmd_Argv(2));
4240 else if (!strcmp(Cmd_Argv(1), "anglesz"))
4242 if (Cmd_Argc() != 3)
4244 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4247 angles[2] = atof(Cmd_Argv(2));
4249 else if (!strcmp(Cmd_Argv(1), "color"))
4251 if (Cmd_Argc() != 5)
4253 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
4256 color[0] = atof(Cmd_Argv(2));
4257 color[1] = atof(Cmd_Argv(3));
4258 color[2] = atof(Cmd_Argv(4));
4260 else if (!strcmp(Cmd_Argv(1), "radius"))
4262 if (Cmd_Argc() != 3)
4264 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4267 radius = atof(Cmd_Argv(2));
4269 else if (!strcmp(Cmd_Argv(1), "colorscale"))
4271 if (Cmd_Argc() == 3)
4273 double scale = atof(Cmd_Argv(2));
4280 if (Cmd_Argc() != 5)
4282 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
4285 color[0] *= atof(Cmd_Argv(2));
4286 color[1] *= atof(Cmd_Argv(3));
4287 color[2] *= atof(Cmd_Argv(4));
4290 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
4292 if (Cmd_Argc() != 3)
4294 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4297 radius *= atof(Cmd_Argv(2));
4299 else if (!strcmp(Cmd_Argv(1), "style"))
4301 if (Cmd_Argc() != 3)
4303 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4306 style = atoi(Cmd_Argv(2));
4308 else if (!strcmp(Cmd_Argv(1), "cubemap"))
4312 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4315 if (Cmd_Argc() == 3)
4316 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
4320 else if (!strcmp(Cmd_Argv(1), "shadows"))
4322 if (Cmd_Argc() != 3)
4324 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4327 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4329 else if (!strcmp(Cmd_Argv(1), "corona"))
4331 if (Cmd_Argc() != 3)
4333 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4336 corona = atof(Cmd_Argv(2));
4338 else if (!strcmp(Cmd_Argv(1), "coronasize"))
4340 if (Cmd_Argc() != 3)
4342 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4345 coronasizescale = atof(Cmd_Argv(2));
4347 else if (!strcmp(Cmd_Argv(1), "ambient"))
4349 if (Cmd_Argc() != 3)
4351 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4354 ambientscale = atof(Cmd_Argv(2));
4356 else if (!strcmp(Cmd_Argv(1), "diffuse"))
4358 if (Cmd_Argc() != 3)
4360 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4363 diffusescale = atof(Cmd_Argv(2));
4365 else if (!strcmp(Cmd_Argv(1), "specular"))
4367 if (Cmd_Argc() != 3)
4369 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4372 specularscale = atof(Cmd_Argv(2));
4374 else if (!strcmp(Cmd_Argv(1), "normalmode"))
4376 if (Cmd_Argc() != 3)
4378 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4381 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4383 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
4385 if (Cmd_Argc() != 3)
4387 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4390 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4394 Con_Print("usage: r_editlights_edit [property] [value]\n");
4395 Con_Print("Selected light's properties:\n");
4396 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
4397 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
4398 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
4399 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
4400 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
4401 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
4402 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
4403 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
4404 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
4405 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
4406 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
4407 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
4408 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
4409 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
4412 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
4413 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4416 void R_Shadow_EditLights_EditAll_f(void)
4421 if (!r_editlights.integer)
4423 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
4427 for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
4429 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4432 R_Shadow_SelectLight(light);
4433 R_Shadow_EditLights_Edit_f();
4437 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
4439 int lightnumber, lightcount;
4444 if (!r_editlights.integer)
4446 x = vid_conwidth.value - 240;
4448 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
4451 for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
4453 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4456 if (light == r_shadow_selectedlight)
4457 lightnumber = lightindex;
4460 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;
4461 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;
4463 if (r_shadow_selectedlight == NULL)
4465 sprintf(temp, "Light #%i properties:", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
4466 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;
4467 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;
4468 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;
4469 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;
4470 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;
4471 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;
4472 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;
4473 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;
4474 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;
4475 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;
4476 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;
4477 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;
4478 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;
4479 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;
4482 void R_Shadow_EditLights_ToggleShadow_f(void)
4484 if (!r_editlights.integer)
4486 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4489 if (!r_shadow_selectedlight)
4491 Con_Print("No selected light.\n");
4494 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);
4497 void R_Shadow_EditLights_ToggleCorona_f(void)
4499 if (!r_editlights.integer)
4501 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4504 if (!r_shadow_selectedlight)
4506 Con_Print("No selected light.\n");
4509 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);
4512 void R_Shadow_EditLights_Remove_f(void)
4514 if (!r_editlights.integer)
4516 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
4519 if (!r_shadow_selectedlight)
4521 Con_Print("No selected light.\n");
4524 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
4525 r_shadow_selectedlight = NULL;
4528 void R_Shadow_EditLights_Help_f(void)
4531 "Documentation on r_editlights system:\n"
4533 "r_editlights : enable/disable editing mode\n"
4534 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
4535 "r_editlights_cursorpushback : push back cursor this far from surface\n"
4536 "r_editlights_cursorpushoff : push cursor off surface this far\n"
4537 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
4538 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
4540 "r_editlights_help : this help\n"
4541 "r_editlights_clear : remove all lights\n"
4542 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
4543 "r_editlights_save : save to .rtlights file\n"
4544 "r_editlights_spawn : create a light with default settings\n"
4545 "r_editlights_edit command : edit selected light - more documentation below\n"
4546 "r_editlights_remove : remove selected light\n"
4547 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
4548 "r_editlights_importlightentitiesfrommap : reload light entities\n"
4549 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
4551 "origin x y z : set light location\n"
4552 "originx x: set x component of light location\n"
4553 "originy y: set y component of light location\n"
4554 "originz z: set z component of light location\n"
4555 "move x y z : adjust light location\n"
4556 "movex x: adjust x component of light location\n"
4557 "movey y: adjust y component of light location\n"
4558 "movez z: adjust z component of light location\n"
4559 "angles x y z : set light angles\n"
4560 "anglesx x: set x component of light angles\n"
4561 "anglesy y: set y component of light angles\n"
4562 "anglesz z: set z component of light angles\n"
4563 "color r g b : set color of light (can be brighter than 1 1 1)\n"
4564 "radius radius : set radius (size) of light\n"
4565 "colorscale grey : multiply color of light (1 does nothing)\n"
4566 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
4567 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
4568 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
4569 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
4570 "cubemap basename : set filter cubemap of light (not yet supported)\n"
4571 "shadows 1/0 : turn on/off shadows\n"
4572 "corona n : set corona intensity\n"
4573 "coronasize n : set corona size (0-1)\n"
4574 "ambient n : set ambient intensity (0-1)\n"
4575 "diffuse n : set diffuse intensity (0-1)\n"
4576 "specular n : set specular intensity (0-1)\n"
4577 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
4578 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
4579 "<nothing> : print light properties to console\n"
4583 void R_Shadow_EditLights_CopyInfo_f(void)
4585 if (!r_editlights.integer)
4587 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
4590 if (!r_shadow_selectedlight)
4592 Con_Print("No selected light.\n");
4595 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
4596 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
4597 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
4598 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
4599 if (r_shadow_selectedlight->cubemapname)
4600 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
4602 r_shadow_bufferlight.cubemapname[0] = 0;
4603 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
4604 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
4605 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
4606 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
4607 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
4608 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
4609 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
4612 void R_Shadow_EditLights_PasteInfo_f(void)
4614 if (!r_editlights.integer)
4616 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
4619 if (!r_shadow_selectedlight)
4621 Con_Print("No selected light.\n");
4624 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);
4627 void R_Shadow_EditLights_Init(void)
4629 Cvar_RegisterVariable(&r_editlights);
4630 Cvar_RegisterVariable(&r_editlights_cursordistance);
4631 Cvar_RegisterVariable(&r_editlights_cursorpushback);
4632 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
4633 Cvar_RegisterVariable(&r_editlights_cursorgrid);
4634 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
4635 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
4636 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
4637 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)");
4638 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
4639 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
4640 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
4641 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)");
4642 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
4643 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
4644 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
4645 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
4646 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
4647 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
4648 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)");
4654 =============================================================================
4658 =============================================================================
4661 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
4663 VectorClear(diffusecolor);
4664 VectorClear(diffusenormal);
4666 if (!r_fullbright.integer && r_refdef.worldmodel && r_refdef.worldmodel->brush.LightPoint)
4668 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_ambient.value * (2.0f / 128.0f);
4669 r_refdef.worldmodel->brush.LightPoint(r_refdef.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
4672 VectorSet(ambientcolor, 1, 1, 1);
4679 for (i = 0;i < r_refdef.numlights;i++)
4681 light = &r_refdef.lights[i];
4682 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
4683 f = 1 - VectorLength2(v);
4684 if (f > 0 && CL_Move(p, vec3_origin, vec3_origin, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
4685 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);