3 Terminology: Stencil Shadow Volume (sometimes called Stencil Shadows)
4 An extrusion of the lit faces, beginning at the original geometry and ending
5 further from the light source than the original geometry (presumably at least
6 as far as the light's radius, if the light has a radius at all), capped at
7 both front and back to avoid any problems (extrusion from dark faces also
8 works but has a different set of problems)
10 This is normally rendered using Carmack's Reverse technique, in which
11 backfaces behind zbuffer (zfail) increment the stencil, and frontfaces behind
12 zbuffer (zfail) decrement the stencil, the result is a stencil value of zero
13 where shadows did not intersect the visible geometry, suitable as a stencil
14 mask for rendering lighting everywhere but shadow.
16 In our case to hopefully avoid the Creative Labs patent, we draw the backfaces
17 as decrement and the frontfaces as increment, and we redefine the DepthFunc to
18 GL_LESS (the patent uses GL_GEQUAL) which causes zfail when behind surfaces
19 and zpass when infront (the patent draws where zpass with a GL_GEQUAL test),
20 additionally we clear stencil to 128 to avoid the need for the unclamped
21 incr/decr extension (not related to patent).
24 This algorithm may be covered by Creative's patent (US Patent #6384822),
25 however that patent is quite specific about increment on backfaces and
26 decrement on frontfaces where zpass with GL_GEQUAL depth test, which is
27 opposite this implementation and partially opposite Carmack's Reverse paper
28 (which uses GL_LESS, but increments on backfaces and decrements on frontfaces).
32 Terminology: Stencil Light Volume (sometimes called Light Volumes)
33 Similar to a Stencil Shadow Volume, but inverted; rather than containing the
34 areas in shadow it contains the areas in light, this can only be built
35 quickly for certain limited cases (such as portal visibility from a point),
36 but is quite useful for some effects (sunlight coming from sky polygons is
37 one possible example, translucent occluders is another example).
41 Terminology: Optimized Stencil Shadow Volume
42 A Stencil Shadow Volume that has been processed sufficiently to ensure it has
43 no duplicate coverage of areas (no need to shadow an area twice), often this
44 greatly improves performance but is an operation too costly to use on moving
45 lights (however completely optimal Stencil Light Volumes can be constructed
50 Terminology: Per Pixel Lighting (sometimes abbreviated PPL)
51 Per pixel evaluation of lighting equations, at a bare minimum this involves
52 DOT3 shading of diffuse lighting (per pixel dotproduct of negated incidence
53 vector and surface normal, using a texture of the surface bumps, called a
54 NormalMap) if supported by hardware; in our case there is support for cards
55 which are incapable of DOT3, the quality is quite poor however. Additionally
56 it is desirable to have specular evaluation per pixel, per vertex
57 normalization of specular halfangle vectors causes noticable distortion but
58 is unavoidable on hardware without GL_ARB_fragment_program or
59 GL_ARB_fragment_shader.
63 Terminology: Normalization CubeMap
64 A cubemap containing normalized dot3-encoded (vectors of length 1 or less
65 encoded as RGB colors) for any possible direction, this technique allows per
66 pixel calculation of incidence vector for per pixel lighting purposes, which
67 would not otherwise be possible per pixel without GL_ARB_fragment_program or
68 GL_ARB_fragment_shader.
72 Terminology: 2D+1D Attenuation Texturing
73 A very crude approximation of light attenuation with distance which results
74 in cylindrical light shapes which fade vertically as a streak (some games
75 such as Doom3 allow this to be rotated to be less noticable in specific
76 cases), the technique is simply modulating lighting by two 2D textures (which
77 can be the same) on different axes of projection (XY and Z, typically), this
78 is the second best technique available without 3D Attenuation Texturing,
79 GL_ARB_fragment_program or GL_ARB_fragment_shader technology.
83 Terminology: 2D+1D Inverse Attenuation Texturing
84 A clever method described in papers on the Abducted engine, this has a squared
85 distance texture (bright on the outside, black in the middle), which is used
86 twice using GL_ADD blending, the result of this is used in an inverse modulate
87 (GL_ONE_MINUS_DST_ALPHA, GL_ZERO) to implement the equation
88 lighting*=(1-((X*X+Y*Y)+(Z*Z))) which is spherical (unlike 2D+1D attenuation
93 Terminology: 3D Attenuation Texturing
94 A slightly crude approximation of light attenuation with distance, its flaws
95 are limited radius and resolution (performance tradeoffs).
99 Terminology: 3D Attenuation-Normalization Texturing
100 A 3D Attenuation Texture merged with a Normalization CubeMap, by making the
101 vectors shorter the lighting becomes darker, a very effective optimization of
102 diffuse lighting if 3D Attenuation Textures are already used.
106 Terminology: Light Cubemap Filtering
107 A technique for modeling non-uniform light distribution according to
108 direction, for example a lantern may use a cubemap to describe the light
109 emission pattern of the cage around the lantern (as well as soot buildup
110 discoloring the light in certain areas), often also used for softened grate
111 shadows and light shining through a stained glass window (done crudely by
112 texturing the lighting with a cubemap), another good example would be a disco
113 light. This technique is used heavily in many games (Doom3 does not support
118 Terminology: Light Projection Filtering
119 A technique for modeling shadowing of light passing through translucent
120 surfaces, allowing stained glass windows and other effects to be done more
121 elegantly than possible with Light Cubemap Filtering by applying an occluder
122 texture to the lighting combined with a stencil light volume to limit the lit
123 area, this technique is used by Doom3 for spotlights and flashlights, among
124 other things, this can also be used more generally to render light passing
125 through multiple translucent occluders in a scene (using a light volume to
126 describe the area beyond the occluder, and thus mask off rendering of all
131 Terminology: Doom3 Lighting
132 A combination of Stencil Shadow Volume, Per Pixel Lighting, Normalization
133 CubeMap, 2D+1D Attenuation Texturing, and Light Projection Filtering, as
134 demonstrated by the game Doom3.
137 #include "quakedef.h"
138 #include "r_shadow.h"
139 #include "cl_collision.h"
143 extern void R_Shadow_EditLights_Init(void);
145 typedef enum r_shadow_rendermode_e
147 R_SHADOW_RENDERMODE_NONE,
148 R_SHADOW_RENDERMODE_STENCIL,
149 R_SHADOW_RENDERMODE_SEPARATESTENCIL,
150 R_SHADOW_RENDERMODE_STENCILTWOSIDE,
151 R_SHADOW_RENDERMODE_LIGHT_VERTEX,
152 R_SHADOW_RENDERMODE_LIGHT_DOT3,
153 R_SHADOW_RENDERMODE_LIGHT_GLSL,
154 R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
155 R_SHADOW_RENDERMODE_VISIBLELIGHTING,
157 r_shadow_rendermode_t;
159 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
160 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
161 r_shadow_rendermode_t r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_NONE;
163 int maxshadowtriangles;
166 int maxshadowvertices;
167 float *shadowvertex3f;
180 int r_shadow_buffer_numleafpvsbytes;
181 unsigned char *r_shadow_buffer_leafpvs;
182 int *r_shadow_buffer_leaflist;
184 int r_shadow_buffer_numsurfacepvsbytes;
185 unsigned char *r_shadow_buffer_surfacepvs;
186 int *r_shadow_buffer_surfacelist;
188 int r_shadow_buffer_numshadowtrispvsbytes;
189 unsigned char *r_shadow_buffer_shadowtrispvs;
190 int r_shadow_buffer_numlighttrispvsbytes;
191 unsigned char *r_shadow_buffer_lighttrispvs;
193 rtexturepool_t *r_shadow_texturepool;
194 rtexture_t *r_shadow_attenuationgradienttexture;
195 rtexture_t *r_shadow_attenuation2dtexture;
196 rtexture_t *r_shadow_attenuation3dtexture;
197 rtexture_t *r_shadow_lightcorona;
199 // lights are reloaded when this changes
200 char r_shadow_mapname[MAX_QPATH];
202 // used only for light filters (cubemaps)
203 rtexturepool_t *r_shadow_filters_texturepool;
205 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0", "generate fake bumpmaps from diffuse textures at this bumpyness, try 4 to match tenebrae, higher values increase depth, requires r_restart to take effect"};
206 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4", "what magnitude to interpret _bump.tga textures as, higher values increase depth, requires r_restart to take effect"};
207 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
208 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
209 cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1", "0 disables gloss (specularity) rendering, 1 uses gloss if textures are found, 2 forces a flat metallic specular effect on everything without textures (similar to tenebrae)"};
210 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.125", "how bright the forced flat gloss should look if r_shadow_gloss is 2"};
211 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
212 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
213 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
214 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
215 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
216 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
217 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"};
218 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000", "how far to cast shadows"};
219 cvar_t r_shadow_frontsidecasting = {0, "r_shadow_frontsidecasting", "1", "whether to cast shadows from illuminated triangles (front side of model) or unlit triangles (back side of model)"};
220 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
221 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
222 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
223 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
224 cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0", "enables rendering of full world lighting (whether loaded from the map, or a .rtlights file, or a .ent file, or a .lights file produced by hlight)"};
225 cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0", "brightness to render lightmaps when using full world lighting, try 0.5 for a tenebrae-like appearance"};
226 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
227 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
228 cvar_t r_shadow_realtime_world_compileshadow = {0, "r_shadow_realtime_world_compileshadow", "1", "enables compilation of shadows from world lights for higher performance rendering"};
229 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation"};
230 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation"};
231 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1", "use scissor optimization of light rendering (restricts rendering to the portion of the screen affected by the light)"};
232 cvar_t r_shadow_culltriangles = {0, "r_shadow_culltriangles", "1", "performs more expensive tests to remove unnecessary triangles of lit surfaces"};
233 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
234 cvar_t r_shadow_polygonoffset = {0, "r_shadow_polygonoffset", "1", "how much to push shadow volumes into the distance when rendering, to reduce chances of zfighting artifacts (should not be less than 0)"};
235 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1", "use 3D voxel textures for spherical attenuation rather than cylindrical (does not affect r_glsl lighting)"};
236 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
237 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
238 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
239 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
240 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
241 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
242 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
243 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
244 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
245 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
247 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
248 #define ATTENTABLESIZE 256
249 // 1D gradient, 2D circle and 3D sphere attenuation textures
250 #define ATTEN1DSIZE 32
251 #define ATTEN2DSIZE 64
252 #define ATTEN3DSIZE 32
254 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
255 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
256 static float r_shadow_attentable[ATTENTABLESIZE+1];
258 rtlight_t *r_shadow_compilingrtlight;
259 static memexpandablearray_t r_shadow_worldlightsarray;
260 dlight_t *r_shadow_selectedlight;
261 dlight_t r_shadow_bufferlight;
262 vec3_t r_editlights_cursorlocation;
264 extern int con_vislines;
266 typedef struct cubemapinfo_s
273 #define MAX_CUBEMAPS 256
274 static int numcubemaps;
275 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
277 void R_Shadow_UncompileWorldLights(void);
278 void R_Shadow_ClearWorldLights(void);
279 void R_Shadow_SaveWorldLights(void);
280 void R_Shadow_LoadWorldLights(void);
281 void R_Shadow_LoadLightsFile(void);
282 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
283 void R_Shadow_EditLights_Reload_f(void);
284 void R_Shadow_ValidateCvars(void);
285 static void R_Shadow_MakeTextures(void);
287 // VorteX: custom editor light sprites
288 #define EDLIGHTSPRSIZE 8
289 cachepic_t *r_editlights_sprcursor;
290 cachepic_t *r_editlights_sprlight;
291 cachepic_t *r_editlights_sprnoshadowlight;
292 cachepic_t *r_editlights_sprcubemaplight;
293 cachepic_t *r_editlights_sprcubemapnoshadowlight;
294 cachepic_t *r_editlights_sprselection;
296 void r_shadow_start(void)
298 // allocate vertex processing arrays
300 r_shadow_attenuationgradienttexture = NULL;
301 r_shadow_attenuation2dtexture = NULL;
302 r_shadow_attenuation3dtexture = NULL;
303 r_shadow_texturepool = NULL;
304 r_shadow_filters_texturepool = NULL;
305 R_Shadow_ValidateCvars();
306 R_Shadow_MakeTextures();
307 maxshadowtriangles = 0;
308 shadowelements = NULL;
309 maxshadowvertices = 0;
310 shadowvertex3f = NULL;
318 shadowmarklist = NULL;
320 r_shadow_buffer_numleafpvsbytes = 0;
321 r_shadow_buffer_leafpvs = NULL;
322 r_shadow_buffer_leaflist = NULL;
323 r_shadow_buffer_numsurfacepvsbytes = 0;
324 r_shadow_buffer_surfacepvs = NULL;
325 r_shadow_buffer_surfacelist = NULL;
326 r_shadow_buffer_numshadowtrispvsbytes = 0;
327 r_shadow_buffer_shadowtrispvs = NULL;
328 r_shadow_buffer_numlighttrispvsbytes = 0;
329 r_shadow_buffer_lighttrispvs = NULL;
332 void r_shadow_shutdown(void)
334 R_Shadow_UncompileWorldLights();
336 r_shadow_attenuationgradienttexture = NULL;
337 r_shadow_attenuation2dtexture = NULL;
338 r_shadow_attenuation3dtexture = NULL;
339 R_FreeTexturePool(&r_shadow_texturepool);
340 R_FreeTexturePool(&r_shadow_filters_texturepool);
341 maxshadowtriangles = 0;
343 Mem_Free(shadowelements);
344 shadowelements = NULL;
346 Mem_Free(shadowvertex3f);
347 shadowvertex3f = NULL;
350 Mem_Free(vertexupdate);
353 Mem_Free(vertexremap);
359 Mem_Free(shadowmark);
362 Mem_Free(shadowmarklist);
363 shadowmarklist = NULL;
365 r_shadow_buffer_numleafpvsbytes = 0;
366 if (r_shadow_buffer_leafpvs)
367 Mem_Free(r_shadow_buffer_leafpvs);
368 r_shadow_buffer_leafpvs = NULL;
369 if (r_shadow_buffer_leaflist)
370 Mem_Free(r_shadow_buffer_leaflist);
371 r_shadow_buffer_leaflist = NULL;
372 r_shadow_buffer_numsurfacepvsbytes = 0;
373 if (r_shadow_buffer_surfacepvs)
374 Mem_Free(r_shadow_buffer_surfacepvs);
375 r_shadow_buffer_surfacepvs = NULL;
376 if (r_shadow_buffer_surfacelist)
377 Mem_Free(r_shadow_buffer_surfacelist);
378 r_shadow_buffer_surfacelist = NULL;
379 r_shadow_buffer_numshadowtrispvsbytes = 0;
380 if (r_shadow_buffer_shadowtrispvs)
381 Mem_Free(r_shadow_buffer_shadowtrispvs);
382 r_shadow_buffer_numlighttrispvsbytes = 0;
383 if (r_shadow_buffer_lighttrispvs)
384 Mem_Free(r_shadow_buffer_lighttrispvs);
387 void r_shadow_newmap(void)
389 if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
390 R_Shadow_EditLights_Reload_f();
393 void R_Shadow_Help_f(void)
396 "Documentation on r_shadow system:\n"
398 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
399 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
400 "r_shadow_debuglight : render only this light number (-1 = all)\n"
401 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
402 "r_shadow_gloss2intensity : brightness of forced gloss\n"
403 "r_shadow_glossintensity : brightness of textured gloss\n"
404 "r_shadow_lightattenuationlinearscale : used to generate attenuation texture\n"
405 "r_shadow_lightattenuationdividebias : used to generate attenuation texture\n"
406 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
407 "r_shadow_lightradiusscale : scale rendering radius of all lights\n"
408 "r_shadow_portallight : use portal visibility for static light precomputation\n"
409 "r_shadow_projectdistance : shadow volume projection distance\n"
410 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
411 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
412 "r_shadow_realtime_world : use high quality world lighting mode\n"
413 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
414 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
415 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
416 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
417 "r_shadow_scissor : use scissor optimization\n"
418 "r_shadow_polygonfactor : nudge shadow volumes closer/further\n"
419 "r_shadow_polygonoffset : nudge shadow volumes closer/further\n"
420 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
421 "r_showlighting : useful for performance testing; bright = slow!\n"
422 "r_showshadowvolumes : useful for performance testing; bright = slow!\n"
424 "r_shadow_help : this help\n"
428 void R_Shadow_Init(void)
430 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
431 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
432 Cvar_RegisterVariable(&r_shadow_usenormalmap);
433 Cvar_RegisterVariable(&r_shadow_debuglight);
434 Cvar_RegisterVariable(&r_shadow_gloss);
435 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
436 Cvar_RegisterVariable(&r_shadow_glossintensity);
437 Cvar_RegisterVariable(&r_shadow_glossexponent);
438 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
439 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
440 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
441 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
442 Cvar_RegisterVariable(&r_shadow_portallight);
443 Cvar_RegisterVariable(&r_shadow_projectdistance);
444 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
445 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
446 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
447 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
448 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
449 Cvar_RegisterVariable(&r_shadow_realtime_world);
450 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
451 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
452 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
453 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
454 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
455 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
456 Cvar_RegisterVariable(&r_shadow_scissor);
457 Cvar_RegisterVariable(&r_shadow_culltriangles);
458 Cvar_RegisterVariable(&r_shadow_polygonfactor);
459 Cvar_RegisterVariable(&r_shadow_polygonoffset);
460 Cvar_RegisterVariable(&r_shadow_texture3d);
461 Cvar_RegisterVariable(&r_coronas);
462 Cvar_RegisterVariable(&gl_flashblend);
463 Cvar_RegisterVariable(&gl_ext_separatestencil);
464 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
465 if (gamemode == GAME_TENEBRAE)
467 Cvar_SetValue("r_shadow_gloss", 2);
468 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
470 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f, "prints documentation on console commands and variables used by realtime lighting and shadowing system");
471 R_Shadow_EditLights_Init();
472 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
473 maxshadowtriangles = 0;
474 shadowelements = NULL;
475 maxshadowvertices = 0;
476 shadowvertex3f = NULL;
484 shadowmarklist = NULL;
486 r_shadow_buffer_numleafpvsbytes = 0;
487 r_shadow_buffer_leafpvs = NULL;
488 r_shadow_buffer_leaflist = NULL;
489 r_shadow_buffer_numsurfacepvsbytes = 0;
490 r_shadow_buffer_surfacepvs = NULL;
491 r_shadow_buffer_surfacelist = NULL;
492 r_shadow_buffer_shadowtrispvs = NULL;
493 r_shadow_buffer_lighttrispvs = NULL;
494 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
497 matrix4x4_t matrix_attenuationxyz =
500 {0.5, 0.0, 0.0, 0.5},
501 {0.0, 0.5, 0.0, 0.5},
502 {0.0, 0.0, 0.5, 0.5},
507 matrix4x4_t matrix_attenuationz =
510 {0.0, 0.0, 0.5, 0.5},
511 {0.0, 0.0, 0.0, 0.5},
512 {0.0, 0.0, 0.0, 0.5},
517 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles)
519 // make sure shadowelements is big enough for this volume
520 if (maxshadowtriangles < numtriangles)
522 maxshadowtriangles = numtriangles;
524 Mem_Free(shadowelements);
525 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[24]));
527 // make sure shadowvertex3f is big enough for this volume
528 if (maxshadowvertices < numvertices)
530 maxshadowvertices = numvertices;
532 Mem_Free(shadowvertex3f);
533 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[6]));
537 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
539 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
540 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
541 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
542 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
543 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
545 if (r_shadow_buffer_leafpvs)
546 Mem_Free(r_shadow_buffer_leafpvs);
547 if (r_shadow_buffer_leaflist)
548 Mem_Free(r_shadow_buffer_leaflist);
549 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
550 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
551 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
553 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
555 if (r_shadow_buffer_surfacepvs)
556 Mem_Free(r_shadow_buffer_surfacepvs);
557 if (r_shadow_buffer_surfacelist)
558 Mem_Free(r_shadow_buffer_surfacelist);
559 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
560 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
561 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
563 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
565 if (r_shadow_buffer_shadowtrispvs)
566 Mem_Free(r_shadow_buffer_shadowtrispvs);
567 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
568 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
570 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
572 if (r_shadow_buffer_lighttrispvs)
573 Mem_Free(r_shadow_buffer_lighttrispvs);
574 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
575 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
579 void R_Shadow_PrepareShadowMark(int numtris)
581 // make sure shadowmark is big enough for this volume
582 if (maxshadowmark < numtris)
584 maxshadowmark = numtris;
586 Mem_Free(shadowmark);
588 Mem_Free(shadowmarklist);
589 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
590 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
594 // if shadowmarkcount wrapped we clear the array and adjust accordingly
595 if (shadowmarkcount == 0)
598 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
603 int R_Shadow_ConstructShadowVolume(int innumvertices, int innumtris, const int *inelement3i, const int *inneighbor3i, const float *invertex3f, int *outnumvertices, int *outelement3i, float *outvertex3f, const float *projectorigin, const float *projectdirection, float projectdistance, int numshadowmarktris, const int *shadowmarktris)
606 int outtriangles = 0, outvertices = 0;
609 float ratio, direction[3], projectvector[3];
611 if (projectdirection)
612 VectorScale(projectdirection, projectdistance, projectvector);
614 VectorClear(projectvector);
616 if (maxvertexupdate < innumvertices)
618 maxvertexupdate = innumvertices;
620 Mem_Free(vertexupdate);
622 Mem_Free(vertexremap);
623 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
624 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
628 if (vertexupdatenum == 0)
631 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
632 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
635 for (i = 0;i < numshadowmarktris;i++)
636 shadowmark[shadowmarktris[i]] = shadowmarkcount;
638 // create the vertices
639 if (projectdirection)
641 for (i = 0;i < numshadowmarktris;i++)
643 element = inelement3i + shadowmarktris[i] * 3;
644 for (j = 0;j < 3;j++)
646 if (vertexupdate[element[j]] != vertexupdatenum)
648 vertexupdate[element[j]] = vertexupdatenum;
649 vertexremap[element[j]] = outvertices;
650 vertex = invertex3f + element[j] * 3;
651 // project one copy of the vertex according to projectvector
652 VectorCopy(vertex, outvertex3f);
653 VectorAdd(vertex, projectvector, (outvertex3f + 3));
662 for (i = 0;i < numshadowmarktris;i++)
664 element = inelement3i + shadowmarktris[i] * 3;
665 for (j = 0;j < 3;j++)
667 if (vertexupdate[element[j]] != vertexupdatenum)
669 vertexupdate[element[j]] = vertexupdatenum;
670 vertexremap[element[j]] = outvertices;
671 vertex = invertex3f + element[j] * 3;
672 // project one copy of the vertex to the sphere radius of the light
673 // (FIXME: would projecting it to the light box be better?)
674 VectorSubtract(vertex, projectorigin, direction);
675 ratio = projectdistance / VectorLength(direction);
676 VectorCopy(vertex, outvertex3f);
677 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
685 if (r_shadow_frontsidecasting.integer)
687 for (i = 0;i < numshadowmarktris;i++)
689 int remappedelement[3];
691 const int *neighbortriangle;
693 markindex = shadowmarktris[i] * 3;
694 element = inelement3i + markindex;
695 neighbortriangle = inneighbor3i + markindex;
696 // output the front and back triangles
697 outelement3i[0] = vertexremap[element[0]];
698 outelement3i[1] = vertexremap[element[1]];
699 outelement3i[2] = vertexremap[element[2]];
700 outelement3i[3] = vertexremap[element[2]] + 1;
701 outelement3i[4] = vertexremap[element[1]] + 1;
702 outelement3i[5] = vertexremap[element[0]] + 1;
706 // output the sides (facing outward from this triangle)
707 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
709 remappedelement[0] = vertexremap[element[0]];
710 remappedelement[1] = vertexremap[element[1]];
711 outelement3i[0] = remappedelement[1];
712 outelement3i[1] = remappedelement[0];
713 outelement3i[2] = remappedelement[0] + 1;
714 outelement3i[3] = remappedelement[1];
715 outelement3i[4] = remappedelement[0] + 1;
716 outelement3i[5] = remappedelement[1] + 1;
721 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
723 remappedelement[1] = vertexremap[element[1]];
724 remappedelement[2] = vertexremap[element[2]];
725 outelement3i[0] = remappedelement[2];
726 outelement3i[1] = remappedelement[1];
727 outelement3i[2] = remappedelement[1] + 1;
728 outelement3i[3] = remappedelement[2];
729 outelement3i[4] = remappedelement[1] + 1;
730 outelement3i[5] = remappedelement[2] + 1;
735 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
737 remappedelement[0] = vertexremap[element[0]];
738 remappedelement[2] = vertexremap[element[2]];
739 outelement3i[0] = remappedelement[0];
740 outelement3i[1] = remappedelement[2];
741 outelement3i[2] = remappedelement[2] + 1;
742 outelement3i[3] = remappedelement[0];
743 outelement3i[4] = remappedelement[2] + 1;
744 outelement3i[5] = remappedelement[0] + 1;
753 for (i = 0;i < numshadowmarktris;i++)
755 int remappedelement[3];
757 const int *neighbortriangle;
759 markindex = shadowmarktris[i] * 3;
760 element = inelement3i + markindex;
761 neighbortriangle = inneighbor3i + markindex;
762 // output the front and back triangles
763 outelement3i[0] = vertexremap[element[2]];
764 outelement3i[1] = vertexremap[element[1]];
765 outelement3i[2] = vertexremap[element[0]];
766 outelement3i[3] = vertexremap[element[0]] + 1;
767 outelement3i[4] = vertexremap[element[1]] + 1;
768 outelement3i[5] = vertexremap[element[2]] + 1;
772 // output the sides (facing outward from this triangle)
773 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
775 remappedelement[0] = vertexremap[element[0]];
776 remappedelement[1] = vertexremap[element[1]];
777 outelement3i[0] = remappedelement[0];
778 outelement3i[1] = remappedelement[1];
779 outelement3i[2] = remappedelement[1] + 1;
780 outelement3i[3] = remappedelement[0];
781 outelement3i[4] = remappedelement[1] + 1;
782 outelement3i[5] = remappedelement[0] + 1;
787 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
789 remappedelement[1] = vertexremap[element[1]];
790 remappedelement[2] = vertexremap[element[2]];
791 outelement3i[0] = remappedelement[1];
792 outelement3i[1] = remappedelement[2];
793 outelement3i[2] = remappedelement[2] + 1;
794 outelement3i[3] = remappedelement[1];
795 outelement3i[4] = remappedelement[2] + 1;
796 outelement3i[5] = remappedelement[1] + 1;
801 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
803 remappedelement[0] = vertexremap[element[0]];
804 remappedelement[2] = vertexremap[element[2]];
805 outelement3i[0] = remappedelement[2];
806 outelement3i[1] = remappedelement[0];
807 outelement3i[2] = remappedelement[0] + 1;
808 outelement3i[3] = remappedelement[2];
809 outelement3i[4] = remappedelement[0] + 1;
810 outelement3i[5] = remappedelement[2] + 1;
818 *outnumvertices = outvertices;
822 void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, const vec3_t projectdirection, float projectdistance, int nummarktris, const int *marktris)
825 if (projectdistance < 0.1)
827 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
830 if (!numverts || !nummarktris)
832 // make sure shadowelements is big enough for this volume
833 if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
834 R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
835 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
836 r_refdef.stats.lights_dynamicshadowtriangles += tris;
837 R_Shadow_RenderVolume(outverts, tris, shadowvertex3f, shadowelements);
840 void R_Shadow_MarkVolumeFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const vec3_t projectorigin, const vec3_t projectdirection, const vec3_t lightmins, const vec3_t lightmaxs, const vec3_t surfacemins, const vec3_t surfacemaxs)
846 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
848 tend = firsttriangle + numtris;
849 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
851 // surface box entirely inside light box, no box cull
852 if (projectdirection)
854 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
856 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
857 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
858 shadowmarklist[numshadowmark++] = t;
863 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
864 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
865 shadowmarklist[numshadowmark++] = t;
870 // surface box not entirely inside light box, cull each triangle
871 if (projectdirection)
873 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
875 v[0] = invertex3f + e[0] * 3;
876 v[1] = invertex3f + e[1] * 3;
877 v[2] = invertex3f + e[2] * 3;
878 TriangleNormal(v[0], v[1], v[2], normal);
879 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
880 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
881 shadowmarklist[numshadowmark++] = t;
886 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
888 v[0] = invertex3f + e[0] * 3;
889 v[1] = invertex3f + e[1] * 3;
890 v[2] = invertex3f + e[2] * 3;
891 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
892 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
893 shadowmarklist[numshadowmark++] = t;
899 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
901 if (r_shadow_compilingrtlight)
903 // if we're compiling an rtlight, capture the mesh
904 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
907 r_refdef.stats.lights_shadowtriangles += numtriangles;
909 R_Mesh_VertexPointer(vertex3f, 0, 0);
910 GL_LockArrays(0, numvertices);
911 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
913 // decrement stencil if backface is behind depthbuffer
914 GL_CullFace(r_refdef.view.cullface_front);
915 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
916 R_Mesh_Draw(0, numvertices, numtriangles, element3i, 0, 0);
917 // increment stencil if frontface is behind depthbuffer
918 GL_CullFace(r_refdef.view.cullface_back);
919 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
921 R_Mesh_Draw(0, numvertices, numtriangles, element3i, 0, 0);
926 static void R_Shadow_MakeTextures_MakeCorona(void)
930 unsigned char pixels[32][32][4];
931 for (y = 0;y < 32;y++)
933 dy = (y - 15.5f) * (1.0f / 16.0f);
934 for (x = 0;x < 32;x++)
936 dx = (x - 15.5f) * (1.0f / 16.0f);
937 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
938 a = bound(0, a, 255);
942 pixels[y][x][3] = 255;
945 r_shadow_lightcorona = R_LoadTexture2D(r_shadow_texturepool, "lightcorona", 32, 32, &pixels[0][0][0], TEXTYPE_BGRA, TEXF_PRECACHE, NULL);
948 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
950 float dist = sqrt(x*x+y*y+z*z);
951 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
952 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
953 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
956 static void R_Shadow_MakeTextures(void)
959 float intensity, dist;
961 R_FreeTexturePool(&r_shadow_texturepool);
962 r_shadow_texturepool = R_AllocTexturePool();
963 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
964 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
965 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
966 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
967 for (x = 0;x <= ATTENTABLESIZE;x++)
969 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
970 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
971 r_shadow_attentable[x] = bound(0, intensity, 1);
973 // 1D gradient texture
974 for (x = 0;x < ATTEN1DSIZE;x++)
975 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
976 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
978 for (y = 0;y < ATTEN2DSIZE;y++)
979 for (x = 0;x < ATTEN2DSIZE;x++)
980 data[y*ATTEN2DSIZE+x] = R_Shadow_MakeTextures_SamplePoint(((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375), ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375), 0);
981 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
983 if (r_shadow_texture3d.integer && gl_texture3d)
985 for (z = 0;z < ATTEN3DSIZE;z++)
986 for (y = 0;y < ATTEN3DSIZE;y++)
987 for (x = 0;x < ATTEN3DSIZE;x++)
988 data[(z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x] = R_Shadow_MakeTextures_SamplePoint(((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375), ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375), ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375));
989 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
992 r_shadow_attenuation3dtexture = NULL;
995 R_Shadow_MakeTextures_MakeCorona();
997 // Editor light sprites
998 r_editlights_sprcursor = Draw_CachePic("gfx/editlights/cursor", true);
999 r_editlights_sprlight = Draw_CachePic("gfx/editlights/light", true);
1000 r_editlights_sprnoshadowlight = Draw_CachePic("gfx/editlights/noshadow", true);
1001 r_editlights_sprcubemaplight = Draw_CachePic("gfx/editlights/cubemaplight", true);
1002 r_editlights_sprcubemapnoshadowlight = Draw_CachePic("gfx/editlights/cubemapnoshadowlight", true);
1003 r_editlights_sprselection = Draw_CachePic("gfx/editlights/selection", true);
1006 void R_Shadow_ValidateCvars(void)
1008 if (r_shadow_texture3d.integer && !gl_texture3d)
1009 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1010 if (gl_ext_separatestencil.integer && !gl_support_separatestencil)
1011 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1012 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1013 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1016 void R_Shadow_RenderMode_Begin(void)
1018 R_Shadow_ValidateCvars();
1020 if (!r_shadow_attenuation2dtexture
1021 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1022 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1023 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1024 R_Shadow_MakeTextures();
1027 R_Mesh_ColorPointer(NULL, 0, 0);
1028 R_Mesh_ResetTextureState();
1029 GL_BlendFunc(GL_ONE, GL_ZERO);
1030 GL_DepthRange(0, 1);
1031 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1033 GL_DepthMask(false);
1034 GL_Color(0, 0, 0, 1);
1035 GL_Scissor(r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
1037 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1039 if (gl_ext_separatestencil.integer)
1040 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
1041 else if (gl_ext_stenciltwoside.integer)
1042 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
1044 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
1046 if (r_glsl.integer && gl_support_fragment_shader)
1047 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1048 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
1049 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
1051 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1054 void R_Shadow_RenderMode_ActiveLight(rtlight_t *rtlight)
1056 rsurface.rtlight = rtlight;
1059 void R_Shadow_RenderMode_Reset(void)
1062 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
1064 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1066 R_Mesh_ColorPointer(NULL, 0, 0);
1067 R_Mesh_ResetTextureState();
1068 GL_DepthRange(0, 1);
1070 GL_DepthMask(false);
1071 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1072 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1073 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1074 qglStencilMask(~0);CHECKGLERROR
1075 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1076 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1077 GL_CullFace(r_refdef.view.cullface_back);
1078 GL_Color(1, 1, 1, 1);
1079 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1080 GL_BlendFunc(GL_ONE, GL_ZERO);
1081 R_SetupGenericShader(false);
1084 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean clearstencil)
1087 R_Shadow_RenderMode_Reset();
1088 GL_ColorMask(0, 0, 0, 0);
1089 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1090 R_SetupDepthOrShadowShader();
1091 qglDepthFunc(GL_LESS);CHECKGLERROR
1092 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1093 r_shadow_rendermode = r_shadow_shadowingrendermode;
1094 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SEPARATESTENCIL)
1096 GL_CullFace(GL_NONE);
1097 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1098 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1100 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
1102 GL_CullFace(GL_NONE);
1103 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1104 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1105 qglStencilMask(~0);CHECKGLERROR
1106 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1107 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1108 qglStencilMask(~0);CHECKGLERROR
1109 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1112 GL_Clear(GL_STENCIL_BUFFER_BIT);
1113 r_refdef.stats.lights_clears++;
1116 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent)
1119 R_Shadow_RenderMode_Reset();
1120 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1123 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1127 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1128 // only draw light where this geometry was already rendered AND the
1129 // stencil is 128 (values other than this mean shadow)
1130 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1132 r_shadow_rendermode = r_shadow_lightingrendermode;
1133 // do global setup needed for the chosen lighting mode
1134 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1136 R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap)); // light filter
1137 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1138 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
1143 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
1146 R_Shadow_RenderMode_Reset();
1147 GL_BlendFunc(GL_ONE, GL_ONE);
1148 GL_DepthRange(0, 1);
1149 GL_DepthTest(r_showshadowvolumes.integer < 2);
1150 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
1151 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1152 GL_CullFace(GL_NONE);
1153 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
1156 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
1159 R_Shadow_RenderMode_Reset();
1160 GL_BlendFunc(GL_ONE, GL_ONE);
1161 GL_DepthRange(0, 1);
1162 GL_DepthTest(r_showlighting.integer < 2);
1163 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
1166 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1170 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1171 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1173 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
1176 void R_Shadow_RenderMode_End(void)
1179 R_Shadow_RenderMode_Reset();
1180 R_Shadow_RenderMode_ActiveLight(NULL);
1182 GL_Scissor(r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
1183 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1186 int bboxedges[12][2] =
1205 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1207 int i, ix1, iy1, ix2, iy2;
1208 float x1, y1, x2, y2;
1210 float vertex[20][3];
1219 if (!r_shadow_scissor.integer)
1222 // if view is inside the light box, just say yes it's visible
1223 if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
1225 GL_Scissor(r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
1229 x1 = y1 = x2 = y2 = 0;
1231 // transform all corners that are infront of the nearclip plane
1232 VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
1233 plane4f[3] = r_refdef.view.frustum[4].dist;
1235 for (i = 0;i < 8;i++)
1237 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
1238 dist[i] = DotProduct4(corner[i], plane4f);
1239 sign[i] = dist[i] > 0;
1242 VectorCopy(corner[i], vertex[numvertices]);
1246 // if some points are behind the nearclip, add clipped edge points to make
1247 // sure that the scissor boundary is complete
1248 if (numvertices > 0 && numvertices < 8)
1250 // add clipped edge points
1251 for (i = 0;i < 12;i++)
1253 j = bboxedges[i][0];
1254 k = bboxedges[i][1];
1255 if (sign[j] != sign[k])
1257 f = dist[j] / (dist[j] - dist[k]);
1258 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
1264 // if we have no points to check, the light is behind the view plane
1268 // if we have some points to transform, check what screen area is covered
1269 x1 = y1 = x2 = y2 = 0;
1271 //Con_Printf("%i vertices to transform...\n", numvertices);
1272 for (i = 0;i < numvertices;i++)
1274 VectorCopy(vertex[i], v);
1275 GL_TransformToScreen(v, v2);
1276 //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]);
1279 if (x1 > v2[0]) x1 = v2[0];
1280 if (x2 < v2[0]) x2 = v2[0];
1281 if (y1 > v2[1]) y1 = v2[1];
1282 if (y2 < v2[1]) y2 = v2[1];
1291 // now convert the scissor rectangle to integer screen coordinates
1292 ix1 = (int)(x1 - 1.0f);
1293 iy1 = (int)(y1 - 1.0f);
1294 ix2 = (int)(x2 + 1.0f);
1295 iy2 = (int)(y2 + 1.0f);
1296 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1298 // clamp it to the screen
1299 if (ix1 < r_refdef.view.x) ix1 = r_refdef.view.x;
1300 if (iy1 < r_refdef.view.y) iy1 = r_refdef.view.y;
1301 if (ix2 > r_refdef.view.x + r_refdef.view.width) ix2 = r_refdef.view.x + r_refdef.view.width;
1302 if (iy2 > r_refdef.view.y + r_refdef.view.height) iy2 = r_refdef.view.y + r_refdef.view.height;
1304 // if it is inside out, it's not visible
1305 if (ix2 <= ix1 || iy2 <= iy1)
1308 // the light area is visible, set up the scissor rectangle
1309 GL_Scissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1310 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);CHECKGLERROR
1311 //qglEnable(GL_SCISSOR_TEST);CHECKGLERROR
1312 r_refdef.stats.lights_scissored++;
1316 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
1318 float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1319 float *normal3f = rsurface.normal3f + 3 * firstvertex;
1320 float *color4f = rsurface.array_color4f + 4 * firstvertex;
1321 float dist, dot, distintensity, shadeintensity, v[3], n[3];
1322 if (r_textureunits.integer >= 3)
1324 if (VectorLength2(diffusecolor) > 0)
1326 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1328 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1329 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1330 if ((dot = DotProduct(n, v)) < 0)
1332 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1333 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
1336 VectorCopy(ambientcolor, color4f);
1337 if (r_refdef.fogenabled)
1340 f = FogPoint_Model(vertex3f);
1341 VectorScale(color4f, f, color4f);
1348 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1350 VectorCopy(ambientcolor, color4f);
1351 if (r_refdef.fogenabled)
1354 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1355 f = FogPoint_Model(vertex3f);
1356 VectorScale(color4f, f, color4f);
1362 else if (r_textureunits.integer >= 2)
1364 if (VectorLength2(diffusecolor) > 0)
1366 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1368 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1369 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1371 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1372 if ((dot = DotProduct(n, v)) < 0)
1374 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1375 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1376 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1377 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1381 color4f[0] = ambientcolor[0] * distintensity;
1382 color4f[1] = ambientcolor[1] * distintensity;
1383 color4f[2] = ambientcolor[2] * distintensity;
1385 if (r_refdef.fogenabled)
1388 f = FogPoint_Model(vertex3f);
1389 VectorScale(color4f, f, color4f);
1393 VectorClear(color4f);
1399 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1401 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1402 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1404 color4f[0] = ambientcolor[0] * distintensity;
1405 color4f[1] = ambientcolor[1] * distintensity;
1406 color4f[2] = ambientcolor[2] * distintensity;
1407 if (r_refdef.fogenabled)
1410 f = FogPoint_Model(vertex3f);
1411 VectorScale(color4f, f, color4f);
1415 VectorClear(color4f);
1422 if (VectorLength2(diffusecolor) > 0)
1424 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1426 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1427 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1429 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
1430 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1431 if ((dot = DotProduct(n, v)) < 0)
1433 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1434 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1435 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1436 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1440 color4f[0] = ambientcolor[0] * distintensity;
1441 color4f[1] = ambientcolor[1] * distintensity;
1442 color4f[2] = ambientcolor[2] * distintensity;
1444 if (r_refdef.fogenabled)
1447 f = FogPoint_Model(vertex3f);
1448 VectorScale(color4f, f, color4f);
1452 VectorClear(color4f);
1458 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1460 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1461 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1463 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
1464 color4f[0] = ambientcolor[0] * distintensity;
1465 color4f[1] = ambientcolor[1] * distintensity;
1466 color4f[2] = ambientcolor[2] * distintensity;
1467 if (r_refdef.fogenabled)
1470 f = FogPoint_Model(vertex3f);
1471 VectorScale(color4f, f, color4f);
1475 VectorClear(color4f);
1482 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1484 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
1487 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
1488 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1489 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
1490 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
1491 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
1493 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1495 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
1496 // the cubemap normalizes this for us
1497 out3f[0] = DotProduct(svector3f, lightdir);
1498 out3f[1] = DotProduct(tvector3f, lightdir);
1499 out3f[2] = DotProduct(normal3f, lightdir);
1503 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
1506 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
1507 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1508 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
1509 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
1510 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
1511 float lightdir[3], eyedir[3], halfdir[3];
1512 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1514 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
1515 VectorNormalize(lightdir);
1516 VectorSubtract(rsurface.modelorg, vertex3f, eyedir);
1517 VectorNormalize(eyedir);
1518 VectorAdd(lightdir, eyedir, halfdir);
1519 // the cubemap normalizes this for us
1520 out3f[0] = DotProduct(svector3f, halfdir);
1521 out3f[1] = DotProduct(tvector3f, halfdir);
1522 out3f[2] = DotProduct(normal3f, halfdir);
1526 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)
1528 // used to display how many times a surface is lit for level design purposes
1529 GL_Color(0.1 * r_refdef.view.colorscale, 0.025 * r_refdef.view.colorscale, 0, 1);
1530 R_Mesh_ColorPointer(NULL, 0, 0);
1531 R_Mesh_ResetTextureState();
1532 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1535 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)
1537 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
1538 R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
1539 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND))
1540 R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
1542 R_Mesh_ColorPointer(NULL, 0, 0);
1543 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
1544 R_Mesh_TexBind(GL20TU_NORMAL, R_GetTexture(rsurface.texture->currentskinframe->nmap));
1545 R_Mesh_TexBind(GL20TU_COLOR, R_GetTexture(rsurface.texture->basetexture));
1546 R_Mesh_TexBind(GL20TU_GLOSS, R_GetTexture(rsurface.texture->glosstexture));
1547 if (rsurface.texture->backgroundcurrentskinframe)
1549 R_Mesh_TexBind(GL20TU_SECONDARY_NORMAL, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->nmap));
1550 R_Mesh_TexBind(GL20TU_SECONDARY_COLOR, R_GetTexture(rsurface.texture->backgroundbasetexture));
1551 R_Mesh_TexBind(GL20TU_SECONDARY_GLOSS, R_GetTexture(rsurface.texture->backgroundglosstexture));
1553 //R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap));
1554 R_Mesh_TexBind(GL20TU_FOGMASK, R_GetTexture(r_texture_fogattenuation));
1555 R_Mesh_TexBind(GL20TU_PANTS, R_GetTexture(rsurface.texture->currentskinframe->pants));
1556 R_Mesh_TexBind(GL20TU_SHIRT, R_GetTexture(rsurface.texture->currentskinframe->shirt));
1557 R_Mesh_TexBind(GL20TU_ATTENUATION, R_GetTexture(r_shadow_attenuationgradienttexture));
1558 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
1559 R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
1560 R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
1561 R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
1562 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1564 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1566 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1567 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1569 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1573 static void R_Shadow_RenderLighting_Light_Dot3_Finalize(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset, float r, float g, float b)
1575 // shared final code for all the dot3 layers
1577 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
1578 for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
1580 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
1581 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1585 static void R_Shadow_RenderLighting_Light_Dot3_AmbientPass(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset, const vec3_t lightcolorbase, rtexture_t *basetexture, float colorscale)
1588 // colorscale accounts for how much we multiply the brightness
1591 // mult is how many times the final pass of the lighting will be
1592 // performed to get more brightness than otherwise possible.
1594 // Limit mult to 64 for sanity sake.
1596 if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1598 // 3 3D combine path (Geforce3, Radeon 8500)
1599 memset(&m, 0, sizeof(m));
1600 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1601 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1602 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1603 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1604 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1605 m.tex[1] = R_GetTexture(basetexture);
1606 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
1607 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
1608 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
1609 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
1610 m.texcubemap[2] = R_GetTexture(rsurface.rtlight->currentcubemap);
1611 m.pointer_texcoord3f[2] = rsurface.vertex3f;
1612 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
1613 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
1614 m.texmatrix[2] = rsurface.entitytolight;
1615 GL_BlendFunc(GL_ONE, GL_ONE);
1617 else if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1619 // 2 3D combine path (Geforce3, original Radeon)
1620 memset(&m, 0, sizeof(m));
1621 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1622 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1623 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1624 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1625 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1626 m.tex[1] = R_GetTexture(basetexture);
1627 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
1628 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
1629 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
1630 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
1631 GL_BlendFunc(GL_ONE, GL_ONE);
1633 else if (r_textureunits.integer >= 4 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
1635 // 4 2D combine path (Geforce3, Radeon 8500)
1636 memset(&m, 0, sizeof(m));
1637 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1638 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1639 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1640 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1641 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1642 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1643 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1644 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1645 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1646 m.texmatrix[1] = rsurface.entitytoattenuationz;
1647 m.tex[2] = R_GetTexture(basetexture);
1648 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
1649 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
1650 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
1651 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
1652 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1654 m.texcubemap[3] = R_GetTexture(rsurface.rtlight->currentcubemap);
1655 m.pointer_texcoord3f[3] = rsurface.vertex3f;
1656 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
1657 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
1658 m.texmatrix[3] = rsurface.entitytolight;
1660 GL_BlendFunc(GL_ONE, GL_ONE);
1662 else if (r_textureunits.integer >= 3 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
1664 // 3 2D combine path (Geforce3, original Radeon)
1665 memset(&m, 0, sizeof(m));
1666 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1667 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1668 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1669 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1670 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1671 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1672 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1673 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1674 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1675 m.texmatrix[1] = rsurface.entitytoattenuationz;
1676 m.tex[2] = R_GetTexture(basetexture);
1677 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
1678 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
1679 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
1680 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
1681 GL_BlendFunc(GL_ONE, GL_ONE);
1685 // 2/2/2 2D combine path (any dot3 card)
1686 memset(&m, 0, sizeof(m));
1687 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1688 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1689 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1690 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1691 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1692 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1693 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1694 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1695 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1696 m.texmatrix[1] = rsurface.entitytoattenuationz;
1697 R_Mesh_TextureState(&m);
1698 GL_ColorMask(0,0,0,1);
1699 GL_BlendFunc(GL_ONE, GL_ZERO);
1700 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1703 memset(&m, 0, sizeof(m));
1704 m.tex[0] = R_GetTexture(basetexture);
1705 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1706 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1707 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1708 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1709 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1711 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1712 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1713 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1714 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1715 m.texmatrix[1] = rsurface.entitytolight;
1717 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1719 // this final code is shared
1720 R_Mesh_TextureState(&m);
1721 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1724 static void R_Shadow_RenderLighting_Light_Dot3_DiffusePass(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset, const vec3_t lightcolorbase, rtexture_t *basetexture, rtexture_t *normalmaptexture, float colorscale)
1727 // colorscale accounts for how much we multiply the brightness
1730 // mult is how many times the final pass of the lighting will be
1731 // performed to get more brightness than otherwise possible.
1733 // Limit mult to 64 for sanity sake.
1735 // generate normalization cubemap texcoords
1736 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
1737 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1739 // 3/2 3D combine path (Geforce3, Radeon 8500)
1740 memset(&m, 0, sizeof(m));
1741 m.tex[0] = R_GetTexture(normalmaptexture);
1742 m.texcombinergb[0] = GL_REPLACE;
1743 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1744 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1745 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1746 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1747 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1748 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1749 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1750 m.pointer_texcoord_bufferobject[1] = 0;
1751 m.pointer_texcoord_bufferoffset[1] = 0;
1752 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1753 m.pointer_texcoord3f[2] = rsurface.vertex3f;
1754 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
1755 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
1756 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
1757 R_Mesh_TextureState(&m);
1758 GL_ColorMask(0,0,0,1);
1759 GL_BlendFunc(GL_ONE, GL_ZERO);
1760 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1763 memset(&m, 0, sizeof(m));
1764 m.tex[0] = R_GetTexture(basetexture);
1765 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1766 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1767 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1768 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1769 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1771 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1772 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1773 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1774 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1775 m.texmatrix[1] = rsurface.entitytolight;
1777 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1779 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
1781 // 1/2/2 3D combine path (original Radeon)
1782 memset(&m, 0, sizeof(m));
1783 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1784 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1785 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1786 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1787 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1788 R_Mesh_TextureState(&m);
1789 GL_ColorMask(0,0,0,1);
1790 GL_BlendFunc(GL_ONE, GL_ZERO);
1791 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1794 memset(&m, 0, sizeof(m));
1795 m.tex[0] = R_GetTexture(normalmaptexture);
1796 m.texcombinergb[0] = GL_REPLACE;
1797 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1798 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1799 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1800 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1801 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1802 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1803 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1804 m.pointer_texcoord_bufferobject[1] = 0;
1805 m.pointer_texcoord_bufferoffset[1] = 0;
1806 R_Mesh_TextureState(&m);
1807 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1808 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1811 memset(&m, 0, sizeof(m));
1812 m.tex[0] = R_GetTexture(basetexture);
1813 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1814 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1815 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1816 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1817 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1819 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1820 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1821 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1822 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1823 m.texmatrix[1] = rsurface.entitytolight;
1825 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1827 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
1829 // 2/2 3D combine path (original Radeon)
1830 memset(&m, 0, sizeof(m));
1831 m.tex[0] = R_GetTexture(normalmaptexture);
1832 m.texcombinergb[0] = GL_REPLACE;
1833 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1834 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1835 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1836 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1837 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1838 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1839 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1840 m.pointer_texcoord_bufferobject[1] = 0;
1841 m.pointer_texcoord_bufferoffset[1] = 0;
1842 R_Mesh_TextureState(&m);
1843 GL_ColorMask(0,0,0,1);
1844 GL_BlendFunc(GL_ONE, GL_ZERO);
1845 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1848 memset(&m, 0, sizeof(m));
1849 m.tex[0] = R_GetTexture(basetexture);
1850 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1851 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1852 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1853 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1854 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1855 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1856 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1857 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1858 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
1859 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1861 else if (r_textureunits.integer >= 4)
1863 // 4/2 2D combine path (Geforce3, Radeon 8500)
1864 memset(&m, 0, sizeof(m));
1865 m.tex[0] = R_GetTexture(normalmaptexture);
1866 m.texcombinergb[0] = GL_REPLACE;
1867 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1868 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1869 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1870 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1871 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1872 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1873 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1874 m.pointer_texcoord_bufferobject[1] = 0;
1875 m.pointer_texcoord_bufferoffset[1] = 0;
1876 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1877 m.pointer_texcoord3f[2] = rsurface.vertex3f;
1878 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
1879 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
1880 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
1881 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1882 m.pointer_texcoord3f[3] = rsurface.vertex3f;
1883 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
1884 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
1885 m.texmatrix[3] = rsurface.entitytoattenuationz;
1886 R_Mesh_TextureState(&m);
1887 GL_ColorMask(0,0,0,1);
1888 GL_BlendFunc(GL_ONE, GL_ZERO);
1889 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1892 memset(&m, 0, sizeof(m));
1893 m.tex[0] = R_GetTexture(basetexture);
1894 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1895 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1896 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1897 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1898 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1900 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1901 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1902 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1903 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1904 m.texmatrix[1] = rsurface.entitytolight;
1906 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1910 // 2/2/2 2D combine path (any dot3 card)
1911 memset(&m, 0, sizeof(m));
1912 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1913 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1914 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1915 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1916 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1917 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1918 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1919 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1920 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1921 m.texmatrix[1] = rsurface.entitytoattenuationz;
1922 R_Mesh_TextureState(&m);
1923 GL_ColorMask(0,0,0,1);
1924 GL_BlendFunc(GL_ONE, GL_ZERO);
1925 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1928 memset(&m, 0, sizeof(m));
1929 m.tex[0] = R_GetTexture(normalmaptexture);
1930 m.texcombinergb[0] = GL_REPLACE;
1931 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1932 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1933 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1934 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1935 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1936 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1937 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1938 m.pointer_texcoord_bufferobject[1] = 0;
1939 m.pointer_texcoord_bufferoffset[1] = 0;
1940 R_Mesh_TextureState(&m);
1941 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1942 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1945 memset(&m, 0, sizeof(m));
1946 m.tex[0] = R_GetTexture(basetexture);
1947 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1948 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1949 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1950 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1951 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1953 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1954 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1955 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1956 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1957 m.texmatrix[1] = rsurface.entitytolight;
1959 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1961 // this final code is shared
1962 R_Mesh_TextureState(&m);
1963 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1966 static void R_Shadow_RenderLighting_Light_Dot3_SpecularPass(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset, const vec3_t lightcolorbase, rtexture_t *glosstexture, rtexture_t *normalmaptexture, float colorscale)
1968 float glossexponent;
1970 // FIXME: detect blendsquare!
1971 //if (!gl_support_blendsquare)
1974 // generate normalization cubemap texcoords
1975 R_Shadow_GenTexCoords_Specular_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
1976 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
1978 // 2/0/0/1/2 3D combine blendsquare path
1979 memset(&m, 0, sizeof(m));
1980 m.tex[0] = R_GetTexture(normalmaptexture);
1981 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1982 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1983 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1984 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1985 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1986 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1987 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1988 m.pointer_texcoord_bufferobject[1] = 0;
1989 m.pointer_texcoord_bufferoffset[1] = 0;
1990 R_Mesh_TextureState(&m);
1991 GL_ColorMask(0,0,0,1);
1992 // this squares the result
1993 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1994 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1996 // second and third pass
1997 R_Mesh_ResetTextureState();
1998 // square alpha in framebuffer a few times to make it shiny
1999 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2000 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2001 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2004 memset(&m, 0, sizeof(m));
2005 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2006 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2007 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2008 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2009 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2010 R_Mesh_TextureState(&m);
2011 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2012 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2015 memset(&m, 0, sizeof(m));
2016 m.tex[0] = R_GetTexture(glosstexture);
2017 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2018 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2019 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2020 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2021 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2023 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2024 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2025 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2026 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2027 m.texmatrix[1] = rsurface.entitytolight;
2029 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2031 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
2033 // 2/0/0/2 3D combine blendsquare path
2034 memset(&m, 0, sizeof(m));
2035 m.tex[0] = R_GetTexture(normalmaptexture);
2036 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2037 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2038 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2039 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2040 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2041 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2042 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2043 m.pointer_texcoord_bufferobject[1] = 0;
2044 m.pointer_texcoord_bufferoffset[1] = 0;
2045 R_Mesh_TextureState(&m);
2046 GL_ColorMask(0,0,0,1);
2047 // this squares the result
2048 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2049 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2051 // second and third pass
2052 R_Mesh_ResetTextureState();
2053 // square alpha in framebuffer a few times to make it shiny
2054 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2055 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2056 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2059 memset(&m, 0, sizeof(m));
2060 m.tex[0] = R_GetTexture(glosstexture);
2061 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2062 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2063 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2064 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2065 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2066 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2067 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2068 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2069 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2070 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2074 // 2/0/0/2/2 2D combine blendsquare path
2075 memset(&m, 0, sizeof(m));
2076 m.tex[0] = R_GetTexture(normalmaptexture);
2077 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2078 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2079 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2080 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2081 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2082 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2083 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2084 m.pointer_texcoord_bufferobject[1] = 0;
2085 m.pointer_texcoord_bufferoffset[1] = 0;
2086 R_Mesh_TextureState(&m);
2087 GL_ColorMask(0,0,0,1);
2088 // this squares the result
2089 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2090 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2092 // second and third pass
2093 R_Mesh_ResetTextureState();
2094 // square alpha in framebuffer a few times to make it shiny
2095 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2096 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2097 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2100 memset(&m, 0, sizeof(m));
2101 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2102 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2103 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2104 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2105 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2106 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2107 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2108 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2109 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2110 m.texmatrix[1] = rsurface.entitytoattenuationz;
2111 R_Mesh_TextureState(&m);
2112 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2113 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2116 memset(&m, 0, sizeof(m));
2117 m.tex[0] = R_GetTexture(glosstexture);
2118 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2119 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2120 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2121 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2122 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2124 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2125 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2126 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2127 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2128 m.texmatrix[1] = rsurface.entitytolight;
2130 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2132 // this final code is shared
2133 R_Mesh_TextureState(&m);
2134 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
2137 static void R_Shadow_RenderLighting_Light_Dot3(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float ambientscale, float diffusescale, float specularscale, qboolean dopants, qboolean doshirt)
2139 // ARB path (any Geforce, any Radeon)
2140 qboolean doambient = ambientscale > 0;
2141 qboolean dodiffuse = diffusescale > 0;
2142 qboolean dospecular = specularscale > 0;
2143 if (!doambient && !dodiffuse && !dospecular)
2145 R_Mesh_ColorPointer(NULL, 0, 0);
2147 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, basetexture, ambientscale * r_refdef.view.colorscale);
2149 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, basetexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2153 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorpants, pantstexture, ambientscale * r_refdef.view.colorscale);
2155 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorpants, pantstexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2160 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorshirt, shirttexture, ambientscale * r_refdef.view.colorscale);
2162 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorshirt, shirttexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2165 R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_refdef.view.colorscale);
2168 void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset, vec3_t diffusecolor2, vec3_t ambientcolor2)
2175 int newnumtriangles;
2179 int newelements[4096*3];
2180 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
2181 for (renders = 0;renders < 64;renders++)
2186 newnumtriangles = 0;
2188 // due to low fillrate on the cards this vertex lighting path is
2189 // designed for, we manually cull all triangles that do not
2190 // contain a lit vertex
2191 // this builds batches of triangles from multiple surfaces and
2192 // renders them at once
2193 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2195 if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
2197 if (newnumtriangles)
2199 newfirstvertex = min(newfirstvertex, e[0]);
2200 newlastvertex = max(newlastvertex, e[0]);
2204 newfirstvertex = e[0];
2205 newlastvertex = e[0];
2207 newfirstvertex = min(newfirstvertex, e[1]);
2208 newlastvertex = max(newlastvertex, e[1]);
2209 newfirstvertex = min(newfirstvertex, e[2]);
2210 newlastvertex = max(newlastvertex, e[2]);
2216 if (newnumtriangles >= (int)(sizeof(newelements)/sizeof(float[3])))
2218 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, newnumtriangles, newelements, 0, 0);
2219 newnumtriangles = 0;
2225 if (newnumtriangles >= 1)
2227 // if all triangles are included, use the original array to take advantage of the bufferobject if possible
2228 if (newnumtriangles == numtriangles)
2229 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2231 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, newnumtriangles, newelements, 0, 0);
2234 // if we couldn't find any lit triangles, exit early
2237 // now reduce the intensity for the next overbright pass
2238 // we have to clamp to 0 here incase the drivers have improper
2239 // handling of negative colors
2240 // (some old drivers even have improper handling of >1 color)
2242 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2244 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2246 c[0] = max(0, c[0] - 1);
2247 c[1] = max(0, c[1] - 1);
2248 c[2] = max(0, c[2] - 1);
2260 static void R_Shadow_RenderLighting_Light_Vertex(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float ambientscale, float diffusescale, float specularscale, qboolean dopants, qboolean doshirt)
2262 // OpenGL 1.1 path (anything)
2263 float ambientcolorbase[3], diffusecolorbase[3];
2264 float ambientcolorpants[3], diffusecolorpants[3];
2265 float ambientcolorshirt[3], diffusecolorshirt[3];
2267 VectorScale(lightcolorbase, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorbase);
2268 VectorScale(lightcolorbase, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorbase);
2269 VectorScale(lightcolorpants, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorpants);
2270 VectorScale(lightcolorpants, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorpants);
2271 VectorScale(lightcolorshirt, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorshirt);
2272 VectorScale(lightcolorshirt, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorshirt);
2273 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2274 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
2275 memset(&m, 0, sizeof(m));
2276 m.tex[0] = R_GetTexture(basetexture);
2277 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2278 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2279 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2280 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2281 if (r_textureunits.integer >= 2)
2284 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2285 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2286 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2287 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2288 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2289 if (r_textureunits.integer >= 3)
2291 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
2292 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2293 m.texmatrix[2] = rsurface.entitytoattenuationz;
2294 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2295 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2296 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2299 R_Mesh_TextureState(&m);
2300 //R_Mesh_TexBind(0, R_GetTexture(basetexture));
2301 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, diffusecolorbase, ambientcolorbase);
2304 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
2305 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, diffusecolorpants, ambientcolorpants);
2309 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
2310 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, diffusecolorshirt, ambientcolorshirt);
2314 extern cvar_t gl_lightmaps;
2315 void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset)
2317 float ambientscale, diffusescale, specularscale;
2318 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
2320 // calculate colors to render this texture with
2321 lightcolorbase[0] = rsurface.rtlight->currentcolor[0] * rsurface.texture->dlightcolor[0];
2322 lightcolorbase[1] = rsurface.rtlight->currentcolor[1] * rsurface.texture->dlightcolor[1];
2323 lightcolorbase[2] = rsurface.rtlight->currentcolor[2] * rsurface.texture->dlightcolor[2];
2324 ambientscale = rsurface.rtlight->ambientscale;
2325 diffusescale = rsurface.rtlight->diffusescale;
2326 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2327 if (!r_shadow_usenormalmap.integer)
2329 ambientscale += 1.0f * diffusescale;
2333 if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
2335 RSurf_SetupDepthAndCulling();
2336 nmap = rsurface.texture->currentskinframe->nmap;
2337 if (gl_lightmaps.integer)
2338 nmap = r_texture_blanknormalmap;
2339 if (rsurface.texture->colormapping && !gl_lightmaps.integer)
2341 qboolean dopants = rsurface.texture->currentskinframe->pants != NULL && VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f);
2342 qboolean doshirt = rsurface.texture->currentskinframe->shirt != NULL && VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f);
2345 lightcolorpants[0] = lightcolorbase[0] * rsurface.colormap_pantscolor[0];
2346 lightcolorpants[1] = lightcolorbase[1] * rsurface.colormap_pantscolor[1];
2347 lightcolorpants[2] = lightcolorbase[2] * rsurface.colormap_pantscolor[2];
2350 VectorClear(lightcolorpants);
2353 lightcolorshirt[0] = lightcolorbase[0] * rsurface.colormap_shirtcolor[0];
2354 lightcolorshirt[1] = lightcolorbase[1] * rsurface.colormap_shirtcolor[1];
2355 lightcolorshirt[2] = lightcolorbase[2] * rsurface.colormap_shirtcolor[2];
2358 VectorClear(lightcolorshirt);
2359 switch (r_shadow_rendermode)
2361 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2362 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2363 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);
2365 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2366 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);
2368 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2369 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);
2371 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2372 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);
2375 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2381 switch (r_shadow_rendermode)
2383 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2384 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2385 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);
2387 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2388 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);
2390 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2391 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);
2393 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2394 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);
2397 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2403 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)
2405 matrix4x4_t tempmatrix = *matrix;
2406 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2408 // if this light has been compiled before, free the associated data
2409 R_RTLight_Uncompile(rtlight);
2411 // clear it completely to avoid any lingering data
2412 memset(rtlight, 0, sizeof(*rtlight));
2414 // copy the properties
2415 rtlight->matrix_lighttoworld = tempmatrix;
2416 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2417 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2418 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2419 VectorCopy(color, rtlight->color);
2420 rtlight->cubemapname[0] = 0;
2421 if (cubemapname && cubemapname[0])
2422 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2423 rtlight->shadow = shadow;
2424 rtlight->corona = corona;
2425 rtlight->style = style;
2426 rtlight->isstatic = isstatic;
2427 rtlight->coronasizescale = coronasizescale;
2428 rtlight->ambientscale = ambientscale;
2429 rtlight->diffusescale = diffusescale;
2430 rtlight->specularscale = specularscale;
2431 rtlight->flags = flags;
2433 // compute derived data
2434 //rtlight->cullradius = rtlight->radius;
2435 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2436 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2437 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2438 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2439 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2440 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2441 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2444 // compiles rtlight geometry
2445 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2446 void R_RTLight_Compile(rtlight_t *rtlight)
2449 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2450 int lighttris, shadowtris, shadowmeshes, shadowmeshtris;
2451 entity_render_t *ent = r_refdef.scene.worldentity;
2452 model_t *model = r_refdef.scene.worldmodel;
2453 unsigned char *data;
2455 // compile the light
2456 rtlight->compiled = true;
2457 rtlight->static_numleafs = 0;
2458 rtlight->static_numleafpvsbytes = 0;
2459 rtlight->static_leaflist = NULL;
2460 rtlight->static_leafpvs = NULL;
2461 rtlight->static_numsurfaces = 0;
2462 rtlight->static_surfacelist = NULL;
2463 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2464 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2465 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2466 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2467 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2468 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2470 if (model && model->GetLightInfo)
2472 // this variable must be set for the CompileShadowVolume code
2473 r_shadow_compilingrtlight = rtlight;
2474 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);
2475 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);
2476 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2477 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
2478 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
2479 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
2480 rtlight->static_numsurfaces = numsurfaces;
2481 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2482 rtlight->static_numleafs = numleafs;
2483 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2484 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2485 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2486 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
2487 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
2488 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
2489 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
2490 if (rtlight->static_numsurfaces)
2491 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2492 if (rtlight->static_numleafs)
2493 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2494 if (rtlight->static_numleafpvsbytes)
2495 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2496 if (rtlight->static_numshadowtrispvsbytes)
2497 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
2498 if (rtlight->static_numlighttrispvsbytes)
2499 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
2500 if (model->CompileShadowVolume && rtlight->shadow)
2501 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2502 // now we're done compiling the rtlight
2503 r_shadow_compilingrtlight = NULL;
2507 // use smallest available cullradius - box radius or light radius
2508 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2509 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2513 if (rtlight->static_meshchain_shadow)
2516 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2519 shadowmeshtris += mesh->numtriangles;
2524 if (rtlight->static_numlighttrispvsbytes)
2525 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
2526 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
2530 if (rtlight->static_numlighttrispvsbytes)
2531 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
2532 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
2535 if (developer.integer >= 10)
2536 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);
2539 void R_RTLight_Uncompile(rtlight_t *rtlight)
2541 if (rtlight->compiled)
2543 if (rtlight->static_meshchain_shadow)
2544 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2545 rtlight->static_meshchain_shadow = NULL;
2546 // these allocations are grouped
2547 if (rtlight->static_surfacelist)
2548 Mem_Free(rtlight->static_surfacelist);
2549 rtlight->static_numleafs = 0;
2550 rtlight->static_numleafpvsbytes = 0;
2551 rtlight->static_leaflist = NULL;
2552 rtlight->static_leafpvs = NULL;
2553 rtlight->static_numsurfaces = 0;
2554 rtlight->static_surfacelist = NULL;
2555 rtlight->static_numshadowtrispvsbytes = 0;
2556 rtlight->static_shadowtrispvs = NULL;
2557 rtlight->static_numlighttrispvsbytes = 0;
2558 rtlight->static_lighttrispvs = NULL;
2559 rtlight->compiled = false;
2563 void R_Shadow_UncompileWorldLights(void)
2567 for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
2569 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2572 R_RTLight_Uncompile(&light->rtlight);
2576 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
2580 // reset the count of frustum planes
2581 // see rsurface.rtlight_frustumplanes definition for how much this array
2583 rsurface.rtlight_numfrustumplanes = 0;
2585 // haven't implemented a culling path for ortho rendering
2586 if (!r_refdef.view.useperspective)
2588 // check if the light is on screen and copy the 4 planes if it is
2589 for (i = 0;i < 4;i++)
2590 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
2593 for (i = 0;i < 4;i++)
2594 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
2599 // generate a deformed frustum that includes the light origin, this is
2600 // used to cull shadow casting surfaces that can not possibly cast a
2601 // shadow onto the visible light-receiving surfaces, which can be a
2604 // if the light origin is onscreen the result will be 4 planes exactly
2605 // if the light origin is offscreen on only one axis the result will
2606 // be exactly 5 planes (split-side case)
2607 // if the light origin is offscreen on two axes the result will be
2608 // exactly 4 planes (stretched corner case)
2609 for (i = 0;i < 4;i++)
2611 // quickly reject standard frustum planes that put the light
2612 // origin outside the frustum
2613 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
2616 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
2618 // if all the standard frustum planes were accepted, the light is onscreen
2619 // otherwise we need to generate some more planes below...
2620 if (rsurface.rtlight_numfrustumplanes < 4)
2622 // at least one of the stock frustum planes failed, so we need to
2623 // create one or two custom planes to enclose the light origin
2624 for (i = 0;i < 4;i++)
2626 // create a plane using the view origin and light origin, and a
2627 // single point from the frustum corner set
2628 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
2629 VectorNormalize(plane.normal);
2630 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
2631 // see if this plane is backwards and flip it if so
2632 for (j = 0;j < 4;j++)
2633 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
2637 VectorNegate(plane.normal, plane.normal);
2639 // flipped plane, test again to see if it is now valid
2640 for (j = 0;j < 4;j++)
2641 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
2643 // if the plane is still not valid, then it is dividing the
2644 // frustum and has to be rejected
2648 // we have created a valid plane, compute extra info
2649 PlaneClassify(&plane);
2651 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
2653 // if we've found 5 frustum planes then we have constructed a
2654 // proper split-side case and do not need to keep searching for
2655 // planes to enclose the light origin
2656 if (rsurface.rtlight_numfrustumplanes == 5)
2664 for (i = 0;i < rsurface.rtlight_numfrustumplanes;i++)
2666 plane = rsurface.rtlight_frustumplanes[i];
2667 Con_Printf("light %p plane #%i %f %f %f : %f (%f %f %f %f %f)\n", rtlight, i, plane.normal[0], plane.normal[1], plane.normal[2], plane.dist, PlaneDiff(r_refdef.view.frustumcorner[0], &plane), PlaneDiff(r_refdef.view.frustumcorner[1], &plane), PlaneDiff(r_refdef.view.frustumcorner[2], &plane), PlaneDiff(r_refdef.view.frustumcorner[3], &plane), PlaneDiff(rtlight->shadoworigin, &plane));
2672 // now add the light-space box planes if the light box is rotated, as any
2673 // caster outside the oriented light box is irrelevant (even if it passed
2674 // the worldspace light box, which is axial)
2675 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
2677 for (i = 0;i < 6;i++)
2681 v[i >> 1] = (i & 1) ? -1 : 1;
2682 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
2683 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
2684 plane.dist = VectorNormalizeLength(plane.normal);
2685 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
2686 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
2692 // add the world-space reduced box planes
2693 for (i = 0;i < 6;i++)
2695 VectorClear(plane.normal);
2696 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
2697 plane.dist = (i & 1) ? -rsurface.rtlight_cullmaxs[i >> 1] : rsurface.rtlight_cullmins[i >> 1];
2698 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
2707 // reduce all plane distances to tightly fit the rtlight cull box, which
2709 VectorSet(points[0], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
2710 VectorSet(points[1], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
2711 VectorSet(points[2], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
2712 VectorSet(points[3], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
2713 VectorSet(points[4], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
2714 VectorSet(points[5], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
2715 VectorSet(points[6], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
2716 VectorSet(points[7], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
2717 oldnum = rsurface.rtlight_numfrustumplanes;
2718 rsurface.rtlight_numfrustumplanes = 0;
2719 for (j = 0;j < oldnum;j++)
2721 // find the nearest point on the box to this plane
2722 bestdist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[0]);
2723 for (i = 1;i < 8;i++)
2725 dist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[i]);
2726 if (bestdist > dist)
2729 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);
2730 // if the nearest point is near or behind the plane, we want this
2731 // plane, otherwise the plane is useless as it won't cull anything
2732 if (rsurface.rtlight_frustumplanes[j].dist < bestdist + 0.03125)
2734 PlaneClassify(&rsurface.rtlight_frustumplanes[j]);
2735 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = rsurface.rtlight_frustumplanes[j];
2742 void R_Shadow_DrawWorldShadow(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
2744 RSurf_ActiveWorldEntity();
2745 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2749 for (mesh = rsurface.rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2751 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
2752 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
2753 GL_LockArrays(0, mesh->numverts);
2754 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
2756 // decrement stencil if backface is behind depthbuffer
2757 GL_CullFace(r_refdef.view.cullface_front);
2758 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2759 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->ebo, 0);
2760 // increment stencil if frontface is behind depthbuffer
2761 GL_CullFace(r_refdef.view.cullface_back);
2762 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2764 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->ebo, 0);
2765 GL_LockArrays(0, 0);
2769 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
2772 int surfacelistindex;
2773 msurface_t *surface;
2774 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
2775 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
2777 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
2778 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
2779 if (CHECKPVSBIT(trispvs, t))
2780 shadowmarklist[numshadowmark++] = t;
2782 R_Shadow_VolumeFromList(r_refdef.scene.worldmodel->brush.shadowmesh->numverts, r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles, r_refdef.scene.worldmodel->brush.shadowmesh->vertex3f, r_refdef.scene.worldmodel->brush.shadowmesh->element3i, r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius + r_refdef.scene.worldmodel->radius*2 + r_shadow_projectdistance.value, numshadowmark, shadowmarklist);
2784 else if (numsurfaces)
2785 r_refdef.scene.worldmodel->DrawShadowVolume(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
2788 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
2790 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
2791 vec_t relativeshadowradius;
2792 RSurf_ActiveModelEntity(ent, false, false);
2793 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
2794 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
2795 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
2796 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
2797 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
2798 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
2799 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
2800 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
2801 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2804 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
2806 // set up properties for rendering light onto this entity
2807 RSurf_ActiveModelEntity(ent, true, true);
2808 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
2809 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
2810 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
2811 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
2812 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2813 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
2816 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
2818 if (!r_refdef.scene.worldmodel->DrawLight)
2821 // set up properties for rendering light onto this entity
2822 RSurf_ActiveWorldEntity();
2823 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
2824 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
2825 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
2826 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
2827 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2828 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
2830 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, trispvs);
2833 void R_Shadow_DrawEntityLight(entity_render_t *ent)
2835 model_t *model = ent->model;
2836 if (!model->DrawLight)
2839 R_Shadow_SetupEntityLight(ent);
2841 model->DrawLight(ent, model->nummodelsurfaces, model->surfacelist, NULL);
2844 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
2848 int numleafs, numsurfaces;
2849 int *leaflist, *surfacelist;
2850 unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs;
2851 int numlightentities;
2852 int numlightentities_noselfshadow;
2853 int numshadowentities;
2854 int numshadowentities_noselfshadow;
2855 entity_render_t *lightentities[MAX_EDICTS];
2856 entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
2857 entity_render_t *shadowentities[MAX_EDICTS];
2858 entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
2860 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
2861 // skip lights that are basically invisible (color 0 0 0)
2862 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
2865 // loading is done before visibility checks because loading should happen
2866 // all at once at the start of a level, not when it stalls gameplay.
2867 // (especially important to benchmarks)
2869 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2870 R_RTLight_Compile(rtlight);
2872 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
2874 // look up the light style value at this time
2875 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
2876 VectorScale(rtlight->color, f, rtlight->currentcolor);
2878 if (rtlight->selected)
2880 f = 2 + sin(realtime * M_PI * 4.0);
2881 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
2885 // if lightstyle is currently off, don't draw the light
2886 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
2889 // if the light box is offscreen, skip it
2890 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2893 VectorCopy(rtlight->cullmins, rsurface.rtlight_cullmins);
2894 VectorCopy(rtlight->cullmaxs, rsurface.rtlight_cullmaxs);
2896 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2898 // compiled light, world available and can receive realtime lighting
2899 // retrieve leaf information
2900 numleafs = rtlight->static_numleafs;
2901 leaflist = rtlight->static_leaflist;
2902 leafpvs = rtlight->static_leafpvs;
2903 numsurfaces = rtlight->static_numsurfaces;
2904 surfacelist = rtlight->static_surfacelist;
2905 shadowtrispvs = rtlight->static_shadowtrispvs;
2906 lighttrispvs = rtlight->static_lighttrispvs;
2908 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
2910 // dynamic light, world available and can receive realtime lighting
2911 // calculate lit surfaces and leafs
2912 R_Shadow_EnlargeLeafSurfaceTrisBuffer(r_refdef.scene.worldmodel->brush.num_leafs, r_refdef.scene.worldmodel->num_surfaces, r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles, r_refdef.scene.worldmodel->surfmesh.num_triangles);
2913 r_refdef.scene.worldmodel->GetLightInfo(r_refdef.scene.worldentity, rtlight->shadoworigin, rtlight->radius, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs, r_shadow_buffer_leaflist, r_shadow_buffer_leafpvs, &numleafs, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces, r_shadow_buffer_shadowtrispvs, r_shadow_buffer_lighttrispvs);
2914 leaflist = r_shadow_buffer_leaflist;
2915 leafpvs = r_shadow_buffer_leafpvs;
2916 surfacelist = r_shadow_buffer_surfacelist;
2917 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
2918 lighttrispvs = r_shadow_buffer_lighttrispvs;
2919 // if the reduced leaf bounds are offscreen, skip it
2920 if (R_CullBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
2931 shadowtrispvs = NULL;
2932 lighttrispvs = NULL;
2934 // check if light is illuminating any visible leafs
2937 for (i = 0;i < numleafs;i++)
2938 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
2943 // set up a scissor rectangle for this light
2944 if (R_Shadow_ScissorForBBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
2947 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
2949 // make a list of lit entities and shadow casting entities
2950 numlightentities = 0;
2951 numlightentities_noselfshadow = 0;
2952 numshadowentities = 0;
2953 numshadowentities_noselfshadow = 0;
2954 // add dynamic entities that are lit by the light
2955 if (r_drawentities.integer)
2957 for (i = 0;i < r_refdef.scene.numentities;i++)
2960 entity_render_t *ent = r_refdef.scene.entities[i];
2962 if (!BoxesOverlap(ent->mins, ent->maxs, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
2964 // skip the object entirely if it is not within the valid
2965 // shadow-casting region (which includes the lit region)
2966 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rsurface.rtlight_numfrustumplanes, rsurface.rtlight_frustumplanes))
2968 if (!(model = ent->model))
2970 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
2972 // this entity wants to receive light, is visible, and is
2973 // inside the light box
2974 // TODO: check if the surfaces in the model can receive light
2975 // so now check if it's in a leaf seen by the light
2976 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.scene.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.scene.worldmodel, leafpvs, ent->mins, ent->maxs))
2978 if (ent->flags & RENDER_NOSELFSHADOW)
2979 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
2981 lightentities[numlightentities++] = ent;
2982 // since it is lit, it probably also casts a shadow...
2983 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2984 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
2985 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
2987 // note: exterior models without the RENDER_NOSELFSHADOW
2988 // flag still create a RENDER_NOSELFSHADOW shadow but
2989 // are lit normally, this means that they are
2990 // self-shadowing but do not shadow other
2991 // RENDER_NOSELFSHADOW entities such as the gun
2992 // (very weird, but keeps the player shadow off the gun)
2993 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
2994 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
2996 shadowentities[numshadowentities++] = ent;
2999 else if (ent->flags & RENDER_SHADOW)
3001 // this entity is not receiving light, but may still need to
3003 // TODO: check if the surfaces in the model can cast shadow
3004 // now check if it is in a leaf seen by the light
3005 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.scene.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.scene.worldmodel, leafpvs, ent->mins, ent->maxs))
3007 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3008 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3009 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3011 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3012 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3014 shadowentities[numshadowentities++] = ent;
3020 // return if there's nothing at all to light
3021 if (!numlightentities && !numsurfaces)
3024 // don't let sound skip if going slow
3025 if (r_refdef.scene.extraupdate)
3028 // make this the active rtlight for rendering purposes
3029 R_Shadow_RenderMode_ActiveLight(rtlight);
3030 // count this light in the r_speeds
3031 r_refdef.stats.lights++;
3033 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.rtworldshadows : r_refdef.rtdlightshadows))
3035 // optionally draw visible shape of the shadow volumes
3036 // for performance analysis by level designers
3037 R_Shadow_RenderMode_VisibleShadowVolumes();
3039 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3040 for (i = 0;i < numshadowentities;i++)
3041 R_Shadow_DrawEntityShadow(shadowentities[i]);
3042 for (i = 0;i < numshadowentities_noselfshadow;i++)
3043 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3046 if (gl_stencil && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.rtworldshadows : r_refdef.rtdlightshadows))
3048 // draw stencil shadow volumes to mask off pixels that are in shadow
3049 // so that they won't receive lighting
3050 R_Shadow_RenderMode_StencilShadowVolumes(true);
3052 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3053 for (i = 0;i < numshadowentities;i++)
3054 R_Shadow_DrawEntityShadow(shadowentities[i]);
3055 if (numlightentities_noselfshadow)
3057 // draw lighting in the unmasked areas
3058 R_Shadow_RenderMode_Lighting(true, false);
3059 for (i = 0;i < numlightentities_noselfshadow;i++)
3060 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3062 // optionally draw the illuminated areas
3063 // for performance analysis by level designers
3064 if (r_showlighting.integer && r_refdef.view.showdebug)
3066 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
3067 for (i = 0;i < numlightentities_noselfshadow;i++)
3068 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3071 R_Shadow_RenderMode_StencilShadowVolumes(false);
3073 for (i = 0;i < numshadowentities_noselfshadow;i++)
3074 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3076 if (numsurfaces + numlightentities)
3078 // draw lighting in the unmasked areas
3079 R_Shadow_RenderMode_Lighting(true, false);
3081 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3082 for (i = 0;i < numlightentities;i++)
3083 R_Shadow_DrawEntityLight(lightentities[i]);
3085 // optionally draw the illuminated areas
3086 // for performance analysis by level designers
3087 if (r_showlighting.integer && r_refdef.view.showdebug)
3089 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
3091 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3092 for (i = 0;i < numlightentities;i++)
3093 R_Shadow_DrawEntityLight(lightentities[i]);
3099 if (numsurfaces + numlightentities)
3101 // draw lighting in the unmasked areas
3102 R_Shadow_RenderMode_Lighting(false, false);
3104 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3105 for (i = 0;i < numlightentities;i++)
3106 R_Shadow_DrawEntityLight(lightentities[i]);
3107 for (i = 0;i < numlightentities_noselfshadow;i++)
3108 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3110 // optionally draw the illuminated areas
3111 // for performance analysis by level designers
3112 if (r_showlighting.integer && r_refdef.view.showdebug)
3114 R_Shadow_RenderMode_VisibleLighting(false, false);
3116 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3117 for (i = 0;i < numlightentities;i++)
3118 R_Shadow_DrawEntityLight(lightentities[i]);
3119 for (i = 0;i < numlightentities_noselfshadow;i++)
3120 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3126 void R_Shadow_DrawLightSprites(void);
3127 void R_ShadowVolumeLighting(qboolean visible)
3134 if (r_editlights.integer)
3135 R_Shadow_DrawLightSprites();
3137 R_Shadow_RenderMode_Begin();
3139 flag = r_refdef.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3140 if (r_shadow_debuglight.integer >= 0)
3142 lightindex = r_shadow_debuglight.integer;
3143 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3144 if (light && (light->flags & flag))
3145 R_DrawRTLight(&light->rtlight, visible);
3149 for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
3151 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3152 if (light && (light->flags & flag))
3153 R_DrawRTLight(&light->rtlight, visible);
3156 if (r_refdef.rtdlight)
3157 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3158 R_DrawRTLight(&r_refdef.scene.lights[lnum], visible);
3160 R_Shadow_RenderMode_End();
3163 extern void R_SetupView(qboolean allowwaterclippingplane);
3164 extern cvar_t r_shadows_throwdistance;
3165 void R_DrawModelShadows(void)
3168 float relativethrowdistance;
3169 entity_render_t *ent;
3170 vec3_t relativelightorigin;
3171 vec3_t relativelightdirection;
3172 vec3_t relativeshadowmins, relativeshadowmaxs;
3175 if (!r_drawentities.integer || !gl_stencil)
3179 GL_Scissor(r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
3181 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
3183 if (gl_ext_separatestencil.integer)
3184 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
3185 else if (gl_ext_stenciltwoside.integer)
3186 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
3188 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
3190 R_Shadow_RenderMode_StencilShadowVolumes(true);
3192 for (i = 0;i < r_refdef.scene.numentities;i++)
3194 ent = r_refdef.scene.entities[i];
3195 // cast shadows from anything that is not a submodel of the map
3196 if (ent->model && ent->model->DrawShadowVolume != NULL && !ent->model->brush.submodel && (ent->flags & RENDER_SHADOW))
3198 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
3199 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
3200 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
3201 VectorNegate(ent->modellight_lightdir, relativelightdirection);
3202 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
3203 RSurf_ActiveModelEntity(ent, false, false);
3204 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
3208 // not really the right mode, but this will disable any silly stencil features
3209 R_Shadow_RenderMode_VisibleLighting(true, true);
3211 // vertex coordinates for a quad that covers the screen exactly
3212 vertex3f[0] = 0;vertex3f[1] = 0;vertex3f[2] = 0;
3213 vertex3f[3] = 1;vertex3f[4] = 0;vertex3f[5] = 0;
3214 vertex3f[6] = 1;vertex3f[7] = 1;vertex3f[8] = 0;
3215 vertex3f[9] = 0;vertex3f[10] = 1;vertex3f[11] = 0;
3217 // set up ortho view for rendering this pass
3218 GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
3219 GL_Scissor(r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
3220 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
3221 GL_ScissorTest(true);
3222 R_Mesh_Matrix(&identitymatrix);
3223 R_Mesh_ResetTextureState();
3224 R_Mesh_VertexPointer(vertex3f, 0, 0);
3225 R_Mesh_ColorPointer(NULL, 0, 0);
3227 // set up a 50% darkening blend on shadowed areas
3228 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3229 GL_DepthRange(0, 1);
3230 GL_DepthTest(false);
3231 GL_DepthMask(false);
3232 GL_PolygonOffset(0, 0);CHECKGLERROR
3233 GL_Color(0, 0, 0, 0.5);
3234 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
3235 qglDepthFunc(GL_ALWAYS);CHECKGLERROR
3236 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
3237 qglStencilMask(~0);CHECKGLERROR
3238 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
3239 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
3241 // apply the blend to the shadowed areas
3242 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3244 // restoring the perspective view is done by R_RenderScene
3245 //R_SetupView(true);
3247 // restore other state to normal
3248 R_Shadow_RenderMode_End();
3251 void R_DrawCoronas(void)
3254 float cscale, scale;
3258 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
3260 R_Mesh_Matrix(&identitymatrix);
3261 flag = r_refdef.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3262 // FIXME: these traces should scan all render entities instead of cl.world
3263 for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
3265 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3268 rtlight = &light->rtlight;
3269 if (!(rtlight->flags & flag))
3271 if (rtlight->corona * r_coronas.value <= 0)
3273 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
3275 cscale = rtlight->corona * r_coronas.value* 0.25f;
3276 scale = rtlight->radius * rtlight->coronasizescale;
3277 if (VectorDistance2(rtlight->shadoworigin, r_refdef.view.origin) < 16.0f * 16.0f)
3279 if (CL_Move(r_refdef.view.origin, vec3_origin, vec3_origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
3281 R_DrawSprite(GL_ONE, GL_ONE, r_shadow_lightcorona, NULL, true, false, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale, rtlight->color[0] * cscale, rtlight->color[1] * cscale, rtlight->color[2] * cscale, 1);
3283 for (i = 0;i < r_refdef.scene.numlights;i++)
3285 rtlight = &r_refdef.scene.lights[i];
3286 if (!(rtlight->flags & flag))
3288 if (rtlight->corona <= 0)
3290 if (VectorDistance2(rtlight->shadoworigin, r_refdef.view.origin) < 32.0f * 32.0f)
3292 if (gl_flashblend.integer)
3294 cscale = rtlight->corona * 1.0f;
3295 scale = rtlight->radius * rtlight->coronasizescale * 2.0f;
3299 cscale = rtlight->corona * r_coronas.value* 0.25f;
3300 scale = rtlight->radius * rtlight->coronasizescale;
3302 if (VectorLength(rtlight->color) * cscale < (1.0f / 256.0f))
3304 if (CL_Move(r_refdef.view.origin, vec3_origin, vec3_origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
3306 R_DrawSprite(GL_ONE, GL_ONE, r_shadow_lightcorona, NULL, true, false, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale, rtlight->color[0] * cscale, rtlight->color[1] * cscale, rtlight->color[2] * cscale, 1);
3312 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
3313 typedef struct suffixinfo_s
3316 qboolean flipx, flipy, flipdiagonal;
3319 static suffixinfo_t suffix[3][6] =
3322 {"px", false, false, false},
3323 {"nx", false, false, false},
3324 {"py", false, false, false},
3325 {"ny", false, false, false},
3326 {"pz", false, false, false},
3327 {"nz", false, false, false}
3330 {"posx", false, false, false},
3331 {"negx", false, false, false},
3332 {"posy", false, false, false},
3333 {"negy", false, false, false},
3334 {"posz", false, false, false},
3335 {"negz", false, false, false}
3338 {"rt", true, false, true},
3339 {"lf", false, true, true},
3340 {"ft", true, true, false},
3341 {"bk", false, false, false},
3342 {"up", true, false, true},
3343 {"dn", true, false, true}
3347 static int componentorder[4] = {0, 1, 2, 3};
3349 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
3351 int i, j, cubemapsize;
3352 unsigned char *cubemappixels, *image_buffer;
3353 rtexture_t *cubemaptexture;
3355 // must start 0 so the first loadimagepixels has no requested width/height
3357 cubemappixels = NULL;
3358 cubemaptexture = NULL;
3359 // keep trying different suffix groups (posx, px, rt) until one loads
3360 for (j = 0;j < 3 && !cubemappixels;j++)
3362 // load the 6 images in the suffix group
3363 for (i = 0;i < 6;i++)
3365 // generate an image name based on the base and and suffix
3366 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
3368 if ((image_buffer = loadimagepixelsbgra(name, false, false)))
3370 // an image loaded, make sure width and height are equal
3371 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
3373 // if this is the first image to load successfully, allocate the cubemap memory
3374 if (!cubemappixels && image_width >= 1)
3376 cubemapsize = image_width;
3377 // note this clears to black, so unavailable sides are black
3378 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
3380 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
3382 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);
3385 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
3387 Mem_Free(image_buffer);
3391 // if a cubemap loaded, upload it
3394 if (!r_shadow_filters_texturepool)
3395 r_shadow_filters_texturepool = R_AllocTexturePool();
3396 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, TEXF_PRECACHE | (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0), NULL);
3397 Mem_Free(cubemappixels);
3401 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
3402 for (j = 0;j < 3;j++)
3403 for (i = 0;i < 6;i++)
3404 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
3405 Con_Print(" and was unable to find any of them.\n");
3407 return cubemaptexture;
3410 rtexture_t *R_Shadow_Cubemap(const char *basename)
3413 for (i = 0;i < numcubemaps;i++)
3414 if (!strcasecmp(cubemaps[i].basename, basename))
3415 return cubemaps[i].texture;
3416 if (i >= MAX_CUBEMAPS)
3417 return r_texture_whitecube;
3419 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
3420 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
3421 if (!cubemaps[i].texture)
3422 cubemaps[i].texture = r_texture_whitecube;
3423 return cubemaps[i].texture;
3426 void R_Shadow_FreeCubemaps(void)
3429 R_FreeTexturePool(&r_shadow_filters_texturepool);
3432 dlight_t *R_Shadow_NewWorldLight(void)
3434 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
3437 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)
3440 // validate parameters
3441 if (style < 0 || style >= MAX_LIGHTSTYLES)
3443 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
3449 // copy to light properties
3450 VectorCopy(origin, light->origin);
3451 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
3452 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
3453 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
3454 light->color[0] = max(color[0], 0);
3455 light->color[1] = max(color[1], 0);
3456 light->color[2] = max(color[2], 0);
3457 light->radius = max(radius, 0);
3458 light->style = style;
3459 light->shadow = shadowenable;
3460 light->corona = corona;
3461 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
3462 light->coronasizescale = coronasizescale;
3463 light->ambientscale = ambientscale;
3464 light->diffusescale = diffusescale;
3465 light->specularscale = specularscale;
3466 light->flags = flags;
3468 // update renderable light data
3469 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
3470 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);
3473 void R_Shadow_FreeWorldLight(dlight_t *light)
3475 if (r_shadow_selectedlight == light)
3476 r_shadow_selectedlight = NULL;
3477 R_RTLight_Uncompile(&light->rtlight);
3478 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
3481 void R_Shadow_ClearWorldLights(void)
3485 for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
3487 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3489 R_Shadow_FreeWorldLight(light);
3491 r_shadow_selectedlight = NULL;
3492 R_Shadow_FreeCubemaps();
3495 void R_Shadow_SelectLight(dlight_t *light)
3497 if (r_shadow_selectedlight)
3498 r_shadow_selectedlight->selected = false;
3499 r_shadow_selectedlight = light;
3500 if (r_shadow_selectedlight)
3501 r_shadow_selectedlight->selected = true;
3504 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
3506 // this is never batched (there can be only one)
3507 R_DrawSprite(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, r_editlights_sprcursor->tex, r_editlights_sprcursor->tex, false, false, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE, 1, 1, 1, 1);
3510 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
3517 // this is never batched (due to the ent parameter changing every time)
3518 // so numsurfaces == 1 and surfacelist[0] == lightnumber
3519 const dlight_t *light = (dlight_t *)ent;
3522 VectorScale(light->color, intensity, spritecolor);
3523 if (VectorLength(spritecolor) < 0.1732f)
3524 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
3525 if (VectorLength(spritecolor) > 1.0f)
3526 VectorNormalize(spritecolor);
3528 // draw light sprite
3529 if (light->cubemapname[0] && !light->shadow)
3530 pic = r_editlights_sprcubemapnoshadowlight;
3531 else if (light->cubemapname[0])
3532 pic = r_editlights_sprcubemaplight;
3533 else if (!light->shadow)
3534 pic = r_editlights_sprnoshadowlight;
3536 pic = r_editlights_sprlight;
3537 R_DrawSprite(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, pic->tex, pic->tex, false, false, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s, spritecolor[0], spritecolor[1], spritecolor[2], 1);
3538 // draw selection sprite if light is selected
3539 if (light->selected)
3540 R_DrawSprite(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, r_editlights_sprselection->tex, r_editlights_sprselection->tex, false, false, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s, 1, 1, 1, 1);
3541 // VorteX todo: add normalmode/realtime mode light overlay sprites?
3544 void R_Shadow_DrawLightSprites(void)
3548 for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
3550 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3552 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
3554 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
3557 void R_Shadow_SelectLightInView(void)
3559 float bestrating, rating, temp[3];
3565 for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
3567 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3570 VectorSubtract(light->origin, r_refdef.view.origin, temp);
3571 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
3574 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
3575 if (bestrating < rating && CL_Move(light->origin, vec3_origin, vec3_origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
3577 bestrating = rating;
3582 R_Shadow_SelectLight(best);
3585 void R_Shadow_LoadWorldLights(void)
3587 int n, a, style, shadow, flags;
3588 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
3589 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
3590 if (cl.worldmodel == NULL)
3592 Con_Print("No map loaded.\n");
3595 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
3596 strlcat (name, ".rtlights", sizeof (name));
3597 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3607 for (;COM_Parse(t, true) && strcmp(
3608 if (COM_Parse(t, true))
3610 if (com_token[0] == '!')
3613 origin[0] = atof(com_token+1);
3616 origin[0] = atof(com_token);
3621 while (*s && *s != '\n' && *s != '\r')
3627 // check for modifier flags
3634 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);
3637 flags = LIGHTFLAG_REALTIMEMODE;
3645 coronasizescale = 0.25f;
3647 VectorClear(angles);
3650 if (a < 9 || !strcmp(cubemapname, "\"\""))
3652 // remove quotes on cubemapname
3653 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
3656 namelen = strlen(cubemapname) - 2;
3657 memmove(cubemapname, cubemapname + 1, namelen);
3658 cubemapname[namelen] = '\0';
3662 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);
3665 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3673 Con_Printf("invalid rtlights file \"%s\"\n", name);
3674 Mem_Free(lightsstring);
3678 void R_Shadow_SaveWorldLights(void)
3682 size_t bufchars, bufmaxchars;
3684 char name[MAX_QPATH];
3685 char line[MAX_INPUTLINE];
3686 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
3688 if (cl.worldmodel == NULL)
3690 Con_Print("No map loaded.\n");
3693 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
3694 strlcat (name, ".rtlights", sizeof (name));
3695 bufchars = bufmaxchars = 0;
3697 for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
3699 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3702 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3703 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);
3704 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3705 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]);
3707 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);
3708 if (bufchars + strlen(line) > bufmaxchars)
3710 bufmaxchars = bufchars + strlen(line) + 2048;
3712 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
3716 memcpy(buf, oldbuf, bufchars);
3722 memcpy(buf + bufchars, line, strlen(line));
3723 bufchars += strlen(line);
3727 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
3732 void R_Shadow_LoadLightsFile(void)
3735 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3736 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3737 if (cl.worldmodel == NULL)
3739 Con_Print("No map loaded.\n");
3742 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
3743 strlcat (name, ".lights", sizeof (name));
3744 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3752 while (*s && *s != '\n' && *s != '\r')
3758 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);
3762 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);
3765 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3766 radius = bound(15, radius, 4096);
3767 VectorScale(color, (2.0f / (8388608.0f)), color);
3768 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3776 Con_Printf("invalid lights file \"%s\"\n", name);
3777 Mem_Free(lightsstring);
3781 // tyrlite/hmap2 light types in the delay field
3782 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3784 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3786 int entnum, style, islight, skin, pflags, effects, type, n;
3789 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3790 char key[256], value[MAX_INPUTLINE];
3792 if (cl.worldmodel == NULL)
3794 Con_Print("No map loaded.\n");
3797 // try to load a .ent file first
3798 FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
3799 strlcat (key, ".ent", sizeof (key));
3800 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
3801 // and if that is not found, fall back to the bsp file entity string
3803 data = cl.worldmodel->brush.entities;
3806 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
3808 type = LIGHTTYPE_MINUSX;
3809 origin[0] = origin[1] = origin[2] = 0;
3810 originhack[0] = originhack[1] = originhack[2] = 0;
3811 angles[0] = angles[1] = angles[2] = 0;
3812 color[0] = color[1] = color[2] = 1;
3813 light[0] = light[1] = light[2] = 1;light[3] = 300;
3814 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3824 if (!COM_ParseToken_Simple(&data, false, false))
3826 if (com_token[0] == '}')
3827 break; // end of entity
3828 if (com_token[0] == '_')
3829 strlcpy(key, com_token + 1, sizeof(key));
3831 strlcpy(key, com_token, sizeof(key));
3832 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3833 key[strlen(key)-1] = 0;
3834 if (!COM_ParseToken_Simple(&data, false, false))
3836 strlcpy(value, com_token, sizeof(value));
3838 // now that we have the key pair worked out...
3839 if (!strcmp("light", key))
3841 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3845 light[0] = vec[0] * (1.0f / 256.0f);
3846 light[1] = vec[0] * (1.0f / 256.0f);
3847 light[2] = vec[0] * (1.0f / 256.0f);
3853 light[0] = vec[0] * (1.0f / 255.0f);
3854 light[1] = vec[1] * (1.0f / 255.0f);
3855 light[2] = vec[2] * (1.0f / 255.0f);
3859 else if (!strcmp("delay", key))
3861 else if (!strcmp("origin", key))
3862 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3863 else if (!strcmp("angle", key))
3864 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3865 else if (!strcmp("angles", key))
3866 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3867 else if (!strcmp("color", key))
3868 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3869 else if (!strcmp("wait", key))
3870 fadescale = atof(value);
3871 else if (!strcmp("classname", key))
3873 if (!strncmp(value, "light", 5))
3876 if (!strcmp(value, "light_fluoro"))
3881 overridecolor[0] = 1;
3882 overridecolor[1] = 1;
3883 overridecolor[2] = 1;
3885 if (!strcmp(value, "light_fluorospark"))
3890 overridecolor[0] = 1;
3891 overridecolor[1] = 1;
3892 overridecolor[2] = 1;
3894 if (!strcmp(value, "light_globe"))
3899 overridecolor[0] = 1;
3900 overridecolor[1] = 0.8;
3901 overridecolor[2] = 0.4;
3903 if (!strcmp(value, "light_flame_large_yellow"))
3908 overridecolor[0] = 1;
3909 overridecolor[1] = 0.5;
3910 overridecolor[2] = 0.1;
3912 if (!strcmp(value, "light_flame_small_yellow"))
3917 overridecolor[0] = 1;
3918 overridecolor[1] = 0.5;
3919 overridecolor[2] = 0.1;
3921 if (!strcmp(value, "light_torch_small_white"))
3926 overridecolor[0] = 1;
3927 overridecolor[1] = 0.5;
3928 overridecolor[2] = 0.1;
3930 if (!strcmp(value, "light_torch_small_walltorch"))
3935 overridecolor[0] = 1;
3936 overridecolor[1] = 0.5;
3937 overridecolor[2] = 0.1;
3941 else if (!strcmp("style", key))
3942 style = atoi(value);
3943 else if (!strcmp("skin", key))
3944 skin = (int)atof(value);
3945 else if (!strcmp("pflags", key))
3946 pflags = (int)atof(value);
3947 else if (!strcmp("effects", key))
3948 effects = (int)atof(value);
3949 else if (cl.worldmodel->type == mod_brushq3)
3951 if (!strcmp("scale", key))
3952 lightscale = atof(value);
3953 if (!strcmp("fade", key))
3954 fadescale = atof(value);
3959 if (lightscale <= 0)
3963 if (color[0] == color[1] && color[0] == color[2])
3965 color[0] *= overridecolor[0];
3966 color[1] *= overridecolor[1];
3967 color[2] *= overridecolor[2];
3969 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3970 color[0] = color[0] * light[0];
3971 color[1] = color[1] * light[1];
3972 color[2] = color[2] * light[2];
3975 case LIGHTTYPE_MINUSX:
3977 case LIGHTTYPE_RECIPX:
3979 VectorScale(color, (1.0f / 16.0f), color);
3981 case LIGHTTYPE_RECIPXX:
3983 VectorScale(color, (1.0f / 16.0f), color);
3986 case LIGHTTYPE_NONE:
3990 case LIGHTTYPE_MINUSXX:
3993 VectorAdd(origin, originhack, origin);
3995 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);
3998 Mem_Free(entfiledata);
4002 void R_Shadow_SetCursorLocationForView(void)
4005 vec3_t dest, endpos;
4007 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
4008 trace = CL_Move(r_refdef.view.origin, vec3_origin, vec3_origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
4009 if (trace.fraction < 1)
4011 dist = trace.fraction * r_editlights_cursordistance.value;
4012 push = r_editlights_cursorpushback.value;
4016 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
4017 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
4021 VectorClear( endpos );
4023 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4024 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4025 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4028 void R_Shadow_UpdateWorldLightSelection(void)
4030 if (r_editlights.integer)
4032 R_Shadow_SetCursorLocationForView();
4033 R_Shadow_SelectLightInView();
4036 R_Shadow_SelectLight(NULL);
4039 void R_Shadow_EditLights_Clear_f(void)
4041 R_Shadow_ClearWorldLights();
4044 void R_Shadow_EditLights_Reload_f(void)
4048 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
4049 R_Shadow_ClearWorldLights();
4050 R_Shadow_LoadWorldLights();
4051 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
4053 R_Shadow_LoadLightsFile();
4054 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
4055 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
4059 void R_Shadow_EditLights_Save_f(void)
4063 R_Shadow_SaveWorldLights();
4066 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
4068 R_Shadow_ClearWorldLights();
4069 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
4072 void R_Shadow_EditLights_ImportLightsFile_f(void)
4074 R_Shadow_ClearWorldLights();
4075 R_Shadow_LoadLightsFile();
4078 void R_Shadow_EditLights_Spawn_f(void)
4081 if (!r_editlights.integer)
4083 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4086 if (Cmd_Argc() != 1)
4088 Con_Print("r_editlights_spawn does not take parameters\n");
4091 color[0] = color[1] = color[2] = 1;
4092 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
4095 void R_Shadow_EditLights_Edit_f(void)
4097 vec3_t origin, angles, color;
4098 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
4099 int style, shadows, flags, normalmode, realtimemode;
4100 char cubemapname[MAX_INPUTLINE];
4101 if (!r_editlights.integer)
4103 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4106 if (!r_shadow_selectedlight)
4108 Con_Print("No selected light.\n");
4111 VectorCopy(r_shadow_selectedlight->origin, origin);
4112 VectorCopy(r_shadow_selectedlight->angles, angles);
4113 VectorCopy(r_shadow_selectedlight->color, color);
4114 radius = r_shadow_selectedlight->radius;
4115 style = r_shadow_selectedlight->style;
4116 if (r_shadow_selectedlight->cubemapname)
4117 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
4120 shadows = r_shadow_selectedlight->shadow;
4121 corona = r_shadow_selectedlight->corona;
4122 coronasizescale = r_shadow_selectedlight->coronasizescale;
4123 ambientscale = r_shadow_selectedlight->ambientscale;
4124 diffusescale = r_shadow_selectedlight->diffusescale;
4125 specularscale = r_shadow_selectedlight->specularscale;
4126 flags = r_shadow_selectedlight->flags;
4127 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
4128 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
4129 if (!strcmp(Cmd_Argv(1), "origin"))
4131 if (Cmd_Argc() != 5)
4133 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
4136 origin[0] = atof(Cmd_Argv(2));
4137 origin[1] = atof(Cmd_Argv(3));
4138 origin[2] = atof(Cmd_Argv(4));
4140 else if (!strcmp(Cmd_Argv(1), "originx"))
4142 if (Cmd_Argc() != 3)
4144 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4147 origin[0] = atof(Cmd_Argv(2));
4149 else if (!strcmp(Cmd_Argv(1), "originy"))
4151 if (Cmd_Argc() != 3)
4153 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4156 origin[1] = atof(Cmd_Argv(2));
4158 else if (!strcmp(Cmd_Argv(1), "originz"))
4160 if (Cmd_Argc() != 3)
4162 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4165 origin[2] = atof(Cmd_Argv(2));
4167 else if (!strcmp(Cmd_Argv(1), "move"))
4169 if (Cmd_Argc() != 5)
4171 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
4174 origin[0] += atof(Cmd_Argv(2));
4175 origin[1] += atof(Cmd_Argv(3));
4176 origin[2] += atof(Cmd_Argv(4));
4178 else if (!strcmp(Cmd_Argv(1), "movex"))
4180 if (Cmd_Argc() != 3)
4182 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4185 origin[0] += atof(Cmd_Argv(2));
4187 else if (!strcmp(Cmd_Argv(1), "movey"))
4189 if (Cmd_Argc() != 3)
4191 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4194 origin[1] += atof(Cmd_Argv(2));
4196 else if (!strcmp(Cmd_Argv(1), "movez"))
4198 if (Cmd_Argc() != 3)
4200 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4203 origin[2] += atof(Cmd_Argv(2));
4205 else if (!strcmp(Cmd_Argv(1), "angles"))
4207 if (Cmd_Argc() != 5)
4209 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
4212 angles[0] = atof(Cmd_Argv(2));
4213 angles[1] = atof(Cmd_Argv(3));
4214 angles[2] = atof(Cmd_Argv(4));
4216 else if (!strcmp(Cmd_Argv(1), "anglesx"))
4218 if (Cmd_Argc() != 3)
4220 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4223 angles[0] = atof(Cmd_Argv(2));
4225 else if (!strcmp(Cmd_Argv(1), "anglesy"))
4227 if (Cmd_Argc() != 3)
4229 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4232 angles[1] = atof(Cmd_Argv(2));
4234 else if (!strcmp(Cmd_Argv(1), "anglesz"))
4236 if (Cmd_Argc() != 3)
4238 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4241 angles[2] = atof(Cmd_Argv(2));
4243 else if (!strcmp(Cmd_Argv(1), "color"))
4245 if (Cmd_Argc() != 5)
4247 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
4250 color[0] = atof(Cmd_Argv(2));
4251 color[1] = atof(Cmd_Argv(3));
4252 color[2] = atof(Cmd_Argv(4));
4254 else if (!strcmp(Cmd_Argv(1), "radius"))
4256 if (Cmd_Argc() != 3)
4258 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4261 radius = atof(Cmd_Argv(2));
4263 else if (!strcmp(Cmd_Argv(1), "colorscale"))
4265 if (Cmd_Argc() == 3)
4267 double scale = atof(Cmd_Argv(2));
4274 if (Cmd_Argc() != 5)
4276 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
4279 color[0] *= atof(Cmd_Argv(2));
4280 color[1] *= atof(Cmd_Argv(3));
4281 color[2] *= atof(Cmd_Argv(4));
4284 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
4286 if (Cmd_Argc() != 3)
4288 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4291 radius *= atof(Cmd_Argv(2));
4293 else if (!strcmp(Cmd_Argv(1), "style"))
4295 if (Cmd_Argc() != 3)
4297 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4300 style = atoi(Cmd_Argv(2));
4302 else if (!strcmp(Cmd_Argv(1), "cubemap"))
4306 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4309 if (Cmd_Argc() == 3)
4310 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
4314 else if (!strcmp(Cmd_Argv(1), "shadows"))
4316 if (Cmd_Argc() != 3)
4318 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4321 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4323 else if (!strcmp(Cmd_Argv(1), "corona"))
4325 if (Cmd_Argc() != 3)
4327 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4330 corona = atof(Cmd_Argv(2));
4332 else if (!strcmp(Cmd_Argv(1), "coronasize"))
4334 if (Cmd_Argc() != 3)
4336 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4339 coronasizescale = atof(Cmd_Argv(2));
4341 else if (!strcmp(Cmd_Argv(1), "ambient"))
4343 if (Cmd_Argc() != 3)
4345 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4348 ambientscale = atof(Cmd_Argv(2));
4350 else if (!strcmp(Cmd_Argv(1), "diffuse"))
4352 if (Cmd_Argc() != 3)
4354 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4357 diffusescale = atof(Cmd_Argv(2));
4359 else if (!strcmp(Cmd_Argv(1), "specular"))
4361 if (Cmd_Argc() != 3)
4363 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4366 specularscale = atof(Cmd_Argv(2));
4368 else if (!strcmp(Cmd_Argv(1), "normalmode"))
4370 if (Cmd_Argc() != 3)
4372 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4375 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4377 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
4379 if (Cmd_Argc() != 3)
4381 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4384 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4388 Con_Print("usage: r_editlights_edit [property] [value]\n");
4389 Con_Print("Selected light's properties:\n");
4390 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
4391 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
4392 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
4393 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
4394 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
4395 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
4396 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
4397 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
4398 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
4399 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
4400 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
4401 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
4402 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
4403 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
4406 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
4407 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4410 void R_Shadow_EditLights_EditAll_f(void)
4415 if (!r_editlights.integer)
4417 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
4421 for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
4423 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4426 R_Shadow_SelectLight(light);
4427 R_Shadow_EditLights_Edit_f();
4431 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
4433 int lightnumber, lightcount;
4438 if (!r_editlights.integer)
4440 x = vid_conwidth.value - 240;
4442 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
4445 for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
4447 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4450 if (light == r_shadow_selectedlight)
4451 lightnumber = lightindex;
4454 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;
4455 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;
4457 if (r_shadow_selectedlight == NULL)
4459 sprintf(temp, "Light #%i properties:", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
4460 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;
4461 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;
4462 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;
4463 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;
4464 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;
4465 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;
4466 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;
4467 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;
4468 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;
4469 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;
4470 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;
4471 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;
4472 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;
4473 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;
4476 void R_Shadow_EditLights_ToggleShadow_f(void)
4478 if (!r_editlights.integer)
4480 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4483 if (!r_shadow_selectedlight)
4485 Con_Print("No selected light.\n");
4488 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);
4491 void R_Shadow_EditLights_ToggleCorona_f(void)
4493 if (!r_editlights.integer)
4495 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4498 if (!r_shadow_selectedlight)
4500 Con_Print("No selected light.\n");
4503 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);
4506 void R_Shadow_EditLights_Remove_f(void)
4508 if (!r_editlights.integer)
4510 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
4513 if (!r_shadow_selectedlight)
4515 Con_Print("No selected light.\n");
4518 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
4519 r_shadow_selectedlight = NULL;
4522 void R_Shadow_EditLights_Help_f(void)
4525 "Documentation on r_editlights system:\n"
4527 "r_editlights : enable/disable editing mode\n"
4528 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
4529 "r_editlights_cursorpushback : push back cursor this far from surface\n"
4530 "r_editlights_cursorpushoff : push cursor off surface this far\n"
4531 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
4532 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
4534 "r_editlights_help : this help\n"
4535 "r_editlights_clear : remove all lights\n"
4536 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
4537 "r_editlights_save : save to .rtlights file\n"
4538 "r_editlights_spawn : create a light with default settings\n"
4539 "r_editlights_edit command : edit selected light - more documentation below\n"
4540 "r_editlights_remove : remove selected light\n"
4541 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
4542 "r_editlights_importlightentitiesfrommap : reload light entities\n"
4543 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
4545 "origin x y z : set light location\n"
4546 "originx x: set x component of light location\n"
4547 "originy y: set y component of light location\n"
4548 "originz z: set z component of light location\n"
4549 "move x y z : adjust light location\n"
4550 "movex x: adjust x component of light location\n"
4551 "movey y: adjust y component of light location\n"
4552 "movez z: adjust z component of light location\n"
4553 "angles x y z : set light angles\n"
4554 "anglesx x: set x component of light angles\n"
4555 "anglesy y: set y component of light angles\n"
4556 "anglesz z: set z component of light angles\n"
4557 "color r g b : set color of light (can be brighter than 1 1 1)\n"
4558 "radius radius : set radius (size) of light\n"
4559 "colorscale grey : multiply color of light (1 does nothing)\n"
4560 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
4561 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
4562 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
4563 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
4564 "cubemap basename : set filter cubemap of light (not yet supported)\n"
4565 "shadows 1/0 : turn on/off shadows\n"
4566 "corona n : set corona intensity\n"
4567 "coronasize n : set corona size (0-1)\n"
4568 "ambient n : set ambient intensity (0-1)\n"
4569 "diffuse n : set diffuse intensity (0-1)\n"
4570 "specular n : set specular intensity (0-1)\n"
4571 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
4572 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
4573 "<nothing> : print light properties to console\n"
4577 void R_Shadow_EditLights_CopyInfo_f(void)
4579 if (!r_editlights.integer)
4581 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
4584 if (!r_shadow_selectedlight)
4586 Con_Print("No selected light.\n");
4589 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
4590 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
4591 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
4592 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
4593 if (r_shadow_selectedlight->cubemapname)
4594 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
4596 r_shadow_bufferlight.cubemapname[0] = 0;
4597 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
4598 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
4599 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
4600 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
4601 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
4602 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
4603 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
4606 void R_Shadow_EditLights_PasteInfo_f(void)
4608 if (!r_editlights.integer)
4610 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
4613 if (!r_shadow_selectedlight)
4615 Con_Print("No selected light.\n");
4618 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);
4621 void R_Shadow_EditLights_Init(void)
4623 Cvar_RegisterVariable(&r_editlights);
4624 Cvar_RegisterVariable(&r_editlights_cursordistance);
4625 Cvar_RegisterVariable(&r_editlights_cursorpushback);
4626 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
4627 Cvar_RegisterVariable(&r_editlights_cursorgrid);
4628 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
4629 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
4630 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
4631 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)");
4632 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
4633 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
4634 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
4635 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)");
4636 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
4637 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
4638 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
4639 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
4640 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
4641 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
4642 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)");
4648 =============================================================================
4652 =============================================================================
4655 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
4657 VectorClear(diffusecolor);
4658 VectorClear(diffusenormal);
4660 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
4662 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_ambient.value * (2.0f / 128.0f);
4663 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
4666 VectorSet(ambientcolor, 1, 1, 1);
4673 for (i = 0;i < r_refdef.scene.numlights;i++)
4675 light = &r_refdef.scene.lights[i];
4676 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
4677 f = 1 - VectorLength2(v);
4678 if (f > 0 && CL_Move(p, vec3_origin, vec3_origin, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
4679 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);