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;
198 // lights are reloaded when this changes
199 char r_shadow_mapname[MAX_QPATH];
201 // used only for light filters (cubemaps)
202 rtexturepool_t *r_shadow_filters_texturepool;
204 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"};
205 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"};
206 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
207 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
208 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)"};
209 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"};
210 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
211 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
212 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
213 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
214 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
215 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
216 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"};
217 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000", "how far to cast shadows"};
218 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)"};
219 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
220 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
221 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
222 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
223 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)"};
224 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"};
225 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
226 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
227 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"};
228 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation"};
229 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation"};
230 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)"};
231 cvar_t r_shadow_culltriangles = {0, "r_shadow_culltriangles", "1", "performs more expensive tests to remove unnecessary triangles of lit surfaces"};
232 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
233 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)"};
234 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)"};
235 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
236 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
237 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
238 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
239 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
240 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
241 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
242 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
244 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
245 #define ATTENTABLESIZE 256
246 // 1D gradient, 2D circle and 3D sphere attenuation textures
247 #define ATTEN1DSIZE 32
248 #define ATTEN2DSIZE 64
249 #define ATTEN3DSIZE 32
251 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
252 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
253 static float r_shadow_attentable[ATTENTABLESIZE+1];
255 rtlight_t *r_shadow_compilingrtlight;
256 dlight_t *r_shadow_worldlightchain;
257 dlight_t *r_shadow_selectedlight;
258 dlight_t r_shadow_bufferlight;
259 vec3_t r_editlights_cursorlocation;
261 extern int con_vislines;
263 typedef struct cubemapinfo_s
270 #define MAX_CUBEMAPS 256
271 static int numcubemaps;
272 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
274 void R_Shadow_UncompileWorldLights(void);
275 void R_Shadow_ClearWorldLights(void);
276 void R_Shadow_SaveWorldLights(void);
277 void R_Shadow_LoadWorldLights(void);
278 void R_Shadow_LoadLightsFile(void);
279 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
280 void R_Shadow_EditLights_Reload_f(void);
281 void R_Shadow_ValidateCvars(void);
282 static void R_Shadow_MakeTextures(void);
284 void r_shadow_start(void)
286 // allocate vertex processing arrays
288 r_shadow_attenuationgradienttexture = NULL;
289 r_shadow_attenuation2dtexture = NULL;
290 r_shadow_attenuation3dtexture = NULL;
291 r_shadow_texturepool = NULL;
292 r_shadow_filters_texturepool = NULL;
293 R_Shadow_ValidateCvars();
294 R_Shadow_MakeTextures();
295 maxshadowtriangles = 0;
296 shadowelements = NULL;
297 maxshadowvertices = 0;
298 shadowvertex3f = NULL;
306 shadowmarklist = NULL;
308 r_shadow_buffer_numleafpvsbytes = 0;
309 r_shadow_buffer_leafpvs = NULL;
310 r_shadow_buffer_leaflist = NULL;
311 r_shadow_buffer_numsurfacepvsbytes = 0;
312 r_shadow_buffer_surfacepvs = NULL;
313 r_shadow_buffer_surfacelist = NULL;
314 r_shadow_buffer_numshadowtrispvsbytes = 0;
315 r_shadow_buffer_shadowtrispvs = NULL;
316 r_shadow_buffer_numlighttrispvsbytes = 0;
317 r_shadow_buffer_lighttrispvs = NULL;
320 void r_shadow_shutdown(void)
322 R_Shadow_UncompileWorldLights();
324 r_shadow_attenuationgradienttexture = NULL;
325 r_shadow_attenuation2dtexture = NULL;
326 r_shadow_attenuation3dtexture = NULL;
327 R_FreeTexturePool(&r_shadow_texturepool);
328 R_FreeTexturePool(&r_shadow_filters_texturepool);
329 maxshadowtriangles = 0;
331 Mem_Free(shadowelements);
332 shadowelements = NULL;
334 Mem_Free(shadowvertex3f);
335 shadowvertex3f = NULL;
338 Mem_Free(vertexupdate);
341 Mem_Free(vertexremap);
347 Mem_Free(shadowmark);
350 Mem_Free(shadowmarklist);
351 shadowmarklist = NULL;
353 r_shadow_buffer_numleafpvsbytes = 0;
354 if (r_shadow_buffer_leafpvs)
355 Mem_Free(r_shadow_buffer_leafpvs);
356 r_shadow_buffer_leafpvs = NULL;
357 if (r_shadow_buffer_leaflist)
358 Mem_Free(r_shadow_buffer_leaflist);
359 r_shadow_buffer_leaflist = NULL;
360 r_shadow_buffer_numsurfacepvsbytes = 0;
361 if (r_shadow_buffer_surfacepvs)
362 Mem_Free(r_shadow_buffer_surfacepvs);
363 r_shadow_buffer_surfacepvs = NULL;
364 if (r_shadow_buffer_surfacelist)
365 Mem_Free(r_shadow_buffer_surfacelist);
366 r_shadow_buffer_surfacelist = NULL;
367 r_shadow_buffer_numshadowtrispvsbytes = 0;
368 if (r_shadow_buffer_shadowtrispvs)
369 Mem_Free(r_shadow_buffer_shadowtrispvs);
370 r_shadow_buffer_numlighttrispvsbytes = 0;
371 if (r_shadow_buffer_lighttrispvs)
372 Mem_Free(r_shadow_buffer_lighttrispvs);
375 void r_shadow_newmap(void)
379 void R_Shadow_Help_f(void)
382 "Documentation on r_shadow system:\n"
384 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
385 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
386 "r_shadow_debuglight : render only this light number (-1 = all)\n"
387 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
388 "r_shadow_gloss2intensity : brightness of forced gloss\n"
389 "r_shadow_glossintensity : brightness of textured gloss\n"
390 "r_shadow_lightattenuationlinearscale : used to generate attenuation texture\n"
391 "r_shadow_lightattenuationdividebias : used to generate attenuation texture\n"
392 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
393 "r_shadow_lightradiusscale : scale rendering radius of all lights\n"
394 "r_shadow_portallight : use portal visibility for static light precomputation\n"
395 "r_shadow_projectdistance : shadow volume projection distance\n"
396 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
397 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
398 "r_shadow_realtime_world : use high quality world lighting mode\n"
399 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
400 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
401 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
402 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
403 "r_shadow_scissor : use scissor optimization\n"
404 "r_shadow_polygonfactor : nudge shadow volumes closer/further\n"
405 "r_shadow_polygonoffset : nudge shadow volumes closer/further\n"
406 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
407 "r_showlighting : useful for performance testing; bright = slow!\n"
408 "r_showshadowvolumes : useful for performance testing; bright = slow!\n"
410 "r_shadow_help : this help\n"
414 void R_Shadow_Init(void)
416 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
417 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
418 Cvar_RegisterVariable(&r_shadow_usenormalmap);
419 Cvar_RegisterVariable(&r_shadow_debuglight);
420 Cvar_RegisterVariable(&r_shadow_gloss);
421 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
422 Cvar_RegisterVariable(&r_shadow_glossintensity);
423 Cvar_RegisterVariable(&r_shadow_glossexponent);
424 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
425 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
426 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
427 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
428 Cvar_RegisterVariable(&r_shadow_portallight);
429 Cvar_RegisterVariable(&r_shadow_projectdistance);
430 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
431 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
432 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
433 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
434 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
435 Cvar_RegisterVariable(&r_shadow_realtime_world);
436 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
437 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
438 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
439 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
440 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
441 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
442 Cvar_RegisterVariable(&r_shadow_scissor);
443 Cvar_RegisterVariable(&r_shadow_culltriangles);
444 Cvar_RegisterVariable(&r_shadow_polygonfactor);
445 Cvar_RegisterVariable(&r_shadow_polygonoffset);
446 Cvar_RegisterVariable(&r_shadow_texture3d);
447 Cvar_RegisterVariable(&gl_ext_separatestencil);
448 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
449 if (gamemode == GAME_TENEBRAE)
451 Cvar_SetValue("r_shadow_gloss", 2);
452 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
454 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f, "prints documentation on console commands and variables used by realtime lighting and shadowing system");
455 R_Shadow_EditLights_Init();
456 r_shadow_worldlightchain = NULL;
457 maxshadowtriangles = 0;
458 shadowelements = NULL;
459 maxshadowvertices = 0;
460 shadowvertex3f = NULL;
468 shadowmarklist = NULL;
470 r_shadow_buffer_numleafpvsbytes = 0;
471 r_shadow_buffer_leafpvs = NULL;
472 r_shadow_buffer_leaflist = NULL;
473 r_shadow_buffer_numsurfacepvsbytes = 0;
474 r_shadow_buffer_surfacepvs = NULL;
475 r_shadow_buffer_surfacelist = NULL;
476 r_shadow_buffer_shadowtrispvs = NULL;
477 r_shadow_buffer_lighttrispvs = NULL;
478 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
481 matrix4x4_t matrix_attenuationxyz =
484 {0.5, 0.0, 0.0, 0.5},
485 {0.0, 0.5, 0.0, 0.5},
486 {0.0, 0.0, 0.5, 0.5},
491 matrix4x4_t matrix_attenuationz =
494 {0.0, 0.0, 0.5, 0.5},
495 {0.0, 0.0, 0.0, 0.5},
496 {0.0, 0.0, 0.0, 0.5},
501 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles)
503 // make sure shadowelements is big enough for this volume
504 if (maxshadowtriangles < numtriangles)
506 maxshadowtriangles = numtriangles;
508 Mem_Free(shadowelements);
509 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[24]));
511 // make sure shadowvertex3f is big enough for this volume
512 if (maxshadowvertices < numvertices)
514 maxshadowvertices = numvertices;
516 Mem_Free(shadowvertex3f);
517 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[6]));
521 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
523 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
524 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
525 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
526 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
527 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
529 if (r_shadow_buffer_leafpvs)
530 Mem_Free(r_shadow_buffer_leafpvs);
531 if (r_shadow_buffer_leaflist)
532 Mem_Free(r_shadow_buffer_leaflist);
533 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
534 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
535 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
537 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
539 if (r_shadow_buffer_surfacepvs)
540 Mem_Free(r_shadow_buffer_surfacepvs);
541 if (r_shadow_buffer_surfacelist)
542 Mem_Free(r_shadow_buffer_surfacelist);
543 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
544 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
545 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
547 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
549 if (r_shadow_buffer_shadowtrispvs)
550 Mem_Free(r_shadow_buffer_shadowtrispvs);
551 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
552 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
554 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
556 if (r_shadow_buffer_lighttrispvs)
557 Mem_Free(r_shadow_buffer_lighttrispvs);
558 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
559 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
563 void R_Shadow_PrepareShadowMark(int numtris)
565 // make sure shadowmark is big enough for this volume
566 if (maxshadowmark < numtris)
568 maxshadowmark = numtris;
570 Mem_Free(shadowmark);
572 Mem_Free(shadowmarklist);
573 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
574 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
578 // if shadowmarkcount wrapped we clear the array and adjust accordingly
579 if (shadowmarkcount == 0)
582 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
587 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)
590 int outtriangles = 0, outvertices = 0;
593 float ratio, direction[3], projectvector[3];
595 if (projectdirection)
596 VectorScale(projectdirection, projectdistance, projectvector);
598 VectorClear(projectvector);
600 if (maxvertexupdate < innumvertices)
602 maxvertexupdate = innumvertices;
604 Mem_Free(vertexupdate);
606 Mem_Free(vertexremap);
607 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
608 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
612 if (vertexupdatenum == 0)
615 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
616 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
619 for (i = 0;i < numshadowmarktris;i++)
620 shadowmark[shadowmarktris[i]] = shadowmarkcount;
622 // create the vertices
623 if (projectdirection)
625 for (i = 0;i < numshadowmarktris;i++)
627 element = inelement3i + shadowmarktris[i] * 3;
628 for (j = 0;j < 3;j++)
630 if (vertexupdate[element[j]] != vertexupdatenum)
632 vertexupdate[element[j]] = vertexupdatenum;
633 vertexremap[element[j]] = outvertices;
634 vertex = invertex3f + element[j] * 3;
635 // project one copy of the vertex according to projectvector
636 VectorCopy(vertex, outvertex3f);
637 VectorAdd(vertex, projectvector, (outvertex3f + 3));
646 for (i = 0;i < numshadowmarktris;i++)
648 element = inelement3i + shadowmarktris[i] * 3;
649 for (j = 0;j < 3;j++)
651 if (vertexupdate[element[j]] != vertexupdatenum)
653 vertexupdate[element[j]] = vertexupdatenum;
654 vertexremap[element[j]] = outvertices;
655 vertex = invertex3f + element[j] * 3;
656 // project one copy of the vertex to the sphere radius of the light
657 // (FIXME: would projecting it to the light box be better?)
658 VectorSubtract(vertex, projectorigin, direction);
659 ratio = projectdistance / VectorLength(direction);
660 VectorCopy(vertex, outvertex3f);
661 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
669 if (r_shadow_frontsidecasting.integer)
671 for (i = 0;i < numshadowmarktris;i++)
673 int remappedelement[3];
675 const int *neighbortriangle;
677 markindex = shadowmarktris[i] * 3;
678 element = inelement3i + markindex;
679 neighbortriangle = inneighbor3i + markindex;
680 // output the front and back triangles
681 outelement3i[0] = vertexremap[element[0]];
682 outelement3i[1] = vertexremap[element[1]];
683 outelement3i[2] = vertexremap[element[2]];
684 outelement3i[3] = vertexremap[element[2]] + 1;
685 outelement3i[4] = vertexremap[element[1]] + 1;
686 outelement3i[5] = vertexremap[element[0]] + 1;
690 // output the sides (facing outward from this triangle)
691 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
693 remappedelement[0] = vertexremap[element[0]];
694 remappedelement[1] = vertexremap[element[1]];
695 outelement3i[0] = remappedelement[1];
696 outelement3i[1] = remappedelement[0];
697 outelement3i[2] = remappedelement[0] + 1;
698 outelement3i[3] = remappedelement[1];
699 outelement3i[4] = remappedelement[0] + 1;
700 outelement3i[5] = remappedelement[1] + 1;
705 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
707 remappedelement[1] = vertexremap[element[1]];
708 remappedelement[2] = vertexremap[element[2]];
709 outelement3i[0] = remappedelement[2];
710 outelement3i[1] = remappedelement[1];
711 outelement3i[2] = remappedelement[1] + 1;
712 outelement3i[3] = remappedelement[2];
713 outelement3i[4] = remappedelement[1] + 1;
714 outelement3i[5] = remappedelement[2] + 1;
719 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
721 remappedelement[0] = vertexremap[element[0]];
722 remappedelement[2] = vertexremap[element[2]];
723 outelement3i[0] = remappedelement[0];
724 outelement3i[1] = remappedelement[2];
725 outelement3i[2] = remappedelement[2] + 1;
726 outelement3i[3] = remappedelement[0];
727 outelement3i[4] = remappedelement[2] + 1;
728 outelement3i[5] = remappedelement[0] + 1;
737 for (i = 0;i < numshadowmarktris;i++)
739 int remappedelement[3];
741 const int *neighbortriangle;
743 markindex = shadowmarktris[i] * 3;
744 element = inelement3i + markindex;
745 neighbortriangle = inneighbor3i + markindex;
746 // output the front and back triangles
747 outelement3i[0] = vertexremap[element[2]];
748 outelement3i[1] = vertexremap[element[1]];
749 outelement3i[2] = vertexremap[element[0]];
750 outelement3i[3] = vertexremap[element[0]] + 1;
751 outelement3i[4] = vertexremap[element[1]] + 1;
752 outelement3i[5] = vertexremap[element[2]] + 1;
756 // output the sides (facing outward from this triangle)
757 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
759 remappedelement[0] = vertexremap[element[0]];
760 remappedelement[1] = vertexremap[element[1]];
761 outelement3i[0] = remappedelement[0];
762 outelement3i[1] = remappedelement[1];
763 outelement3i[2] = remappedelement[1] + 1;
764 outelement3i[3] = remappedelement[0];
765 outelement3i[4] = remappedelement[1] + 1;
766 outelement3i[5] = remappedelement[0] + 1;
771 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
773 remappedelement[1] = vertexremap[element[1]];
774 remappedelement[2] = vertexremap[element[2]];
775 outelement3i[0] = remappedelement[1];
776 outelement3i[1] = remappedelement[2];
777 outelement3i[2] = remappedelement[2] + 1;
778 outelement3i[3] = remappedelement[1];
779 outelement3i[4] = remappedelement[2] + 1;
780 outelement3i[5] = remappedelement[1] + 1;
785 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
787 remappedelement[0] = vertexremap[element[0]];
788 remappedelement[2] = vertexremap[element[2]];
789 outelement3i[0] = remappedelement[2];
790 outelement3i[1] = remappedelement[0];
791 outelement3i[2] = remappedelement[0] + 1;
792 outelement3i[3] = remappedelement[2];
793 outelement3i[4] = remappedelement[0] + 1;
794 outelement3i[5] = remappedelement[2] + 1;
802 *outnumvertices = outvertices;
806 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)
809 if (projectdistance < 0.1)
811 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
814 if (!numverts || !nummarktris)
816 // make sure shadowelements is big enough for this volume
817 if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
818 R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
819 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
820 r_refdef.stats.lights_dynamicshadowtriangles += tris;
821 R_Shadow_RenderVolume(outverts, tris, shadowvertex3f, shadowelements);
824 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)
830 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
832 tend = firsttriangle + numtris;
833 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
835 // surface box entirely inside light box, no box cull
836 if (projectdirection)
838 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
840 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
841 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
842 shadowmarklist[numshadowmark++] = t;
847 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
848 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
849 shadowmarklist[numshadowmark++] = t;
854 // surface box not entirely inside light box, cull each triangle
855 if (projectdirection)
857 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
859 v[0] = invertex3f + e[0] * 3;
860 v[1] = invertex3f + e[1] * 3;
861 v[2] = invertex3f + e[2] * 3;
862 TriangleNormal(v[0], v[1], v[2], normal);
863 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
864 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
865 shadowmarklist[numshadowmark++] = t;
870 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
872 v[0] = invertex3f + e[0] * 3;
873 v[1] = invertex3f + e[1] * 3;
874 v[2] = invertex3f + e[2] * 3;
875 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
876 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
877 shadowmarklist[numshadowmark++] = t;
883 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
885 if (r_shadow_compilingrtlight)
887 // if we're compiling an rtlight, capture the mesh
888 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
891 r_refdef.stats.lights_shadowtriangles += numtriangles;
893 R_Mesh_VertexPointer(vertex3f, 0, 0);
894 GL_LockArrays(0, numvertices);
895 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
897 // decrement stencil if backface is behind depthbuffer
898 GL_CullFace(r_view.cullface_front);
899 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
900 R_Mesh_Draw(0, numvertices, numtriangles, element3i, 0, 0);
901 // increment stencil if frontface is behind depthbuffer
902 GL_CullFace(r_view.cullface_back);
903 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
905 R_Mesh_Draw(0, numvertices, numtriangles, element3i, 0, 0);
910 static unsigned char R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
912 float dist = sqrt(x*x+y*y+z*z);
913 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
914 return (unsigned char)bound(0, intensity * 256.0f, 255);
917 static void R_Shadow_MakeTextures(void)
920 float intensity, dist;
922 unsigned int palette[256];
923 R_FreeTexturePool(&r_shadow_texturepool);
924 r_shadow_texturepool = R_AllocTexturePool();
925 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
926 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
927 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
928 for (x = 0;x < 256;x++)
929 palette[x] = x * 0x01010101;
930 data = (unsigned char *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE));
931 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
932 for (x = 0;x <= ATTENTABLESIZE;x++)
934 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
935 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
936 r_shadow_attentable[x] = bound(0, intensity, 1);
938 // 1D gradient texture
939 for (x = 0;x < ATTEN1DSIZE;x++)
940 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
941 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, data, TEXTYPE_PALETTE, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, palette);
943 for (y = 0;y < ATTEN2DSIZE;y++)
944 for (x = 0;x < ATTEN2DSIZE;x++)
945 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);
946 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_PALETTE, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, palette);
948 if (r_shadow_texture3d.integer && gl_texture3d)
950 for (z = 0;z < ATTEN3DSIZE;z++)
951 for (y = 0;y < ATTEN3DSIZE;y++)
952 for (x = 0;x < ATTEN3DSIZE;x++)
953 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));
954 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_PALETTE, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, palette);
957 r_shadow_attenuation3dtexture = NULL;
961 void R_Shadow_ValidateCvars(void)
963 if (r_shadow_texture3d.integer && !gl_texture3d)
964 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
965 if (gl_ext_separatestencil.integer && !gl_support_separatestencil)
966 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
967 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
968 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
971 void R_Shadow_RenderMode_Begin(void)
973 R_Shadow_ValidateCvars();
975 if (!r_shadow_attenuation2dtexture
976 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
977 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
978 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
979 R_Shadow_MakeTextures();
982 R_Mesh_ColorPointer(NULL, 0, 0);
983 R_Mesh_ResetTextureState();
984 GL_BlendFunc(GL_ONE, GL_ZERO);
986 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
989 GL_Color(0, 0, 0, 1);
990 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
992 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
994 if (gl_ext_separatestencil.integer)
995 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
996 else if (gl_ext_stenciltwoside.integer)
997 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
999 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
1001 if (r_glsl.integer && gl_support_fragment_shader)
1002 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1003 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
1004 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
1006 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1009 void R_Shadow_RenderMode_ActiveLight(rtlight_t *rtlight)
1011 rsurface.rtlight = rtlight;
1014 void R_Shadow_RenderMode_Reset(void)
1017 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1019 qglUseProgramObjectARB(0);CHECKGLERROR
1021 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
1023 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1025 R_Mesh_ColorPointer(NULL, 0, 0);
1026 R_Mesh_ResetTextureState();
1027 GL_DepthRange(0, 1);
1029 GL_DepthMask(false);
1030 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1031 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1032 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1033 qglStencilMask(~0);CHECKGLERROR
1034 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1035 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1036 GL_CullFace(r_view.cullface_back);
1037 GL_Color(1, 1, 1, 1);
1038 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
1039 GL_BlendFunc(GL_ONE, GL_ZERO);
1042 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean clearstencil)
1045 R_Shadow_RenderMode_Reset();
1046 GL_ColorMask(0, 0, 0, 0);
1047 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1048 qglDepthFunc(GL_LESS);CHECKGLERROR
1049 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1050 r_shadow_rendermode = r_shadow_shadowingrendermode;
1051 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SEPARATESTENCIL)
1053 GL_CullFace(GL_NONE);
1054 qglStencilOpSeparate(r_view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1055 qglStencilOpSeparate(r_view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1057 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
1059 GL_CullFace(GL_NONE);
1060 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1061 qglActiveStencilFaceEXT(r_view.cullface_front);CHECKGLERROR
1062 qglStencilMask(~0);CHECKGLERROR
1063 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1064 qglActiveStencilFaceEXT(r_view.cullface_back);CHECKGLERROR
1065 qglStencilMask(~0);CHECKGLERROR
1066 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1069 GL_Clear(GL_STENCIL_BUFFER_BIT);
1070 r_refdef.stats.lights_clears++;
1073 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent)
1076 R_Shadow_RenderMode_Reset();
1077 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1080 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1084 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1085 // only draw light where this geometry was already rendered AND the
1086 // stencil is 128 (values other than this mean shadow)
1087 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1089 r_shadow_rendermode = r_shadow_lightingrendermode;
1090 // do global setup needed for the chosen lighting mode
1091 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1093 R_Mesh_TexBind(0, R_GetTexture(r_texture_blanknormalmap)); // normal
1094 R_Mesh_TexBind(1, R_GetTexture(r_texture_white)); // diffuse
1095 R_Mesh_TexBind(2, R_GetTexture(r_texture_white)); // gloss
1096 R_Mesh_TexBindCubeMap(3, R_GetTexture(rsurface.rtlight->currentcubemap)); // light filter
1097 R_Mesh_TexBind(4, R_GetTexture(r_texture_fogattenuation)); // fog
1098 R_Mesh_TexBind(5, R_GetTexture(r_texture_white)); // pants
1099 R_Mesh_TexBind(6, R_GetTexture(r_texture_white)); // shirt
1100 R_Mesh_TexBind(7, R_GetTexture(r_texture_white)); // lightmap
1101 R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap)); // deluxemap
1102 R_Mesh_TexBind(9, R_GetTexture(r_texture_black)); // glow
1103 //R_Mesh_TexMatrix(3, rsurface.entitytolight); // light filter matrix
1104 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1105 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 0);
1110 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
1113 R_Shadow_RenderMode_Reset();
1114 GL_BlendFunc(GL_ONE, GL_ONE);
1115 GL_DepthRange(0, 1);
1116 GL_DepthTest(r_showshadowvolumes.integer < 2);
1117 GL_Color(0.0, 0.0125 * r_view.colorscale, 0.1 * r_view.colorscale, 1);
1118 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1119 GL_CullFace(GL_NONE);
1120 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
1123 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
1126 R_Shadow_RenderMode_Reset();
1127 GL_BlendFunc(GL_ONE, GL_ONE);
1128 GL_DepthRange(0, 1);
1129 GL_DepthTest(r_showlighting.integer < 2);
1130 GL_Color(0.1 * r_view.colorscale, 0.0125 * r_view.colorscale, 0, 1);
1133 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1137 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1138 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1140 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
1143 void R_Shadow_RenderMode_End(void)
1146 R_Shadow_RenderMode_Reset();
1147 R_Shadow_RenderMode_ActiveLight(NULL);
1149 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
1150 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1153 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1155 int i, ix1, iy1, ix2, iy2;
1156 float x1, y1, x2, y2;
1159 mplane_t planes[11];
1160 float vertex3f[256*3];
1162 // if view is inside the light box, just say yes it's visible
1163 if (BoxesOverlap(r_view.origin, r_view.origin, mins, maxs))
1165 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
1169 // create a temporary brush describing the area the light can affect in worldspace
1170 VectorNegate(r_view.frustum[0].normal, planes[ 0].normal);planes[ 0].dist = -r_view.frustum[0].dist;
1171 VectorNegate(r_view.frustum[1].normal, planes[ 1].normal);planes[ 1].dist = -r_view.frustum[1].dist;
1172 VectorNegate(r_view.frustum[2].normal, planes[ 2].normal);planes[ 2].dist = -r_view.frustum[2].dist;
1173 VectorNegate(r_view.frustum[3].normal, planes[ 3].normal);planes[ 3].dist = -r_view.frustum[3].dist;
1174 VectorNegate(r_view.frustum[4].normal, planes[ 4].normal);planes[ 4].dist = -r_view.frustum[4].dist;
1175 VectorSet (planes[ 5].normal, 1, 0, 0); planes[ 5].dist = maxs[0];
1176 VectorSet (planes[ 6].normal, -1, 0, 0); planes[ 6].dist = -mins[0];
1177 VectorSet (planes[ 7].normal, 0, 1, 0); planes[ 7].dist = maxs[1];
1178 VectorSet (planes[ 8].normal, 0, -1, 0); planes[ 8].dist = -mins[1];
1179 VectorSet (planes[ 9].normal, 0, 0, 1); planes[ 9].dist = maxs[2];
1180 VectorSet (planes[10].normal, 0, 0, -1); planes[10].dist = -mins[2];
1182 // turn the brush into a mesh
1183 memset(&mesh, 0, sizeof(rmesh_t));
1184 mesh.maxvertices = 256;
1185 mesh.vertex3f = vertex3f;
1186 mesh.epsilon2 = (1.0f / (32.0f * 32.0f));
1187 R_Mesh_AddBrushMeshFromPlanes(&mesh, 11, planes);
1189 // if that mesh is empty, the light is not visible at all
1190 if (!mesh.numvertices)
1193 if (!r_shadow_scissor.integer)
1196 // if that mesh is not empty, check what area of the screen it covers
1197 x1 = y1 = x2 = y2 = 0;
1199 //Con_Printf("%i vertices to transform...\n", mesh.numvertices);
1200 for (i = 0;i < mesh.numvertices;i++)
1202 VectorCopy(mesh.vertex3f + i * 3, v);
1203 GL_TransformToScreen(v, v2);
1204 //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]);
1207 if (x1 > v2[0]) x1 = v2[0];
1208 if (x2 < v2[0]) x2 = v2[0];
1209 if (y1 > v2[1]) y1 = v2[1];
1210 if (y2 < v2[1]) y2 = v2[1];
1219 // now convert the scissor rectangle to integer screen coordinates
1220 ix1 = (int)(x1 - 1.0f);
1221 iy1 = (int)(y1 - 1.0f);
1222 ix2 = (int)(x2 + 1.0f);
1223 iy2 = (int)(y2 + 1.0f);
1224 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1226 // clamp it to the screen
1227 if (ix1 < r_view.x) ix1 = r_view.x;
1228 if (iy1 < r_view.y) iy1 = r_view.y;
1229 if (ix2 > r_view.x + r_view.width) ix2 = r_view.x + r_view.width;
1230 if (iy2 > r_view.y + r_view.height) iy2 = r_view.y + r_view.height;
1232 // if it is inside out, it's not visible
1233 if (ix2 <= ix1 || iy2 <= iy1)
1236 // the light area is visible, set up the scissor rectangle
1237 GL_Scissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1238 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);CHECKGLERROR
1239 //qglEnable(GL_SCISSOR_TEST);CHECKGLERROR
1240 r_refdef.stats.lights_scissored++;
1244 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
1246 float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1247 float *normal3f = rsurface.normal3f + 3 * firstvertex;
1248 float *color4f = rsurface.array_color4f + 4 * firstvertex;
1249 float dist, dot, distintensity, shadeintensity, v[3], n[3];
1250 if (r_textureunits.integer >= 3)
1252 if (VectorLength2(diffusecolor) > 0)
1254 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1256 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1257 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1258 if ((dot = DotProduct(n, v)) < 0)
1260 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1261 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
1264 VectorCopy(ambientcolor, color4f);
1265 if (r_refdef.fogenabled)
1268 f = FogPoint_Model(vertex3f);
1269 VectorScale(color4f, f, color4f);
1276 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1278 VectorCopy(ambientcolor, color4f);
1279 if (r_refdef.fogenabled)
1282 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1283 f = FogPoint_Model(vertex3f);
1284 VectorScale(color4f, f, color4f);
1290 else if (r_textureunits.integer >= 2)
1292 if (VectorLength2(diffusecolor) > 0)
1294 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1296 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1297 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1299 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1300 if ((dot = DotProduct(n, v)) < 0)
1302 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1303 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1304 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1305 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1309 color4f[0] = ambientcolor[0] * distintensity;
1310 color4f[1] = ambientcolor[1] * distintensity;
1311 color4f[2] = ambientcolor[2] * distintensity;
1313 if (r_refdef.fogenabled)
1316 f = FogPoint_Model(vertex3f);
1317 VectorScale(color4f, f, color4f);
1321 VectorClear(color4f);
1327 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1329 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1330 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1332 color4f[0] = ambientcolor[0] * distintensity;
1333 color4f[1] = ambientcolor[1] * distintensity;
1334 color4f[2] = ambientcolor[2] * distintensity;
1335 if (r_refdef.fogenabled)
1338 f = FogPoint_Model(vertex3f);
1339 VectorScale(color4f, f, color4f);
1343 VectorClear(color4f);
1350 if (VectorLength2(diffusecolor) > 0)
1352 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1354 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1355 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1357 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
1358 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1359 if ((dot = DotProduct(n, v)) < 0)
1361 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1362 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1363 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1364 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1368 color4f[0] = ambientcolor[0] * distintensity;
1369 color4f[1] = ambientcolor[1] * distintensity;
1370 color4f[2] = ambientcolor[2] * distintensity;
1372 if (r_refdef.fogenabled)
1375 f = FogPoint_Model(vertex3f);
1376 VectorScale(color4f, f, color4f);
1380 VectorClear(color4f);
1386 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1388 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1389 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1391 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
1392 color4f[0] = ambientcolor[0] * distintensity;
1393 color4f[1] = ambientcolor[1] * distintensity;
1394 color4f[2] = ambientcolor[2] * distintensity;
1395 if (r_refdef.fogenabled)
1398 f = FogPoint_Model(vertex3f);
1399 VectorScale(color4f, f, color4f);
1403 VectorClear(color4f);
1410 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1412 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
1415 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
1416 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1417 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
1418 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
1419 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
1421 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1423 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
1424 // the cubemap normalizes this for us
1425 out3f[0] = DotProduct(svector3f, lightdir);
1426 out3f[1] = DotProduct(tvector3f, lightdir);
1427 out3f[2] = DotProduct(normal3f, lightdir);
1431 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
1434 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
1435 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1436 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
1437 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
1438 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
1439 float lightdir[3], eyedir[3], halfdir[3];
1440 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1442 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
1443 VectorNormalize(lightdir);
1444 VectorSubtract(rsurface.modelorg, vertex3f, eyedir);
1445 VectorNormalize(eyedir);
1446 VectorAdd(lightdir, eyedir, halfdir);
1447 // the cubemap normalizes this for us
1448 out3f[0] = DotProduct(svector3f, halfdir);
1449 out3f[1] = DotProduct(tvector3f, halfdir);
1450 out3f[2] = DotProduct(normal3f, halfdir);
1454 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)
1456 // used to display how many times a surface is lit for level design purposes
1457 GL_Color(0.1 * r_view.colorscale, 0.025 * r_view.colorscale, 0, 1);
1458 R_Mesh_ColorPointer(NULL, 0, 0);
1459 R_Mesh_ResetTextureState();
1460 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1463 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)
1465 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
1466 R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
1467 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
1468 R_Mesh_TexBind(0, R_GetTexture(rsurface.texture->currentskinframe->nmap));
1469 R_Mesh_TexBind(1, R_GetTexture(rsurface.texture->basetexture));
1470 R_Mesh_TexBind(2, R_GetTexture(rsurface.texture->glosstexture));
1471 R_Mesh_TexBindCubeMap(3, R_GetTexture(rsurface.rtlight->currentcubemap));
1472 R_Mesh_TexBind(4, R_GetTexture(r_texture_fogattenuation));
1473 R_Mesh_TexBind(5, R_GetTexture(rsurface.texture->currentskinframe->pants));
1474 R_Mesh_TexBind(6, R_GetTexture(rsurface.texture->currentskinframe->shirt));
1475 R_Mesh_TexBind(10, R_GetTexture(r_shadow_attenuationgradienttexture));
1476 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
1477 R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
1478 R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
1479 R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
1480 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1482 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1484 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1485 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1487 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1491 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)
1493 // shared final code for all the dot3 layers
1495 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 0);
1496 for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
1498 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
1499 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1503 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)
1506 // colorscale accounts for how much we multiply the brightness
1509 // mult is how many times the final pass of the lighting will be
1510 // performed to get more brightness than otherwise possible.
1512 // Limit mult to 64 for sanity sake.
1514 if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1516 // 3 3D combine path (Geforce3, Radeon 8500)
1517 memset(&m, 0, sizeof(m));
1518 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1519 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1520 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1521 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1522 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1523 m.tex[1] = R_GetTexture(basetexture);
1524 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
1525 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
1526 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
1527 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
1528 m.texcubemap[2] = R_GetTexture(rsurface.rtlight->currentcubemap);
1529 m.pointer_texcoord3f[2] = rsurface.vertex3f;
1530 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
1531 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
1532 m.texmatrix[2] = rsurface.entitytolight;
1533 GL_BlendFunc(GL_ONE, GL_ONE);
1535 else if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1537 // 2 3D combine path (Geforce3, original Radeon)
1538 memset(&m, 0, sizeof(m));
1539 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1540 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1541 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1542 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1543 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1544 m.tex[1] = R_GetTexture(basetexture);
1545 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
1546 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
1547 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
1548 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
1549 GL_BlendFunc(GL_ONE, GL_ONE);
1551 else if (r_textureunits.integer >= 4 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
1553 // 4 2D combine path (Geforce3, Radeon 8500)
1554 memset(&m, 0, sizeof(m));
1555 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1556 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1557 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1558 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1559 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1560 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1561 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1562 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1563 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1564 m.texmatrix[1] = rsurface.entitytoattenuationz;
1565 m.tex[2] = R_GetTexture(basetexture);
1566 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
1567 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
1568 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
1569 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
1570 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1572 m.texcubemap[3] = R_GetTexture(rsurface.rtlight->currentcubemap);
1573 m.pointer_texcoord3f[3] = rsurface.vertex3f;
1574 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
1575 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
1576 m.texmatrix[3] = rsurface.entitytolight;
1578 GL_BlendFunc(GL_ONE, GL_ONE);
1580 else if (r_textureunits.integer >= 3 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
1582 // 3 2D combine path (Geforce3, original Radeon)
1583 memset(&m, 0, sizeof(m));
1584 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1585 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1586 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1587 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1588 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1589 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1590 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1591 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1592 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1593 m.texmatrix[1] = rsurface.entitytoattenuationz;
1594 m.tex[2] = R_GetTexture(basetexture);
1595 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
1596 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
1597 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
1598 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
1599 GL_BlendFunc(GL_ONE, GL_ONE);
1603 // 2/2/2 2D combine path (any dot3 card)
1604 memset(&m, 0, sizeof(m));
1605 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1606 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1607 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1608 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1609 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1610 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1611 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1612 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1613 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1614 m.texmatrix[1] = rsurface.entitytoattenuationz;
1615 R_Mesh_TextureState(&m);
1616 GL_ColorMask(0,0,0,1);
1617 GL_BlendFunc(GL_ONE, GL_ZERO);
1618 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1621 memset(&m, 0, sizeof(m));
1622 m.tex[0] = R_GetTexture(basetexture);
1623 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1624 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1625 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1626 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1627 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1629 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1630 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1631 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1632 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1633 m.texmatrix[1] = rsurface.entitytolight;
1635 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1637 // this final code is shared
1638 R_Mesh_TextureState(&m);
1639 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1642 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)
1645 // colorscale accounts for how much we multiply the brightness
1648 // mult is how many times the final pass of the lighting will be
1649 // performed to get more brightness than otherwise possible.
1651 // Limit mult to 64 for sanity sake.
1653 // generate normalization cubemap texcoords
1654 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
1655 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1657 // 3/2 3D combine path (Geforce3, Radeon 8500)
1658 memset(&m, 0, sizeof(m));
1659 m.tex[0] = R_GetTexture(normalmaptexture);
1660 m.texcombinergb[0] = GL_REPLACE;
1661 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1662 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1663 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1664 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1665 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1666 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1667 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1668 m.pointer_texcoord_bufferobject[1] = 0;
1669 m.pointer_texcoord_bufferoffset[1] = 0;
1670 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1671 m.pointer_texcoord3f[2] = rsurface.vertex3f;
1672 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
1673 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
1674 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
1675 R_Mesh_TextureState(&m);
1676 GL_ColorMask(0,0,0,1);
1677 GL_BlendFunc(GL_ONE, GL_ZERO);
1678 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1681 memset(&m, 0, sizeof(m));
1682 m.tex[0] = R_GetTexture(basetexture);
1683 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1684 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1685 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1686 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1687 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1689 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1690 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1691 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1692 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1693 m.texmatrix[1] = rsurface.entitytolight;
1695 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1697 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
1699 // 1/2/2 3D combine path (original Radeon)
1700 memset(&m, 0, sizeof(m));
1701 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1702 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1703 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1704 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1705 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1706 R_Mesh_TextureState(&m);
1707 GL_ColorMask(0,0,0,1);
1708 GL_BlendFunc(GL_ONE, GL_ZERO);
1709 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1712 memset(&m, 0, sizeof(m));
1713 m.tex[0] = R_GetTexture(normalmaptexture);
1714 m.texcombinergb[0] = GL_REPLACE;
1715 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1716 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1717 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1718 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1719 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1720 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1721 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1722 m.pointer_texcoord_bufferobject[1] = 0;
1723 m.pointer_texcoord_bufferoffset[1] = 0;
1724 R_Mesh_TextureState(&m);
1725 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1726 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1729 memset(&m, 0, sizeof(m));
1730 m.tex[0] = R_GetTexture(basetexture);
1731 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1732 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1733 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1734 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1735 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1737 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1738 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1739 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1740 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1741 m.texmatrix[1] = rsurface.entitytolight;
1743 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1745 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
1747 // 2/2 3D combine path (original Radeon)
1748 memset(&m, 0, sizeof(m));
1749 m.tex[0] = R_GetTexture(normalmaptexture);
1750 m.texcombinergb[0] = GL_REPLACE;
1751 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1752 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1753 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1754 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1755 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1756 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1757 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1758 m.pointer_texcoord_bufferobject[1] = 0;
1759 m.pointer_texcoord_bufferoffset[1] = 0;
1760 R_Mesh_TextureState(&m);
1761 GL_ColorMask(0,0,0,1);
1762 GL_BlendFunc(GL_ONE, GL_ZERO);
1763 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1766 memset(&m, 0, sizeof(m));
1767 m.tex[0] = R_GetTexture(basetexture);
1768 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1769 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1770 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1771 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1772 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1773 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1774 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1775 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1776 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
1777 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1779 else if (r_textureunits.integer >= 4)
1781 // 4/2 2D combine path (Geforce3, Radeon 8500)
1782 memset(&m, 0, sizeof(m));
1783 m.tex[0] = R_GetTexture(normalmaptexture);
1784 m.texcombinergb[0] = GL_REPLACE;
1785 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1786 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1787 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1788 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1789 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1790 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1791 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1792 m.pointer_texcoord_bufferobject[1] = 0;
1793 m.pointer_texcoord_bufferoffset[1] = 0;
1794 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1795 m.pointer_texcoord3f[2] = rsurface.vertex3f;
1796 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
1797 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
1798 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
1799 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1800 m.pointer_texcoord3f[3] = rsurface.vertex3f;
1801 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
1802 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
1803 m.texmatrix[3] = rsurface.entitytoattenuationz;
1804 R_Mesh_TextureState(&m);
1805 GL_ColorMask(0,0,0,1);
1806 GL_BlendFunc(GL_ONE, GL_ZERO);
1807 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1810 memset(&m, 0, sizeof(m));
1811 m.tex[0] = R_GetTexture(basetexture);
1812 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1813 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1814 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1815 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1816 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1818 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1819 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1820 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1821 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1822 m.texmatrix[1] = rsurface.entitytolight;
1824 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1828 // 2/2/2 2D combine path (any dot3 card)
1829 memset(&m, 0, sizeof(m));
1830 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1831 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1832 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1833 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1834 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1835 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1836 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1837 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1838 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1839 m.texmatrix[1] = rsurface.entitytoattenuationz;
1840 R_Mesh_TextureState(&m);
1841 GL_ColorMask(0,0,0,1);
1842 GL_BlendFunc(GL_ONE, GL_ZERO);
1843 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1846 memset(&m, 0, sizeof(m));
1847 m.tex[0] = R_GetTexture(normalmaptexture);
1848 m.texcombinergb[0] = GL_REPLACE;
1849 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1850 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1851 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1852 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1853 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1854 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1855 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1856 m.pointer_texcoord_bufferobject[1] = 0;
1857 m.pointer_texcoord_bufferoffset[1] = 0;
1858 R_Mesh_TextureState(&m);
1859 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1860 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1863 memset(&m, 0, sizeof(m));
1864 m.tex[0] = R_GetTexture(basetexture);
1865 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1866 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1867 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1868 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1869 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1871 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1872 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1873 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1874 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1875 m.texmatrix[1] = rsurface.entitytolight;
1877 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1879 // this final code is shared
1880 R_Mesh_TextureState(&m);
1881 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1884 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)
1886 float glossexponent;
1888 // FIXME: detect blendsquare!
1889 //if (!gl_support_blendsquare)
1892 // generate normalization cubemap texcoords
1893 R_Shadow_GenTexCoords_Specular_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
1894 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
1896 // 2/0/0/1/2 3D combine blendsquare path
1897 memset(&m, 0, sizeof(m));
1898 m.tex[0] = R_GetTexture(normalmaptexture);
1899 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1900 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1901 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1902 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1903 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1904 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1905 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1906 m.pointer_texcoord_bufferobject[1] = 0;
1907 m.pointer_texcoord_bufferoffset[1] = 0;
1908 R_Mesh_TextureState(&m);
1909 GL_ColorMask(0,0,0,1);
1910 // this squares the result
1911 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1912 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1914 // second and third pass
1915 R_Mesh_ResetTextureState();
1916 // square alpha in framebuffer a few times to make it shiny
1917 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1918 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
1919 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1922 memset(&m, 0, sizeof(m));
1923 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1924 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1925 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1926 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1927 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1928 R_Mesh_TextureState(&m);
1929 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1930 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1933 memset(&m, 0, sizeof(m));
1934 m.tex[0] = R_GetTexture(glosstexture);
1935 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1936 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1937 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1938 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1939 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1941 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1942 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1943 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1944 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1945 m.texmatrix[1] = rsurface.entitytolight;
1947 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1949 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
1951 // 2/0/0/2 3D combine blendsquare path
1952 memset(&m, 0, sizeof(m));
1953 m.tex[0] = R_GetTexture(normalmaptexture);
1954 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1955 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1956 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1957 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1958 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1959 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1960 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1961 m.pointer_texcoord_bufferobject[1] = 0;
1962 m.pointer_texcoord_bufferoffset[1] = 0;
1963 R_Mesh_TextureState(&m);
1964 GL_ColorMask(0,0,0,1);
1965 // this squares the result
1966 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1967 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1969 // second and third pass
1970 R_Mesh_ResetTextureState();
1971 // square alpha in framebuffer a few times to make it shiny
1972 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1973 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
1974 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1977 memset(&m, 0, sizeof(m));
1978 m.tex[0] = R_GetTexture(glosstexture);
1979 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1980 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1981 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1982 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1983 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1984 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1985 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1986 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1987 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
1988 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1992 // 2/0/0/2/2 2D combine blendsquare path
1993 memset(&m, 0, sizeof(m));
1994 m.tex[0] = R_GetTexture(normalmaptexture);
1995 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1996 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1997 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1998 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1999 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2000 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2001 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2002 m.pointer_texcoord_bufferobject[1] = 0;
2003 m.pointer_texcoord_bufferoffset[1] = 0;
2004 R_Mesh_TextureState(&m);
2005 GL_ColorMask(0,0,0,1);
2006 // this squares the result
2007 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2008 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2010 // second and third pass
2011 R_Mesh_ResetTextureState();
2012 // square alpha in framebuffer a few times to make it shiny
2013 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2014 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2015 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2018 memset(&m, 0, sizeof(m));
2019 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2020 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2021 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2022 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2023 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2024 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2025 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2026 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2027 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2028 m.texmatrix[1] = rsurface.entitytoattenuationz;
2029 R_Mesh_TextureState(&m);
2030 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2031 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2034 memset(&m, 0, sizeof(m));
2035 m.tex[0] = R_GetTexture(glosstexture);
2036 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2037 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2038 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2039 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2040 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2042 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2043 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2044 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2045 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2046 m.texmatrix[1] = rsurface.entitytolight;
2048 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2050 // this final code is shared
2051 R_Mesh_TextureState(&m);
2052 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
2055 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)
2057 // ARB path (any Geforce, any Radeon)
2058 qboolean doambient = ambientscale > 0;
2059 qboolean dodiffuse = diffusescale > 0;
2060 qboolean dospecular = specularscale > 0;
2061 if (!doambient && !dodiffuse && !dospecular)
2063 R_Mesh_ColorPointer(NULL, 0, 0);
2065 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, basetexture, ambientscale * r_view.colorscale);
2067 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, basetexture, normalmaptexture, diffusescale * r_view.colorscale);
2071 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorpants, pantstexture, ambientscale * r_view.colorscale);
2073 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorpants, pantstexture, normalmaptexture, diffusescale * r_view.colorscale);
2078 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorshirt, shirttexture, ambientscale * r_view.colorscale);
2080 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorshirt, shirttexture, normalmaptexture, diffusescale * r_view.colorscale);
2083 R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_view.colorscale);
2086 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)
2093 int newnumtriangles;
2097 int newelements[4096*3];
2098 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
2099 for (renders = 0;renders < 64;renders++)
2104 newnumtriangles = 0;
2106 // due to low fillrate on the cards this vertex lighting path is
2107 // designed for, we manually cull all triangles that do not
2108 // contain a lit vertex
2109 // this builds batches of triangles from multiple surfaces and
2110 // renders them at once
2111 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2113 if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
2115 if (newnumtriangles)
2117 newfirstvertex = min(newfirstvertex, e[0]);
2118 newlastvertex = max(newlastvertex, e[0]);
2122 newfirstvertex = e[0];
2123 newlastvertex = e[0];
2125 newfirstvertex = min(newfirstvertex, e[1]);
2126 newlastvertex = max(newlastvertex, e[1]);
2127 newfirstvertex = min(newfirstvertex, e[2]);
2128 newlastvertex = max(newlastvertex, e[2]);
2134 if (newnumtriangles >= (int)(sizeof(newelements)/sizeof(float[3])))
2136 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, newnumtriangles, newelements, 0, 0);
2137 newnumtriangles = 0;
2143 if (newnumtriangles >= 1)
2145 // if all triangles are included, use the original array to take advantage of the bufferobject if possible
2146 if (newnumtriangles == numtriangles)
2147 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2149 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, newnumtriangles, newelements, 0, 0);
2152 // if we couldn't find any lit triangles, exit early
2155 // now reduce the intensity for the next overbright pass
2156 // we have to clamp to 0 here incase the drivers have improper
2157 // handling of negative colors
2158 // (some old drivers even have improper handling of >1 color)
2160 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2162 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2164 c[0] = max(0, c[0] - 1);
2165 c[1] = max(0, c[1] - 1);
2166 c[2] = max(0, c[2] - 1);
2178 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)
2180 // OpenGL 1.1 path (anything)
2181 float ambientcolorbase[3], diffusecolorbase[3];
2182 float ambientcolorpants[3], diffusecolorpants[3];
2183 float ambientcolorshirt[3], diffusecolorshirt[3];
2185 VectorScale(lightcolorbase, ambientscale * 2 * r_view.colorscale, ambientcolorbase);
2186 VectorScale(lightcolorbase, diffusescale * 2 * r_view.colorscale, diffusecolorbase);
2187 VectorScale(lightcolorpants, ambientscale * 2 * r_view.colorscale, ambientcolorpants);
2188 VectorScale(lightcolorpants, diffusescale * 2 * r_view.colorscale, diffusecolorpants);
2189 VectorScale(lightcolorshirt, ambientscale * 2 * r_view.colorscale, ambientcolorshirt);
2190 VectorScale(lightcolorshirt, diffusescale * 2 * r_view.colorscale, diffusecolorshirt);
2191 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2192 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
2193 memset(&m, 0, sizeof(m));
2194 m.tex[0] = R_GetTexture(basetexture);
2195 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2196 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2197 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2198 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2199 if (r_textureunits.integer >= 2)
2202 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2203 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2204 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2205 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2206 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2207 if (r_textureunits.integer >= 3)
2209 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
2210 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2211 m.texmatrix[2] = rsurface.entitytoattenuationz;
2212 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2213 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2214 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2217 R_Mesh_TextureState(&m);
2218 //R_Mesh_TexBind(0, R_GetTexture(basetexture));
2219 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, diffusecolorbase, ambientcolorbase);
2222 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
2223 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, diffusecolorpants, ambientcolorpants);
2227 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
2228 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, diffusecolorshirt, ambientcolorshirt);
2232 extern cvar_t gl_lightmaps;
2233 void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset)
2235 float ambientscale, diffusescale, specularscale;
2236 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
2238 // calculate colors to render this texture with
2239 lightcolorbase[0] = rsurface.rtlight->currentcolor[0] * rsurface.texture->dlightcolor[0];
2240 lightcolorbase[1] = rsurface.rtlight->currentcolor[1] * rsurface.texture->dlightcolor[1];
2241 lightcolorbase[2] = rsurface.rtlight->currentcolor[2] * rsurface.texture->dlightcolor[2];
2242 ambientscale = rsurface.rtlight->ambientscale;
2243 diffusescale = rsurface.rtlight->diffusescale;
2244 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2245 if (!r_shadow_usenormalmap.integer)
2247 ambientscale += 1.0f * diffusescale;
2251 if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
2253 GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
2254 GL_PolygonOffset(rsurface.texture->currentpolygonfactor, rsurface.texture->currentpolygonoffset);
2255 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
2256 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_view.cullface_back);
2257 nmap = rsurface.texture->currentskinframe->nmap;
2258 if (gl_lightmaps.integer)
2259 nmap = r_texture_blanknormalmap;
2260 if (rsurface.texture->colormapping && !gl_lightmaps.integer)
2262 qboolean dopants = rsurface.texture->currentskinframe->pants != NULL && VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f);
2263 qboolean doshirt = rsurface.texture->currentskinframe->shirt != NULL && VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f);
2266 lightcolorpants[0] = lightcolorbase[0] * rsurface.colormap_pantscolor[0];
2267 lightcolorpants[1] = lightcolorbase[1] * rsurface.colormap_pantscolor[1];
2268 lightcolorpants[2] = lightcolorbase[2] * rsurface.colormap_pantscolor[2];
2271 VectorClear(lightcolorpants);
2274 lightcolorshirt[0] = lightcolorbase[0] * rsurface.colormap_shirtcolor[0];
2275 lightcolorshirt[1] = lightcolorbase[1] * rsurface.colormap_shirtcolor[1];
2276 lightcolorshirt[2] = lightcolorbase[2] * rsurface.colormap_shirtcolor[2];
2279 VectorClear(lightcolorshirt);
2280 switch (r_shadow_rendermode)
2282 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2283 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2284 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);
2286 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2287 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);
2289 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2290 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);
2292 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2293 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);
2296 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2302 switch (r_shadow_rendermode)
2304 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2305 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2306 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);
2308 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2309 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);
2311 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2312 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);
2314 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2315 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);
2318 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2324 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)
2326 matrix4x4_t tempmatrix = *matrix;
2327 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2329 // if this light has been compiled before, free the associated data
2330 R_RTLight_Uncompile(rtlight);
2332 // clear it completely to avoid any lingering data
2333 memset(rtlight, 0, sizeof(*rtlight));
2335 // copy the properties
2336 rtlight->matrix_lighttoworld = tempmatrix;
2337 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2338 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2339 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2340 VectorCopy(color, rtlight->color);
2341 rtlight->cubemapname[0] = 0;
2342 if (cubemapname && cubemapname[0])
2343 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2344 rtlight->shadow = shadow;
2345 rtlight->corona = corona;
2346 rtlight->style = style;
2347 rtlight->isstatic = isstatic;
2348 rtlight->coronasizescale = coronasizescale;
2349 rtlight->ambientscale = ambientscale;
2350 rtlight->diffusescale = diffusescale;
2351 rtlight->specularscale = specularscale;
2352 rtlight->flags = flags;
2354 // compute derived data
2355 //rtlight->cullradius = rtlight->radius;
2356 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2357 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2358 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2359 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2360 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2361 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2362 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2365 // compiles rtlight geometry
2366 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2367 void R_RTLight_Compile(rtlight_t *rtlight)
2370 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2371 int lighttris, shadowtris, shadowmeshes, shadowmeshtris;
2372 entity_render_t *ent = r_refdef.worldentity;
2373 model_t *model = r_refdef.worldmodel;
2374 unsigned char *data;
2376 // compile the light
2377 rtlight->compiled = true;
2378 rtlight->static_numleafs = 0;
2379 rtlight->static_numleafpvsbytes = 0;
2380 rtlight->static_leaflist = NULL;
2381 rtlight->static_leafpvs = NULL;
2382 rtlight->static_numsurfaces = 0;
2383 rtlight->static_surfacelist = NULL;
2384 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2385 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2386 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2387 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2388 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2389 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2391 if (model && model->GetLightInfo)
2393 // this variable must be set for the CompileShadowVolume code
2394 r_shadow_compilingrtlight = rtlight;
2395 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);
2396 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);
2397 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2398 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
2399 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
2400 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
2401 rtlight->static_numsurfaces = numsurfaces;
2402 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2403 rtlight->static_numleafs = numleafs;
2404 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2405 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2406 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2407 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
2408 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
2409 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
2410 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
2411 if (rtlight->static_numsurfaces)
2412 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2413 if (rtlight->static_numleafs)
2414 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2415 if (rtlight->static_numleafpvsbytes)
2416 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2417 if (rtlight->static_numshadowtrispvsbytes)
2418 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
2419 if (rtlight->static_numlighttrispvsbytes)
2420 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
2421 if (model->CompileShadowVolume && rtlight->shadow)
2422 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2423 // now we're done compiling the rtlight
2424 r_shadow_compilingrtlight = NULL;
2428 // use smallest available cullradius - box radius or light radius
2429 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2430 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2434 if (rtlight->static_meshchain_shadow)
2437 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2440 shadowmeshtris += mesh->numtriangles;
2445 if (rtlight->static_numlighttrispvsbytes)
2446 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
2447 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
2451 if (rtlight->static_numlighttrispvsbytes)
2452 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
2453 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
2456 if (developer.integer >= 10)
2457 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);
2460 void R_RTLight_Uncompile(rtlight_t *rtlight)
2462 if (rtlight->compiled)
2464 if (rtlight->static_meshchain_shadow)
2465 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2466 rtlight->static_meshchain_shadow = NULL;
2467 // these allocations are grouped
2468 if (rtlight->static_surfacelist)
2469 Mem_Free(rtlight->static_surfacelist);
2470 rtlight->static_numleafs = 0;
2471 rtlight->static_numleafpvsbytes = 0;
2472 rtlight->static_leaflist = NULL;
2473 rtlight->static_leafpvs = NULL;
2474 rtlight->static_numsurfaces = 0;
2475 rtlight->static_surfacelist = NULL;
2476 rtlight->static_numshadowtrispvsbytes = 0;
2477 rtlight->static_shadowtrispvs = NULL;
2478 rtlight->static_numlighttrispvsbytes = 0;
2479 rtlight->static_lighttrispvs = NULL;
2480 rtlight->compiled = false;
2484 void R_Shadow_UncompileWorldLights(void)
2487 for (light = r_shadow_worldlightchain;light;light = light->next)
2488 R_RTLight_Uncompile(&light->rtlight);
2491 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
2495 // reset the count of frustum planes
2496 // see rsurface.rtlight_frustumplanes definition for how much this array
2498 rsurface.rtlight_numfrustumplanes = 0;
2500 // haven't implemented a culling path for ortho rendering
2501 if (!r_view.useperspective)
2503 // check if the light is on screen and copy the 4 planes if it is
2504 for (i = 0;i < 4;i++)
2505 if (PlaneDiff(rtlight->shadoworigin, &r_view.frustum[i]) < -0.03125)
2508 for (i = 0;i < 4;i++)
2509 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_view.frustum[i];
2514 // generate a deformed frustum that includes the light origin, this is
2515 // used to cull shadow casting surfaces that can not possibly cast a
2516 // shadow onto the visible light-receiving surfaces, which can be a
2519 // if the light origin is onscreen the result will be 4 planes exactly
2520 // if the light origin is offscreen on only one axis the result will
2521 // be exactly 5 planes (split-side case)
2522 // if the light origin is offscreen on two axes the result will be
2523 // exactly 4 planes (stretched corner case)
2524 for (i = 0;i < 4;i++)
2526 // quickly reject standard frustum planes that put the light
2527 // origin outside the frustum
2528 if (PlaneDiff(rtlight->shadoworigin, &r_view.frustum[i]) < -0.03125)
2531 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_view.frustum[i];
2533 // if all the standard frustum planes were accepted, the light is onscreen
2534 // otherwise we need to generate some more planes below...
2535 if (rsurface.rtlight_numfrustumplanes < 4)
2537 // at least one of the stock frustum planes failed, so we need to
2538 // create one or two custom planes to enclose the light origin
2539 for (i = 0;i < 4;i++)
2541 // create a plane using the view origin and light origin, and a
2542 // single point from the frustum corner set
2543 TriangleNormal(r_view.origin, r_view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
2544 VectorNormalize(plane.normal);
2545 plane.dist = DotProduct(r_view.origin, plane.normal);
2546 // see if this plane is backwards and flip it if so
2547 for (j = 0;j < 4;j++)
2548 if (j != i && DotProduct(r_view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
2552 VectorNegate(plane.normal, plane.normal);
2554 // flipped plane, test again to see if it is now valid
2555 for (j = 0;j < 4;j++)
2556 if (j != i && DotProduct(r_view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
2558 // if the plane is still not valid, then it is dividing the
2559 // frustum and has to be rejected
2563 // we have created a valid plane, compute extra info
2564 PlaneClassify(&plane);
2566 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
2568 // if we've found 5 frustum planes then we have constructed a
2569 // proper split-side case and do not need to keep searching for
2570 // planes to enclose the light origin
2571 if (rsurface.rtlight_numfrustumplanes == 5)
2579 for (i = 0;i < rsurface.rtlight_numfrustumplanes;i++)
2581 plane = rsurface.rtlight_frustumplanes[i];
2582 Con_Printf("light %p plane #%i %f %f %f : %f (%f %f %f %f %f)\n", rtlight, i, plane.normal[0], plane.normal[1], plane.normal[2], plane.dist, PlaneDiff(r_view.frustumcorner[0], &plane), PlaneDiff(r_view.frustumcorner[1], &plane), PlaneDiff(r_view.frustumcorner[2], &plane), PlaneDiff(r_view.frustumcorner[3], &plane), PlaneDiff(rtlight->shadoworigin, &plane));
2587 // now add the light-space box planes if the light box is rotated, as any
2588 // caster outside the oriented light box is irrelevant (even if it passed
2589 // the worldspace light box, which is axial)
2590 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
2592 for (i = 0;i < 6;i++)
2596 v[i >> 1] = (i & 1) ? -1 : 1;
2597 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
2598 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
2599 plane.dist = VectorNormalizeLength(plane.normal);
2600 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
2601 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
2607 // add the world-space reduced box planes
2608 for (i = 0;i < 6;i++)
2610 VectorClear(plane.normal);
2611 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
2612 plane.dist = (i & 1) ? -rsurface.rtlight_cullmaxs[i >> 1] : rsurface.rtlight_cullmins[i >> 1];
2613 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
2622 // reduce all plane distances to tightly fit the rtlight cull box, which
2624 VectorSet(points[0], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
2625 VectorSet(points[1], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
2626 VectorSet(points[2], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
2627 VectorSet(points[3], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
2628 VectorSet(points[4], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
2629 VectorSet(points[5], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
2630 VectorSet(points[6], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
2631 VectorSet(points[7], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
2632 oldnum = rsurface.rtlight_numfrustumplanes;
2633 rsurface.rtlight_numfrustumplanes = 0;
2634 for (j = 0;j < oldnum;j++)
2636 // find the nearest point on the box to this plane
2637 bestdist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[0]);
2638 for (i = 1;i < 8;i++)
2640 dist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[i]);
2641 if (bestdist > dist)
2644 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);
2645 // if the nearest point is near or behind the plane, we want this
2646 // plane, otherwise the plane is useless as it won't cull anything
2647 if (rsurface.rtlight_frustumplanes[j].dist < bestdist + 0.03125)
2649 PlaneClassify(&rsurface.rtlight_frustumplanes[j]);
2650 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = rsurface.rtlight_frustumplanes[j];
2657 void R_Shadow_DrawWorldShadow(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
2659 RSurf_ActiveWorldEntity();
2660 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2664 for (mesh = rsurface.rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2666 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
2667 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
2668 GL_LockArrays(0, mesh->numverts);
2669 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
2671 // decrement stencil if backface is behind depthbuffer
2672 GL_CullFace(r_view.cullface_front);
2673 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2674 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->ebo, 0);
2675 // increment stencil if frontface is behind depthbuffer
2676 GL_CullFace(r_view.cullface_back);
2677 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2679 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->ebo, 0);
2680 GL_LockArrays(0, 0);
2684 else if (numsurfaces && r_refdef.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
2687 int surfacelistindex;
2688 msurface_t *surface;
2689 R_Shadow_PrepareShadowMark(r_refdef.worldmodel->brush.shadowmesh->numtriangles);
2690 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
2692 surface = r_refdef.worldmodel->data_surfaces + surfacelist[surfacelistindex];
2693 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
2694 if (CHECKPVSBIT(trispvs, t))
2695 shadowmarklist[numshadowmark++] = t;
2697 R_Shadow_VolumeFromList(r_refdef.worldmodel->brush.shadowmesh->numverts, r_refdef.worldmodel->brush.shadowmesh->numtriangles, r_refdef.worldmodel->brush.shadowmesh->vertex3f, r_refdef.worldmodel->brush.shadowmesh->element3i, r_refdef.worldmodel->brush.shadowmesh->neighbor3i, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius + r_refdef.worldmodel->radius*2 + r_shadow_projectdistance.value, numshadowmark, shadowmarklist);
2699 else if (numsurfaces)
2700 r_refdef.worldmodel->DrawShadowVolume(r_refdef.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
2703 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
2705 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
2706 vec_t relativeshadowradius;
2707 RSurf_ActiveModelEntity(ent, false, false);
2708 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
2709 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
2710 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
2711 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
2712 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
2713 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
2714 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
2715 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
2716 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2719 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
2721 // set up properties for rendering light onto this entity
2722 RSurf_ActiveModelEntity(ent, true, true);
2723 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
2724 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
2725 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
2726 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
2727 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2728 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
2731 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
2733 if (!r_refdef.worldmodel->DrawLight)
2736 // set up properties for rendering light onto this entity
2737 RSurf_ActiveWorldEntity();
2738 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
2739 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
2740 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
2741 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
2742 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2743 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
2745 r_refdef.worldmodel->DrawLight(r_refdef.worldentity, numsurfaces, surfacelist, trispvs);
2748 void R_Shadow_DrawEntityLight(entity_render_t *ent, int numsurfaces, int *surfacelist)
2750 model_t *model = ent->model;
2751 if (!model->DrawLight)
2754 R_Shadow_SetupEntityLight(ent);
2756 model->DrawLight(ent, model->nummodelsurfaces, model->surfacelist, NULL);
2759 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
2763 int numleafs, numsurfaces;
2764 int *leaflist, *surfacelist;
2765 unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs;
2766 int numlightentities;
2767 int numlightentities_noselfshadow;
2768 int numshadowentities;
2769 int numshadowentities_noselfshadow;
2770 entity_render_t *lightentities[MAX_EDICTS];
2771 entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
2772 entity_render_t *shadowentities[MAX_EDICTS];
2773 entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
2775 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
2776 // skip lights that are basically invisible (color 0 0 0)
2777 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
2780 // loading is done before visibility checks because loading should happen
2781 // all at once at the start of a level, not when it stalls gameplay.
2782 // (especially important to benchmarks)
2784 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2785 R_RTLight_Compile(rtlight);
2787 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
2789 // look up the light style value at this time
2790 f = (rtlight->style >= 0 ? r_refdef.lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2791 VectorScale(rtlight->color, f, rtlight->currentcolor);
2793 if (rtlight->selected)
2795 f = 2 + sin(realtime * M_PI * 4.0);
2796 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
2800 // if lightstyle is currently off, don't draw the light
2801 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
2804 // if the light box is offscreen, skip it
2805 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2808 VectorCopy(rtlight->cullmins, rsurface.rtlight_cullmins);
2809 VectorCopy(rtlight->cullmaxs, rsurface.rtlight_cullmaxs);
2811 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2813 // compiled light, world available and can receive realtime lighting
2814 // retrieve leaf information
2815 numleafs = rtlight->static_numleafs;
2816 leaflist = rtlight->static_leaflist;
2817 leafpvs = rtlight->static_leafpvs;
2818 numsurfaces = rtlight->static_numsurfaces;
2819 surfacelist = rtlight->static_surfacelist;
2820 shadowtrispvs = rtlight->static_shadowtrispvs;
2821 lighttrispvs = rtlight->static_lighttrispvs;
2823 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2825 // dynamic light, world available and can receive realtime lighting
2826 // calculate lit surfaces and leafs
2827 R_Shadow_EnlargeLeafSurfaceTrisBuffer(r_refdef.worldmodel->brush.num_leafs, r_refdef.worldmodel->num_surfaces, r_refdef.worldmodel->brush.shadowmesh ? r_refdef.worldmodel->brush.shadowmesh->numtriangles : r_refdef.worldmodel->surfmesh.num_triangles, r_refdef.worldmodel->surfmesh.num_triangles);
2828 r_refdef.worldmodel->GetLightInfo(r_refdef.worldentity, rtlight->shadoworigin, rtlight->radius, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs, r_shadow_buffer_leaflist, r_shadow_buffer_leafpvs, &numleafs, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces, r_shadow_buffer_shadowtrispvs, r_shadow_buffer_lighttrispvs);
2829 leaflist = r_shadow_buffer_leaflist;
2830 leafpvs = r_shadow_buffer_leafpvs;
2831 surfacelist = r_shadow_buffer_surfacelist;
2832 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
2833 lighttrispvs = r_shadow_buffer_lighttrispvs;
2834 // if the reduced leaf bounds are offscreen, skip it
2835 if (R_CullBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
2846 shadowtrispvs = NULL;
2847 lighttrispvs = NULL;
2849 // check if light is illuminating any visible leafs
2852 for (i = 0;i < numleafs;i++)
2853 if (r_viewcache.world_leafvisible[leaflist[i]])
2858 // set up a scissor rectangle for this light
2859 if (R_Shadow_ScissorForBBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
2862 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
2864 // make a list of lit entities and shadow casting entities
2865 numlightentities = 0;
2866 numlightentities_noselfshadow = 0;
2867 numshadowentities = 0;
2868 numshadowentities_noselfshadow = 0;
2869 // add dynamic entities that are lit by the light
2870 if (r_drawentities.integer)
2872 for (i = 0;i < r_refdef.numentities;i++)
2875 entity_render_t *ent = r_refdef.entities[i];
2877 if (!BoxesOverlap(ent->mins, ent->maxs, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
2879 // skip the object entirely if it is not within the valid
2880 // shadow-casting region (which includes the lit region)
2881 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rsurface.rtlight_numfrustumplanes, rsurface.rtlight_frustumplanes))
2883 if (!(model = ent->model))
2885 if (r_viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
2887 // this entity wants to receive light, is visible, and is
2888 // inside the light box
2889 // TODO: check if the surfaces in the model can receive light
2890 // so now check if it's in a leaf seen by the light
2891 if (r_refdef.worldmodel && r_refdef.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs))
2893 if (ent->flags & RENDER_NOSELFSHADOW)
2894 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
2896 lightentities[numlightentities++] = ent;
2897 // since it is lit, it probably also casts a shadow...
2898 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2899 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
2900 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
2902 // note: exterior models without the RENDER_NOSELFSHADOW
2903 // flag still create a RENDER_NOSELFSHADOW shadow but
2904 // are lit normally, this means that they are
2905 // self-shadowing but do not shadow other
2906 // RENDER_NOSELFSHADOW entities such as the gun
2907 // (very weird, but keeps the player shadow off the gun)
2908 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
2909 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
2911 shadowentities[numshadowentities++] = ent;
2914 else if (ent->flags & RENDER_SHADOW)
2916 // this entity is not receiving light, but may still need to
2918 // TODO: check if the surfaces in the model can cast shadow
2919 // now check if it is in a leaf seen by the light
2920 if (r_refdef.worldmodel && r_refdef.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs))
2922 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2923 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
2924 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
2926 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
2927 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
2929 shadowentities[numshadowentities++] = ent;
2935 // return if there's nothing at all to light
2936 if (!numlightentities && !numsurfaces)
2939 // don't let sound skip if going slow
2940 if (r_refdef.extraupdate)
2943 // make this the active rtlight for rendering purposes
2944 R_Shadow_RenderMode_ActiveLight(rtlight);
2945 // count this light in the r_speeds
2946 r_refdef.stats.lights++;
2948 if (r_showshadowvolumes.integer && r_view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.rtworldshadows : r_refdef.rtdlightshadows))
2950 // optionally draw visible shape of the shadow volumes
2951 // for performance analysis by level designers
2952 R_Shadow_RenderMode_VisibleShadowVolumes();
2954 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
2955 for (i = 0;i < numshadowentities;i++)
2956 R_Shadow_DrawEntityShadow(shadowentities[i]);
2957 for (i = 0;i < numshadowentities_noselfshadow;i++)
2958 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
2961 if (gl_stencil && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.rtworldshadows : r_refdef.rtdlightshadows))
2963 // draw stencil shadow volumes to mask off pixels that are in shadow
2964 // so that they won't receive lighting
2965 R_Shadow_RenderMode_StencilShadowVolumes(true);
2967 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
2968 for (i = 0;i < numshadowentities;i++)
2969 R_Shadow_DrawEntityShadow(shadowentities[i]);
2970 if (numlightentities_noselfshadow)
2972 // draw lighting in the unmasked areas
2973 R_Shadow_RenderMode_Lighting(true, false);
2974 for (i = 0;i < numlightentities_noselfshadow;i++)
2975 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i], numsurfaces, surfacelist);
2977 // optionally draw the illuminated areas
2978 // for performance analysis by level designers
2979 if (r_showlighting.integer && r_view.showdebug)
2981 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
2982 for (i = 0;i < numlightentities_noselfshadow;i++)
2983 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i], numsurfaces, surfacelist);
2986 R_Shadow_RenderMode_StencilShadowVolumes(false);
2988 for (i = 0;i < numshadowentities_noselfshadow;i++)
2989 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
2991 if (numsurfaces + numlightentities)
2993 // draw lighting in the unmasked areas
2994 R_Shadow_RenderMode_Lighting(true, false);
2996 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
2997 for (i = 0;i < numlightentities;i++)
2998 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
3000 // optionally draw the illuminated areas
3001 // for performance analysis by level designers
3002 if (r_showlighting.integer && r_view.showdebug)
3004 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
3006 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3007 for (i = 0;i < numlightentities;i++)
3008 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
3014 if (numsurfaces + numlightentities)
3016 // draw lighting in the unmasked areas
3017 R_Shadow_RenderMode_Lighting(false, false);
3019 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3020 for (i = 0;i < numlightentities;i++)
3021 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
3022 for (i = 0;i < numlightentities_noselfshadow;i++)
3023 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i], numsurfaces, surfacelist);
3025 // optionally draw the illuminated areas
3026 // for performance analysis by level designers
3027 if (r_showlighting.integer && r_view.showdebug)
3029 R_Shadow_RenderMode_VisibleLighting(false, false);
3031 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3032 for (i = 0;i < numlightentities;i++)
3033 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
3034 for (i = 0;i < numlightentities_noselfshadow;i++)
3035 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i], numsurfaces, surfacelist);
3041 void R_Shadow_DrawLightSprites(void);
3042 void R_ShadowVolumeLighting(qboolean visible)
3047 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
3048 R_Shadow_EditLights_Reload_f();
3050 if (r_editlights.integer)
3051 R_Shadow_DrawLightSprites();
3053 R_Shadow_RenderMode_Begin();
3055 flag = r_refdef.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3056 if (r_shadow_debuglight.integer >= 0)
3058 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
3059 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
3060 R_DrawRTLight(&light->rtlight, visible);
3063 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
3064 if (light->flags & flag)
3065 R_DrawRTLight(&light->rtlight, visible);
3066 if (r_refdef.rtdlight)
3067 for (lnum = 0;lnum < r_refdef.numlights;lnum++)
3068 R_DrawRTLight(&r_refdef.lights[lnum], visible);
3070 R_Shadow_RenderMode_End();
3073 extern void R_SetupView(void);
3074 extern cvar_t r_shadows_throwdistance;
3075 void R_DrawModelShadows(void)
3078 float relativethrowdistance;
3079 entity_render_t *ent;
3080 vec3_t relativelightorigin;
3081 vec3_t relativelightdirection;
3082 vec3_t relativeshadowmins, relativeshadowmaxs;
3085 if (!r_drawentities.integer || !gl_stencil)
3089 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
3091 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
3093 if (gl_ext_separatestencil.integer)
3094 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
3095 else if (gl_ext_stenciltwoside.integer)
3096 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
3098 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
3100 R_Shadow_RenderMode_StencilShadowVolumes(true);
3102 for (i = 0;i < r_refdef.numentities;i++)
3104 ent = r_refdef.entities[i];
3105 // cast shadows from anything that is not a submodel of the map
3106 if (ent->model && ent->model->DrawShadowVolume != NULL && !ent->model->brush.submodel && (ent->flags & RENDER_SHADOW))
3108 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
3109 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
3110 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
3111 VectorNegate(ent->modellight_lightdir, relativelightdirection);
3112 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
3113 RSurf_ActiveModelEntity(ent, false, false);
3114 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
3118 // not really the right mode, but this will disable any silly stencil features
3119 R_Shadow_RenderMode_VisibleLighting(true, true);
3121 // vertex coordinates for a quad that covers the screen exactly
3122 vertex3f[0] = 0;vertex3f[1] = 0;vertex3f[2] = 0;
3123 vertex3f[3] = 1;vertex3f[4] = 0;vertex3f[5] = 0;
3124 vertex3f[6] = 1;vertex3f[7] = 1;vertex3f[8] = 0;
3125 vertex3f[9] = 0;vertex3f[10] = 1;vertex3f[11] = 0;
3127 // set up ortho view for rendering this pass
3128 GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
3129 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
3130 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
3131 GL_ScissorTest(true);
3132 R_Mesh_Matrix(&identitymatrix);
3133 R_Mesh_ResetTextureState();
3134 R_Mesh_VertexPointer(vertex3f, 0, 0);
3135 R_Mesh_ColorPointer(NULL, 0, 0);
3137 // set up a 50% darkening blend on shadowed areas
3138 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3139 GL_DepthRange(0, 1);
3140 GL_DepthTest(false);
3141 GL_DepthMask(false);
3142 GL_PolygonOffset(0, 0);CHECKGLERROR
3143 GL_Color(0, 0, 0, 0.5);
3144 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
3145 qglDepthFunc(GL_ALWAYS);CHECKGLERROR
3146 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
3147 qglStencilMask(~0);CHECKGLERROR
3148 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
3149 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
3151 // apply the blend to the shadowed areas
3152 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3154 // restoring the perspective view is done by R_RenderScene
3157 // restore other state to normal
3158 R_Shadow_RenderMode_End();
3162 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
3163 typedef struct suffixinfo_s
3166 qboolean flipx, flipy, flipdiagonal;
3169 static suffixinfo_t suffix[3][6] =
3172 {"px", false, false, false},
3173 {"nx", false, false, false},
3174 {"py", false, false, false},
3175 {"ny", false, false, false},
3176 {"pz", false, false, false},
3177 {"nz", false, false, false}
3180 {"posx", false, false, false},
3181 {"negx", false, false, false},
3182 {"posy", false, false, false},
3183 {"negy", false, false, false},
3184 {"posz", false, false, false},
3185 {"negz", false, false, false}
3188 {"rt", true, false, true},
3189 {"lf", false, true, true},
3190 {"ft", true, true, false},
3191 {"bk", false, false, false},
3192 {"up", true, false, true},
3193 {"dn", true, false, true}
3197 static int componentorder[4] = {0, 1, 2, 3};
3199 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
3201 int i, j, cubemapsize;
3202 unsigned char *cubemappixels, *image_rgba;
3203 rtexture_t *cubemaptexture;
3205 // must start 0 so the first loadimagepixels has no requested width/height
3207 cubemappixels = NULL;
3208 cubemaptexture = NULL;
3209 // keep trying different suffix groups (posx, px, rt) until one loads
3210 for (j = 0;j < 3 && !cubemappixels;j++)
3212 // load the 6 images in the suffix group
3213 for (i = 0;i < 6;i++)
3215 // generate an image name based on the base and and suffix
3216 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
3218 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
3220 // an image loaded, make sure width and height are equal
3221 if (image_width == image_height)
3223 // if this is the first image to load successfully, allocate the cubemap memory
3224 if (!cubemappixels && image_width >= 1)
3226 cubemapsize = image_width;
3227 // note this clears to black, so unavailable sides are black
3228 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
3230 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
3232 Image_CopyMux(cubemappixels+i*cubemapsize*cubemapsize*4, image_rgba, cubemapsize, cubemapsize, suffix[j][i].flipx, suffix[j][i].flipy, suffix[j][i].flipdiagonal, 4, 4, componentorder);
3235 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
3237 Mem_Free(image_rgba);
3241 // if a cubemap loaded, upload it
3244 if (!r_shadow_filters_texturepool)
3245 r_shadow_filters_texturepool = R_AllocTexturePool();
3246 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE | (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0), NULL);
3247 Mem_Free(cubemappixels);
3251 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
3252 for (j = 0;j < 3;j++)
3253 for (i = 0;i < 6;i++)
3254 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
3255 Con_Print(" and was unable to find any of them.\n");
3257 return cubemaptexture;
3260 rtexture_t *R_Shadow_Cubemap(const char *basename)
3263 for (i = 0;i < numcubemaps;i++)
3264 if (!strcasecmp(cubemaps[i].basename, basename))
3265 return cubemaps[i].texture;
3266 if (i >= MAX_CUBEMAPS)
3267 return r_texture_whitecube;
3269 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
3270 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
3271 if (!cubemaps[i].texture)
3272 cubemaps[i].texture = r_texture_whitecube;
3273 return cubemaps[i].texture;
3276 void R_Shadow_FreeCubemaps(void)
3279 R_FreeTexturePool(&r_shadow_filters_texturepool);
3282 dlight_t *R_Shadow_NewWorldLight(void)
3285 light = (dlight_t *)Mem_Alloc(r_main_mempool, sizeof(dlight_t));
3286 light->next = r_shadow_worldlightchain;
3287 r_shadow_worldlightchain = light;
3291 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)
3294 // validate parameters
3295 if (style < 0 || style >= MAX_LIGHTSTYLES)
3297 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
3303 // copy to light properties
3304 VectorCopy(origin, light->origin);
3305 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
3306 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
3307 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
3308 light->color[0] = max(color[0], 0);
3309 light->color[1] = max(color[1], 0);
3310 light->color[2] = max(color[2], 0);
3311 light->radius = max(radius, 0);
3312 light->style = style;
3313 light->shadow = shadowenable;
3314 light->corona = corona;
3315 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
3316 light->coronasizescale = coronasizescale;
3317 light->ambientscale = ambientscale;
3318 light->diffusescale = diffusescale;
3319 light->specularscale = specularscale;
3320 light->flags = flags;
3322 // update renderable light data
3323 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
3324 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);
3327 void R_Shadow_FreeWorldLight(dlight_t *light)
3329 dlight_t **lightpointer;
3330 R_RTLight_Uncompile(&light->rtlight);
3331 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
3332 if (*lightpointer != light)
3333 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain");
3334 *lightpointer = light->next;
3338 void R_Shadow_ClearWorldLights(void)
3340 while (r_shadow_worldlightchain)
3341 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
3342 r_shadow_selectedlight = NULL;
3343 R_Shadow_FreeCubemaps();
3346 void R_Shadow_SelectLight(dlight_t *light)
3348 if (r_shadow_selectedlight)
3349 r_shadow_selectedlight->selected = false;
3350 r_shadow_selectedlight = light;
3351 if (r_shadow_selectedlight)
3352 r_shadow_selectedlight->selected = true;
3355 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
3357 // this is never batched (there can be only one)
3358 float scale = r_editlights_cursorgrid.value * 0.5f;
3359 R_DrawSprite(GL_SRC_ALPHA, GL_ONE, r_crosshairs[1]->tex, NULL, false, false, r_editlights_cursorlocation, r_view.right, r_view.up, scale, -scale, -scale, scale, 1, 1, 1, 0.5f);
3362 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
3364 // this is never batched (due to the ent parameter changing every time)
3365 // so numsurfaces == 1 and surfacelist[0] == lightnumber
3367 const dlight_t *light = (dlight_t *)ent;
3369 if (light->selected)
3370 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
3373 R_DrawSprite(GL_SRC_ALPHA, GL_ONE, r_crosshairs[surfacelist[0]]->tex, NULL, false, false, light->origin, r_view.right, r_view.up, 8, -8, -8, 8, intensity, intensity, intensity, 0.5f);
3376 void R_Shadow_DrawLightSprites(void)
3381 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
3382 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 1+(i % 5), &light->rtlight);
3383 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
3386 void R_Shadow_SelectLightInView(void)
3388 float bestrating, rating, temp[3];
3389 dlight_t *best, *light;
3392 for (light = r_shadow_worldlightchain;light;light = light->next)
3394 VectorSubtract(light->origin, r_view.origin, temp);
3395 rating = (DotProduct(temp, r_view.forward) / sqrt(DotProduct(temp, temp)));
3398 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
3399 if (bestrating < rating && CL_Move(light->origin, vec3_origin, vec3_origin, r_view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
3401 bestrating = rating;
3406 R_Shadow_SelectLight(best);
3409 void R_Shadow_LoadWorldLights(void)
3411 int n, a, style, shadow, flags;
3412 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
3413 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
3414 if (r_refdef.worldmodel == NULL)
3416 Con_Print("No map loaded.\n");
3419 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3420 strlcat (name, ".rtlights", sizeof (name));
3421 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3431 for (;COM_Parse(t, true) && strcmp(
3432 if (COM_Parse(t, true))
3434 if (com_token[0] == '!')
3437 origin[0] = atof(com_token+1);
3440 origin[0] = atof(com_token);
3445 while (*s && *s != '\n' && *s != '\r')
3451 // check for modifier flags
3458 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);
3461 flags = LIGHTFLAG_REALTIMEMODE;
3469 coronasizescale = 0.25f;
3471 VectorClear(angles);
3474 if (a < 9 || !strcmp(cubemapname, "\"\""))
3476 // remove quotes on cubemapname
3477 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
3480 namelen = strlen(cubemapname) - 2;
3481 memmove(cubemapname, cubemapname + 1, namelen);
3482 cubemapname[namelen] = '\0';
3486 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);
3489 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3497 Con_Printf("invalid rtlights file \"%s\"\n", name);
3498 Mem_Free(lightsstring);
3502 void R_Shadow_SaveWorldLights(void)
3505 size_t bufchars, bufmaxchars;
3507 char name[MAX_QPATH];
3508 char line[MAX_INPUTLINE];
3509 if (!r_shadow_worldlightchain)
3511 if (r_refdef.worldmodel == NULL)
3513 Con_Print("No map loaded.\n");
3516 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3517 strlcat (name, ".rtlights", sizeof (name));
3518 bufchars = bufmaxchars = 0;
3520 for (light = r_shadow_worldlightchain;light;light = light->next)
3522 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3523 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);
3524 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3525 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]);
3527 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);
3528 if (bufchars + strlen(line) > bufmaxchars)
3530 bufmaxchars = bufchars + strlen(line) + 2048;
3532 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
3536 memcpy(buf, oldbuf, bufchars);
3542 memcpy(buf + bufchars, line, strlen(line));
3543 bufchars += strlen(line);
3547 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
3552 void R_Shadow_LoadLightsFile(void)
3555 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3556 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3557 if (r_refdef.worldmodel == NULL)
3559 Con_Print("No map loaded.\n");
3562 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3563 strlcat (name, ".lights", sizeof (name));
3564 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3572 while (*s && *s != '\n' && *s != '\r')
3578 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);
3582 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);
3585 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3586 radius = bound(15, radius, 4096);
3587 VectorScale(color, (2.0f / (8388608.0f)), color);
3588 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3596 Con_Printf("invalid lights file \"%s\"\n", name);
3597 Mem_Free(lightsstring);
3601 // tyrlite/hmap2 light types in the delay field
3602 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3604 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3606 int entnum, style, islight, skin, pflags, effects, type, n;
3609 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3610 char key[256], value[MAX_INPUTLINE];
3612 if (r_refdef.worldmodel == NULL)
3614 Con_Print("No map loaded.\n");
3617 // try to load a .ent file first
3618 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3619 strlcat (key, ".ent", sizeof (key));
3620 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
3621 // and if that is not found, fall back to the bsp file entity string
3623 data = r_refdef.worldmodel->brush.entities;
3626 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
3628 type = LIGHTTYPE_MINUSX;
3629 origin[0] = origin[1] = origin[2] = 0;
3630 originhack[0] = originhack[1] = originhack[2] = 0;
3631 angles[0] = angles[1] = angles[2] = 0;
3632 color[0] = color[1] = color[2] = 1;
3633 light[0] = light[1] = light[2] = 1;light[3] = 300;
3634 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3644 if (!COM_ParseToken_Simple(&data, false, false))
3646 if (com_token[0] == '}')
3647 break; // end of entity
3648 if (com_token[0] == '_')
3649 strlcpy(key, com_token + 1, sizeof(key));
3651 strlcpy(key, com_token, sizeof(key));
3652 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3653 key[strlen(key)-1] = 0;
3654 if (!COM_ParseToken_Simple(&data, false, false))
3656 strlcpy(value, com_token, sizeof(value));
3658 // now that we have the key pair worked out...
3659 if (!strcmp("light", key))
3661 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3665 light[0] = vec[0] * (1.0f / 256.0f);
3666 light[1] = vec[0] * (1.0f / 256.0f);
3667 light[2] = vec[0] * (1.0f / 256.0f);
3673 light[0] = vec[0] * (1.0f / 255.0f);
3674 light[1] = vec[1] * (1.0f / 255.0f);
3675 light[2] = vec[2] * (1.0f / 255.0f);
3679 else if (!strcmp("delay", key))
3681 else if (!strcmp("origin", key))
3682 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3683 else if (!strcmp("angle", key))
3684 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3685 else if (!strcmp("angles", key))
3686 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3687 else if (!strcmp("color", key))
3688 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3689 else if (!strcmp("wait", key))
3690 fadescale = atof(value);
3691 else if (!strcmp("classname", key))
3693 if (!strncmp(value, "light", 5))
3696 if (!strcmp(value, "light_fluoro"))
3701 overridecolor[0] = 1;
3702 overridecolor[1] = 1;
3703 overridecolor[2] = 1;
3705 if (!strcmp(value, "light_fluorospark"))
3710 overridecolor[0] = 1;
3711 overridecolor[1] = 1;
3712 overridecolor[2] = 1;
3714 if (!strcmp(value, "light_globe"))
3719 overridecolor[0] = 1;
3720 overridecolor[1] = 0.8;
3721 overridecolor[2] = 0.4;
3723 if (!strcmp(value, "light_flame_large_yellow"))
3728 overridecolor[0] = 1;
3729 overridecolor[1] = 0.5;
3730 overridecolor[2] = 0.1;
3732 if (!strcmp(value, "light_flame_small_yellow"))
3737 overridecolor[0] = 1;
3738 overridecolor[1] = 0.5;
3739 overridecolor[2] = 0.1;
3741 if (!strcmp(value, "light_torch_small_white"))
3746 overridecolor[0] = 1;
3747 overridecolor[1] = 0.5;
3748 overridecolor[2] = 0.1;
3750 if (!strcmp(value, "light_torch_small_walltorch"))
3755 overridecolor[0] = 1;
3756 overridecolor[1] = 0.5;
3757 overridecolor[2] = 0.1;
3761 else if (!strcmp("style", key))
3762 style = atoi(value);
3763 else if (!strcmp("skin", key))
3764 skin = (int)atof(value);
3765 else if (!strcmp("pflags", key))
3766 pflags = (int)atof(value);
3767 else if (!strcmp("effects", key))
3768 effects = (int)atof(value);
3769 else if (r_refdef.worldmodel->type == mod_brushq3)
3771 if (!strcmp("scale", key))
3772 lightscale = atof(value);
3773 if (!strcmp("fade", key))
3774 fadescale = atof(value);
3779 if (lightscale <= 0)
3783 if (color[0] == color[1] && color[0] == color[2])
3785 color[0] *= overridecolor[0];
3786 color[1] *= overridecolor[1];
3787 color[2] *= overridecolor[2];
3789 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3790 color[0] = color[0] * light[0];
3791 color[1] = color[1] * light[1];
3792 color[2] = color[2] * light[2];
3795 case LIGHTTYPE_MINUSX:
3797 case LIGHTTYPE_RECIPX:
3799 VectorScale(color, (1.0f / 16.0f), color);
3801 case LIGHTTYPE_RECIPXX:
3803 VectorScale(color, (1.0f / 16.0f), color);
3806 case LIGHTTYPE_NONE:
3810 case LIGHTTYPE_MINUSXX:
3813 VectorAdd(origin, originhack, origin);
3815 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);
3818 Mem_Free(entfiledata);
3822 void R_Shadow_SetCursorLocationForView(void)
3825 vec3_t dest, endpos;
3827 VectorMA(r_view.origin, r_editlights_cursordistance.value, r_view.forward, dest);
3828 trace = CL_Move(r_view.origin, vec3_origin, vec3_origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
3829 if (trace.fraction < 1)
3831 dist = trace.fraction * r_editlights_cursordistance.value;
3832 push = r_editlights_cursorpushback.value;
3836 VectorMA(trace.endpos, push, r_view.forward, endpos);
3837 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
3841 VectorClear( endpos );
3843 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3844 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3845 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3848 void R_Shadow_UpdateWorldLightSelection(void)
3850 if (r_editlights.integer)
3852 R_Shadow_SetCursorLocationForView();
3853 R_Shadow_SelectLightInView();
3856 R_Shadow_SelectLight(NULL);
3859 void R_Shadow_EditLights_Clear_f(void)
3861 R_Shadow_ClearWorldLights();
3864 void R_Shadow_EditLights_Reload_f(void)
3866 if (!r_refdef.worldmodel)
3868 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3869 R_Shadow_ClearWorldLights();
3870 R_Shadow_LoadWorldLights();
3871 if (r_shadow_worldlightchain == NULL)
3873 R_Shadow_LoadLightsFile();
3874 if (r_shadow_worldlightchain == NULL)
3875 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3879 void R_Shadow_EditLights_Save_f(void)
3881 if (!r_refdef.worldmodel)
3883 R_Shadow_SaveWorldLights();
3886 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3888 R_Shadow_ClearWorldLights();
3889 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3892 void R_Shadow_EditLights_ImportLightsFile_f(void)
3894 R_Shadow_ClearWorldLights();
3895 R_Shadow_LoadLightsFile();
3898 void R_Shadow_EditLights_Spawn_f(void)
3901 if (!r_editlights.integer)
3903 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3906 if (Cmd_Argc() != 1)
3908 Con_Print("r_editlights_spawn does not take parameters\n");
3911 color[0] = color[1] = color[2] = 1;
3912 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3915 void R_Shadow_EditLights_Edit_f(void)
3917 vec3_t origin, angles, color;
3918 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3919 int style, shadows, flags, normalmode, realtimemode;
3920 char cubemapname[MAX_INPUTLINE];
3921 if (!r_editlights.integer)
3923 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3926 if (!r_shadow_selectedlight)
3928 Con_Print("No selected light.\n");
3931 VectorCopy(r_shadow_selectedlight->origin, origin);
3932 VectorCopy(r_shadow_selectedlight->angles, angles);
3933 VectorCopy(r_shadow_selectedlight->color, color);
3934 radius = r_shadow_selectedlight->radius;
3935 style = r_shadow_selectedlight->style;
3936 if (r_shadow_selectedlight->cubemapname)
3937 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
3940 shadows = r_shadow_selectedlight->shadow;
3941 corona = r_shadow_selectedlight->corona;
3942 coronasizescale = r_shadow_selectedlight->coronasizescale;
3943 ambientscale = r_shadow_selectedlight->ambientscale;
3944 diffusescale = r_shadow_selectedlight->diffusescale;
3945 specularscale = r_shadow_selectedlight->specularscale;
3946 flags = r_shadow_selectedlight->flags;
3947 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3948 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3949 if (!strcmp(Cmd_Argv(1), "origin"))
3951 if (Cmd_Argc() != 5)
3953 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3956 origin[0] = atof(Cmd_Argv(2));
3957 origin[1] = atof(Cmd_Argv(3));
3958 origin[2] = atof(Cmd_Argv(4));
3960 else if (!strcmp(Cmd_Argv(1), "originx"))
3962 if (Cmd_Argc() != 3)
3964 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3967 origin[0] = atof(Cmd_Argv(2));
3969 else if (!strcmp(Cmd_Argv(1), "originy"))
3971 if (Cmd_Argc() != 3)
3973 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3976 origin[1] = atof(Cmd_Argv(2));
3978 else if (!strcmp(Cmd_Argv(1), "originz"))
3980 if (Cmd_Argc() != 3)
3982 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3985 origin[2] = atof(Cmd_Argv(2));
3987 else if (!strcmp(Cmd_Argv(1), "move"))
3989 if (Cmd_Argc() != 5)
3991 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3994 origin[0] += atof(Cmd_Argv(2));
3995 origin[1] += atof(Cmd_Argv(3));
3996 origin[2] += atof(Cmd_Argv(4));
3998 else if (!strcmp(Cmd_Argv(1), "movex"))
4000 if (Cmd_Argc() != 3)
4002 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4005 origin[0] += atof(Cmd_Argv(2));
4007 else if (!strcmp(Cmd_Argv(1), "movey"))
4009 if (Cmd_Argc() != 3)
4011 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4014 origin[1] += atof(Cmd_Argv(2));
4016 else if (!strcmp(Cmd_Argv(1), "movez"))
4018 if (Cmd_Argc() != 3)
4020 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4023 origin[2] += atof(Cmd_Argv(2));
4025 else if (!strcmp(Cmd_Argv(1), "angles"))
4027 if (Cmd_Argc() != 5)
4029 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
4032 angles[0] = atof(Cmd_Argv(2));
4033 angles[1] = atof(Cmd_Argv(3));
4034 angles[2] = atof(Cmd_Argv(4));
4036 else if (!strcmp(Cmd_Argv(1), "anglesx"))
4038 if (Cmd_Argc() != 3)
4040 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4043 angles[0] = atof(Cmd_Argv(2));
4045 else if (!strcmp(Cmd_Argv(1), "anglesy"))
4047 if (Cmd_Argc() != 3)
4049 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4052 angles[1] = atof(Cmd_Argv(2));
4054 else if (!strcmp(Cmd_Argv(1), "anglesz"))
4056 if (Cmd_Argc() != 3)
4058 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4061 angles[2] = atof(Cmd_Argv(2));
4063 else if (!strcmp(Cmd_Argv(1), "color"))
4065 if (Cmd_Argc() != 5)
4067 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
4070 color[0] = atof(Cmd_Argv(2));
4071 color[1] = atof(Cmd_Argv(3));
4072 color[2] = atof(Cmd_Argv(4));
4074 else if (!strcmp(Cmd_Argv(1), "radius"))
4076 if (Cmd_Argc() != 3)
4078 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4081 radius = atof(Cmd_Argv(2));
4083 else if (!strcmp(Cmd_Argv(1), "colorscale"))
4085 if (Cmd_Argc() == 3)
4087 double scale = atof(Cmd_Argv(2));
4094 if (Cmd_Argc() != 5)
4096 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
4099 color[0] *= atof(Cmd_Argv(2));
4100 color[1] *= atof(Cmd_Argv(3));
4101 color[2] *= atof(Cmd_Argv(4));
4104 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
4106 if (Cmd_Argc() != 3)
4108 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4111 radius *= atof(Cmd_Argv(2));
4113 else if (!strcmp(Cmd_Argv(1), "style"))
4115 if (Cmd_Argc() != 3)
4117 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4120 style = atoi(Cmd_Argv(2));
4122 else if (!strcmp(Cmd_Argv(1), "cubemap"))
4126 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4129 if (Cmd_Argc() == 3)
4130 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
4134 else if (!strcmp(Cmd_Argv(1), "shadows"))
4136 if (Cmd_Argc() != 3)
4138 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4141 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4143 else if (!strcmp(Cmd_Argv(1), "corona"))
4145 if (Cmd_Argc() != 3)
4147 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4150 corona = atof(Cmd_Argv(2));
4152 else if (!strcmp(Cmd_Argv(1), "coronasize"))
4154 if (Cmd_Argc() != 3)
4156 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4159 coronasizescale = atof(Cmd_Argv(2));
4161 else if (!strcmp(Cmd_Argv(1), "ambient"))
4163 if (Cmd_Argc() != 3)
4165 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4168 ambientscale = atof(Cmd_Argv(2));
4170 else if (!strcmp(Cmd_Argv(1), "diffuse"))
4172 if (Cmd_Argc() != 3)
4174 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4177 diffusescale = atof(Cmd_Argv(2));
4179 else if (!strcmp(Cmd_Argv(1), "specular"))
4181 if (Cmd_Argc() != 3)
4183 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4186 specularscale = atof(Cmd_Argv(2));
4188 else if (!strcmp(Cmd_Argv(1), "normalmode"))
4190 if (Cmd_Argc() != 3)
4192 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4195 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4197 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
4199 if (Cmd_Argc() != 3)
4201 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4204 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4208 Con_Print("usage: r_editlights_edit [property] [value]\n");
4209 Con_Print("Selected light's properties:\n");
4210 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
4211 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
4212 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
4213 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
4214 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
4215 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
4216 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
4217 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
4218 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
4219 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
4220 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
4221 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
4222 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
4223 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
4226 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
4227 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4230 void R_Shadow_EditLights_EditAll_f(void)
4234 if (!r_editlights.integer)
4236 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
4240 for (light = r_shadow_worldlightchain;light;light = light->next)
4242 R_Shadow_SelectLight(light);
4243 R_Shadow_EditLights_Edit_f();
4247 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
4249 int lightnumber, lightcount;
4253 if (!r_editlights.integer)
4259 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
4260 if (light == r_shadow_selectedlight)
4261 lightnumber = lightcount;
4262 sprintf(temp, "Cursor %f %f %f Total Lights %i", r_editlights_cursorlocation[0], r_editlights_cursorlocation[1], r_editlights_cursorlocation[2], lightcount);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
4263 if (r_shadow_selectedlight == NULL)
4265 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
4266 sprintf(temp, "Origin : %f %f %f\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;
4267 sprintf(temp, "Angles : %f %f %f\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;
4268 sprintf(temp, "Color : %f %f %f\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;
4269 sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
4270 sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
4271 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;
4272 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;
4273 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;
4274 sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
4275 sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
4276 sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
4277 sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
4278 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;
4279 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;
4282 void R_Shadow_EditLights_ToggleShadow_f(void)
4284 if (!r_editlights.integer)
4286 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4289 if (!r_shadow_selectedlight)
4291 Con_Print("No selected light.\n");
4294 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);
4297 void R_Shadow_EditLights_ToggleCorona_f(void)
4299 if (!r_editlights.integer)
4301 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4304 if (!r_shadow_selectedlight)
4306 Con_Print("No selected light.\n");
4309 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);
4312 void R_Shadow_EditLights_Remove_f(void)
4314 if (!r_editlights.integer)
4316 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
4319 if (!r_shadow_selectedlight)
4321 Con_Print("No selected light.\n");
4324 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
4325 r_shadow_selectedlight = NULL;
4328 void R_Shadow_EditLights_Help_f(void)
4331 "Documentation on r_editlights system:\n"
4333 "r_editlights : enable/disable editing mode\n"
4334 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
4335 "r_editlights_cursorpushback : push back cursor this far from surface\n"
4336 "r_editlights_cursorpushoff : push cursor off surface this far\n"
4337 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
4338 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
4340 "r_editlights_help : this help\n"
4341 "r_editlights_clear : remove all lights\n"
4342 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
4343 "r_editlights_save : save to .rtlights file\n"
4344 "r_editlights_spawn : create a light with default settings\n"
4345 "r_editlights_edit command : edit selected light - more documentation below\n"
4346 "r_editlights_remove : remove selected light\n"
4347 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
4348 "r_editlights_importlightentitiesfrommap : reload light entities\n"
4349 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
4351 "origin x y z : set light location\n"
4352 "originx x: set x component of light location\n"
4353 "originy y: set y component of light location\n"
4354 "originz z: set z component of light location\n"
4355 "move x y z : adjust light location\n"
4356 "movex x: adjust x component of light location\n"
4357 "movey y: adjust y component of light location\n"
4358 "movez z: adjust z component of light location\n"
4359 "angles x y z : set light angles\n"
4360 "anglesx x: set x component of light angles\n"
4361 "anglesy y: set y component of light angles\n"
4362 "anglesz z: set z component of light angles\n"
4363 "color r g b : set color of light (can be brighter than 1 1 1)\n"
4364 "radius radius : set radius (size) of light\n"
4365 "colorscale grey : multiply color of light (1 does nothing)\n"
4366 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
4367 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
4368 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
4369 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
4370 "cubemap basename : set filter cubemap of light (not yet supported)\n"
4371 "shadows 1/0 : turn on/off shadows\n"
4372 "corona n : set corona intensity\n"
4373 "coronasize n : set corona size (0-1)\n"
4374 "ambient n : set ambient intensity (0-1)\n"
4375 "diffuse n : set diffuse intensity (0-1)\n"
4376 "specular n : set specular intensity (0-1)\n"
4377 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
4378 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
4379 "<nothing> : print light properties to console\n"
4383 void R_Shadow_EditLights_CopyInfo_f(void)
4385 if (!r_editlights.integer)
4387 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
4390 if (!r_shadow_selectedlight)
4392 Con_Print("No selected light.\n");
4395 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
4396 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
4397 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
4398 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
4399 if (r_shadow_selectedlight->cubemapname)
4400 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
4402 r_shadow_bufferlight.cubemapname[0] = 0;
4403 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
4404 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
4405 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
4406 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
4407 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
4408 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
4409 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
4412 void R_Shadow_EditLights_PasteInfo_f(void)
4414 if (!r_editlights.integer)
4416 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
4419 if (!r_shadow_selectedlight)
4421 Con_Print("No selected light.\n");
4424 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);
4427 void R_Shadow_EditLights_Init(void)
4429 Cvar_RegisterVariable(&r_editlights);
4430 Cvar_RegisterVariable(&r_editlights_cursordistance);
4431 Cvar_RegisterVariable(&r_editlights_cursorpushback);
4432 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
4433 Cvar_RegisterVariable(&r_editlights_cursorgrid);
4434 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
4435 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
4436 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
4437 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)");
4438 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
4439 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
4440 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
4441 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)");
4442 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
4443 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
4444 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
4445 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
4446 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
4447 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
4448 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)");