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 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1198 int i, ix1, iy1, ix2, iy2;
1199 float x1, y1, x2, y2;
1202 mplane_t planes[11];
1203 float vertex3f[256*3];
1205 // if view is inside the light box, just say yes it's visible
1206 if (BoxesOverlap(r_view.origin, r_view.origin, mins, maxs))
1208 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
1212 // create a temporary brush describing the area the light can affect in worldspace
1213 VectorNegate(r_view.frustum[0].normal, planes[ 0].normal);planes[ 0].dist = -r_view.frustum[0].dist;
1214 VectorNegate(r_view.frustum[1].normal, planes[ 1].normal);planes[ 1].dist = -r_view.frustum[1].dist;
1215 VectorNegate(r_view.frustum[2].normal, planes[ 2].normal);planes[ 2].dist = -r_view.frustum[2].dist;
1216 VectorNegate(r_view.frustum[3].normal, planes[ 3].normal);planes[ 3].dist = -r_view.frustum[3].dist;
1217 VectorNegate(r_view.frustum[4].normal, planes[ 4].normal);planes[ 4].dist = -r_view.frustum[4].dist;
1218 VectorSet (planes[ 5].normal, 1, 0, 0); planes[ 5].dist = maxs[0];
1219 VectorSet (planes[ 6].normal, -1, 0, 0); planes[ 6].dist = -mins[0];
1220 VectorSet (planes[ 7].normal, 0, 1, 0); planes[ 7].dist = maxs[1];
1221 VectorSet (planes[ 8].normal, 0, -1, 0); planes[ 8].dist = -mins[1];
1222 VectorSet (planes[ 9].normal, 0, 0, 1); planes[ 9].dist = maxs[2];
1223 VectorSet (planes[10].normal, 0, 0, -1); planes[10].dist = -mins[2];
1225 // turn the brush into a mesh
1226 memset(&mesh, 0, sizeof(rmesh_t));
1227 mesh.maxvertices = 256;
1228 mesh.vertex3f = vertex3f;
1229 mesh.epsilon2 = (1.0f / (32.0f * 32.0f));
1230 R_Mesh_AddBrushMeshFromPlanes(&mesh, 11, planes);
1232 // if that mesh is empty, the light is not visible at all
1233 if (!mesh.numvertices)
1236 if (!r_shadow_scissor.integer)
1239 // if that mesh is not empty, check what area of the screen it covers
1240 x1 = y1 = x2 = y2 = 0;
1242 //Con_Printf("%i vertices to transform...\n", mesh.numvertices);
1243 for (i = 0;i < mesh.numvertices;i++)
1245 VectorCopy(mesh.vertex3f + i * 3, v);
1246 GL_TransformToScreen(v, v2);
1247 //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]);
1250 if (x1 > v2[0]) x1 = v2[0];
1251 if (x2 < v2[0]) x2 = v2[0];
1252 if (y1 > v2[1]) y1 = v2[1];
1253 if (y2 < v2[1]) y2 = v2[1];
1262 // now convert the scissor rectangle to integer screen coordinates
1263 ix1 = (int)(x1 - 1.0f);
1264 iy1 = (int)(y1 - 1.0f);
1265 ix2 = (int)(x2 + 1.0f);
1266 iy2 = (int)(y2 + 1.0f);
1267 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1269 // clamp it to the screen
1270 if (ix1 < r_view.x) ix1 = r_view.x;
1271 if (iy1 < r_view.y) iy1 = r_view.y;
1272 if (ix2 > r_view.x + r_view.width) ix2 = r_view.x + r_view.width;
1273 if (iy2 > r_view.y + r_view.height) iy2 = r_view.y + r_view.height;
1275 // if it is inside out, it's not visible
1276 if (ix2 <= ix1 || iy2 <= iy1)
1279 // the light area is visible, set up the scissor rectangle
1280 GL_Scissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1281 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);CHECKGLERROR
1282 //qglEnable(GL_SCISSOR_TEST);CHECKGLERROR
1283 r_refdef.stats.lights_scissored++;
1287 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
1289 float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1290 float *normal3f = rsurface.normal3f + 3 * firstvertex;
1291 float *color4f = rsurface.array_color4f + 4 * firstvertex;
1292 float dist, dot, distintensity, shadeintensity, v[3], n[3];
1293 if (r_textureunits.integer >= 3)
1295 if (VectorLength2(diffusecolor) > 0)
1297 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1299 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1300 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1301 if ((dot = DotProduct(n, v)) < 0)
1303 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1304 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
1307 VectorCopy(ambientcolor, color4f);
1308 if (r_refdef.fogenabled)
1311 f = FogPoint_Model(vertex3f);
1312 VectorScale(color4f, f, color4f);
1319 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1321 VectorCopy(ambientcolor, color4f);
1322 if (r_refdef.fogenabled)
1325 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1326 f = FogPoint_Model(vertex3f);
1327 VectorScale(color4f, f, color4f);
1333 else if (r_textureunits.integer >= 2)
1335 if (VectorLength2(diffusecolor) > 0)
1337 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1339 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1340 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1342 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1343 if ((dot = DotProduct(n, v)) < 0)
1345 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1346 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1347 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1348 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1352 color4f[0] = ambientcolor[0] * distintensity;
1353 color4f[1] = ambientcolor[1] * distintensity;
1354 color4f[2] = ambientcolor[2] * distintensity;
1356 if (r_refdef.fogenabled)
1359 f = FogPoint_Model(vertex3f);
1360 VectorScale(color4f, f, color4f);
1364 VectorClear(color4f);
1370 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1372 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1373 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1375 color4f[0] = ambientcolor[0] * distintensity;
1376 color4f[1] = ambientcolor[1] * distintensity;
1377 color4f[2] = ambientcolor[2] * distintensity;
1378 if (r_refdef.fogenabled)
1381 f = FogPoint_Model(vertex3f);
1382 VectorScale(color4f, f, color4f);
1386 VectorClear(color4f);
1393 if (VectorLength2(diffusecolor) > 0)
1395 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1397 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1398 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1400 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
1401 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1402 if ((dot = DotProduct(n, v)) < 0)
1404 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1405 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1406 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1407 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1411 color4f[0] = ambientcolor[0] * distintensity;
1412 color4f[1] = ambientcolor[1] * distintensity;
1413 color4f[2] = ambientcolor[2] * distintensity;
1415 if (r_refdef.fogenabled)
1418 f = FogPoint_Model(vertex3f);
1419 VectorScale(color4f, f, color4f);
1423 VectorClear(color4f);
1429 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1431 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1432 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1434 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
1435 color4f[0] = ambientcolor[0] * distintensity;
1436 color4f[1] = ambientcolor[1] * distintensity;
1437 color4f[2] = ambientcolor[2] * distintensity;
1438 if (r_refdef.fogenabled)
1441 f = FogPoint_Model(vertex3f);
1442 VectorScale(color4f, f, color4f);
1446 VectorClear(color4f);
1453 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1455 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
1458 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
1459 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1460 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
1461 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
1462 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
1464 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1466 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
1467 // the cubemap normalizes this for us
1468 out3f[0] = DotProduct(svector3f, lightdir);
1469 out3f[1] = DotProduct(tvector3f, lightdir);
1470 out3f[2] = DotProduct(normal3f, lightdir);
1474 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
1477 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
1478 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1479 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
1480 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
1481 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
1482 float lightdir[3], eyedir[3], halfdir[3];
1483 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1485 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
1486 VectorNormalize(lightdir);
1487 VectorSubtract(rsurface.modelorg, vertex3f, eyedir);
1488 VectorNormalize(eyedir);
1489 VectorAdd(lightdir, eyedir, halfdir);
1490 // the cubemap normalizes this for us
1491 out3f[0] = DotProduct(svector3f, halfdir);
1492 out3f[1] = DotProduct(tvector3f, halfdir);
1493 out3f[2] = DotProduct(normal3f, halfdir);
1497 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)
1499 // used to display how many times a surface is lit for level design purposes
1500 GL_Color(0.1 * r_view.colorscale, 0.025 * r_view.colorscale, 0, 1);
1501 R_Mesh_ColorPointer(NULL, 0, 0);
1502 R_Mesh_ResetTextureState();
1503 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1506 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)
1508 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
1509 R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
1510 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
1511 R_Mesh_TexBind(0, R_GetTexture(rsurface.texture->currentskinframe->nmap));
1512 R_Mesh_TexBind(1, R_GetTexture(rsurface.texture->basetexture));
1513 R_Mesh_TexBind(2, R_GetTexture(rsurface.texture->glosstexture));
1514 R_Mesh_TexBindCubeMap(3, R_GetTexture(rsurface.rtlight->currentcubemap));
1515 R_Mesh_TexBind(4, R_GetTexture(r_texture_fogattenuation));
1516 R_Mesh_TexBind(5, R_GetTexture(rsurface.texture->currentskinframe->pants));
1517 R_Mesh_TexBind(6, R_GetTexture(rsurface.texture->currentskinframe->shirt));
1518 R_Mesh_TexBind(10, R_GetTexture(r_shadow_attenuationgradienttexture));
1519 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
1520 R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
1521 R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
1522 R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
1523 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1525 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1527 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1528 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1530 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1534 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)
1536 // shared final code for all the dot3 layers
1538 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 0);
1539 for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
1541 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
1542 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1546 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)
1549 // colorscale accounts for how much we multiply the brightness
1552 // mult is how many times the final pass of the lighting will be
1553 // performed to get more brightness than otherwise possible.
1555 // Limit mult to 64 for sanity sake.
1557 if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1559 // 3 3D combine path (Geforce3, Radeon 8500)
1560 memset(&m, 0, sizeof(m));
1561 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1562 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1563 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1564 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1565 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1566 m.tex[1] = R_GetTexture(basetexture);
1567 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
1568 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
1569 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
1570 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
1571 m.texcubemap[2] = R_GetTexture(rsurface.rtlight->currentcubemap);
1572 m.pointer_texcoord3f[2] = rsurface.vertex3f;
1573 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
1574 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
1575 m.texmatrix[2] = rsurface.entitytolight;
1576 GL_BlendFunc(GL_ONE, GL_ONE);
1578 else if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1580 // 2 3D combine path (Geforce3, original Radeon)
1581 memset(&m, 0, sizeof(m));
1582 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1583 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1584 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1585 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1586 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1587 m.tex[1] = R_GetTexture(basetexture);
1588 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
1589 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
1590 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
1591 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
1592 GL_BlendFunc(GL_ONE, GL_ONE);
1594 else if (r_textureunits.integer >= 4 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
1596 // 4 2D combine path (Geforce3, Radeon 8500)
1597 memset(&m, 0, sizeof(m));
1598 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1599 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1600 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1601 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1602 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1603 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1604 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1605 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1606 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1607 m.texmatrix[1] = rsurface.entitytoattenuationz;
1608 m.tex[2] = R_GetTexture(basetexture);
1609 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
1610 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
1611 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
1612 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
1613 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1615 m.texcubemap[3] = R_GetTexture(rsurface.rtlight->currentcubemap);
1616 m.pointer_texcoord3f[3] = rsurface.vertex3f;
1617 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
1618 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
1619 m.texmatrix[3] = rsurface.entitytolight;
1621 GL_BlendFunc(GL_ONE, GL_ONE);
1623 else if (r_textureunits.integer >= 3 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
1625 // 3 2D combine path (Geforce3, original Radeon)
1626 memset(&m, 0, sizeof(m));
1627 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1628 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1629 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1630 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1631 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1632 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1633 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1634 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1635 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1636 m.texmatrix[1] = rsurface.entitytoattenuationz;
1637 m.tex[2] = R_GetTexture(basetexture);
1638 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
1639 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
1640 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
1641 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
1642 GL_BlendFunc(GL_ONE, GL_ONE);
1646 // 2/2/2 2D combine path (any dot3 card)
1647 memset(&m, 0, sizeof(m));
1648 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1649 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1650 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1651 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1652 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1653 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1654 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1655 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1656 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1657 m.texmatrix[1] = rsurface.entitytoattenuationz;
1658 R_Mesh_TextureState(&m);
1659 GL_ColorMask(0,0,0,1);
1660 GL_BlendFunc(GL_ONE, GL_ZERO);
1661 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1664 memset(&m, 0, sizeof(m));
1665 m.tex[0] = R_GetTexture(basetexture);
1666 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1667 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1668 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1669 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1670 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1672 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1673 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1674 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1675 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1676 m.texmatrix[1] = rsurface.entitytolight;
1678 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1680 // this final code is shared
1681 R_Mesh_TextureState(&m);
1682 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1685 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)
1688 // colorscale accounts for how much we multiply the brightness
1691 // mult is how many times the final pass of the lighting will be
1692 // performed to get more brightness than otherwise possible.
1694 // Limit mult to 64 for sanity sake.
1696 // generate normalization cubemap texcoords
1697 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
1698 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1700 // 3/2 3D combine path (Geforce3, Radeon 8500)
1701 memset(&m, 0, sizeof(m));
1702 m.tex[0] = R_GetTexture(normalmaptexture);
1703 m.texcombinergb[0] = GL_REPLACE;
1704 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1705 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1706 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1707 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1708 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1709 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1710 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1711 m.pointer_texcoord_bufferobject[1] = 0;
1712 m.pointer_texcoord_bufferoffset[1] = 0;
1713 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1714 m.pointer_texcoord3f[2] = rsurface.vertex3f;
1715 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
1716 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
1717 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
1718 R_Mesh_TextureState(&m);
1719 GL_ColorMask(0,0,0,1);
1720 GL_BlendFunc(GL_ONE, GL_ZERO);
1721 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1724 memset(&m, 0, sizeof(m));
1725 m.tex[0] = R_GetTexture(basetexture);
1726 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1727 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1728 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1729 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1730 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1732 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1733 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1734 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1735 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1736 m.texmatrix[1] = rsurface.entitytolight;
1738 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1740 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
1742 // 1/2/2 3D combine path (original Radeon)
1743 memset(&m, 0, sizeof(m));
1744 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1745 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1746 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1747 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1748 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1749 R_Mesh_TextureState(&m);
1750 GL_ColorMask(0,0,0,1);
1751 GL_BlendFunc(GL_ONE, GL_ZERO);
1752 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1755 memset(&m, 0, sizeof(m));
1756 m.tex[0] = R_GetTexture(normalmaptexture);
1757 m.texcombinergb[0] = GL_REPLACE;
1758 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1759 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1760 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1761 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1762 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1763 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1764 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1765 m.pointer_texcoord_bufferobject[1] = 0;
1766 m.pointer_texcoord_bufferoffset[1] = 0;
1767 R_Mesh_TextureState(&m);
1768 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1769 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1772 memset(&m, 0, sizeof(m));
1773 m.tex[0] = R_GetTexture(basetexture);
1774 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1775 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1776 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1777 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1778 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1780 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1781 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1782 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1783 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1784 m.texmatrix[1] = rsurface.entitytolight;
1786 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1788 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
1790 // 2/2 3D combine path (original Radeon)
1791 memset(&m, 0, sizeof(m));
1792 m.tex[0] = R_GetTexture(normalmaptexture);
1793 m.texcombinergb[0] = GL_REPLACE;
1794 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1795 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1796 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1797 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1798 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1799 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1800 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1801 m.pointer_texcoord_bufferobject[1] = 0;
1802 m.pointer_texcoord_bufferoffset[1] = 0;
1803 R_Mesh_TextureState(&m);
1804 GL_ColorMask(0,0,0,1);
1805 GL_BlendFunc(GL_ONE, GL_ZERO);
1806 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1809 memset(&m, 0, sizeof(m));
1810 m.tex[0] = R_GetTexture(basetexture);
1811 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1812 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1813 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1814 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1815 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1816 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1817 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1818 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1819 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
1820 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1822 else if (r_textureunits.integer >= 4)
1824 // 4/2 2D combine path (Geforce3, Radeon 8500)
1825 memset(&m, 0, sizeof(m));
1826 m.tex[0] = R_GetTexture(normalmaptexture);
1827 m.texcombinergb[0] = GL_REPLACE;
1828 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1829 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1830 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1831 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1832 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1833 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1834 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1835 m.pointer_texcoord_bufferobject[1] = 0;
1836 m.pointer_texcoord_bufferoffset[1] = 0;
1837 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1838 m.pointer_texcoord3f[2] = rsurface.vertex3f;
1839 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
1840 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
1841 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
1842 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1843 m.pointer_texcoord3f[3] = rsurface.vertex3f;
1844 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
1845 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
1846 m.texmatrix[3] = rsurface.entitytoattenuationz;
1847 R_Mesh_TextureState(&m);
1848 GL_ColorMask(0,0,0,1);
1849 GL_BlendFunc(GL_ONE, GL_ZERO);
1850 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1853 memset(&m, 0, sizeof(m));
1854 m.tex[0] = R_GetTexture(basetexture);
1855 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1856 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1857 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1858 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1859 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1861 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1862 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1863 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1864 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1865 m.texmatrix[1] = rsurface.entitytolight;
1867 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1871 // 2/2/2 2D combine path (any dot3 card)
1872 memset(&m, 0, sizeof(m));
1873 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1874 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1875 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1876 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1877 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1878 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1879 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1880 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1881 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1882 m.texmatrix[1] = rsurface.entitytoattenuationz;
1883 R_Mesh_TextureState(&m);
1884 GL_ColorMask(0,0,0,1);
1885 GL_BlendFunc(GL_ONE, GL_ZERO);
1886 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1889 memset(&m, 0, sizeof(m));
1890 m.tex[0] = R_GetTexture(normalmaptexture);
1891 m.texcombinergb[0] = GL_REPLACE;
1892 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1893 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1894 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1895 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1896 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1897 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1898 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1899 m.pointer_texcoord_bufferobject[1] = 0;
1900 m.pointer_texcoord_bufferoffset[1] = 0;
1901 R_Mesh_TextureState(&m);
1902 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1903 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1906 memset(&m, 0, sizeof(m));
1907 m.tex[0] = R_GetTexture(basetexture);
1908 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1909 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1910 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1911 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1912 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1914 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1915 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1916 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1917 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1918 m.texmatrix[1] = rsurface.entitytolight;
1920 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1922 // this final code is shared
1923 R_Mesh_TextureState(&m);
1924 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1927 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)
1929 float glossexponent;
1931 // FIXME: detect blendsquare!
1932 //if (!gl_support_blendsquare)
1935 // generate normalization cubemap texcoords
1936 R_Shadow_GenTexCoords_Specular_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
1937 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
1939 // 2/0/0/1/2 3D combine blendsquare path
1940 memset(&m, 0, sizeof(m));
1941 m.tex[0] = R_GetTexture(normalmaptexture);
1942 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1943 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1944 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1945 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1946 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1947 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1948 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1949 m.pointer_texcoord_bufferobject[1] = 0;
1950 m.pointer_texcoord_bufferoffset[1] = 0;
1951 R_Mesh_TextureState(&m);
1952 GL_ColorMask(0,0,0,1);
1953 // this squares the result
1954 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1955 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1957 // second and third pass
1958 R_Mesh_ResetTextureState();
1959 // square alpha in framebuffer a few times to make it shiny
1960 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1961 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
1962 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1965 memset(&m, 0, sizeof(m));
1966 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1967 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1968 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1969 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1970 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1971 R_Mesh_TextureState(&m);
1972 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1973 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1976 memset(&m, 0, sizeof(m));
1977 m.tex[0] = R_GetTexture(glosstexture);
1978 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1979 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1980 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1981 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1982 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1984 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1985 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1986 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1987 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1988 m.texmatrix[1] = rsurface.entitytolight;
1990 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1992 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
1994 // 2/0/0/2 3D combine blendsquare path
1995 memset(&m, 0, sizeof(m));
1996 m.tex[0] = R_GetTexture(normalmaptexture);
1997 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1998 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1999 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2000 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2001 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2002 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2003 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2004 m.pointer_texcoord_bufferobject[1] = 0;
2005 m.pointer_texcoord_bufferoffset[1] = 0;
2006 R_Mesh_TextureState(&m);
2007 GL_ColorMask(0,0,0,1);
2008 // this squares the result
2009 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2010 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2012 // second and third pass
2013 R_Mesh_ResetTextureState();
2014 // square alpha in framebuffer a few times to make it shiny
2015 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2016 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2017 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2020 memset(&m, 0, sizeof(m));
2021 m.tex[0] = R_GetTexture(glosstexture);
2022 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2023 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2024 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2025 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2026 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2027 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2028 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2029 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2030 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2031 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2035 // 2/0/0/2/2 2D combine blendsquare path
2036 memset(&m, 0, sizeof(m));
2037 m.tex[0] = R_GetTexture(normalmaptexture);
2038 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2039 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2040 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2041 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2042 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2043 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2044 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2045 m.pointer_texcoord_bufferobject[1] = 0;
2046 m.pointer_texcoord_bufferoffset[1] = 0;
2047 R_Mesh_TextureState(&m);
2048 GL_ColorMask(0,0,0,1);
2049 // this squares the result
2050 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2051 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2053 // second and third pass
2054 R_Mesh_ResetTextureState();
2055 // square alpha in framebuffer a few times to make it shiny
2056 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2057 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2058 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2061 memset(&m, 0, sizeof(m));
2062 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2063 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2064 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2065 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2066 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2067 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2068 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2069 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2070 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2071 m.texmatrix[1] = rsurface.entitytoattenuationz;
2072 R_Mesh_TextureState(&m);
2073 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2074 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2077 memset(&m, 0, sizeof(m));
2078 m.tex[0] = R_GetTexture(glosstexture);
2079 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2080 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2081 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2082 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2083 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2085 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2086 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2087 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2088 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2089 m.texmatrix[1] = rsurface.entitytolight;
2091 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2093 // this final code is shared
2094 R_Mesh_TextureState(&m);
2095 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
2098 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)
2100 // ARB path (any Geforce, any Radeon)
2101 qboolean doambient = ambientscale > 0;
2102 qboolean dodiffuse = diffusescale > 0;
2103 qboolean dospecular = specularscale > 0;
2104 if (!doambient && !dodiffuse && !dospecular)
2106 R_Mesh_ColorPointer(NULL, 0, 0);
2108 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, basetexture, ambientscale * r_view.colorscale);
2110 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, basetexture, normalmaptexture, diffusescale * r_view.colorscale);
2114 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorpants, pantstexture, ambientscale * r_view.colorscale);
2116 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorpants, pantstexture, normalmaptexture, diffusescale * r_view.colorscale);
2121 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorshirt, shirttexture, ambientscale * r_view.colorscale);
2123 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorshirt, shirttexture, normalmaptexture, diffusescale * r_view.colorscale);
2126 R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_view.colorscale);
2129 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)
2136 int newnumtriangles;
2140 int newelements[4096*3];
2141 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
2142 for (renders = 0;renders < 64;renders++)
2147 newnumtriangles = 0;
2149 // due to low fillrate on the cards this vertex lighting path is
2150 // designed for, we manually cull all triangles that do not
2151 // contain a lit vertex
2152 // this builds batches of triangles from multiple surfaces and
2153 // renders them at once
2154 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2156 if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
2158 if (newnumtriangles)
2160 newfirstvertex = min(newfirstvertex, e[0]);
2161 newlastvertex = max(newlastvertex, e[0]);
2165 newfirstvertex = e[0];
2166 newlastvertex = e[0];
2168 newfirstvertex = min(newfirstvertex, e[1]);
2169 newlastvertex = max(newlastvertex, e[1]);
2170 newfirstvertex = min(newfirstvertex, e[2]);
2171 newlastvertex = max(newlastvertex, e[2]);
2177 if (newnumtriangles >= (int)(sizeof(newelements)/sizeof(float[3])))
2179 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, newnumtriangles, newelements, 0, 0);
2180 newnumtriangles = 0;
2186 if (newnumtriangles >= 1)
2188 // if all triangles are included, use the original array to take advantage of the bufferobject if possible
2189 if (newnumtriangles == numtriangles)
2190 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2192 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, newnumtriangles, newelements, 0, 0);
2195 // if we couldn't find any lit triangles, exit early
2198 // now reduce the intensity for the next overbright pass
2199 // we have to clamp to 0 here incase the drivers have improper
2200 // handling of negative colors
2201 // (some old drivers even have improper handling of >1 color)
2203 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2205 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2207 c[0] = max(0, c[0] - 1);
2208 c[1] = max(0, c[1] - 1);
2209 c[2] = max(0, c[2] - 1);
2221 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)
2223 // OpenGL 1.1 path (anything)
2224 float ambientcolorbase[3], diffusecolorbase[3];
2225 float ambientcolorpants[3], diffusecolorpants[3];
2226 float ambientcolorshirt[3], diffusecolorshirt[3];
2228 VectorScale(lightcolorbase, ambientscale * 2 * r_view.colorscale, ambientcolorbase);
2229 VectorScale(lightcolorbase, diffusescale * 2 * r_view.colorscale, diffusecolorbase);
2230 VectorScale(lightcolorpants, ambientscale * 2 * r_view.colorscale, ambientcolorpants);
2231 VectorScale(lightcolorpants, diffusescale * 2 * r_view.colorscale, diffusecolorpants);
2232 VectorScale(lightcolorshirt, ambientscale * 2 * r_view.colorscale, ambientcolorshirt);
2233 VectorScale(lightcolorshirt, diffusescale * 2 * r_view.colorscale, diffusecolorshirt);
2234 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2235 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
2236 memset(&m, 0, sizeof(m));
2237 m.tex[0] = R_GetTexture(basetexture);
2238 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2239 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2240 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2241 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2242 if (r_textureunits.integer >= 2)
2245 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2246 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2247 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2248 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2249 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2250 if (r_textureunits.integer >= 3)
2252 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
2253 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2254 m.texmatrix[2] = rsurface.entitytoattenuationz;
2255 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2256 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2257 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2260 R_Mesh_TextureState(&m);
2261 //R_Mesh_TexBind(0, R_GetTexture(basetexture));
2262 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, diffusecolorbase, ambientcolorbase);
2265 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
2266 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, diffusecolorpants, ambientcolorpants);
2270 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
2271 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, diffusecolorshirt, ambientcolorshirt);
2275 extern cvar_t gl_lightmaps;
2276 void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset)
2278 float ambientscale, diffusescale, specularscale;
2279 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
2281 // calculate colors to render this texture with
2282 lightcolorbase[0] = rsurface.rtlight->currentcolor[0] * rsurface.texture->dlightcolor[0];
2283 lightcolorbase[1] = rsurface.rtlight->currentcolor[1] * rsurface.texture->dlightcolor[1];
2284 lightcolorbase[2] = rsurface.rtlight->currentcolor[2] * rsurface.texture->dlightcolor[2];
2285 ambientscale = rsurface.rtlight->ambientscale;
2286 diffusescale = rsurface.rtlight->diffusescale;
2287 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2288 if (!r_shadow_usenormalmap.integer)
2290 ambientscale += 1.0f * diffusescale;
2294 if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
2296 GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
2297 GL_PolygonOffset(rsurface.texture->currentpolygonfactor, rsurface.texture->currentpolygonoffset);
2298 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
2299 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_view.cullface_back);
2300 nmap = rsurface.texture->currentskinframe->nmap;
2301 if (gl_lightmaps.integer)
2302 nmap = r_texture_blanknormalmap;
2303 if (rsurface.texture->colormapping && !gl_lightmaps.integer)
2305 qboolean dopants = rsurface.texture->currentskinframe->pants != NULL && VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f);
2306 qboolean doshirt = rsurface.texture->currentskinframe->shirt != NULL && VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f);
2309 lightcolorpants[0] = lightcolorbase[0] * rsurface.colormap_pantscolor[0];
2310 lightcolorpants[1] = lightcolorbase[1] * rsurface.colormap_pantscolor[1];
2311 lightcolorpants[2] = lightcolorbase[2] * rsurface.colormap_pantscolor[2];
2314 VectorClear(lightcolorpants);
2317 lightcolorshirt[0] = lightcolorbase[0] * rsurface.colormap_shirtcolor[0];
2318 lightcolorshirt[1] = lightcolorbase[1] * rsurface.colormap_shirtcolor[1];
2319 lightcolorshirt[2] = lightcolorbase[2] * rsurface.colormap_shirtcolor[2];
2322 VectorClear(lightcolorshirt);
2323 switch (r_shadow_rendermode)
2325 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2326 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2327 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);
2329 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2330 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);
2332 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2333 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);
2335 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2336 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);
2339 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2345 switch (r_shadow_rendermode)
2347 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2348 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2349 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);
2351 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2352 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);
2354 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2355 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);
2357 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2358 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);
2361 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2367 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)
2369 matrix4x4_t tempmatrix = *matrix;
2370 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2372 // if this light has been compiled before, free the associated data
2373 R_RTLight_Uncompile(rtlight);
2375 // clear it completely to avoid any lingering data
2376 memset(rtlight, 0, sizeof(*rtlight));
2378 // copy the properties
2379 rtlight->matrix_lighttoworld = tempmatrix;
2380 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2381 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2382 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2383 VectorCopy(color, rtlight->color);
2384 rtlight->cubemapname[0] = 0;
2385 if (cubemapname && cubemapname[0])
2386 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2387 rtlight->shadow = shadow;
2388 rtlight->corona = corona;
2389 rtlight->style = style;
2390 rtlight->isstatic = isstatic;
2391 rtlight->coronasizescale = coronasizescale;
2392 rtlight->ambientscale = ambientscale;
2393 rtlight->diffusescale = diffusescale;
2394 rtlight->specularscale = specularscale;
2395 rtlight->flags = flags;
2397 // compute derived data
2398 //rtlight->cullradius = rtlight->radius;
2399 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2400 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2401 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2402 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2403 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2404 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2405 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2408 // compiles rtlight geometry
2409 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2410 void R_RTLight_Compile(rtlight_t *rtlight)
2413 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2414 int lighttris, shadowtris, shadowmeshes, shadowmeshtris;
2415 entity_render_t *ent = r_refdef.worldentity;
2416 model_t *model = r_refdef.worldmodel;
2417 unsigned char *data;
2419 // compile the light
2420 rtlight->compiled = true;
2421 rtlight->static_numleafs = 0;
2422 rtlight->static_numleafpvsbytes = 0;
2423 rtlight->static_leaflist = NULL;
2424 rtlight->static_leafpvs = NULL;
2425 rtlight->static_numsurfaces = 0;
2426 rtlight->static_surfacelist = NULL;
2427 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2428 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2429 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2430 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2431 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2432 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2434 if (model && model->GetLightInfo)
2436 // this variable must be set for the CompileShadowVolume code
2437 r_shadow_compilingrtlight = rtlight;
2438 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);
2439 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);
2440 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2441 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
2442 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
2443 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
2444 rtlight->static_numsurfaces = numsurfaces;
2445 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2446 rtlight->static_numleafs = numleafs;
2447 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2448 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2449 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2450 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
2451 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
2452 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
2453 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
2454 if (rtlight->static_numsurfaces)
2455 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2456 if (rtlight->static_numleafs)
2457 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2458 if (rtlight->static_numleafpvsbytes)
2459 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2460 if (rtlight->static_numshadowtrispvsbytes)
2461 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
2462 if (rtlight->static_numlighttrispvsbytes)
2463 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
2464 if (model->CompileShadowVolume && rtlight->shadow)
2465 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2466 // now we're done compiling the rtlight
2467 r_shadow_compilingrtlight = NULL;
2471 // use smallest available cullradius - box radius or light radius
2472 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2473 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2477 if (rtlight->static_meshchain_shadow)
2480 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2483 shadowmeshtris += mesh->numtriangles;
2488 if (rtlight->static_numlighttrispvsbytes)
2489 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
2490 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
2494 if (rtlight->static_numlighttrispvsbytes)
2495 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
2496 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
2499 if (developer.integer >= 10)
2500 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);
2503 void R_RTLight_Uncompile(rtlight_t *rtlight)
2505 if (rtlight->compiled)
2507 if (rtlight->static_meshchain_shadow)
2508 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2509 rtlight->static_meshchain_shadow = NULL;
2510 // these allocations are grouped
2511 if (rtlight->static_surfacelist)
2512 Mem_Free(rtlight->static_surfacelist);
2513 rtlight->static_numleafs = 0;
2514 rtlight->static_numleafpvsbytes = 0;
2515 rtlight->static_leaflist = NULL;
2516 rtlight->static_leafpvs = NULL;
2517 rtlight->static_numsurfaces = 0;
2518 rtlight->static_surfacelist = NULL;
2519 rtlight->static_numshadowtrispvsbytes = 0;
2520 rtlight->static_shadowtrispvs = NULL;
2521 rtlight->static_numlighttrispvsbytes = 0;
2522 rtlight->static_lighttrispvs = NULL;
2523 rtlight->compiled = false;
2527 void R_Shadow_UncompileWorldLights(void)
2531 for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
2533 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2536 R_RTLight_Uncompile(&light->rtlight);
2540 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
2544 // reset the count of frustum planes
2545 // see rsurface.rtlight_frustumplanes definition for how much this array
2547 rsurface.rtlight_numfrustumplanes = 0;
2549 // haven't implemented a culling path for ortho rendering
2550 if (!r_view.useperspective)
2552 // check if the light is on screen and copy the 4 planes if it is
2553 for (i = 0;i < 4;i++)
2554 if (PlaneDiff(rtlight->shadoworigin, &r_view.frustum[i]) < -0.03125)
2557 for (i = 0;i < 4;i++)
2558 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_view.frustum[i];
2563 // generate a deformed frustum that includes the light origin, this is
2564 // used to cull shadow casting surfaces that can not possibly cast a
2565 // shadow onto the visible light-receiving surfaces, which can be a
2568 // if the light origin is onscreen the result will be 4 planes exactly
2569 // if the light origin is offscreen on only one axis the result will
2570 // be exactly 5 planes (split-side case)
2571 // if the light origin is offscreen on two axes the result will be
2572 // exactly 4 planes (stretched corner case)
2573 for (i = 0;i < 4;i++)
2575 // quickly reject standard frustum planes that put the light
2576 // origin outside the frustum
2577 if (PlaneDiff(rtlight->shadoworigin, &r_view.frustum[i]) < -0.03125)
2580 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_view.frustum[i];
2582 // if all the standard frustum planes were accepted, the light is onscreen
2583 // otherwise we need to generate some more planes below...
2584 if (rsurface.rtlight_numfrustumplanes < 4)
2586 // at least one of the stock frustum planes failed, so we need to
2587 // create one or two custom planes to enclose the light origin
2588 for (i = 0;i < 4;i++)
2590 // create a plane using the view origin and light origin, and a
2591 // single point from the frustum corner set
2592 TriangleNormal(r_view.origin, r_view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
2593 VectorNormalize(plane.normal);
2594 plane.dist = DotProduct(r_view.origin, plane.normal);
2595 // see if this plane is backwards and flip it if so
2596 for (j = 0;j < 4;j++)
2597 if (j != i && DotProduct(r_view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
2601 VectorNegate(plane.normal, plane.normal);
2603 // flipped plane, test again to see if it is now valid
2604 for (j = 0;j < 4;j++)
2605 if (j != i && DotProduct(r_view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
2607 // if the plane is still not valid, then it is dividing the
2608 // frustum and has to be rejected
2612 // we have created a valid plane, compute extra info
2613 PlaneClassify(&plane);
2615 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
2617 // if we've found 5 frustum planes then we have constructed a
2618 // proper split-side case and do not need to keep searching for
2619 // planes to enclose the light origin
2620 if (rsurface.rtlight_numfrustumplanes == 5)
2628 for (i = 0;i < rsurface.rtlight_numfrustumplanes;i++)
2630 plane = rsurface.rtlight_frustumplanes[i];
2631 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));
2636 // now add the light-space box planes if the light box is rotated, as any
2637 // caster outside the oriented light box is irrelevant (even if it passed
2638 // the worldspace light box, which is axial)
2639 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
2641 for (i = 0;i < 6;i++)
2645 v[i >> 1] = (i & 1) ? -1 : 1;
2646 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
2647 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
2648 plane.dist = VectorNormalizeLength(plane.normal);
2649 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
2650 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
2656 // add the world-space reduced box planes
2657 for (i = 0;i < 6;i++)
2659 VectorClear(plane.normal);
2660 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
2661 plane.dist = (i & 1) ? -rsurface.rtlight_cullmaxs[i >> 1] : rsurface.rtlight_cullmins[i >> 1];
2662 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
2671 // reduce all plane distances to tightly fit the rtlight cull box, which
2673 VectorSet(points[0], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
2674 VectorSet(points[1], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
2675 VectorSet(points[2], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
2676 VectorSet(points[3], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
2677 VectorSet(points[4], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
2678 VectorSet(points[5], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
2679 VectorSet(points[6], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
2680 VectorSet(points[7], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
2681 oldnum = rsurface.rtlight_numfrustumplanes;
2682 rsurface.rtlight_numfrustumplanes = 0;
2683 for (j = 0;j < oldnum;j++)
2685 // find the nearest point on the box to this plane
2686 bestdist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[0]);
2687 for (i = 1;i < 8;i++)
2689 dist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[i]);
2690 if (bestdist > dist)
2693 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);
2694 // if the nearest point is near or behind the plane, we want this
2695 // plane, otherwise the plane is useless as it won't cull anything
2696 if (rsurface.rtlight_frustumplanes[j].dist < bestdist + 0.03125)
2698 PlaneClassify(&rsurface.rtlight_frustumplanes[j]);
2699 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = rsurface.rtlight_frustumplanes[j];
2706 void R_Shadow_DrawWorldShadow(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
2708 RSurf_ActiveWorldEntity();
2709 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2713 for (mesh = rsurface.rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2715 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
2716 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
2717 GL_LockArrays(0, mesh->numverts);
2718 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
2720 // decrement stencil if backface is behind depthbuffer
2721 GL_CullFace(r_view.cullface_front);
2722 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2723 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->ebo, 0);
2724 // increment stencil if frontface is behind depthbuffer
2725 GL_CullFace(r_view.cullface_back);
2726 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2728 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->ebo, 0);
2729 GL_LockArrays(0, 0);
2733 else if (numsurfaces && r_refdef.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
2736 int surfacelistindex;
2737 msurface_t *surface;
2738 R_Shadow_PrepareShadowMark(r_refdef.worldmodel->brush.shadowmesh->numtriangles);
2739 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
2741 surface = r_refdef.worldmodel->data_surfaces + surfacelist[surfacelistindex];
2742 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
2743 if (CHECKPVSBIT(trispvs, t))
2744 shadowmarklist[numshadowmark++] = t;
2746 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);
2748 else if (numsurfaces)
2749 r_refdef.worldmodel->DrawShadowVolume(r_refdef.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
2752 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
2754 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
2755 vec_t relativeshadowradius;
2756 RSurf_ActiveModelEntity(ent, false, false);
2757 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
2758 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
2759 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
2760 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
2761 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
2762 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
2763 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
2764 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
2765 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2768 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
2770 // set up properties for rendering light onto this entity
2771 RSurf_ActiveModelEntity(ent, true, true);
2772 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
2773 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
2774 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
2775 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
2776 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2777 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
2780 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
2782 if (!r_refdef.worldmodel->DrawLight)
2785 // set up properties for rendering light onto this entity
2786 RSurf_ActiveWorldEntity();
2787 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
2788 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
2789 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
2790 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
2791 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2792 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
2794 r_refdef.worldmodel->DrawLight(r_refdef.worldentity, numsurfaces, surfacelist, trispvs);
2797 void R_Shadow_DrawEntityLight(entity_render_t *ent, int numsurfaces, int *surfacelist)
2799 model_t *model = ent->model;
2800 if (!model->DrawLight)
2803 R_Shadow_SetupEntityLight(ent);
2805 model->DrawLight(ent, model->nummodelsurfaces, model->surfacelist, NULL);
2808 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
2812 int numleafs, numsurfaces;
2813 int *leaflist, *surfacelist;
2814 unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs;
2815 int numlightentities;
2816 int numlightentities_noselfshadow;
2817 int numshadowentities;
2818 int numshadowentities_noselfshadow;
2819 entity_render_t *lightentities[MAX_EDICTS];
2820 entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
2821 entity_render_t *shadowentities[MAX_EDICTS];
2822 entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
2824 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
2825 // skip lights that are basically invisible (color 0 0 0)
2826 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
2829 // loading is done before visibility checks because loading should happen
2830 // all at once at the start of a level, not when it stalls gameplay.
2831 // (especially important to benchmarks)
2833 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2834 R_RTLight_Compile(rtlight);
2836 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
2838 // look up the light style value at this time
2839 f = (rtlight->style >= 0 ? r_refdef.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
2840 VectorScale(rtlight->color, f, rtlight->currentcolor);
2842 if (rtlight->selected)
2844 f = 2 + sin(realtime * M_PI * 4.0);
2845 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
2849 // if lightstyle is currently off, don't draw the light
2850 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
2853 // if the light box is offscreen, skip it
2854 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2857 VectorCopy(rtlight->cullmins, rsurface.rtlight_cullmins);
2858 VectorCopy(rtlight->cullmaxs, rsurface.rtlight_cullmaxs);
2860 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2862 // compiled light, world available and can receive realtime lighting
2863 // retrieve leaf information
2864 numleafs = rtlight->static_numleafs;
2865 leaflist = rtlight->static_leaflist;
2866 leafpvs = rtlight->static_leafpvs;
2867 numsurfaces = rtlight->static_numsurfaces;
2868 surfacelist = rtlight->static_surfacelist;
2869 shadowtrispvs = rtlight->static_shadowtrispvs;
2870 lighttrispvs = rtlight->static_lighttrispvs;
2872 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2874 // dynamic light, world available and can receive realtime lighting
2875 // calculate lit surfaces and leafs
2876 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);
2877 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);
2878 leaflist = r_shadow_buffer_leaflist;
2879 leafpvs = r_shadow_buffer_leafpvs;
2880 surfacelist = r_shadow_buffer_surfacelist;
2881 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
2882 lighttrispvs = r_shadow_buffer_lighttrispvs;
2883 // if the reduced leaf bounds are offscreen, skip it
2884 if (R_CullBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
2895 shadowtrispvs = NULL;
2896 lighttrispvs = NULL;
2898 // check if light is illuminating any visible leafs
2901 for (i = 0;i < numleafs;i++)
2902 if (r_viewcache.world_leafvisible[leaflist[i]])
2907 // set up a scissor rectangle for this light
2908 if (R_Shadow_ScissorForBBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
2911 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
2913 // make a list of lit entities and shadow casting entities
2914 numlightentities = 0;
2915 numlightentities_noselfshadow = 0;
2916 numshadowentities = 0;
2917 numshadowentities_noselfshadow = 0;
2918 // add dynamic entities that are lit by the light
2919 if (r_drawentities.integer)
2921 for (i = 0;i < r_refdef.numentities;i++)
2924 entity_render_t *ent = r_refdef.entities[i];
2926 if (!BoxesOverlap(ent->mins, ent->maxs, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
2928 // skip the object entirely if it is not within the valid
2929 // shadow-casting region (which includes the lit region)
2930 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rsurface.rtlight_numfrustumplanes, rsurface.rtlight_frustumplanes))
2932 if (!(model = ent->model))
2934 if (r_viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
2936 // this entity wants to receive light, is visible, and is
2937 // inside the light box
2938 // TODO: check if the surfaces in the model can receive light
2939 // so now check if it's in a leaf seen by the light
2940 if (r_refdef.worldmodel && r_refdef.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs))
2942 if (ent->flags & RENDER_NOSELFSHADOW)
2943 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
2945 lightentities[numlightentities++] = ent;
2946 // since it is lit, it probably also casts a shadow...
2947 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2948 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
2949 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
2951 // note: exterior models without the RENDER_NOSELFSHADOW
2952 // flag still create a RENDER_NOSELFSHADOW shadow but
2953 // are lit normally, this means that they are
2954 // self-shadowing but do not shadow other
2955 // RENDER_NOSELFSHADOW entities such as the gun
2956 // (very weird, but keeps the player shadow off the gun)
2957 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
2958 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
2960 shadowentities[numshadowentities++] = ent;
2963 else if (ent->flags & RENDER_SHADOW)
2965 // this entity is not receiving light, but may still need to
2967 // TODO: check if the surfaces in the model can cast shadow
2968 // now check if it is in a leaf seen by the light
2969 if (r_refdef.worldmodel && r_refdef.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs))
2971 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2972 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
2973 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
2975 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
2976 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
2978 shadowentities[numshadowentities++] = ent;
2984 // return if there's nothing at all to light
2985 if (!numlightentities && !numsurfaces)
2988 // don't let sound skip if going slow
2989 if (r_refdef.extraupdate)
2992 // make this the active rtlight for rendering purposes
2993 R_Shadow_RenderMode_ActiveLight(rtlight);
2994 // count this light in the r_speeds
2995 r_refdef.stats.lights++;
2997 if (r_showshadowvolumes.integer && r_view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.rtworldshadows : r_refdef.rtdlightshadows))
2999 // optionally draw visible shape of the shadow volumes
3000 // for performance analysis by level designers
3001 R_Shadow_RenderMode_VisibleShadowVolumes();
3003 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3004 for (i = 0;i < numshadowentities;i++)
3005 R_Shadow_DrawEntityShadow(shadowentities[i]);
3006 for (i = 0;i < numshadowentities_noselfshadow;i++)
3007 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3010 if (gl_stencil && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.rtworldshadows : r_refdef.rtdlightshadows))
3012 // draw stencil shadow volumes to mask off pixels that are in shadow
3013 // so that they won't receive lighting
3014 R_Shadow_RenderMode_StencilShadowVolumes(true);
3016 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3017 for (i = 0;i < numshadowentities;i++)
3018 R_Shadow_DrawEntityShadow(shadowentities[i]);
3019 if (numlightentities_noselfshadow)
3021 // draw lighting in the unmasked areas
3022 R_Shadow_RenderMode_Lighting(true, false);
3023 for (i = 0;i < numlightentities_noselfshadow;i++)
3024 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i], numsurfaces, surfacelist);
3026 // optionally draw the illuminated areas
3027 // for performance analysis by level designers
3028 if (r_showlighting.integer && r_view.showdebug)
3030 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
3031 for (i = 0;i < numlightentities_noselfshadow;i++)
3032 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i], numsurfaces, surfacelist);
3035 R_Shadow_RenderMode_StencilShadowVolumes(false);
3037 for (i = 0;i < numshadowentities_noselfshadow;i++)
3038 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3040 if (numsurfaces + numlightentities)
3042 // draw lighting in the unmasked areas
3043 R_Shadow_RenderMode_Lighting(true, false);
3045 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3046 for (i = 0;i < numlightentities;i++)
3047 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
3049 // optionally draw the illuminated areas
3050 // for performance analysis by level designers
3051 if (r_showlighting.integer && r_view.showdebug)
3053 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
3055 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3056 for (i = 0;i < numlightentities;i++)
3057 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
3063 if (numsurfaces + numlightentities)
3065 // draw lighting in the unmasked areas
3066 R_Shadow_RenderMode_Lighting(false, false);
3068 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3069 for (i = 0;i < numlightentities;i++)
3070 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
3071 for (i = 0;i < numlightentities_noselfshadow;i++)
3072 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i], numsurfaces, surfacelist);
3074 // optionally draw the illuminated areas
3075 // for performance analysis by level designers
3076 if (r_showlighting.integer && r_view.showdebug)
3078 R_Shadow_RenderMode_VisibleLighting(false, false);
3080 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3081 for (i = 0;i < numlightentities;i++)
3082 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
3083 for (i = 0;i < numlightentities_noselfshadow;i++)
3084 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i], numsurfaces, surfacelist);
3090 void R_Shadow_DrawLightSprites(void);
3091 void R_ShadowVolumeLighting(qboolean visible)
3098 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
3099 R_Shadow_EditLights_Reload_f();
3101 if (r_editlights.integer)
3102 R_Shadow_DrawLightSprites();
3104 R_Shadow_RenderMode_Begin();
3106 flag = r_refdef.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3107 if (r_shadow_debuglight.integer >= 0)
3109 lightindex = r_shadow_debuglight.integer;
3110 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3111 if (light && (light->flags & flag))
3112 R_DrawRTLight(&light->rtlight, visible);
3116 for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
3118 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3119 if (light && (light->flags & flag))
3120 R_DrawRTLight(&light->rtlight, visible);
3123 if (r_refdef.rtdlight)
3124 for (lnum = 0;lnum < r_refdef.numlights;lnum++)
3125 R_DrawRTLight(&r_refdef.lights[lnum], visible);
3127 R_Shadow_RenderMode_End();
3130 extern void R_SetupView(void);
3131 extern cvar_t r_shadows_throwdistance;
3132 void R_DrawModelShadows(void)
3135 float relativethrowdistance;
3136 entity_render_t *ent;
3137 vec3_t relativelightorigin;
3138 vec3_t relativelightdirection;
3139 vec3_t relativeshadowmins, relativeshadowmaxs;
3142 if (!r_drawentities.integer || !gl_stencil)
3146 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
3148 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
3150 if (gl_ext_separatestencil.integer)
3151 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
3152 else if (gl_ext_stenciltwoside.integer)
3153 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
3155 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
3157 R_Shadow_RenderMode_StencilShadowVolumes(true);
3159 for (i = 0;i < r_refdef.numentities;i++)
3161 ent = r_refdef.entities[i];
3162 // cast shadows from anything that is not a submodel of the map
3163 if (ent->model && ent->model->DrawShadowVolume != NULL && !ent->model->brush.submodel && (ent->flags & RENDER_SHADOW))
3165 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
3166 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
3167 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
3168 VectorNegate(ent->modellight_lightdir, relativelightdirection);
3169 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
3170 RSurf_ActiveModelEntity(ent, false, false);
3171 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
3175 // not really the right mode, but this will disable any silly stencil features
3176 R_Shadow_RenderMode_VisibleLighting(true, true);
3178 // vertex coordinates for a quad that covers the screen exactly
3179 vertex3f[0] = 0;vertex3f[1] = 0;vertex3f[2] = 0;
3180 vertex3f[3] = 1;vertex3f[4] = 0;vertex3f[5] = 0;
3181 vertex3f[6] = 1;vertex3f[7] = 1;vertex3f[8] = 0;
3182 vertex3f[9] = 0;vertex3f[10] = 1;vertex3f[11] = 0;
3184 // set up ortho view for rendering this pass
3185 GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
3186 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
3187 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
3188 GL_ScissorTest(true);
3189 R_Mesh_Matrix(&identitymatrix);
3190 R_Mesh_ResetTextureState();
3191 R_Mesh_VertexPointer(vertex3f, 0, 0);
3192 R_Mesh_ColorPointer(NULL, 0, 0);
3194 // set up a 50% darkening blend on shadowed areas
3195 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3196 GL_DepthRange(0, 1);
3197 GL_DepthTest(false);
3198 GL_DepthMask(false);
3199 GL_PolygonOffset(0, 0);CHECKGLERROR
3200 GL_Color(0, 0, 0, 0.5);
3201 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
3202 qglDepthFunc(GL_ALWAYS);CHECKGLERROR
3203 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
3204 qglStencilMask(~0);CHECKGLERROR
3205 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
3206 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
3208 // apply the blend to the shadowed areas
3209 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3211 // restoring the perspective view is done by R_RenderScene
3214 // restore other state to normal
3215 R_Shadow_RenderMode_End();
3218 void R_DrawCoronas(void)
3221 float cscale, scale;
3225 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
3227 R_Mesh_Matrix(&identitymatrix);
3228 flag = r_refdef.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3229 // FIXME: these traces should scan all render entities instead of cl.world
3230 for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
3232 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3235 rtlight = &light->rtlight;
3236 if (!(rtlight->flags & flag))
3238 if (rtlight->corona * r_coronas.value <= 0)
3240 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
3242 cscale = rtlight->corona * r_coronas.value* 0.25f;
3243 scale = rtlight->radius * rtlight->coronasizescale;
3244 if (VectorDistance2(rtlight->shadoworigin, r_view.origin) < 16.0f * 16.0f)
3246 if (CL_Move(r_view.origin, vec3_origin, vec3_origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
3248 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);
3250 for (i = 0;i < r_refdef.numlights;i++)
3252 rtlight = &r_refdef.lights[i];
3253 if (!(rtlight->flags & flag))
3255 if (rtlight->corona <= 0)
3257 if (VectorDistance2(rtlight->shadoworigin, r_view.origin) < 32.0f * 32.0f)
3259 if (gl_flashblend.integer)
3261 cscale = rtlight->corona * 1.0f;
3262 scale = rtlight->radius * rtlight->coronasizescale * 2.0f;
3266 cscale = rtlight->corona * r_coronas.value* 0.25f;
3267 scale = rtlight->radius * rtlight->coronasizescale;
3269 if (VectorLength(rtlight->color) * cscale < (1.0f / 256.0f))
3271 if (CL_Move(r_view.origin, vec3_origin, vec3_origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
3273 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);
3279 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
3280 typedef struct suffixinfo_s
3283 qboolean flipx, flipy, flipdiagonal;
3286 static suffixinfo_t suffix[3][6] =
3289 {"px", false, false, false},
3290 {"nx", false, false, false},
3291 {"py", false, false, false},
3292 {"ny", false, false, false},
3293 {"pz", false, false, false},
3294 {"nz", false, false, false}
3297 {"posx", false, false, false},
3298 {"negx", false, false, false},
3299 {"posy", false, false, false},
3300 {"negy", false, false, false},
3301 {"posz", false, false, false},
3302 {"negz", false, false, false}
3305 {"rt", true, false, true},
3306 {"lf", false, true, true},
3307 {"ft", true, true, false},
3308 {"bk", false, false, false},
3309 {"up", true, false, true},
3310 {"dn", true, false, true}
3314 static int componentorder[4] = {0, 1, 2, 3};
3316 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
3318 int i, j, cubemapsize;
3319 unsigned char *cubemappixels, *image_buffer;
3320 rtexture_t *cubemaptexture;
3322 // must start 0 so the first loadimagepixels has no requested width/height
3324 cubemappixels = NULL;
3325 cubemaptexture = NULL;
3326 // keep trying different suffix groups (posx, px, rt) until one loads
3327 for (j = 0;j < 3 && !cubemappixels;j++)
3329 // load the 6 images in the suffix group
3330 for (i = 0;i < 6;i++)
3332 // generate an image name based on the base and and suffix
3333 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
3335 if ((image_buffer = loadimagepixelsbgra(name, false, false)))
3337 // an image loaded, make sure width and height are equal
3338 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
3340 // if this is the first image to load successfully, allocate the cubemap memory
3341 if (!cubemappixels && image_width >= 1)
3343 cubemapsize = image_width;
3344 // note this clears to black, so unavailable sides are black
3345 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
3347 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
3349 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);
3352 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
3354 Mem_Free(image_buffer);
3358 // if a cubemap loaded, upload it
3361 if (!r_shadow_filters_texturepool)
3362 r_shadow_filters_texturepool = R_AllocTexturePool();
3363 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, TEXF_PRECACHE | (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0), NULL);
3364 Mem_Free(cubemappixels);
3368 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
3369 for (j = 0;j < 3;j++)
3370 for (i = 0;i < 6;i++)
3371 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
3372 Con_Print(" and was unable to find any of them.\n");
3374 return cubemaptexture;
3377 rtexture_t *R_Shadow_Cubemap(const char *basename)
3380 for (i = 0;i < numcubemaps;i++)
3381 if (!strcasecmp(cubemaps[i].basename, basename))
3382 return cubemaps[i].texture;
3383 if (i >= MAX_CUBEMAPS)
3384 return r_texture_whitecube;
3386 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
3387 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
3388 if (!cubemaps[i].texture)
3389 cubemaps[i].texture = r_texture_whitecube;
3390 return cubemaps[i].texture;
3393 void R_Shadow_FreeCubemaps(void)
3396 R_FreeTexturePool(&r_shadow_filters_texturepool);
3399 dlight_t *R_Shadow_NewWorldLight(void)
3401 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
3404 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)
3407 // validate parameters
3408 if (style < 0 || style >= MAX_LIGHTSTYLES)
3410 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
3416 // copy to light properties
3417 VectorCopy(origin, light->origin);
3418 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
3419 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
3420 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
3421 light->color[0] = max(color[0], 0);
3422 light->color[1] = max(color[1], 0);
3423 light->color[2] = max(color[2], 0);
3424 light->radius = max(radius, 0);
3425 light->style = style;
3426 light->shadow = shadowenable;
3427 light->corona = corona;
3428 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
3429 light->coronasizescale = coronasizescale;
3430 light->ambientscale = ambientscale;
3431 light->diffusescale = diffusescale;
3432 light->specularscale = specularscale;
3433 light->flags = flags;
3435 // update renderable light data
3436 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
3437 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);
3440 void R_Shadow_FreeWorldLight(dlight_t *light)
3442 if (r_shadow_selectedlight == light)
3443 r_shadow_selectedlight = NULL;
3444 R_RTLight_Uncompile(&light->rtlight);
3445 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
3448 void R_Shadow_ClearWorldLights(void)
3452 for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
3454 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3456 R_Shadow_FreeWorldLight(light);
3458 r_shadow_selectedlight = NULL;
3459 R_Shadow_FreeCubemaps();
3462 void R_Shadow_SelectLight(dlight_t *light)
3464 if (r_shadow_selectedlight)
3465 r_shadow_selectedlight->selected = false;
3466 r_shadow_selectedlight = light;
3467 if (r_shadow_selectedlight)
3468 r_shadow_selectedlight->selected = true;
3471 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
3473 // this is never batched (there can be only one)
3474 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);
3477 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
3484 // this is never batched (due to the ent parameter changing every time)
3485 // so numsurfaces == 1 and surfacelist[0] == lightnumber
3486 const dlight_t *light = (dlight_t *)ent;
3489 VectorScale(light->color, intensity, spritecolor);
3490 if (VectorLength(spritecolor) < 0.1732f)
3491 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
3492 if (VectorLength(spritecolor) > 1.0f)
3493 VectorNormalize(spritecolor);
3495 // draw light sprite
3496 if (light->cubemapname[0] && !light->shadow)
3497 pic = r_editlights_sprcubemapnoshadowlight;
3498 else if (light->cubemapname[0])
3499 pic = r_editlights_sprcubemaplight;
3500 else if (!light->shadow)
3501 pic = r_editlights_sprnoshadowlight;
3503 pic = r_editlights_sprlight;
3504 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);
3505 // draw selection sprite if light is selected
3506 if (light->selected)
3507 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);
3508 // VorteX todo: add normalmode/realtime mode light overlay sprites?
3511 void R_Shadow_DrawLightSprites(void)
3515 for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
3517 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3519 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
3521 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
3524 void R_Shadow_SelectLightInView(void)
3526 float bestrating, rating, temp[3];
3532 for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
3534 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3537 VectorSubtract(light->origin, r_view.origin, temp);
3538 rating = (DotProduct(temp, r_view.forward) / sqrt(DotProduct(temp, temp)));
3541 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
3542 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)
3544 bestrating = rating;
3549 R_Shadow_SelectLight(best);
3552 void R_Shadow_LoadWorldLights(void)
3554 int n, a, style, shadow, flags;
3555 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
3556 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
3557 if (r_refdef.worldmodel == NULL)
3559 Con_Print("No map loaded.\n");
3562 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3563 strlcat (name, ".rtlights", sizeof (name));
3564 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3574 for (;COM_Parse(t, true) && strcmp(
3575 if (COM_Parse(t, true))
3577 if (com_token[0] == '!')
3580 origin[0] = atof(com_token+1);
3583 origin[0] = atof(com_token);
3588 while (*s && *s != '\n' && *s != '\r')
3594 // check for modifier flags
3601 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);
3604 flags = LIGHTFLAG_REALTIMEMODE;
3612 coronasizescale = 0.25f;
3614 VectorClear(angles);
3617 if (a < 9 || !strcmp(cubemapname, "\"\""))
3619 // remove quotes on cubemapname
3620 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
3623 namelen = strlen(cubemapname) - 2;
3624 memmove(cubemapname, cubemapname + 1, namelen);
3625 cubemapname[namelen] = '\0';
3629 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);
3632 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3640 Con_Printf("invalid rtlights file \"%s\"\n", name);
3641 Mem_Free(lightsstring);
3645 void R_Shadow_SaveWorldLights(void)
3649 size_t bufchars, bufmaxchars;
3651 char name[MAX_QPATH];
3652 char line[MAX_INPUTLINE];
3653 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
3655 if (r_refdef.worldmodel == NULL)
3657 Con_Print("No map loaded.\n");
3660 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3661 strlcat (name, ".rtlights", sizeof (name));
3662 bufchars = bufmaxchars = 0;
3664 for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
3666 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3669 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3670 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);
3671 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3672 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]);
3674 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);
3675 if (bufchars + strlen(line) > bufmaxchars)
3677 bufmaxchars = bufchars + strlen(line) + 2048;
3679 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
3683 memcpy(buf, oldbuf, bufchars);
3689 memcpy(buf + bufchars, line, strlen(line));
3690 bufchars += strlen(line);
3694 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
3699 void R_Shadow_LoadLightsFile(void)
3702 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3703 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3704 if (r_refdef.worldmodel == NULL)
3706 Con_Print("No map loaded.\n");
3709 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3710 strlcat (name, ".lights", sizeof (name));
3711 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3719 while (*s && *s != '\n' && *s != '\r')
3725 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);
3729 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);
3732 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3733 radius = bound(15, radius, 4096);
3734 VectorScale(color, (2.0f / (8388608.0f)), color);
3735 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3743 Con_Printf("invalid lights file \"%s\"\n", name);
3744 Mem_Free(lightsstring);
3748 // tyrlite/hmap2 light types in the delay field
3749 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3751 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3753 int entnum, style, islight, skin, pflags, effects, type, n;
3756 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3757 char key[256], value[MAX_INPUTLINE];
3759 if (r_refdef.worldmodel == NULL)
3761 Con_Print("No map loaded.\n");
3764 // try to load a .ent file first
3765 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3766 strlcat (key, ".ent", sizeof (key));
3767 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
3768 // and if that is not found, fall back to the bsp file entity string
3770 data = r_refdef.worldmodel->brush.entities;
3773 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
3775 type = LIGHTTYPE_MINUSX;
3776 origin[0] = origin[1] = origin[2] = 0;
3777 originhack[0] = originhack[1] = originhack[2] = 0;
3778 angles[0] = angles[1] = angles[2] = 0;
3779 color[0] = color[1] = color[2] = 1;
3780 light[0] = light[1] = light[2] = 1;light[3] = 300;
3781 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3791 if (!COM_ParseToken_Simple(&data, false, false))
3793 if (com_token[0] == '}')
3794 break; // end of entity
3795 if (com_token[0] == '_')
3796 strlcpy(key, com_token + 1, sizeof(key));
3798 strlcpy(key, com_token, sizeof(key));
3799 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3800 key[strlen(key)-1] = 0;
3801 if (!COM_ParseToken_Simple(&data, false, false))
3803 strlcpy(value, com_token, sizeof(value));
3805 // now that we have the key pair worked out...
3806 if (!strcmp("light", key))
3808 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3812 light[0] = vec[0] * (1.0f / 256.0f);
3813 light[1] = vec[0] * (1.0f / 256.0f);
3814 light[2] = vec[0] * (1.0f / 256.0f);
3820 light[0] = vec[0] * (1.0f / 255.0f);
3821 light[1] = vec[1] * (1.0f / 255.0f);
3822 light[2] = vec[2] * (1.0f / 255.0f);
3826 else if (!strcmp("delay", key))
3828 else if (!strcmp("origin", key))
3829 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3830 else if (!strcmp("angle", key))
3831 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3832 else if (!strcmp("angles", key))
3833 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3834 else if (!strcmp("color", key))
3835 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3836 else if (!strcmp("wait", key))
3837 fadescale = atof(value);
3838 else if (!strcmp("classname", key))
3840 if (!strncmp(value, "light", 5))
3843 if (!strcmp(value, "light_fluoro"))
3848 overridecolor[0] = 1;
3849 overridecolor[1] = 1;
3850 overridecolor[2] = 1;
3852 if (!strcmp(value, "light_fluorospark"))
3857 overridecolor[0] = 1;
3858 overridecolor[1] = 1;
3859 overridecolor[2] = 1;
3861 if (!strcmp(value, "light_globe"))
3866 overridecolor[0] = 1;
3867 overridecolor[1] = 0.8;
3868 overridecolor[2] = 0.4;
3870 if (!strcmp(value, "light_flame_large_yellow"))
3875 overridecolor[0] = 1;
3876 overridecolor[1] = 0.5;
3877 overridecolor[2] = 0.1;
3879 if (!strcmp(value, "light_flame_small_yellow"))
3884 overridecolor[0] = 1;
3885 overridecolor[1] = 0.5;
3886 overridecolor[2] = 0.1;
3888 if (!strcmp(value, "light_torch_small_white"))
3893 overridecolor[0] = 1;
3894 overridecolor[1] = 0.5;
3895 overridecolor[2] = 0.1;
3897 if (!strcmp(value, "light_torch_small_walltorch"))
3902 overridecolor[0] = 1;
3903 overridecolor[1] = 0.5;
3904 overridecolor[2] = 0.1;
3908 else if (!strcmp("style", key))
3909 style = atoi(value);
3910 else if (!strcmp("skin", key))
3911 skin = (int)atof(value);
3912 else if (!strcmp("pflags", key))
3913 pflags = (int)atof(value);
3914 else if (!strcmp("effects", key))
3915 effects = (int)atof(value);
3916 else if (r_refdef.worldmodel->type == mod_brushq3)
3918 if (!strcmp("scale", key))
3919 lightscale = atof(value);
3920 if (!strcmp("fade", key))
3921 fadescale = atof(value);
3926 if (lightscale <= 0)
3930 if (color[0] == color[1] && color[0] == color[2])
3932 color[0] *= overridecolor[0];
3933 color[1] *= overridecolor[1];
3934 color[2] *= overridecolor[2];
3936 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3937 color[0] = color[0] * light[0];
3938 color[1] = color[1] * light[1];
3939 color[2] = color[2] * light[2];
3942 case LIGHTTYPE_MINUSX:
3944 case LIGHTTYPE_RECIPX:
3946 VectorScale(color, (1.0f / 16.0f), color);
3948 case LIGHTTYPE_RECIPXX:
3950 VectorScale(color, (1.0f / 16.0f), color);
3953 case LIGHTTYPE_NONE:
3957 case LIGHTTYPE_MINUSXX:
3960 VectorAdd(origin, originhack, origin);
3962 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);
3965 Mem_Free(entfiledata);
3969 void R_Shadow_SetCursorLocationForView(void)
3972 vec3_t dest, endpos;
3974 VectorMA(r_view.origin, r_editlights_cursordistance.value, r_view.forward, dest);
3975 trace = CL_Move(r_view.origin, vec3_origin, vec3_origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
3976 if (trace.fraction < 1)
3978 dist = trace.fraction * r_editlights_cursordistance.value;
3979 push = r_editlights_cursorpushback.value;
3983 VectorMA(trace.endpos, push, r_view.forward, endpos);
3984 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
3988 VectorClear( endpos );
3990 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3991 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3992 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3995 void R_Shadow_UpdateWorldLightSelection(void)
3997 if (r_editlights.integer)
3999 R_Shadow_SetCursorLocationForView();
4000 R_Shadow_SelectLightInView();
4003 R_Shadow_SelectLight(NULL);
4006 void R_Shadow_EditLights_Clear_f(void)
4008 R_Shadow_ClearWorldLights();
4011 void R_Shadow_EditLights_Reload_f(void)
4013 if (!r_refdef.worldmodel)
4015 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
4016 R_Shadow_ClearWorldLights();
4017 R_Shadow_LoadWorldLights();
4018 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
4020 R_Shadow_LoadLightsFile();
4021 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
4022 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
4026 void R_Shadow_EditLights_Save_f(void)
4028 if (!r_refdef.worldmodel)
4030 R_Shadow_SaveWorldLights();
4033 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
4035 R_Shadow_ClearWorldLights();
4036 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
4039 void R_Shadow_EditLights_ImportLightsFile_f(void)
4041 R_Shadow_ClearWorldLights();
4042 R_Shadow_LoadLightsFile();
4045 void R_Shadow_EditLights_Spawn_f(void)
4048 if (!r_editlights.integer)
4050 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4053 if (Cmd_Argc() != 1)
4055 Con_Print("r_editlights_spawn does not take parameters\n");
4058 color[0] = color[1] = color[2] = 1;
4059 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
4062 void R_Shadow_EditLights_Edit_f(void)
4064 vec3_t origin, angles, color;
4065 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
4066 int style, shadows, flags, normalmode, realtimemode;
4067 char cubemapname[MAX_INPUTLINE];
4068 if (!r_editlights.integer)
4070 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4073 if (!r_shadow_selectedlight)
4075 Con_Print("No selected light.\n");
4078 VectorCopy(r_shadow_selectedlight->origin, origin);
4079 VectorCopy(r_shadow_selectedlight->angles, angles);
4080 VectorCopy(r_shadow_selectedlight->color, color);
4081 radius = r_shadow_selectedlight->radius;
4082 style = r_shadow_selectedlight->style;
4083 if (r_shadow_selectedlight->cubemapname)
4084 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
4087 shadows = r_shadow_selectedlight->shadow;
4088 corona = r_shadow_selectedlight->corona;
4089 coronasizescale = r_shadow_selectedlight->coronasizescale;
4090 ambientscale = r_shadow_selectedlight->ambientscale;
4091 diffusescale = r_shadow_selectedlight->diffusescale;
4092 specularscale = r_shadow_selectedlight->specularscale;
4093 flags = r_shadow_selectedlight->flags;
4094 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
4095 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
4096 if (!strcmp(Cmd_Argv(1), "origin"))
4098 if (Cmd_Argc() != 5)
4100 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
4103 origin[0] = atof(Cmd_Argv(2));
4104 origin[1] = atof(Cmd_Argv(3));
4105 origin[2] = atof(Cmd_Argv(4));
4107 else if (!strcmp(Cmd_Argv(1), "originx"))
4109 if (Cmd_Argc() != 3)
4111 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4114 origin[0] = atof(Cmd_Argv(2));
4116 else if (!strcmp(Cmd_Argv(1), "originy"))
4118 if (Cmd_Argc() != 3)
4120 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4123 origin[1] = atof(Cmd_Argv(2));
4125 else if (!strcmp(Cmd_Argv(1), "originz"))
4127 if (Cmd_Argc() != 3)
4129 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4132 origin[2] = atof(Cmd_Argv(2));
4134 else if (!strcmp(Cmd_Argv(1), "move"))
4136 if (Cmd_Argc() != 5)
4138 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
4141 origin[0] += atof(Cmd_Argv(2));
4142 origin[1] += atof(Cmd_Argv(3));
4143 origin[2] += atof(Cmd_Argv(4));
4145 else if (!strcmp(Cmd_Argv(1), "movex"))
4147 if (Cmd_Argc() != 3)
4149 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4152 origin[0] += atof(Cmd_Argv(2));
4154 else if (!strcmp(Cmd_Argv(1), "movey"))
4156 if (Cmd_Argc() != 3)
4158 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4161 origin[1] += atof(Cmd_Argv(2));
4163 else if (!strcmp(Cmd_Argv(1), "movez"))
4165 if (Cmd_Argc() != 3)
4167 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4170 origin[2] += atof(Cmd_Argv(2));
4172 else if (!strcmp(Cmd_Argv(1), "angles"))
4174 if (Cmd_Argc() != 5)
4176 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
4179 angles[0] = atof(Cmd_Argv(2));
4180 angles[1] = atof(Cmd_Argv(3));
4181 angles[2] = atof(Cmd_Argv(4));
4183 else if (!strcmp(Cmd_Argv(1), "anglesx"))
4185 if (Cmd_Argc() != 3)
4187 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4190 angles[0] = atof(Cmd_Argv(2));
4192 else if (!strcmp(Cmd_Argv(1), "anglesy"))
4194 if (Cmd_Argc() != 3)
4196 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4199 angles[1] = atof(Cmd_Argv(2));
4201 else if (!strcmp(Cmd_Argv(1), "anglesz"))
4203 if (Cmd_Argc() != 3)
4205 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4208 angles[2] = atof(Cmd_Argv(2));
4210 else if (!strcmp(Cmd_Argv(1), "color"))
4212 if (Cmd_Argc() != 5)
4214 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
4217 color[0] = atof(Cmd_Argv(2));
4218 color[1] = atof(Cmd_Argv(3));
4219 color[2] = atof(Cmd_Argv(4));
4221 else if (!strcmp(Cmd_Argv(1), "radius"))
4223 if (Cmd_Argc() != 3)
4225 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4228 radius = atof(Cmd_Argv(2));
4230 else if (!strcmp(Cmd_Argv(1), "colorscale"))
4232 if (Cmd_Argc() == 3)
4234 double scale = atof(Cmd_Argv(2));
4241 if (Cmd_Argc() != 5)
4243 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
4246 color[0] *= atof(Cmd_Argv(2));
4247 color[1] *= atof(Cmd_Argv(3));
4248 color[2] *= atof(Cmd_Argv(4));
4251 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
4253 if (Cmd_Argc() != 3)
4255 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4258 radius *= atof(Cmd_Argv(2));
4260 else if (!strcmp(Cmd_Argv(1), "style"))
4262 if (Cmd_Argc() != 3)
4264 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4267 style = atoi(Cmd_Argv(2));
4269 else if (!strcmp(Cmd_Argv(1), "cubemap"))
4273 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4276 if (Cmd_Argc() == 3)
4277 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
4281 else if (!strcmp(Cmd_Argv(1), "shadows"))
4283 if (Cmd_Argc() != 3)
4285 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4288 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4290 else if (!strcmp(Cmd_Argv(1), "corona"))
4292 if (Cmd_Argc() != 3)
4294 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4297 corona = atof(Cmd_Argv(2));
4299 else if (!strcmp(Cmd_Argv(1), "coronasize"))
4301 if (Cmd_Argc() != 3)
4303 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4306 coronasizescale = atof(Cmd_Argv(2));
4308 else if (!strcmp(Cmd_Argv(1), "ambient"))
4310 if (Cmd_Argc() != 3)
4312 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4315 ambientscale = atof(Cmd_Argv(2));
4317 else if (!strcmp(Cmd_Argv(1), "diffuse"))
4319 if (Cmd_Argc() != 3)
4321 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4324 diffusescale = atof(Cmd_Argv(2));
4326 else if (!strcmp(Cmd_Argv(1), "specular"))
4328 if (Cmd_Argc() != 3)
4330 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4333 specularscale = atof(Cmd_Argv(2));
4335 else if (!strcmp(Cmd_Argv(1), "normalmode"))
4337 if (Cmd_Argc() != 3)
4339 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4342 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4344 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
4346 if (Cmd_Argc() != 3)
4348 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4351 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4355 Con_Print("usage: r_editlights_edit [property] [value]\n");
4356 Con_Print("Selected light's properties:\n");
4357 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
4358 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
4359 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
4360 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
4361 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
4362 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
4363 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
4364 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
4365 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
4366 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
4367 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
4368 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
4369 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
4370 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
4373 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
4374 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4377 void R_Shadow_EditLights_EditAll_f(void)
4382 if (!r_editlights.integer)
4384 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
4388 for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
4390 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4393 R_Shadow_SelectLight(light);
4394 R_Shadow_EditLights_Edit_f();
4398 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
4400 int lightnumber, lightcount;
4405 if (!r_editlights.integer)
4407 x = vid_conwidth.value - 240;
4409 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
4412 for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
4414 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4417 if (light == r_shadow_selectedlight)
4418 lightnumber = lightindex;
4421 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;
4422 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;
4424 if (r_shadow_selectedlight == NULL)
4426 sprintf(temp, "Light #%i properties:", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
4427 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;
4428 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;
4429 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;
4430 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;
4431 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;
4432 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;
4433 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;
4434 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;
4435 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;
4436 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;
4437 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;
4438 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;
4439 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;
4440 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;
4443 void R_Shadow_EditLights_ToggleShadow_f(void)
4445 if (!r_editlights.integer)
4447 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4450 if (!r_shadow_selectedlight)
4452 Con_Print("No selected light.\n");
4455 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);
4458 void R_Shadow_EditLights_ToggleCorona_f(void)
4460 if (!r_editlights.integer)
4462 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4465 if (!r_shadow_selectedlight)
4467 Con_Print("No selected light.\n");
4470 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);
4473 void R_Shadow_EditLights_Remove_f(void)
4475 if (!r_editlights.integer)
4477 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
4480 if (!r_shadow_selectedlight)
4482 Con_Print("No selected light.\n");
4485 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
4486 r_shadow_selectedlight = NULL;
4489 void R_Shadow_EditLights_Help_f(void)
4492 "Documentation on r_editlights system:\n"
4494 "r_editlights : enable/disable editing mode\n"
4495 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
4496 "r_editlights_cursorpushback : push back cursor this far from surface\n"
4497 "r_editlights_cursorpushoff : push cursor off surface this far\n"
4498 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
4499 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
4501 "r_editlights_help : this help\n"
4502 "r_editlights_clear : remove all lights\n"
4503 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
4504 "r_editlights_save : save to .rtlights file\n"
4505 "r_editlights_spawn : create a light with default settings\n"
4506 "r_editlights_edit command : edit selected light - more documentation below\n"
4507 "r_editlights_remove : remove selected light\n"
4508 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
4509 "r_editlights_importlightentitiesfrommap : reload light entities\n"
4510 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
4512 "origin x y z : set light location\n"
4513 "originx x: set x component of light location\n"
4514 "originy y: set y component of light location\n"
4515 "originz z: set z component of light location\n"
4516 "move x y z : adjust light location\n"
4517 "movex x: adjust x component of light location\n"
4518 "movey y: adjust y component of light location\n"
4519 "movez z: adjust z component of light location\n"
4520 "angles x y z : set light angles\n"
4521 "anglesx x: set x component of light angles\n"
4522 "anglesy y: set y component of light angles\n"
4523 "anglesz z: set z component of light angles\n"
4524 "color r g b : set color of light (can be brighter than 1 1 1)\n"
4525 "radius radius : set radius (size) of light\n"
4526 "colorscale grey : multiply color of light (1 does nothing)\n"
4527 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
4528 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
4529 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
4530 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
4531 "cubemap basename : set filter cubemap of light (not yet supported)\n"
4532 "shadows 1/0 : turn on/off shadows\n"
4533 "corona n : set corona intensity\n"
4534 "coronasize n : set corona size (0-1)\n"
4535 "ambient n : set ambient intensity (0-1)\n"
4536 "diffuse n : set diffuse intensity (0-1)\n"
4537 "specular n : set specular intensity (0-1)\n"
4538 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
4539 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
4540 "<nothing> : print light properties to console\n"
4544 void R_Shadow_EditLights_CopyInfo_f(void)
4546 if (!r_editlights.integer)
4548 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
4551 if (!r_shadow_selectedlight)
4553 Con_Print("No selected light.\n");
4556 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
4557 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
4558 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
4559 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
4560 if (r_shadow_selectedlight->cubemapname)
4561 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
4563 r_shadow_bufferlight.cubemapname[0] = 0;
4564 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
4565 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
4566 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
4567 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
4568 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
4569 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
4570 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
4573 void R_Shadow_EditLights_PasteInfo_f(void)
4575 if (!r_editlights.integer)
4577 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
4580 if (!r_shadow_selectedlight)
4582 Con_Print("No selected light.\n");
4585 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);
4588 void R_Shadow_EditLights_Init(void)
4590 Cvar_RegisterVariable(&r_editlights);
4591 Cvar_RegisterVariable(&r_editlights_cursordistance);
4592 Cvar_RegisterVariable(&r_editlights_cursorpushback);
4593 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
4594 Cvar_RegisterVariable(&r_editlights_cursorgrid);
4595 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
4596 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
4597 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
4598 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)");
4599 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
4600 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
4601 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
4602 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)");
4603 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
4604 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
4605 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
4606 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
4607 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
4608 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
4609 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)");
4615 =============================================================================
4619 =============================================================================
4622 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
4624 VectorClear(diffusecolor);
4625 VectorClear(diffusenormal);
4627 if (!r_fullbright.integer && r_refdef.worldmodel && r_refdef.worldmodel->brush.LightPoint)
4629 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_ambient.value * (2.0f / 128.0f);
4630 r_refdef.worldmodel->brush.LightPoint(r_refdef.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
4633 VectorSet(ambientcolor, 1, 1, 1);
4640 for (i = 0;i < r_refdef.numlights;i++)
4642 light = &r_refdef.lights[i];
4643 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
4644 f = 1 - VectorLength2(v);
4645 if (f > 0 && CL_Move(p, vec3_origin, vec3_origin, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
4646 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);