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_LIGHT_GLSL)
1064 qglUseProgramObjectARB(0);CHECKGLERROR
1066 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
1068 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1070 R_Mesh_ColorPointer(NULL, 0, 0);
1071 R_Mesh_ResetTextureState();
1072 GL_DepthRange(0, 1);
1074 GL_DepthMask(false);
1075 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1076 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1077 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1078 qglStencilMask(~0);CHECKGLERROR
1079 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1080 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1081 GL_CullFace(r_refdef.view.cullface_back);
1082 GL_Color(1, 1, 1, 1);
1083 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1084 GL_BlendFunc(GL_ONE, GL_ZERO);
1087 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean clearstencil)
1090 R_Shadow_RenderMode_Reset();
1091 GL_ColorMask(0, 0, 0, 0);
1092 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1093 qglDepthFunc(GL_LESS);CHECKGLERROR
1094 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1095 r_shadow_rendermode = r_shadow_shadowingrendermode;
1096 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SEPARATESTENCIL)
1098 GL_CullFace(GL_NONE);
1099 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1100 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1102 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
1104 GL_CullFace(GL_NONE);
1105 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1106 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1107 qglStencilMask(~0);CHECKGLERROR
1108 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1109 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1110 qglStencilMask(~0);CHECKGLERROR
1111 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1114 GL_Clear(GL_STENCIL_BUFFER_BIT);
1115 r_refdef.stats.lights_clears++;
1118 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent)
1121 R_Shadow_RenderMode_Reset();
1122 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1125 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1129 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1130 // only draw light where this geometry was already rendered AND the
1131 // stencil is 128 (values other than this mean shadow)
1132 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1134 r_shadow_rendermode = r_shadow_lightingrendermode;
1135 // do global setup needed for the chosen lighting mode
1136 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1138 R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap)); // light filter
1139 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1140 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
1145 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
1148 R_Shadow_RenderMode_Reset();
1149 GL_BlendFunc(GL_ONE, GL_ONE);
1150 GL_DepthRange(0, 1);
1151 GL_DepthTest(r_showshadowvolumes.integer < 2);
1152 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
1153 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1154 GL_CullFace(GL_NONE);
1155 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
1158 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
1161 R_Shadow_RenderMode_Reset();
1162 GL_BlendFunc(GL_ONE, GL_ONE);
1163 GL_DepthRange(0, 1);
1164 GL_DepthTest(r_showlighting.integer < 2);
1165 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
1168 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1172 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1173 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1175 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
1178 void R_Shadow_RenderMode_End(void)
1181 R_Shadow_RenderMode_Reset();
1182 R_Shadow_RenderMode_ActiveLight(NULL);
1184 GL_Scissor(r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
1185 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1188 int bboxedges[12][2] =
1207 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1209 int i, ix1, iy1, ix2, iy2;
1210 float x1, y1, x2, y2;
1212 float vertex[20][3];
1221 if (!r_shadow_scissor.integer)
1224 // if view is inside the light box, just say yes it's visible
1225 if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
1227 GL_Scissor(r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
1231 x1 = y1 = x2 = y2 = 0;
1233 // transform all corners that are infront of the nearclip plane
1234 VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
1235 plane4f[3] = r_refdef.view.frustum[4].dist;
1237 for (i = 0;i < 8;i++)
1239 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
1240 dist[i] = DotProduct4(corner[i], plane4f);
1241 sign[i] = dist[i] > 0;
1244 VectorCopy(corner[i], vertex[numvertices]);
1248 // if some points are behind the nearclip, add clipped edge points to make
1249 // sure that the scissor boundary is complete
1250 if (numvertices > 0 && numvertices < 8)
1252 // add clipped edge points
1253 for (i = 0;i < 12;i++)
1255 j = bboxedges[i][0];
1256 k = bboxedges[i][1];
1257 if (sign[j] != sign[k])
1259 f = dist[j] / (dist[j] - dist[k]);
1260 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
1266 // if we have no points to check, the light is behind the view plane
1270 // if we have some points to transform, check what screen area is covered
1271 x1 = y1 = x2 = y2 = 0;
1273 //Con_Printf("%i vertices to transform...\n", numvertices);
1274 for (i = 0;i < numvertices;i++)
1276 VectorCopy(vertex[i], v);
1277 GL_TransformToScreen(v, v2);
1278 //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]);
1281 if (x1 > v2[0]) x1 = v2[0];
1282 if (x2 < v2[0]) x2 = v2[0];
1283 if (y1 > v2[1]) y1 = v2[1];
1284 if (y2 < v2[1]) y2 = v2[1];
1293 // now convert the scissor rectangle to integer screen coordinates
1294 ix1 = (int)(x1 - 1.0f);
1295 iy1 = (int)(y1 - 1.0f);
1296 ix2 = (int)(x2 + 1.0f);
1297 iy2 = (int)(y2 + 1.0f);
1298 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1300 // clamp it to the screen
1301 if (ix1 < r_refdef.view.x) ix1 = r_refdef.view.x;
1302 if (iy1 < r_refdef.view.y) iy1 = r_refdef.view.y;
1303 if (ix2 > r_refdef.view.x + r_refdef.view.width) ix2 = r_refdef.view.x + r_refdef.view.width;
1304 if (iy2 > r_refdef.view.y + r_refdef.view.height) iy2 = r_refdef.view.y + r_refdef.view.height;
1306 // if it is inside out, it's not visible
1307 if (ix2 <= ix1 || iy2 <= iy1)
1310 // the light area is visible, set up the scissor rectangle
1311 GL_Scissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1312 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);CHECKGLERROR
1313 //qglEnable(GL_SCISSOR_TEST);CHECKGLERROR
1314 r_refdef.stats.lights_scissored++;
1318 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
1320 float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1321 float *normal3f = rsurface.normal3f + 3 * firstvertex;
1322 float *color4f = rsurface.array_color4f + 4 * firstvertex;
1323 float dist, dot, distintensity, shadeintensity, v[3], n[3];
1324 if (r_textureunits.integer >= 3)
1326 if (VectorLength2(diffusecolor) > 0)
1328 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1330 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1331 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1332 if ((dot = DotProduct(n, v)) < 0)
1334 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1335 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
1338 VectorCopy(ambientcolor, color4f);
1339 if (r_refdef.fogenabled)
1342 f = FogPoint_Model(vertex3f);
1343 VectorScale(color4f, f, color4f);
1350 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1352 VectorCopy(ambientcolor, color4f);
1353 if (r_refdef.fogenabled)
1356 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1357 f = FogPoint_Model(vertex3f);
1358 VectorScale(color4f, f, color4f);
1364 else if (r_textureunits.integer >= 2)
1366 if (VectorLength2(diffusecolor) > 0)
1368 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1370 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1371 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1373 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1374 if ((dot = DotProduct(n, v)) < 0)
1376 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1377 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1378 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1379 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1383 color4f[0] = ambientcolor[0] * distintensity;
1384 color4f[1] = ambientcolor[1] * distintensity;
1385 color4f[2] = ambientcolor[2] * distintensity;
1387 if (r_refdef.fogenabled)
1390 f = FogPoint_Model(vertex3f);
1391 VectorScale(color4f, f, color4f);
1395 VectorClear(color4f);
1401 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1403 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1404 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1406 color4f[0] = ambientcolor[0] * distintensity;
1407 color4f[1] = ambientcolor[1] * distintensity;
1408 color4f[2] = ambientcolor[2] * distintensity;
1409 if (r_refdef.fogenabled)
1412 f = FogPoint_Model(vertex3f);
1413 VectorScale(color4f, f, color4f);
1417 VectorClear(color4f);
1424 if (VectorLength2(diffusecolor) > 0)
1426 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1428 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1429 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1431 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
1432 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1433 if ((dot = DotProduct(n, v)) < 0)
1435 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1436 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1437 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1438 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1442 color4f[0] = ambientcolor[0] * distintensity;
1443 color4f[1] = ambientcolor[1] * distintensity;
1444 color4f[2] = ambientcolor[2] * distintensity;
1446 if (r_refdef.fogenabled)
1449 f = FogPoint_Model(vertex3f);
1450 VectorScale(color4f, f, color4f);
1454 VectorClear(color4f);
1460 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1462 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1463 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1465 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
1466 color4f[0] = ambientcolor[0] * distintensity;
1467 color4f[1] = ambientcolor[1] * distintensity;
1468 color4f[2] = ambientcolor[2] * distintensity;
1469 if (r_refdef.fogenabled)
1472 f = FogPoint_Model(vertex3f);
1473 VectorScale(color4f, f, color4f);
1477 VectorClear(color4f);
1484 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1486 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
1489 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
1490 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1491 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
1492 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
1493 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
1495 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1497 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
1498 // the cubemap normalizes this for us
1499 out3f[0] = DotProduct(svector3f, lightdir);
1500 out3f[1] = DotProduct(tvector3f, lightdir);
1501 out3f[2] = DotProduct(normal3f, lightdir);
1505 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
1508 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
1509 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1510 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
1511 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
1512 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
1513 float lightdir[3], eyedir[3], halfdir[3];
1514 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1516 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
1517 VectorNormalize(lightdir);
1518 VectorSubtract(rsurface.modelorg, vertex3f, eyedir);
1519 VectorNormalize(eyedir);
1520 VectorAdd(lightdir, eyedir, halfdir);
1521 // the cubemap normalizes this for us
1522 out3f[0] = DotProduct(svector3f, halfdir);
1523 out3f[1] = DotProduct(tvector3f, halfdir);
1524 out3f[2] = DotProduct(normal3f, halfdir);
1528 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)
1530 // used to display how many times a surface is lit for level design purposes
1531 GL_Color(0.1 * r_refdef.view.colorscale, 0.025 * r_refdef.view.colorscale, 0, 1);
1532 R_Mesh_ColorPointer(NULL, 0, 0);
1533 R_Mesh_ResetTextureState();
1534 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1537 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)
1539 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
1540 R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
1541 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
1542 R_Mesh_TexBind(GL20TU_NORMAL, R_GetTexture(rsurface.texture->currentskinframe->nmap));
1543 R_Mesh_TexBind(GL20TU_COLOR, R_GetTexture(rsurface.texture->basetexture));
1544 R_Mesh_TexBind(GL20TU_GLOSS, R_GetTexture(rsurface.texture->glosstexture));
1545 //R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap));
1546 R_Mesh_TexBind(GL20TU_FOGMASK, R_GetTexture(r_texture_fogattenuation));
1547 R_Mesh_TexBind(GL20TU_PANTS, R_GetTexture(rsurface.texture->currentskinframe->pants));
1548 R_Mesh_TexBind(GL20TU_SHIRT, R_GetTexture(rsurface.texture->currentskinframe->shirt));
1549 R_Mesh_TexBind(GL20TU_ATTENUATION, R_GetTexture(r_shadow_attenuationgradienttexture));
1550 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
1551 R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
1552 R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
1553 R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
1554 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1556 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1558 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1559 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1561 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1565 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)
1567 // shared final code for all the dot3 layers
1569 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
1570 for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
1572 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
1573 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1577 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)
1580 // colorscale accounts for how much we multiply the brightness
1583 // mult is how many times the final pass of the lighting will be
1584 // performed to get more brightness than otherwise possible.
1586 // Limit mult to 64 for sanity sake.
1588 if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1590 // 3 3D combine path (Geforce3, Radeon 8500)
1591 memset(&m, 0, sizeof(m));
1592 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1593 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1594 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1595 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1596 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1597 m.tex[1] = R_GetTexture(basetexture);
1598 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
1599 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
1600 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
1601 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
1602 m.texcubemap[2] = R_GetTexture(rsurface.rtlight->currentcubemap);
1603 m.pointer_texcoord3f[2] = rsurface.vertex3f;
1604 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
1605 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
1606 m.texmatrix[2] = rsurface.entitytolight;
1607 GL_BlendFunc(GL_ONE, GL_ONE);
1609 else if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1611 // 2 3D combine path (Geforce3, original Radeon)
1612 memset(&m, 0, sizeof(m));
1613 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1614 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1615 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1616 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1617 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1618 m.tex[1] = R_GetTexture(basetexture);
1619 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
1620 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
1621 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
1622 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
1623 GL_BlendFunc(GL_ONE, GL_ONE);
1625 else if (r_textureunits.integer >= 4 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
1627 // 4 2D combine path (Geforce3, Radeon 8500)
1628 memset(&m, 0, sizeof(m));
1629 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1630 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1631 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1632 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1633 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1634 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1635 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1636 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1637 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1638 m.texmatrix[1] = rsurface.entitytoattenuationz;
1639 m.tex[2] = R_GetTexture(basetexture);
1640 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
1641 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
1642 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
1643 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
1644 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1646 m.texcubemap[3] = R_GetTexture(rsurface.rtlight->currentcubemap);
1647 m.pointer_texcoord3f[3] = rsurface.vertex3f;
1648 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
1649 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
1650 m.texmatrix[3] = rsurface.entitytolight;
1652 GL_BlendFunc(GL_ONE, GL_ONE);
1654 else if (r_textureunits.integer >= 3 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
1656 // 3 2D combine path (Geforce3, original Radeon)
1657 memset(&m, 0, sizeof(m));
1658 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1659 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1660 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1661 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1662 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1663 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1664 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1665 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1666 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1667 m.texmatrix[1] = rsurface.entitytoattenuationz;
1668 m.tex[2] = R_GetTexture(basetexture);
1669 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
1670 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
1671 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
1672 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
1673 GL_BlendFunc(GL_ONE, GL_ONE);
1677 // 2/2/2 2D combine path (any dot3 card)
1678 memset(&m, 0, sizeof(m));
1679 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1680 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1681 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1682 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1683 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1684 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1685 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1686 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1687 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1688 m.texmatrix[1] = rsurface.entitytoattenuationz;
1689 R_Mesh_TextureState(&m);
1690 GL_ColorMask(0,0,0,1);
1691 GL_BlendFunc(GL_ONE, GL_ZERO);
1692 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1695 memset(&m, 0, sizeof(m));
1696 m.tex[0] = R_GetTexture(basetexture);
1697 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1698 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1699 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1700 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1701 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1703 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1704 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1705 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1706 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1707 m.texmatrix[1] = rsurface.entitytolight;
1709 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1711 // this final code is shared
1712 R_Mesh_TextureState(&m);
1713 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1716 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)
1719 // colorscale accounts for how much we multiply the brightness
1722 // mult is how many times the final pass of the lighting will be
1723 // performed to get more brightness than otherwise possible.
1725 // Limit mult to 64 for sanity sake.
1727 // generate normalization cubemap texcoords
1728 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
1729 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1731 // 3/2 3D combine path (Geforce3, Radeon 8500)
1732 memset(&m, 0, sizeof(m));
1733 m.tex[0] = R_GetTexture(normalmaptexture);
1734 m.texcombinergb[0] = GL_REPLACE;
1735 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1736 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1737 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1738 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1739 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1740 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1741 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1742 m.pointer_texcoord_bufferobject[1] = 0;
1743 m.pointer_texcoord_bufferoffset[1] = 0;
1744 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1745 m.pointer_texcoord3f[2] = rsurface.vertex3f;
1746 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
1747 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
1748 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
1749 R_Mesh_TextureState(&m);
1750 GL_ColorMask(0,0,0,1);
1751 GL_BlendFunc(GL_ONE, GL_ZERO);
1752 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1755 memset(&m, 0, sizeof(m));
1756 m.tex[0] = R_GetTexture(basetexture);
1757 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1758 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1759 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1760 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1761 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1763 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1764 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1765 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1766 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1767 m.texmatrix[1] = rsurface.entitytolight;
1769 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1771 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
1773 // 1/2/2 3D combine path (original Radeon)
1774 memset(&m, 0, sizeof(m));
1775 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1776 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1777 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1778 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1779 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1780 R_Mesh_TextureState(&m);
1781 GL_ColorMask(0,0,0,1);
1782 GL_BlendFunc(GL_ONE, GL_ZERO);
1783 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1786 memset(&m, 0, sizeof(m));
1787 m.tex[0] = R_GetTexture(normalmaptexture);
1788 m.texcombinergb[0] = GL_REPLACE;
1789 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1790 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1791 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1792 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1793 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1794 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1795 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1796 m.pointer_texcoord_bufferobject[1] = 0;
1797 m.pointer_texcoord_bufferoffset[1] = 0;
1798 R_Mesh_TextureState(&m);
1799 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1800 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1803 memset(&m, 0, sizeof(m));
1804 m.tex[0] = R_GetTexture(basetexture);
1805 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1806 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1807 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1808 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1809 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1811 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1812 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1813 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1814 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1815 m.texmatrix[1] = rsurface.entitytolight;
1817 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1819 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
1821 // 2/2 3D combine path (original Radeon)
1822 memset(&m, 0, sizeof(m));
1823 m.tex[0] = R_GetTexture(normalmaptexture);
1824 m.texcombinergb[0] = GL_REPLACE;
1825 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1826 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1827 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1828 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1829 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1830 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1831 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1832 m.pointer_texcoord_bufferobject[1] = 0;
1833 m.pointer_texcoord_bufferoffset[1] = 0;
1834 R_Mesh_TextureState(&m);
1835 GL_ColorMask(0,0,0,1);
1836 GL_BlendFunc(GL_ONE, GL_ZERO);
1837 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1840 memset(&m, 0, sizeof(m));
1841 m.tex[0] = R_GetTexture(basetexture);
1842 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1843 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1844 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1845 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1846 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1847 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1848 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1849 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1850 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
1851 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1853 else if (r_textureunits.integer >= 4)
1855 // 4/2 2D combine path (Geforce3, Radeon 8500)
1856 memset(&m, 0, sizeof(m));
1857 m.tex[0] = R_GetTexture(normalmaptexture);
1858 m.texcombinergb[0] = GL_REPLACE;
1859 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1860 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1861 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1862 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1863 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1864 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1865 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1866 m.pointer_texcoord_bufferobject[1] = 0;
1867 m.pointer_texcoord_bufferoffset[1] = 0;
1868 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1869 m.pointer_texcoord3f[2] = rsurface.vertex3f;
1870 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
1871 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
1872 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
1873 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1874 m.pointer_texcoord3f[3] = rsurface.vertex3f;
1875 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
1876 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
1877 m.texmatrix[3] = rsurface.entitytoattenuationz;
1878 R_Mesh_TextureState(&m);
1879 GL_ColorMask(0,0,0,1);
1880 GL_BlendFunc(GL_ONE, GL_ZERO);
1881 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1884 memset(&m, 0, sizeof(m));
1885 m.tex[0] = R_GetTexture(basetexture);
1886 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1887 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1888 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1889 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1890 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1892 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1893 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1894 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1895 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1896 m.texmatrix[1] = rsurface.entitytolight;
1898 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1902 // 2/2/2 2D combine path (any dot3 card)
1903 memset(&m, 0, sizeof(m));
1904 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1905 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1906 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1907 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1908 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1909 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1910 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1911 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1912 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1913 m.texmatrix[1] = rsurface.entitytoattenuationz;
1914 R_Mesh_TextureState(&m);
1915 GL_ColorMask(0,0,0,1);
1916 GL_BlendFunc(GL_ONE, GL_ZERO);
1917 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1920 memset(&m, 0, sizeof(m));
1921 m.tex[0] = R_GetTexture(normalmaptexture);
1922 m.texcombinergb[0] = GL_REPLACE;
1923 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1924 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1925 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1926 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1927 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1928 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1929 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1930 m.pointer_texcoord_bufferobject[1] = 0;
1931 m.pointer_texcoord_bufferoffset[1] = 0;
1932 R_Mesh_TextureState(&m);
1933 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1934 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1937 memset(&m, 0, sizeof(m));
1938 m.tex[0] = R_GetTexture(basetexture);
1939 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1940 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1941 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1942 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1943 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1945 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1946 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1947 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1948 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1949 m.texmatrix[1] = rsurface.entitytolight;
1951 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1953 // this final code is shared
1954 R_Mesh_TextureState(&m);
1955 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1958 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)
1960 float glossexponent;
1962 // FIXME: detect blendsquare!
1963 //if (!gl_support_blendsquare)
1966 // generate normalization cubemap texcoords
1967 R_Shadow_GenTexCoords_Specular_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
1968 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
1970 // 2/0/0/1/2 3D combine blendsquare path
1971 memset(&m, 0, sizeof(m));
1972 m.tex[0] = R_GetTexture(normalmaptexture);
1973 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1974 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1975 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1976 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1977 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1978 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1979 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1980 m.pointer_texcoord_bufferobject[1] = 0;
1981 m.pointer_texcoord_bufferoffset[1] = 0;
1982 R_Mesh_TextureState(&m);
1983 GL_ColorMask(0,0,0,1);
1984 // this squares the result
1985 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1986 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1988 // second and third pass
1989 R_Mesh_ResetTextureState();
1990 // square alpha in framebuffer a few times to make it shiny
1991 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1992 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
1993 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1996 memset(&m, 0, sizeof(m));
1997 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1998 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1999 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2000 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2001 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2002 R_Mesh_TextureState(&m);
2003 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2004 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2007 memset(&m, 0, sizeof(m));
2008 m.tex[0] = R_GetTexture(glosstexture);
2009 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2010 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2011 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2012 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2013 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2015 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2016 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2017 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2018 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2019 m.texmatrix[1] = rsurface.entitytolight;
2021 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2023 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
2025 // 2/0/0/2 3D combine blendsquare path
2026 memset(&m, 0, sizeof(m));
2027 m.tex[0] = R_GetTexture(normalmaptexture);
2028 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2029 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2030 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2031 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2032 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2033 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2034 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2035 m.pointer_texcoord_bufferobject[1] = 0;
2036 m.pointer_texcoord_bufferoffset[1] = 0;
2037 R_Mesh_TextureState(&m);
2038 GL_ColorMask(0,0,0,1);
2039 // this squares the result
2040 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2041 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2043 // second and third pass
2044 R_Mesh_ResetTextureState();
2045 // square alpha in framebuffer a few times to make it shiny
2046 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2047 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2048 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2051 memset(&m, 0, sizeof(m));
2052 m.tex[0] = R_GetTexture(glosstexture);
2053 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2054 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2055 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2056 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2057 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2058 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2059 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2060 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2061 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2062 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2066 // 2/0/0/2/2 2D combine blendsquare path
2067 memset(&m, 0, sizeof(m));
2068 m.tex[0] = R_GetTexture(normalmaptexture);
2069 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2070 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2071 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2072 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2073 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2074 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2075 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2076 m.pointer_texcoord_bufferobject[1] = 0;
2077 m.pointer_texcoord_bufferoffset[1] = 0;
2078 R_Mesh_TextureState(&m);
2079 GL_ColorMask(0,0,0,1);
2080 // this squares the result
2081 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2082 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2084 // second and third pass
2085 R_Mesh_ResetTextureState();
2086 // square alpha in framebuffer a few times to make it shiny
2087 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2088 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2089 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2092 memset(&m, 0, sizeof(m));
2093 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2094 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2095 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2096 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2097 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2098 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2099 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2100 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2101 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2102 m.texmatrix[1] = rsurface.entitytoattenuationz;
2103 R_Mesh_TextureState(&m);
2104 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2105 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2108 memset(&m, 0, sizeof(m));
2109 m.tex[0] = R_GetTexture(glosstexture);
2110 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2111 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2112 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2113 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2114 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2116 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2117 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2118 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2119 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2120 m.texmatrix[1] = rsurface.entitytolight;
2122 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2124 // this final code is shared
2125 R_Mesh_TextureState(&m);
2126 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
2129 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)
2131 // ARB path (any Geforce, any Radeon)
2132 qboolean doambient = ambientscale > 0;
2133 qboolean dodiffuse = diffusescale > 0;
2134 qboolean dospecular = specularscale > 0;
2135 if (!doambient && !dodiffuse && !dospecular)
2137 R_Mesh_ColorPointer(NULL, 0, 0);
2139 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, basetexture, ambientscale * r_refdef.view.colorscale);
2141 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, basetexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2145 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorpants, pantstexture, ambientscale * r_refdef.view.colorscale);
2147 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorpants, pantstexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2152 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorshirt, shirttexture, ambientscale * r_refdef.view.colorscale);
2154 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorshirt, shirttexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2157 R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_refdef.view.colorscale);
2160 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)
2167 int newnumtriangles;
2171 int newelements[4096*3];
2172 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
2173 for (renders = 0;renders < 64;renders++)
2178 newnumtriangles = 0;
2180 // due to low fillrate on the cards this vertex lighting path is
2181 // designed for, we manually cull all triangles that do not
2182 // contain a lit vertex
2183 // this builds batches of triangles from multiple surfaces and
2184 // renders them at once
2185 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2187 if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
2189 if (newnumtriangles)
2191 newfirstvertex = min(newfirstvertex, e[0]);
2192 newlastvertex = max(newlastvertex, e[0]);
2196 newfirstvertex = e[0];
2197 newlastvertex = e[0];
2199 newfirstvertex = min(newfirstvertex, e[1]);
2200 newlastvertex = max(newlastvertex, e[1]);
2201 newfirstvertex = min(newfirstvertex, e[2]);
2202 newlastvertex = max(newlastvertex, e[2]);
2208 if (newnumtriangles >= (int)(sizeof(newelements)/sizeof(float[3])))
2210 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, newnumtriangles, newelements, 0, 0);
2211 newnumtriangles = 0;
2217 if (newnumtriangles >= 1)
2219 // if all triangles are included, use the original array to take advantage of the bufferobject if possible
2220 if (newnumtriangles == numtriangles)
2221 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2223 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, newnumtriangles, newelements, 0, 0);
2226 // if we couldn't find any lit triangles, exit early
2229 // now reduce the intensity for the next overbright pass
2230 // we have to clamp to 0 here incase the drivers have improper
2231 // handling of negative colors
2232 // (some old drivers even have improper handling of >1 color)
2234 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2236 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2238 c[0] = max(0, c[0] - 1);
2239 c[1] = max(0, c[1] - 1);
2240 c[2] = max(0, c[2] - 1);
2252 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)
2254 // OpenGL 1.1 path (anything)
2255 float ambientcolorbase[3], diffusecolorbase[3];
2256 float ambientcolorpants[3], diffusecolorpants[3];
2257 float ambientcolorshirt[3], diffusecolorshirt[3];
2259 VectorScale(lightcolorbase, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorbase);
2260 VectorScale(lightcolorbase, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorbase);
2261 VectorScale(lightcolorpants, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorpants);
2262 VectorScale(lightcolorpants, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorpants);
2263 VectorScale(lightcolorshirt, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorshirt);
2264 VectorScale(lightcolorshirt, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorshirt);
2265 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2266 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
2267 memset(&m, 0, sizeof(m));
2268 m.tex[0] = R_GetTexture(basetexture);
2269 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2270 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2271 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2272 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2273 if (r_textureunits.integer >= 2)
2276 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2277 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2278 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2279 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2280 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2281 if (r_textureunits.integer >= 3)
2283 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
2284 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2285 m.texmatrix[2] = rsurface.entitytoattenuationz;
2286 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2287 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2288 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2291 R_Mesh_TextureState(&m);
2292 //R_Mesh_TexBind(0, R_GetTexture(basetexture));
2293 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, diffusecolorbase, ambientcolorbase);
2296 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
2297 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, diffusecolorpants, ambientcolorpants);
2301 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
2302 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, diffusecolorshirt, ambientcolorshirt);
2306 extern cvar_t gl_lightmaps;
2307 void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset)
2309 float ambientscale, diffusescale, specularscale;
2310 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
2312 // calculate colors to render this texture with
2313 lightcolorbase[0] = rsurface.rtlight->currentcolor[0] * rsurface.texture->dlightcolor[0];
2314 lightcolorbase[1] = rsurface.rtlight->currentcolor[1] * rsurface.texture->dlightcolor[1];
2315 lightcolorbase[2] = rsurface.rtlight->currentcolor[2] * rsurface.texture->dlightcolor[2];
2316 ambientscale = rsurface.rtlight->ambientscale;
2317 diffusescale = rsurface.rtlight->diffusescale;
2318 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2319 if (!r_shadow_usenormalmap.integer)
2321 ambientscale += 1.0f * diffusescale;
2325 if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
2327 RSurf_SetupDepthAndCulling();
2328 nmap = rsurface.texture->currentskinframe->nmap;
2329 if (gl_lightmaps.integer)
2330 nmap = r_texture_blanknormalmap;
2331 if (rsurface.texture->colormapping && !gl_lightmaps.integer)
2333 qboolean dopants = rsurface.texture->currentskinframe->pants != NULL && VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f);
2334 qboolean doshirt = rsurface.texture->currentskinframe->shirt != NULL && VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f);
2337 lightcolorpants[0] = lightcolorbase[0] * rsurface.colormap_pantscolor[0];
2338 lightcolorpants[1] = lightcolorbase[1] * rsurface.colormap_pantscolor[1];
2339 lightcolorpants[2] = lightcolorbase[2] * rsurface.colormap_pantscolor[2];
2342 VectorClear(lightcolorpants);
2345 lightcolorshirt[0] = lightcolorbase[0] * rsurface.colormap_shirtcolor[0];
2346 lightcolorshirt[1] = lightcolorbase[1] * rsurface.colormap_shirtcolor[1];
2347 lightcolorshirt[2] = lightcolorbase[2] * rsurface.colormap_shirtcolor[2];
2350 VectorClear(lightcolorshirt);
2351 switch (r_shadow_rendermode)
2353 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2354 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2355 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);
2357 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2358 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);
2360 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2361 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);
2363 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2364 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);
2367 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2373 switch (r_shadow_rendermode)
2375 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2376 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2377 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);
2379 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2380 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);
2382 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2383 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);
2385 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2386 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);
2389 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2395 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)
2397 matrix4x4_t tempmatrix = *matrix;
2398 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2400 // if this light has been compiled before, free the associated data
2401 R_RTLight_Uncompile(rtlight);
2403 // clear it completely to avoid any lingering data
2404 memset(rtlight, 0, sizeof(*rtlight));
2406 // copy the properties
2407 rtlight->matrix_lighttoworld = tempmatrix;
2408 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2409 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2410 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2411 VectorCopy(color, rtlight->color);
2412 rtlight->cubemapname[0] = 0;
2413 if (cubemapname && cubemapname[0])
2414 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2415 rtlight->shadow = shadow;
2416 rtlight->corona = corona;
2417 rtlight->style = style;
2418 rtlight->isstatic = isstatic;
2419 rtlight->coronasizescale = coronasizescale;
2420 rtlight->ambientscale = ambientscale;
2421 rtlight->diffusescale = diffusescale;
2422 rtlight->specularscale = specularscale;
2423 rtlight->flags = flags;
2425 // compute derived data
2426 //rtlight->cullradius = rtlight->radius;
2427 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2428 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2429 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2430 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2431 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2432 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2433 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2436 // compiles rtlight geometry
2437 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2438 void R_RTLight_Compile(rtlight_t *rtlight)
2441 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2442 int lighttris, shadowtris, shadowmeshes, shadowmeshtris;
2443 entity_render_t *ent = r_refdef.scene.worldentity;
2444 model_t *model = r_refdef.scene.worldmodel;
2445 unsigned char *data;
2447 // compile the light
2448 rtlight->compiled = true;
2449 rtlight->static_numleafs = 0;
2450 rtlight->static_numleafpvsbytes = 0;
2451 rtlight->static_leaflist = NULL;
2452 rtlight->static_leafpvs = NULL;
2453 rtlight->static_numsurfaces = 0;
2454 rtlight->static_surfacelist = NULL;
2455 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2456 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2457 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2458 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2459 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2460 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2462 if (model && model->GetLightInfo)
2464 // this variable must be set for the CompileShadowVolume code
2465 r_shadow_compilingrtlight = rtlight;
2466 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);
2467 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);
2468 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2469 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
2470 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
2471 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
2472 rtlight->static_numsurfaces = numsurfaces;
2473 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2474 rtlight->static_numleafs = numleafs;
2475 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2476 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2477 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2478 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
2479 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
2480 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
2481 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
2482 if (rtlight->static_numsurfaces)
2483 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2484 if (rtlight->static_numleafs)
2485 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2486 if (rtlight->static_numleafpvsbytes)
2487 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2488 if (rtlight->static_numshadowtrispvsbytes)
2489 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
2490 if (rtlight->static_numlighttrispvsbytes)
2491 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
2492 if (model->CompileShadowVolume && rtlight->shadow)
2493 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2494 // now we're done compiling the rtlight
2495 r_shadow_compilingrtlight = NULL;
2499 // use smallest available cullradius - box radius or light radius
2500 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2501 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2505 if (rtlight->static_meshchain_shadow)
2508 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2511 shadowmeshtris += mesh->numtriangles;
2516 if (rtlight->static_numlighttrispvsbytes)
2517 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
2518 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
2522 if (rtlight->static_numlighttrispvsbytes)
2523 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
2524 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
2527 if (developer.integer >= 10)
2528 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);
2531 void R_RTLight_Uncompile(rtlight_t *rtlight)
2533 if (rtlight->compiled)
2535 if (rtlight->static_meshchain_shadow)
2536 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2537 rtlight->static_meshchain_shadow = NULL;
2538 // these allocations are grouped
2539 if (rtlight->static_surfacelist)
2540 Mem_Free(rtlight->static_surfacelist);
2541 rtlight->static_numleafs = 0;
2542 rtlight->static_numleafpvsbytes = 0;
2543 rtlight->static_leaflist = NULL;
2544 rtlight->static_leafpvs = NULL;
2545 rtlight->static_numsurfaces = 0;
2546 rtlight->static_surfacelist = NULL;
2547 rtlight->static_numshadowtrispvsbytes = 0;
2548 rtlight->static_shadowtrispvs = NULL;
2549 rtlight->static_numlighttrispvsbytes = 0;
2550 rtlight->static_lighttrispvs = NULL;
2551 rtlight->compiled = false;
2555 void R_Shadow_UncompileWorldLights(void)
2559 for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
2561 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2564 R_RTLight_Uncompile(&light->rtlight);
2568 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
2572 // reset the count of frustum planes
2573 // see rsurface.rtlight_frustumplanes definition for how much this array
2575 rsurface.rtlight_numfrustumplanes = 0;
2577 // haven't implemented a culling path for ortho rendering
2578 if (!r_refdef.view.useperspective)
2580 // check if the light is on screen and copy the 4 planes if it is
2581 for (i = 0;i < 4;i++)
2582 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
2585 for (i = 0;i < 4;i++)
2586 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
2591 // generate a deformed frustum that includes the light origin, this is
2592 // used to cull shadow casting surfaces that can not possibly cast a
2593 // shadow onto the visible light-receiving surfaces, which can be a
2596 // if the light origin is onscreen the result will be 4 planes exactly
2597 // if the light origin is offscreen on only one axis the result will
2598 // be exactly 5 planes (split-side case)
2599 // if the light origin is offscreen on two axes the result will be
2600 // exactly 4 planes (stretched corner case)
2601 for (i = 0;i < 4;i++)
2603 // quickly reject standard frustum planes that put the light
2604 // origin outside the frustum
2605 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
2608 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
2610 // if all the standard frustum planes were accepted, the light is onscreen
2611 // otherwise we need to generate some more planes below...
2612 if (rsurface.rtlight_numfrustumplanes < 4)
2614 // at least one of the stock frustum planes failed, so we need to
2615 // create one or two custom planes to enclose the light origin
2616 for (i = 0;i < 4;i++)
2618 // create a plane using the view origin and light origin, and a
2619 // single point from the frustum corner set
2620 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
2621 VectorNormalize(plane.normal);
2622 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
2623 // see if this plane is backwards and flip it if so
2624 for (j = 0;j < 4;j++)
2625 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
2629 VectorNegate(plane.normal, plane.normal);
2631 // flipped plane, test again to see if it is now valid
2632 for (j = 0;j < 4;j++)
2633 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
2635 // if the plane is still not valid, then it is dividing the
2636 // frustum and has to be rejected
2640 // we have created a valid plane, compute extra info
2641 PlaneClassify(&plane);
2643 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
2645 // if we've found 5 frustum planes then we have constructed a
2646 // proper split-side case and do not need to keep searching for
2647 // planes to enclose the light origin
2648 if (rsurface.rtlight_numfrustumplanes == 5)
2656 for (i = 0;i < rsurface.rtlight_numfrustumplanes;i++)
2658 plane = rsurface.rtlight_frustumplanes[i];
2659 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));
2664 // now add the light-space box planes if the light box is rotated, as any
2665 // caster outside the oriented light box is irrelevant (even if it passed
2666 // the worldspace light box, which is axial)
2667 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
2669 for (i = 0;i < 6;i++)
2673 v[i >> 1] = (i & 1) ? -1 : 1;
2674 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
2675 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
2676 plane.dist = VectorNormalizeLength(plane.normal);
2677 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
2678 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
2684 // add the world-space reduced box planes
2685 for (i = 0;i < 6;i++)
2687 VectorClear(plane.normal);
2688 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
2689 plane.dist = (i & 1) ? -rsurface.rtlight_cullmaxs[i >> 1] : rsurface.rtlight_cullmins[i >> 1];
2690 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
2699 // reduce all plane distances to tightly fit the rtlight cull box, which
2701 VectorSet(points[0], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
2702 VectorSet(points[1], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
2703 VectorSet(points[2], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
2704 VectorSet(points[3], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
2705 VectorSet(points[4], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
2706 VectorSet(points[5], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
2707 VectorSet(points[6], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
2708 VectorSet(points[7], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
2709 oldnum = rsurface.rtlight_numfrustumplanes;
2710 rsurface.rtlight_numfrustumplanes = 0;
2711 for (j = 0;j < oldnum;j++)
2713 // find the nearest point on the box to this plane
2714 bestdist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[0]);
2715 for (i = 1;i < 8;i++)
2717 dist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[i]);
2718 if (bestdist > dist)
2721 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);
2722 // if the nearest point is near or behind the plane, we want this
2723 // plane, otherwise the plane is useless as it won't cull anything
2724 if (rsurface.rtlight_frustumplanes[j].dist < bestdist + 0.03125)
2726 PlaneClassify(&rsurface.rtlight_frustumplanes[j]);
2727 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = rsurface.rtlight_frustumplanes[j];
2734 void R_Shadow_DrawWorldShadow(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
2736 RSurf_ActiveWorldEntity();
2737 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2741 for (mesh = rsurface.rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2743 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
2744 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
2745 GL_LockArrays(0, mesh->numverts);
2746 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
2748 // decrement stencil if backface is behind depthbuffer
2749 GL_CullFace(r_refdef.view.cullface_front);
2750 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2751 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->ebo, 0);
2752 // increment stencil if frontface is behind depthbuffer
2753 GL_CullFace(r_refdef.view.cullface_back);
2754 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2756 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->ebo, 0);
2757 GL_LockArrays(0, 0);
2761 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
2764 int surfacelistindex;
2765 msurface_t *surface;
2766 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
2767 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
2769 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
2770 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
2771 if (CHECKPVSBIT(trispvs, t))
2772 shadowmarklist[numshadowmark++] = t;
2774 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);
2776 else if (numsurfaces)
2777 r_refdef.scene.worldmodel->DrawShadowVolume(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
2780 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
2782 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
2783 vec_t relativeshadowradius;
2784 RSurf_ActiveModelEntity(ent, false, false);
2785 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
2786 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
2787 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
2788 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
2789 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
2790 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
2791 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
2792 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
2793 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2796 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
2798 // set up properties for rendering light onto this entity
2799 RSurf_ActiveModelEntity(ent, true, true);
2800 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
2801 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
2802 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
2803 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
2804 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2805 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
2808 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
2810 if (!r_refdef.scene.worldmodel->DrawLight)
2813 // set up properties for rendering light onto this entity
2814 RSurf_ActiveWorldEntity();
2815 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
2816 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
2817 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
2818 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
2819 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2820 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
2822 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, trispvs);
2825 void R_Shadow_DrawEntityLight(entity_render_t *ent)
2827 model_t *model = ent->model;
2828 if (!model->DrawLight)
2831 R_Shadow_SetupEntityLight(ent);
2833 model->DrawLight(ent, model->nummodelsurfaces, model->surfacelist, NULL);
2836 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
2840 int numleafs, numsurfaces;
2841 int *leaflist, *surfacelist;
2842 unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs;
2843 int numlightentities;
2844 int numlightentities_noselfshadow;
2845 int numshadowentities;
2846 int numshadowentities_noselfshadow;
2847 entity_render_t *lightentities[MAX_EDICTS];
2848 entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
2849 entity_render_t *shadowentities[MAX_EDICTS];
2850 entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
2852 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
2853 // skip lights that are basically invisible (color 0 0 0)
2854 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
2857 // loading is done before visibility checks because loading should happen
2858 // all at once at the start of a level, not when it stalls gameplay.
2859 // (especially important to benchmarks)
2861 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2862 R_RTLight_Compile(rtlight);
2864 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
2866 // look up the light style value at this time
2867 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
2868 VectorScale(rtlight->color, f, rtlight->currentcolor);
2870 if (rtlight->selected)
2872 f = 2 + sin(realtime * M_PI * 4.0);
2873 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
2877 // if lightstyle is currently off, don't draw the light
2878 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
2881 // if the light box is offscreen, skip it
2882 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2885 VectorCopy(rtlight->cullmins, rsurface.rtlight_cullmins);
2886 VectorCopy(rtlight->cullmaxs, rsurface.rtlight_cullmaxs);
2888 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2890 // compiled light, world available and can receive realtime lighting
2891 // retrieve leaf information
2892 numleafs = rtlight->static_numleafs;
2893 leaflist = rtlight->static_leaflist;
2894 leafpvs = rtlight->static_leafpvs;
2895 numsurfaces = rtlight->static_numsurfaces;
2896 surfacelist = rtlight->static_surfacelist;
2897 shadowtrispvs = rtlight->static_shadowtrispvs;
2898 lighttrispvs = rtlight->static_lighttrispvs;
2900 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
2902 // dynamic light, world available and can receive realtime lighting
2903 // calculate lit surfaces and leafs
2904 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);
2905 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);
2906 leaflist = r_shadow_buffer_leaflist;
2907 leafpvs = r_shadow_buffer_leafpvs;
2908 surfacelist = r_shadow_buffer_surfacelist;
2909 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
2910 lighttrispvs = r_shadow_buffer_lighttrispvs;
2911 // if the reduced leaf bounds are offscreen, skip it
2912 if (R_CullBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
2923 shadowtrispvs = NULL;
2924 lighttrispvs = NULL;
2926 // check if light is illuminating any visible leafs
2929 for (i = 0;i < numleafs;i++)
2930 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
2935 // set up a scissor rectangle for this light
2936 if (R_Shadow_ScissorForBBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
2939 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
2941 // make a list of lit entities and shadow casting entities
2942 numlightentities = 0;
2943 numlightentities_noselfshadow = 0;
2944 numshadowentities = 0;
2945 numshadowentities_noselfshadow = 0;
2946 // add dynamic entities that are lit by the light
2947 if (r_drawentities.integer)
2949 for (i = 0;i < r_refdef.scene.numentities;i++)
2952 entity_render_t *ent = r_refdef.scene.entities[i];
2954 if (!BoxesOverlap(ent->mins, ent->maxs, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
2956 // skip the object entirely if it is not within the valid
2957 // shadow-casting region (which includes the lit region)
2958 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rsurface.rtlight_numfrustumplanes, rsurface.rtlight_frustumplanes))
2960 if (!(model = ent->model))
2962 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
2964 // this entity wants to receive light, is visible, and is
2965 // inside the light box
2966 // TODO: check if the surfaces in the model can receive light
2967 // so now check if it's in a leaf seen by the light
2968 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))
2970 if (ent->flags & RENDER_NOSELFSHADOW)
2971 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
2973 lightentities[numlightentities++] = ent;
2974 // since it is lit, it probably also casts a shadow...
2975 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2976 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
2977 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
2979 // note: exterior models without the RENDER_NOSELFSHADOW
2980 // flag still create a RENDER_NOSELFSHADOW shadow but
2981 // are lit normally, this means that they are
2982 // self-shadowing but do not shadow other
2983 // RENDER_NOSELFSHADOW entities such as the gun
2984 // (very weird, but keeps the player shadow off the gun)
2985 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
2986 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
2988 shadowentities[numshadowentities++] = ent;
2991 else if (ent->flags & RENDER_SHADOW)
2993 // this entity is not receiving light, but may still need to
2995 // TODO: check if the surfaces in the model can cast shadow
2996 // now check if it is in a leaf seen by the light
2997 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))
2999 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3000 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3001 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3003 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3004 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3006 shadowentities[numshadowentities++] = ent;
3012 // return if there's nothing at all to light
3013 if (!numlightentities && !numsurfaces)
3016 // don't let sound skip if going slow
3017 if (r_refdef.scene.extraupdate)
3020 // make this the active rtlight for rendering purposes
3021 R_Shadow_RenderMode_ActiveLight(rtlight);
3022 // count this light in the r_speeds
3023 r_refdef.stats.lights++;
3025 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.rtworldshadows : r_refdef.rtdlightshadows))
3027 // optionally draw visible shape of the shadow volumes
3028 // for performance analysis by level designers
3029 R_Shadow_RenderMode_VisibleShadowVolumes();
3031 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3032 for (i = 0;i < numshadowentities;i++)
3033 R_Shadow_DrawEntityShadow(shadowentities[i]);
3034 for (i = 0;i < numshadowentities_noselfshadow;i++)
3035 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3038 if (gl_stencil && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.rtworldshadows : r_refdef.rtdlightshadows))
3040 // draw stencil shadow volumes to mask off pixels that are in shadow
3041 // so that they won't receive lighting
3042 R_Shadow_RenderMode_StencilShadowVolumes(true);
3044 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3045 for (i = 0;i < numshadowentities;i++)
3046 R_Shadow_DrawEntityShadow(shadowentities[i]);
3047 if (numlightentities_noselfshadow)
3049 // draw lighting in the unmasked areas
3050 R_Shadow_RenderMode_Lighting(true, false);
3051 for (i = 0;i < numlightentities_noselfshadow;i++)
3052 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3054 // optionally draw the illuminated areas
3055 // for performance analysis by level designers
3056 if (r_showlighting.integer && r_refdef.view.showdebug)
3058 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
3059 for (i = 0;i < numlightentities_noselfshadow;i++)
3060 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3063 R_Shadow_RenderMode_StencilShadowVolumes(false);
3065 for (i = 0;i < numshadowentities_noselfshadow;i++)
3066 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3068 if (numsurfaces + numlightentities)
3070 // draw lighting in the unmasked areas
3071 R_Shadow_RenderMode_Lighting(true, false);
3073 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3074 for (i = 0;i < numlightentities;i++)
3075 R_Shadow_DrawEntityLight(lightentities[i]);
3077 // optionally draw the illuminated areas
3078 // for performance analysis by level designers
3079 if (r_showlighting.integer && r_refdef.view.showdebug)
3081 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
3083 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3084 for (i = 0;i < numlightentities;i++)
3085 R_Shadow_DrawEntityLight(lightentities[i]);
3091 if (numsurfaces + numlightentities)
3093 // draw lighting in the unmasked areas
3094 R_Shadow_RenderMode_Lighting(false, false);
3096 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3097 for (i = 0;i < numlightentities;i++)
3098 R_Shadow_DrawEntityLight(lightentities[i]);
3099 for (i = 0;i < numlightentities_noselfshadow;i++)
3100 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3102 // optionally draw the illuminated areas
3103 // for performance analysis by level designers
3104 if (r_showlighting.integer && r_refdef.view.showdebug)
3106 R_Shadow_RenderMode_VisibleLighting(false, false);
3108 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3109 for (i = 0;i < numlightentities;i++)
3110 R_Shadow_DrawEntityLight(lightentities[i]);
3111 for (i = 0;i < numlightentities_noselfshadow;i++)
3112 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3118 void R_Shadow_DrawLightSprites(void);
3119 void R_ShadowVolumeLighting(qboolean visible)
3126 if (r_editlights.integer)
3127 R_Shadow_DrawLightSprites();
3129 R_Shadow_RenderMode_Begin();
3131 flag = r_refdef.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3132 if (r_shadow_debuglight.integer >= 0)
3134 lightindex = r_shadow_debuglight.integer;
3135 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3136 if (light && (light->flags & flag))
3137 R_DrawRTLight(&light->rtlight, visible);
3141 for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
3143 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3144 if (light && (light->flags & flag))
3145 R_DrawRTLight(&light->rtlight, visible);
3148 if (r_refdef.rtdlight)
3149 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3150 R_DrawRTLight(&r_refdef.scene.lights[lnum], visible);
3152 R_Shadow_RenderMode_End();
3155 extern void R_SetupView(void);
3156 extern cvar_t r_shadows_throwdistance;
3157 void R_DrawModelShadows(void)
3160 float relativethrowdistance;
3161 entity_render_t *ent;
3162 vec3_t relativelightorigin;
3163 vec3_t relativelightdirection;
3164 vec3_t relativeshadowmins, relativeshadowmaxs;
3167 if (!r_drawentities.integer || !gl_stencil)
3171 GL_Scissor(r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
3173 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
3175 if (gl_ext_separatestencil.integer)
3176 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
3177 else if (gl_ext_stenciltwoside.integer)
3178 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
3180 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
3182 R_Shadow_RenderMode_StencilShadowVolumes(true);
3184 for (i = 0;i < r_refdef.scene.numentities;i++)
3186 ent = r_refdef.scene.entities[i];
3187 // cast shadows from anything that is not a submodel of the map
3188 if (ent->model && ent->model->DrawShadowVolume != NULL && !ent->model->brush.submodel && (ent->flags & RENDER_SHADOW))
3190 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
3191 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
3192 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
3193 VectorNegate(ent->modellight_lightdir, relativelightdirection);
3194 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
3195 RSurf_ActiveModelEntity(ent, false, false);
3196 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
3200 // not really the right mode, but this will disable any silly stencil features
3201 R_Shadow_RenderMode_VisibleLighting(true, true);
3203 // vertex coordinates for a quad that covers the screen exactly
3204 vertex3f[0] = 0;vertex3f[1] = 0;vertex3f[2] = 0;
3205 vertex3f[3] = 1;vertex3f[4] = 0;vertex3f[5] = 0;
3206 vertex3f[6] = 1;vertex3f[7] = 1;vertex3f[8] = 0;
3207 vertex3f[9] = 0;vertex3f[10] = 1;vertex3f[11] = 0;
3209 // set up ortho view for rendering this pass
3210 GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
3211 GL_Scissor(r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
3212 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
3213 GL_ScissorTest(true);
3214 R_Mesh_Matrix(&identitymatrix);
3215 R_Mesh_ResetTextureState();
3216 R_Mesh_VertexPointer(vertex3f, 0, 0);
3217 R_Mesh_ColorPointer(NULL, 0, 0);
3219 // set up a 50% darkening blend on shadowed areas
3220 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3221 GL_DepthRange(0, 1);
3222 GL_DepthTest(false);
3223 GL_DepthMask(false);
3224 GL_PolygonOffset(0, 0);CHECKGLERROR
3225 GL_Color(0, 0, 0, 0.5);
3226 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
3227 qglDepthFunc(GL_ALWAYS);CHECKGLERROR
3228 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
3229 qglStencilMask(~0);CHECKGLERROR
3230 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
3231 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
3233 // apply the blend to the shadowed areas
3234 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3236 // restoring the perspective view is done by R_RenderScene
3239 // restore other state to normal
3240 R_Shadow_RenderMode_End();
3243 void R_DrawCoronas(void)
3246 float cscale, scale;
3250 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
3252 R_Mesh_Matrix(&identitymatrix);
3253 flag = r_refdef.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3254 // FIXME: these traces should scan all render entities instead of cl.world
3255 for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
3257 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3260 rtlight = &light->rtlight;
3261 if (!(rtlight->flags & flag))
3263 if (rtlight->corona * r_coronas.value <= 0)
3265 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
3267 cscale = rtlight->corona * r_coronas.value* 0.25f;
3268 scale = rtlight->radius * rtlight->coronasizescale;
3269 if (VectorDistance2(rtlight->shadoworigin, r_refdef.view.origin) < 16.0f * 16.0f)
3271 if (CL_Move(r_refdef.view.origin, vec3_origin, vec3_origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
3273 R_DrawSprite(GL_ONE, GL_ONE, r_shadow_lightcorona, NULL, true, false, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale, rtlight->color[0] * cscale, rtlight->color[1] * cscale, rtlight->color[2] * cscale, 1);
3275 for (i = 0;i < r_refdef.scene.numlights;i++)
3277 rtlight = &r_refdef.scene.lights[i];
3278 if (!(rtlight->flags & flag))
3280 if (rtlight->corona <= 0)
3282 if (VectorDistance2(rtlight->shadoworigin, r_refdef.view.origin) < 32.0f * 32.0f)
3284 if (gl_flashblend.integer)
3286 cscale = rtlight->corona * 1.0f;
3287 scale = rtlight->radius * rtlight->coronasizescale * 2.0f;
3291 cscale = rtlight->corona * r_coronas.value* 0.25f;
3292 scale = rtlight->radius * rtlight->coronasizescale;
3294 if (VectorLength(rtlight->color) * cscale < (1.0f / 256.0f))
3296 if (CL_Move(r_refdef.view.origin, vec3_origin, vec3_origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
3298 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);
3304 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
3305 typedef struct suffixinfo_s
3308 qboolean flipx, flipy, flipdiagonal;
3311 static suffixinfo_t suffix[3][6] =
3314 {"px", false, false, false},
3315 {"nx", false, false, false},
3316 {"py", false, false, false},
3317 {"ny", false, false, false},
3318 {"pz", false, false, false},
3319 {"nz", false, false, false}
3322 {"posx", false, false, false},
3323 {"negx", false, false, false},
3324 {"posy", false, false, false},
3325 {"negy", false, false, false},
3326 {"posz", false, false, false},
3327 {"negz", false, false, false}
3330 {"rt", true, false, true},
3331 {"lf", false, true, true},
3332 {"ft", true, true, false},
3333 {"bk", false, false, false},
3334 {"up", true, false, true},
3335 {"dn", true, false, true}
3339 static int componentorder[4] = {0, 1, 2, 3};
3341 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
3343 int i, j, cubemapsize;
3344 unsigned char *cubemappixels, *image_buffer;
3345 rtexture_t *cubemaptexture;
3347 // must start 0 so the first loadimagepixels has no requested width/height
3349 cubemappixels = NULL;
3350 cubemaptexture = NULL;
3351 // keep trying different suffix groups (posx, px, rt) until one loads
3352 for (j = 0;j < 3 && !cubemappixels;j++)
3354 // load the 6 images in the suffix group
3355 for (i = 0;i < 6;i++)
3357 // generate an image name based on the base and and suffix
3358 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
3360 if ((image_buffer = loadimagepixelsbgra(name, false, false)))
3362 // an image loaded, make sure width and height are equal
3363 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
3365 // if this is the first image to load successfully, allocate the cubemap memory
3366 if (!cubemappixels && image_width >= 1)
3368 cubemapsize = image_width;
3369 // note this clears to black, so unavailable sides are black
3370 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
3372 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
3374 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);
3377 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
3379 Mem_Free(image_buffer);
3383 // if a cubemap loaded, upload it
3386 if (!r_shadow_filters_texturepool)
3387 r_shadow_filters_texturepool = R_AllocTexturePool();
3388 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, TEXF_PRECACHE | (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0), NULL);
3389 Mem_Free(cubemappixels);
3393 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
3394 for (j = 0;j < 3;j++)
3395 for (i = 0;i < 6;i++)
3396 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
3397 Con_Print(" and was unable to find any of them.\n");
3399 return cubemaptexture;
3402 rtexture_t *R_Shadow_Cubemap(const char *basename)
3405 for (i = 0;i < numcubemaps;i++)
3406 if (!strcasecmp(cubemaps[i].basename, basename))
3407 return cubemaps[i].texture;
3408 if (i >= MAX_CUBEMAPS)
3409 return r_texture_whitecube;
3411 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
3412 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
3413 if (!cubemaps[i].texture)
3414 cubemaps[i].texture = r_texture_whitecube;
3415 return cubemaps[i].texture;
3418 void R_Shadow_FreeCubemaps(void)
3421 R_FreeTexturePool(&r_shadow_filters_texturepool);
3424 dlight_t *R_Shadow_NewWorldLight(void)
3426 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
3429 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)
3432 // validate parameters
3433 if (style < 0 || style >= MAX_LIGHTSTYLES)
3435 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
3441 // copy to light properties
3442 VectorCopy(origin, light->origin);
3443 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
3444 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
3445 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
3446 light->color[0] = max(color[0], 0);
3447 light->color[1] = max(color[1], 0);
3448 light->color[2] = max(color[2], 0);
3449 light->radius = max(radius, 0);
3450 light->style = style;
3451 light->shadow = shadowenable;
3452 light->corona = corona;
3453 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
3454 light->coronasizescale = coronasizescale;
3455 light->ambientscale = ambientscale;
3456 light->diffusescale = diffusescale;
3457 light->specularscale = specularscale;
3458 light->flags = flags;
3460 // update renderable light data
3461 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
3462 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);
3465 void R_Shadow_FreeWorldLight(dlight_t *light)
3467 if (r_shadow_selectedlight == light)
3468 r_shadow_selectedlight = NULL;
3469 R_RTLight_Uncompile(&light->rtlight);
3470 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
3473 void R_Shadow_ClearWorldLights(void)
3477 for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
3479 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3481 R_Shadow_FreeWorldLight(light);
3483 r_shadow_selectedlight = NULL;
3484 R_Shadow_FreeCubemaps();
3487 void R_Shadow_SelectLight(dlight_t *light)
3489 if (r_shadow_selectedlight)
3490 r_shadow_selectedlight->selected = false;
3491 r_shadow_selectedlight = light;
3492 if (r_shadow_selectedlight)
3493 r_shadow_selectedlight->selected = true;
3496 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
3498 // this is never batched (there can be only one)
3499 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);
3502 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
3509 // this is never batched (due to the ent parameter changing every time)
3510 // so numsurfaces == 1 and surfacelist[0] == lightnumber
3511 const dlight_t *light = (dlight_t *)ent;
3514 VectorScale(light->color, intensity, spritecolor);
3515 if (VectorLength(spritecolor) < 0.1732f)
3516 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
3517 if (VectorLength(spritecolor) > 1.0f)
3518 VectorNormalize(spritecolor);
3520 // draw light sprite
3521 if (light->cubemapname[0] && !light->shadow)
3522 pic = r_editlights_sprcubemapnoshadowlight;
3523 else if (light->cubemapname[0])
3524 pic = r_editlights_sprcubemaplight;
3525 else if (!light->shadow)
3526 pic = r_editlights_sprnoshadowlight;
3528 pic = r_editlights_sprlight;
3529 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);
3530 // draw selection sprite if light is selected
3531 if (light->selected)
3532 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);
3533 // VorteX todo: add normalmode/realtime mode light overlay sprites?
3536 void R_Shadow_DrawLightSprites(void)
3540 for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
3542 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3544 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
3546 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
3549 void R_Shadow_SelectLightInView(void)
3551 float bestrating, rating, temp[3];
3557 for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
3559 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3562 VectorSubtract(light->origin, r_refdef.view.origin, temp);
3563 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
3566 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
3567 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)
3569 bestrating = rating;
3574 R_Shadow_SelectLight(best);
3577 void R_Shadow_LoadWorldLights(void)
3579 int n, a, style, shadow, flags;
3580 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
3581 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
3582 if (cl.worldmodel == NULL)
3584 Con_Print("No map loaded.\n");
3587 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
3588 strlcat (name, ".rtlights", sizeof (name));
3589 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3599 for (;COM_Parse(t, true) && strcmp(
3600 if (COM_Parse(t, true))
3602 if (com_token[0] == '!')
3605 origin[0] = atof(com_token+1);
3608 origin[0] = atof(com_token);
3613 while (*s && *s != '\n' && *s != '\r')
3619 // check for modifier flags
3626 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);
3629 flags = LIGHTFLAG_REALTIMEMODE;
3637 coronasizescale = 0.25f;
3639 VectorClear(angles);
3642 if (a < 9 || !strcmp(cubemapname, "\"\""))
3644 // remove quotes on cubemapname
3645 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
3648 namelen = strlen(cubemapname) - 2;
3649 memmove(cubemapname, cubemapname + 1, namelen);
3650 cubemapname[namelen] = '\0';
3654 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);
3657 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3665 Con_Printf("invalid rtlights file \"%s\"\n", name);
3666 Mem_Free(lightsstring);
3670 void R_Shadow_SaveWorldLights(void)
3674 size_t bufchars, bufmaxchars;
3676 char name[MAX_QPATH];
3677 char line[MAX_INPUTLINE];
3678 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
3680 if (cl.worldmodel == NULL)
3682 Con_Print("No map loaded.\n");
3685 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
3686 strlcat (name, ".rtlights", sizeof (name));
3687 bufchars = bufmaxchars = 0;
3689 for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
3691 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3694 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3695 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);
3696 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3697 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]);
3699 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);
3700 if (bufchars + strlen(line) > bufmaxchars)
3702 bufmaxchars = bufchars + strlen(line) + 2048;
3704 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
3708 memcpy(buf, oldbuf, bufchars);
3714 memcpy(buf + bufchars, line, strlen(line));
3715 bufchars += strlen(line);
3719 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
3724 void R_Shadow_LoadLightsFile(void)
3727 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3728 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3729 if (cl.worldmodel == NULL)
3731 Con_Print("No map loaded.\n");
3734 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
3735 strlcat (name, ".lights", sizeof (name));
3736 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3744 while (*s && *s != '\n' && *s != '\r')
3750 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);
3754 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);
3757 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3758 radius = bound(15, radius, 4096);
3759 VectorScale(color, (2.0f / (8388608.0f)), color);
3760 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3768 Con_Printf("invalid lights file \"%s\"\n", name);
3769 Mem_Free(lightsstring);
3773 // tyrlite/hmap2 light types in the delay field
3774 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3776 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3778 int entnum, style, islight, skin, pflags, effects, type, n;
3781 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3782 char key[256], value[MAX_INPUTLINE];
3784 if (cl.worldmodel == NULL)
3786 Con_Print("No map loaded.\n");
3789 // try to load a .ent file first
3790 FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
3791 strlcat (key, ".ent", sizeof (key));
3792 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
3793 // and if that is not found, fall back to the bsp file entity string
3795 data = cl.worldmodel->brush.entities;
3798 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
3800 type = LIGHTTYPE_MINUSX;
3801 origin[0] = origin[1] = origin[2] = 0;
3802 originhack[0] = originhack[1] = originhack[2] = 0;
3803 angles[0] = angles[1] = angles[2] = 0;
3804 color[0] = color[1] = color[2] = 1;
3805 light[0] = light[1] = light[2] = 1;light[3] = 300;
3806 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3816 if (!COM_ParseToken_Simple(&data, false, false))
3818 if (com_token[0] == '}')
3819 break; // end of entity
3820 if (com_token[0] == '_')
3821 strlcpy(key, com_token + 1, sizeof(key));
3823 strlcpy(key, com_token, sizeof(key));
3824 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3825 key[strlen(key)-1] = 0;
3826 if (!COM_ParseToken_Simple(&data, false, false))
3828 strlcpy(value, com_token, sizeof(value));
3830 // now that we have the key pair worked out...
3831 if (!strcmp("light", key))
3833 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3837 light[0] = vec[0] * (1.0f / 256.0f);
3838 light[1] = vec[0] * (1.0f / 256.0f);
3839 light[2] = vec[0] * (1.0f / 256.0f);
3845 light[0] = vec[0] * (1.0f / 255.0f);
3846 light[1] = vec[1] * (1.0f / 255.0f);
3847 light[2] = vec[2] * (1.0f / 255.0f);
3851 else if (!strcmp("delay", key))
3853 else if (!strcmp("origin", key))
3854 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3855 else if (!strcmp("angle", key))
3856 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3857 else if (!strcmp("angles", key))
3858 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3859 else if (!strcmp("color", key))
3860 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3861 else if (!strcmp("wait", key))
3862 fadescale = atof(value);
3863 else if (!strcmp("classname", key))
3865 if (!strncmp(value, "light", 5))
3868 if (!strcmp(value, "light_fluoro"))
3873 overridecolor[0] = 1;
3874 overridecolor[1] = 1;
3875 overridecolor[2] = 1;
3877 if (!strcmp(value, "light_fluorospark"))
3882 overridecolor[0] = 1;
3883 overridecolor[1] = 1;
3884 overridecolor[2] = 1;
3886 if (!strcmp(value, "light_globe"))
3891 overridecolor[0] = 1;
3892 overridecolor[1] = 0.8;
3893 overridecolor[2] = 0.4;
3895 if (!strcmp(value, "light_flame_large_yellow"))
3900 overridecolor[0] = 1;
3901 overridecolor[1] = 0.5;
3902 overridecolor[2] = 0.1;
3904 if (!strcmp(value, "light_flame_small_yellow"))
3909 overridecolor[0] = 1;
3910 overridecolor[1] = 0.5;
3911 overridecolor[2] = 0.1;
3913 if (!strcmp(value, "light_torch_small_white"))
3918 overridecolor[0] = 1;
3919 overridecolor[1] = 0.5;
3920 overridecolor[2] = 0.1;
3922 if (!strcmp(value, "light_torch_small_walltorch"))
3927 overridecolor[0] = 1;
3928 overridecolor[1] = 0.5;
3929 overridecolor[2] = 0.1;
3933 else if (!strcmp("style", key))
3934 style = atoi(value);
3935 else if (!strcmp("skin", key))
3936 skin = (int)atof(value);
3937 else if (!strcmp("pflags", key))
3938 pflags = (int)atof(value);
3939 else if (!strcmp("effects", key))
3940 effects = (int)atof(value);
3941 else if (cl.worldmodel->type == mod_brushq3)
3943 if (!strcmp("scale", key))
3944 lightscale = atof(value);
3945 if (!strcmp("fade", key))
3946 fadescale = atof(value);
3951 if (lightscale <= 0)
3955 if (color[0] == color[1] && color[0] == color[2])
3957 color[0] *= overridecolor[0];
3958 color[1] *= overridecolor[1];
3959 color[2] *= overridecolor[2];
3961 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3962 color[0] = color[0] * light[0];
3963 color[1] = color[1] * light[1];
3964 color[2] = color[2] * light[2];
3967 case LIGHTTYPE_MINUSX:
3969 case LIGHTTYPE_RECIPX:
3971 VectorScale(color, (1.0f / 16.0f), color);
3973 case LIGHTTYPE_RECIPXX:
3975 VectorScale(color, (1.0f / 16.0f), color);
3978 case LIGHTTYPE_NONE:
3982 case LIGHTTYPE_MINUSXX:
3985 VectorAdd(origin, originhack, origin);
3987 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);
3990 Mem_Free(entfiledata);
3994 void R_Shadow_SetCursorLocationForView(void)
3997 vec3_t dest, endpos;
3999 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
4000 trace = CL_Move(r_refdef.view.origin, vec3_origin, vec3_origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
4001 if (trace.fraction < 1)
4003 dist = trace.fraction * r_editlights_cursordistance.value;
4004 push = r_editlights_cursorpushback.value;
4008 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
4009 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
4013 VectorClear( endpos );
4015 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4016 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4017 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4020 void R_Shadow_UpdateWorldLightSelection(void)
4022 if (r_editlights.integer)
4024 R_Shadow_SetCursorLocationForView();
4025 R_Shadow_SelectLightInView();
4028 R_Shadow_SelectLight(NULL);
4031 void R_Shadow_EditLights_Clear_f(void)
4033 R_Shadow_ClearWorldLights();
4036 void R_Shadow_EditLights_Reload_f(void)
4040 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
4041 R_Shadow_ClearWorldLights();
4042 R_Shadow_LoadWorldLights();
4043 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
4045 R_Shadow_LoadLightsFile();
4046 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
4047 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
4051 void R_Shadow_EditLights_Save_f(void)
4055 R_Shadow_SaveWorldLights();
4058 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
4060 R_Shadow_ClearWorldLights();
4061 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
4064 void R_Shadow_EditLights_ImportLightsFile_f(void)
4066 R_Shadow_ClearWorldLights();
4067 R_Shadow_LoadLightsFile();
4070 void R_Shadow_EditLights_Spawn_f(void)
4073 if (!r_editlights.integer)
4075 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4078 if (Cmd_Argc() != 1)
4080 Con_Print("r_editlights_spawn does not take parameters\n");
4083 color[0] = color[1] = color[2] = 1;
4084 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
4087 void R_Shadow_EditLights_Edit_f(void)
4089 vec3_t origin, angles, color;
4090 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
4091 int style, shadows, flags, normalmode, realtimemode;
4092 char cubemapname[MAX_INPUTLINE];
4093 if (!r_editlights.integer)
4095 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4098 if (!r_shadow_selectedlight)
4100 Con_Print("No selected light.\n");
4103 VectorCopy(r_shadow_selectedlight->origin, origin);
4104 VectorCopy(r_shadow_selectedlight->angles, angles);
4105 VectorCopy(r_shadow_selectedlight->color, color);
4106 radius = r_shadow_selectedlight->radius;
4107 style = r_shadow_selectedlight->style;
4108 if (r_shadow_selectedlight->cubemapname)
4109 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
4112 shadows = r_shadow_selectedlight->shadow;
4113 corona = r_shadow_selectedlight->corona;
4114 coronasizescale = r_shadow_selectedlight->coronasizescale;
4115 ambientscale = r_shadow_selectedlight->ambientscale;
4116 diffusescale = r_shadow_selectedlight->diffusescale;
4117 specularscale = r_shadow_selectedlight->specularscale;
4118 flags = r_shadow_selectedlight->flags;
4119 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
4120 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
4121 if (!strcmp(Cmd_Argv(1), "origin"))
4123 if (Cmd_Argc() != 5)
4125 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
4128 origin[0] = atof(Cmd_Argv(2));
4129 origin[1] = atof(Cmd_Argv(3));
4130 origin[2] = atof(Cmd_Argv(4));
4132 else if (!strcmp(Cmd_Argv(1), "originx"))
4134 if (Cmd_Argc() != 3)
4136 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4139 origin[0] = atof(Cmd_Argv(2));
4141 else if (!strcmp(Cmd_Argv(1), "originy"))
4143 if (Cmd_Argc() != 3)
4145 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4148 origin[1] = atof(Cmd_Argv(2));
4150 else if (!strcmp(Cmd_Argv(1), "originz"))
4152 if (Cmd_Argc() != 3)
4154 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4157 origin[2] = atof(Cmd_Argv(2));
4159 else if (!strcmp(Cmd_Argv(1), "move"))
4161 if (Cmd_Argc() != 5)
4163 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
4166 origin[0] += atof(Cmd_Argv(2));
4167 origin[1] += atof(Cmd_Argv(3));
4168 origin[2] += atof(Cmd_Argv(4));
4170 else if (!strcmp(Cmd_Argv(1), "movex"))
4172 if (Cmd_Argc() != 3)
4174 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4177 origin[0] += atof(Cmd_Argv(2));
4179 else if (!strcmp(Cmd_Argv(1), "movey"))
4181 if (Cmd_Argc() != 3)
4183 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4186 origin[1] += atof(Cmd_Argv(2));
4188 else if (!strcmp(Cmd_Argv(1), "movez"))
4190 if (Cmd_Argc() != 3)
4192 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4195 origin[2] += atof(Cmd_Argv(2));
4197 else if (!strcmp(Cmd_Argv(1), "angles"))
4199 if (Cmd_Argc() != 5)
4201 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
4204 angles[0] = atof(Cmd_Argv(2));
4205 angles[1] = atof(Cmd_Argv(3));
4206 angles[2] = atof(Cmd_Argv(4));
4208 else if (!strcmp(Cmd_Argv(1), "anglesx"))
4210 if (Cmd_Argc() != 3)
4212 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4215 angles[0] = atof(Cmd_Argv(2));
4217 else if (!strcmp(Cmd_Argv(1), "anglesy"))
4219 if (Cmd_Argc() != 3)
4221 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4224 angles[1] = atof(Cmd_Argv(2));
4226 else if (!strcmp(Cmd_Argv(1), "anglesz"))
4228 if (Cmd_Argc() != 3)
4230 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4233 angles[2] = atof(Cmd_Argv(2));
4235 else if (!strcmp(Cmd_Argv(1), "color"))
4237 if (Cmd_Argc() != 5)
4239 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
4242 color[0] = atof(Cmd_Argv(2));
4243 color[1] = atof(Cmd_Argv(3));
4244 color[2] = atof(Cmd_Argv(4));
4246 else if (!strcmp(Cmd_Argv(1), "radius"))
4248 if (Cmd_Argc() != 3)
4250 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4253 radius = atof(Cmd_Argv(2));
4255 else if (!strcmp(Cmd_Argv(1), "colorscale"))
4257 if (Cmd_Argc() == 3)
4259 double scale = atof(Cmd_Argv(2));
4266 if (Cmd_Argc() != 5)
4268 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
4271 color[0] *= atof(Cmd_Argv(2));
4272 color[1] *= atof(Cmd_Argv(3));
4273 color[2] *= atof(Cmd_Argv(4));
4276 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
4278 if (Cmd_Argc() != 3)
4280 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4283 radius *= atof(Cmd_Argv(2));
4285 else if (!strcmp(Cmd_Argv(1), "style"))
4287 if (Cmd_Argc() != 3)
4289 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4292 style = atoi(Cmd_Argv(2));
4294 else if (!strcmp(Cmd_Argv(1), "cubemap"))
4298 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4301 if (Cmd_Argc() == 3)
4302 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
4306 else if (!strcmp(Cmd_Argv(1), "shadows"))
4308 if (Cmd_Argc() != 3)
4310 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4313 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4315 else if (!strcmp(Cmd_Argv(1), "corona"))
4317 if (Cmd_Argc() != 3)
4319 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4322 corona = atof(Cmd_Argv(2));
4324 else if (!strcmp(Cmd_Argv(1), "coronasize"))
4326 if (Cmd_Argc() != 3)
4328 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4331 coronasizescale = atof(Cmd_Argv(2));
4333 else if (!strcmp(Cmd_Argv(1), "ambient"))
4335 if (Cmd_Argc() != 3)
4337 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4340 ambientscale = atof(Cmd_Argv(2));
4342 else if (!strcmp(Cmd_Argv(1), "diffuse"))
4344 if (Cmd_Argc() != 3)
4346 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4349 diffusescale = atof(Cmd_Argv(2));
4351 else if (!strcmp(Cmd_Argv(1), "specular"))
4353 if (Cmd_Argc() != 3)
4355 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4358 specularscale = atof(Cmd_Argv(2));
4360 else if (!strcmp(Cmd_Argv(1), "normalmode"))
4362 if (Cmd_Argc() != 3)
4364 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4367 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4369 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
4371 if (Cmd_Argc() != 3)
4373 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4376 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4380 Con_Print("usage: r_editlights_edit [property] [value]\n");
4381 Con_Print("Selected light's properties:\n");
4382 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
4383 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
4384 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
4385 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
4386 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
4387 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
4388 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
4389 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
4390 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
4391 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
4392 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
4393 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
4394 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
4395 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
4398 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
4399 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4402 void R_Shadow_EditLights_EditAll_f(void)
4407 if (!r_editlights.integer)
4409 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
4413 for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
4415 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4418 R_Shadow_SelectLight(light);
4419 R_Shadow_EditLights_Edit_f();
4423 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
4425 int lightnumber, lightcount;
4430 if (!r_editlights.integer)
4432 x = vid_conwidth.value - 240;
4434 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
4437 for (lightindex = 0;lightindex < Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);lightindex++)
4439 light = Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4442 if (light == r_shadow_selectedlight)
4443 lightnumber = lightindex;
4446 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;
4447 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;
4449 if (r_shadow_selectedlight == NULL)
4451 sprintf(temp, "Light #%i properties:", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
4452 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;
4453 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;
4454 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;
4455 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;
4456 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;
4457 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;
4458 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;
4459 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;
4460 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;
4461 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;
4462 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;
4463 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;
4464 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;
4465 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;
4468 void R_Shadow_EditLights_ToggleShadow_f(void)
4470 if (!r_editlights.integer)
4472 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4475 if (!r_shadow_selectedlight)
4477 Con_Print("No selected light.\n");
4480 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);
4483 void R_Shadow_EditLights_ToggleCorona_f(void)
4485 if (!r_editlights.integer)
4487 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4490 if (!r_shadow_selectedlight)
4492 Con_Print("No selected light.\n");
4495 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);
4498 void R_Shadow_EditLights_Remove_f(void)
4500 if (!r_editlights.integer)
4502 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
4505 if (!r_shadow_selectedlight)
4507 Con_Print("No selected light.\n");
4510 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
4511 r_shadow_selectedlight = NULL;
4514 void R_Shadow_EditLights_Help_f(void)
4517 "Documentation on r_editlights system:\n"
4519 "r_editlights : enable/disable editing mode\n"
4520 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
4521 "r_editlights_cursorpushback : push back cursor this far from surface\n"
4522 "r_editlights_cursorpushoff : push cursor off surface this far\n"
4523 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
4524 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
4526 "r_editlights_help : this help\n"
4527 "r_editlights_clear : remove all lights\n"
4528 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
4529 "r_editlights_save : save to .rtlights file\n"
4530 "r_editlights_spawn : create a light with default settings\n"
4531 "r_editlights_edit command : edit selected light - more documentation below\n"
4532 "r_editlights_remove : remove selected light\n"
4533 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
4534 "r_editlights_importlightentitiesfrommap : reload light entities\n"
4535 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
4537 "origin x y z : set light location\n"
4538 "originx x: set x component of light location\n"
4539 "originy y: set y component of light location\n"
4540 "originz z: set z component of light location\n"
4541 "move x y z : adjust light location\n"
4542 "movex x: adjust x component of light location\n"
4543 "movey y: adjust y component of light location\n"
4544 "movez z: adjust z component of light location\n"
4545 "angles x y z : set light angles\n"
4546 "anglesx x: set x component of light angles\n"
4547 "anglesy y: set y component of light angles\n"
4548 "anglesz z: set z component of light angles\n"
4549 "color r g b : set color of light (can be brighter than 1 1 1)\n"
4550 "radius radius : set radius (size) of light\n"
4551 "colorscale grey : multiply color of light (1 does nothing)\n"
4552 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
4553 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
4554 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
4555 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
4556 "cubemap basename : set filter cubemap of light (not yet supported)\n"
4557 "shadows 1/0 : turn on/off shadows\n"
4558 "corona n : set corona intensity\n"
4559 "coronasize n : set corona size (0-1)\n"
4560 "ambient n : set ambient intensity (0-1)\n"
4561 "diffuse n : set diffuse intensity (0-1)\n"
4562 "specular n : set specular intensity (0-1)\n"
4563 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
4564 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
4565 "<nothing> : print light properties to console\n"
4569 void R_Shadow_EditLights_CopyInfo_f(void)
4571 if (!r_editlights.integer)
4573 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
4576 if (!r_shadow_selectedlight)
4578 Con_Print("No selected light.\n");
4581 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
4582 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
4583 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
4584 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
4585 if (r_shadow_selectedlight->cubemapname)
4586 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
4588 r_shadow_bufferlight.cubemapname[0] = 0;
4589 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
4590 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
4591 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
4592 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
4593 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
4594 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
4595 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
4598 void R_Shadow_EditLights_PasteInfo_f(void)
4600 if (!r_editlights.integer)
4602 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
4605 if (!r_shadow_selectedlight)
4607 Con_Print("No selected light.\n");
4610 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);
4613 void R_Shadow_EditLights_Init(void)
4615 Cvar_RegisterVariable(&r_editlights);
4616 Cvar_RegisterVariable(&r_editlights_cursordistance);
4617 Cvar_RegisterVariable(&r_editlights_cursorpushback);
4618 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
4619 Cvar_RegisterVariable(&r_editlights_cursorgrid);
4620 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
4621 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
4622 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
4623 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)");
4624 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
4625 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
4626 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
4627 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)");
4628 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
4629 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
4630 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
4631 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
4632 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
4633 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
4634 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)");
4640 =============================================================================
4644 =============================================================================
4647 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
4649 VectorClear(diffusecolor);
4650 VectorClear(diffusenormal);
4652 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
4654 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_ambient.value * (2.0f / 128.0f);
4655 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
4658 VectorSet(ambientcolor, 1, 1, 1);
4665 for (i = 0;i < r_refdef.scene.numlights;i++)
4667 light = &r_refdef.scene.lights[i];
4668 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
4669 f = 1 - VectorLength2(v);
4670 if (f > 0 && CL_Move(p, vec3_origin, vec3_origin, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
4671 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);