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 int 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 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
915 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
918 static void R_Shadow_MakeTextures(void)
921 float intensity, dist;
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 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
928 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
929 for (x = 0;x <= ATTENTABLESIZE;x++)
931 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
932 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
933 r_shadow_attentable[x] = bound(0, intensity, 1);
935 // 1D gradient texture
936 for (x = 0;x < ATTEN1DSIZE;x++)
937 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
938 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
940 for (y = 0;y < ATTEN2DSIZE;y++)
941 for (x = 0;x < ATTEN2DSIZE;x++)
942 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);
943 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
945 if (r_shadow_texture3d.integer && gl_texture3d)
947 for (z = 0;z < ATTEN3DSIZE;z++)
948 for (y = 0;y < ATTEN3DSIZE;y++)
949 for (x = 0;x < ATTEN3DSIZE;x++)
950 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));
951 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
954 r_shadow_attenuation3dtexture = NULL;
958 void R_Shadow_ValidateCvars(void)
960 if (r_shadow_texture3d.integer && !gl_texture3d)
961 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
962 if (gl_ext_separatestencil.integer && !gl_support_separatestencil)
963 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
964 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
965 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
968 void R_Shadow_RenderMode_Begin(void)
970 R_Shadow_ValidateCvars();
972 if (!r_shadow_attenuation2dtexture
973 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
974 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
975 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
976 R_Shadow_MakeTextures();
979 R_Mesh_ColorPointer(NULL, 0, 0);
980 R_Mesh_ResetTextureState();
981 GL_BlendFunc(GL_ONE, GL_ZERO);
983 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
986 GL_Color(0, 0, 0, 1);
987 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
989 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
991 if (gl_ext_separatestencil.integer)
992 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
993 else if (gl_ext_stenciltwoside.integer)
994 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
996 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
998 if (r_glsl.integer && gl_support_fragment_shader)
999 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1000 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
1001 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
1003 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1006 void R_Shadow_RenderMode_ActiveLight(rtlight_t *rtlight)
1008 rsurface.rtlight = rtlight;
1011 void R_Shadow_RenderMode_Reset(void)
1014 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1016 qglUseProgramObjectARB(0);CHECKGLERROR
1018 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
1020 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1022 R_Mesh_ColorPointer(NULL, 0, 0);
1023 R_Mesh_ResetTextureState();
1024 GL_DepthRange(0, 1);
1026 GL_DepthMask(false);
1027 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1028 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1029 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1030 qglStencilMask(~0);CHECKGLERROR
1031 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1032 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1033 GL_CullFace(r_view.cullface_back);
1034 GL_Color(1, 1, 1, 1);
1035 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
1036 GL_BlendFunc(GL_ONE, GL_ZERO);
1039 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean clearstencil)
1042 R_Shadow_RenderMode_Reset();
1043 GL_ColorMask(0, 0, 0, 0);
1044 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1045 qglDepthFunc(GL_LESS);CHECKGLERROR
1046 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1047 r_shadow_rendermode = r_shadow_shadowingrendermode;
1048 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SEPARATESTENCIL)
1050 GL_CullFace(GL_NONE);
1051 qglStencilOpSeparate(r_view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1052 qglStencilOpSeparate(r_view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1054 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
1056 GL_CullFace(GL_NONE);
1057 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1058 qglActiveStencilFaceEXT(r_view.cullface_front);CHECKGLERROR
1059 qglStencilMask(~0);CHECKGLERROR
1060 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1061 qglActiveStencilFaceEXT(r_view.cullface_back);CHECKGLERROR
1062 qglStencilMask(~0);CHECKGLERROR
1063 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1066 GL_Clear(GL_STENCIL_BUFFER_BIT);
1067 r_refdef.stats.lights_clears++;
1070 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent)
1073 R_Shadow_RenderMode_Reset();
1074 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1077 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1081 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1082 // only draw light where this geometry was already rendered AND the
1083 // stencil is 128 (values other than this mean shadow)
1084 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1086 r_shadow_rendermode = r_shadow_lightingrendermode;
1087 // do global setup needed for the chosen lighting mode
1088 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1090 R_Mesh_TexBind(0, R_GetTexture(r_texture_blanknormalmap)); // normal
1091 R_Mesh_TexBind(1, R_GetTexture(r_texture_white)); // diffuse
1092 R_Mesh_TexBind(2, R_GetTexture(r_texture_white)); // gloss
1093 R_Mesh_TexBindCubeMap(3, R_GetTexture(rsurface.rtlight->currentcubemap)); // light filter
1094 R_Mesh_TexBind(4, R_GetTexture(r_texture_fogattenuation)); // fog
1095 R_Mesh_TexBind(5, R_GetTexture(r_texture_white)); // pants
1096 R_Mesh_TexBind(6, R_GetTexture(r_texture_white)); // shirt
1097 R_Mesh_TexBind(7, R_GetTexture(r_texture_white)); // lightmap
1098 R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap)); // deluxemap
1099 R_Mesh_TexBind(9, R_GetTexture(r_texture_black)); // glow
1100 //R_Mesh_TexMatrix(3, rsurface.entitytolight); // light filter matrix
1101 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1102 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 0);
1107 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
1110 R_Shadow_RenderMode_Reset();
1111 GL_BlendFunc(GL_ONE, GL_ONE);
1112 GL_DepthRange(0, 1);
1113 GL_DepthTest(r_showshadowvolumes.integer < 2);
1114 GL_Color(0.0, 0.0125 * r_view.colorscale, 0.1 * r_view.colorscale, 1);
1115 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1116 GL_CullFace(GL_NONE);
1117 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
1120 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
1123 R_Shadow_RenderMode_Reset();
1124 GL_BlendFunc(GL_ONE, GL_ONE);
1125 GL_DepthRange(0, 1);
1126 GL_DepthTest(r_showlighting.integer < 2);
1127 GL_Color(0.1 * r_view.colorscale, 0.0125 * r_view.colorscale, 0, 1);
1130 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1134 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1135 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1137 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
1140 void R_Shadow_RenderMode_End(void)
1143 R_Shadow_RenderMode_Reset();
1144 R_Shadow_RenderMode_ActiveLight(NULL);
1146 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
1147 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1150 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1152 int i, ix1, iy1, ix2, iy2;
1153 float x1, y1, x2, y2;
1156 mplane_t planes[11];
1157 float vertex3f[256*3];
1159 // if view is inside the light box, just say yes it's visible
1160 if (BoxesOverlap(r_view.origin, r_view.origin, mins, maxs))
1162 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
1166 // create a temporary brush describing the area the light can affect in worldspace
1167 VectorNegate(r_view.frustum[0].normal, planes[ 0].normal);planes[ 0].dist = -r_view.frustum[0].dist;
1168 VectorNegate(r_view.frustum[1].normal, planes[ 1].normal);planes[ 1].dist = -r_view.frustum[1].dist;
1169 VectorNegate(r_view.frustum[2].normal, planes[ 2].normal);planes[ 2].dist = -r_view.frustum[2].dist;
1170 VectorNegate(r_view.frustum[3].normal, planes[ 3].normal);planes[ 3].dist = -r_view.frustum[3].dist;
1171 VectorNegate(r_view.frustum[4].normal, planes[ 4].normal);planes[ 4].dist = -r_view.frustum[4].dist;
1172 VectorSet (planes[ 5].normal, 1, 0, 0); planes[ 5].dist = maxs[0];
1173 VectorSet (planes[ 6].normal, -1, 0, 0); planes[ 6].dist = -mins[0];
1174 VectorSet (planes[ 7].normal, 0, 1, 0); planes[ 7].dist = maxs[1];
1175 VectorSet (planes[ 8].normal, 0, -1, 0); planes[ 8].dist = -mins[1];
1176 VectorSet (planes[ 9].normal, 0, 0, 1); planes[ 9].dist = maxs[2];
1177 VectorSet (planes[10].normal, 0, 0, -1); planes[10].dist = -mins[2];
1179 // turn the brush into a mesh
1180 memset(&mesh, 0, sizeof(rmesh_t));
1181 mesh.maxvertices = 256;
1182 mesh.vertex3f = vertex3f;
1183 mesh.epsilon2 = (1.0f / (32.0f * 32.0f));
1184 R_Mesh_AddBrushMeshFromPlanes(&mesh, 11, planes);
1186 // if that mesh is empty, the light is not visible at all
1187 if (!mesh.numvertices)
1190 if (!r_shadow_scissor.integer)
1193 // if that mesh is not empty, check what area of the screen it covers
1194 x1 = y1 = x2 = y2 = 0;
1196 //Con_Printf("%i vertices to transform...\n", mesh.numvertices);
1197 for (i = 0;i < mesh.numvertices;i++)
1199 VectorCopy(mesh.vertex3f + i * 3, v);
1200 GL_TransformToScreen(v, v2);
1201 //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]);
1204 if (x1 > v2[0]) x1 = v2[0];
1205 if (x2 < v2[0]) x2 = v2[0];
1206 if (y1 > v2[1]) y1 = v2[1];
1207 if (y2 < v2[1]) y2 = v2[1];
1216 // now convert the scissor rectangle to integer screen coordinates
1217 ix1 = (int)(x1 - 1.0f);
1218 iy1 = (int)(y1 - 1.0f);
1219 ix2 = (int)(x2 + 1.0f);
1220 iy2 = (int)(y2 + 1.0f);
1221 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1223 // clamp it to the screen
1224 if (ix1 < r_view.x) ix1 = r_view.x;
1225 if (iy1 < r_view.y) iy1 = r_view.y;
1226 if (ix2 > r_view.x + r_view.width) ix2 = r_view.x + r_view.width;
1227 if (iy2 > r_view.y + r_view.height) iy2 = r_view.y + r_view.height;
1229 // if it is inside out, it's not visible
1230 if (ix2 <= ix1 || iy2 <= iy1)
1233 // the light area is visible, set up the scissor rectangle
1234 GL_Scissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1235 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);CHECKGLERROR
1236 //qglEnable(GL_SCISSOR_TEST);CHECKGLERROR
1237 r_refdef.stats.lights_scissored++;
1241 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
1243 float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1244 float *normal3f = rsurface.normal3f + 3 * firstvertex;
1245 float *color4f = rsurface.array_color4f + 4 * firstvertex;
1246 float dist, dot, distintensity, shadeintensity, v[3], n[3];
1247 if (r_textureunits.integer >= 3)
1249 if (VectorLength2(diffusecolor) > 0)
1251 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1253 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1254 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1255 if ((dot = DotProduct(n, v)) < 0)
1257 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1258 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
1261 VectorCopy(ambientcolor, color4f);
1262 if (r_refdef.fogenabled)
1265 f = FogPoint_Model(vertex3f);
1266 VectorScale(color4f, f, color4f);
1273 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1275 VectorCopy(ambientcolor, color4f);
1276 if (r_refdef.fogenabled)
1279 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1280 f = FogPoint_Model(vertex3f);
1281 VectorScale(color4f, f, color4f);
1287 else if (r_textureunits.integer >= 2)
1289 if (VectorLength2(diffusecolor) > 0)
1291 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1293 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1294 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1296 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1297 if ((dot = DotProduct(n, v)) < 0)
1299 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1300 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1301 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1302 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1306 color4f[0] = ambientcolor[0] * distintensity;
1307 color4f[1] = ambientcolor[1] * distintensity;
1308 color4f[2] = ambientcolor[2] * distintensity;
1310 if (r_refdef.fogenabled)
1313 f = FogPoint_Model(vertex3f);
1314 VectorScale(color4f, f, color4f);
1318 VectorClear(color4f);
1324 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1326 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1327 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1329 color4f[0] = ambientcolor[0] * distintensity;
1330 color4f[1] = ambientcolor[1] * distintensity;
1331 color4f[2] = ambientcolor[2] * distintensity;
1332 if (r_refdef.fogenabled)
1335 f = FogPoint_Model(vertex3f);
1336 VectorScale(color4f, f, color4f);
1340 VectorClear(color4f);
1347 if (VectorLength2(diffusecolor) > 0)
1349 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1351 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1352 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1354 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
1355 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1356 if ((dot = DotProduct(n, v)) < 0)
1358 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1359 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1360 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1361 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1365 color4f[0] = ambientcolor[0] * distintensity;
1366 color4f[1] = ambientcolor[1] * distintensity;
1367 color4f[2] = ambientcolor[2] * distintensity;
1369 if (r_refdef.fogenabled)
1372 f = FogPoint_Model(vertex3f);
1373 VectorScale(color4f, f, color4f);
1377 VectorClear(color4f);
1383 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1385 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1386 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1388 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
1389 color4f[0] = ambientcolor[0] * distintensity;
1390 color4f[1] = ambientcolor[1] * distintensity;
1391 color4f[2] = ambientcolor[2] * distintensity;
1392 if (r_refdef.fogenabled)
1395 f = FogPoint_Model(vertex3f);
1396 VectorScale(color4f, f, color4f);
1400 VectorClear(color4f);
1407 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1409 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
1412 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
1413 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1414 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
1415 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
1416 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
1418 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1420 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
1421 // the cubemap normalizes this for us
1422 out3f[0] = DotProduct(svector3f, lightdir);
1423 out3f[1] = DotProduct(tvector3f, lightdir);
1424 out3f[2] = DotProduct(normal3f, lightdir);
1428 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
1431 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
1432 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1433 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
1434 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
1435 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
1436 float lightdir[3], eyedir[3], halfdir[3];
1437 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1439 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
1440 VectorNormalize(lightdir);
1441 VectorSubtract(rsurface.modelorg, vertex3f, eyedir);
1442 VectorNormalize(eyedir);
1443 VectorAdd(lightdir, eyedir, halfdir);
1444 // the cubemap normalizes this for us
1445 out3f[0] = DotProduct(svector3f, halfdir);
1446 out3f[1] = DotProduct(tvector3f, halfdir);
1447 out3f[2] = DotProduct(normal3f, halfdir);
1451 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)
1453 // used to display how many times a surface is lit for level design purposes
1454 GL_Color(0.1 * r_view.colorscale, 0.025 * r_view.colorscale, 0, 1);
1455 R_Mesh_ColorPointer(NULL, 0, 0);
1456 R_Mesh_ResetTextureState();
1457 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1460 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)
1462 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
1463 R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
1464 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
1465 R_Mesh_TexBind(0, R_GetTexture(rsurface.texture->currentskinframe->nmap));
1466 R_Mesh_TexBind(1, R_GetTexture(rsurface.texture->basetexture));
1467 R_Mesh_TexBind(2, R_GetTexture(rsurface.texture->glosstexture));
1468 R_Mesh_TexBindCubeMap(3, R_GetTexture(rsurface.rtlight->currentcubemap));
1469 R_Mesh_TexBind(4, R_GetTexture(r_texture_fogattenuation));
1470 R_Mesh_TexBind(5, R_GetTexture(rsurface.texture->currentskinframe->pants));
1471 R_Mesh_TexBind(6, R_GetTexture(rsurface.texture->currentskinframe->shirt));
1472 R_Mesh_TexBind(10, R_GetTexture(r_shadow_attenuationgradienttexture));
1473 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
1474 R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
1475 R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
1476 R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
1477 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1479 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1481 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1482 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1484 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1488 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)
1490 // shared final code for all the dot3 layers
1492 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 0);
1493 for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
1495 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
1496 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1500 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)
1503 // colorscale accounts for how much we multiply the brightness
1506 // mult is how many times the final pass of the lighting will be
1507 // performed to get more brightness than otherwise possible.
1509 // Limit mult to 64 for sanity sake.
1511 if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1513 // 3 3D combine path (Geforce3, Radeon 8500)
1514 memset(&m, 0, sizeof(m));
1515 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1516 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1517 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1518 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1519 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1520 m.tex[1] = R_GetTexture(basetexture);
1521 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
1522 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
1523 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
1524 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
1525 m.texcubemap[2] = R_GetTexture(rsurface.rtlight->currentcubemap);
1526 m.pointer_texcoord3f[2] = rsurface.vertex3f;
1527 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
1528 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
1529 m.texmatrix[2] = rsurface.entitytolight;
1530 GL_BlendFunc(GL_ONE, GL_ONE);
1532 else if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1534 // 2 3D combine path (Geforce3, original Radeon)
1535 memset(&m, 0, sizeof(m));
1536 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1537 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1538 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1539 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1540 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1541 m.tex[1] = R_GetTexture(basetexture);
1542 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
1543 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
1544 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
1545 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
1546 GL_BlendFunc(GL_ONE, GL_ONE);
1548 else if (r_textureunits.integer >= 4 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
1550 // 4 2D combine path (Geforce3, Radeon 8500)
1551 memset(&m, 0, sizeof(m));
1552 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1553 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1554 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1555 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1556 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1557 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1558 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1559 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1560 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1561 m.texmatrix[1] = rsurface.entitytoattenuationz;
1562 m.tex[2] = R_GetTexture(basetexture);
1563 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
1564 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
1565 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
1566 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
1567 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1569 m.texcubemap[3] = R_GetTexture(rsurface.rtlight->currentcubemap);
1570 m.pointer_texcoord3f[3] = rsurface.vertex3f;
1571 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
1572 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
1573 m.texmatrix[3] = rsurface.entitytolight;
1575 GL_BlendFunc(GL_ONE, GL_ONE);
1577 else if (r_textureunits.integer >= 3 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
1579 // 3 2D combine path (Geforce3, original Radeon)
1580 memset(&m, 0, sizeof(m));
1581 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1582 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1583 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1584 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1585 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1586 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1587 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1588 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1589 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1590 m.texmatrix[1] = rsurface.entitytoattenuationz;
1591 m.tex[2] = R_GetTexture(basetexture);
1592 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
1593 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
1594 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
1595 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
1596 GL_BlendFunc(GL_ONE, GL_ONE);
1600 // 2/2/2 2D combine path (any dot3 card)
1601 memset(&m, 0, sizeof(m));
1602 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1603 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1604 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1605 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1606 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1607 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1608 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1609 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1610 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1611 m.texmatrix[1] = rsurface.entitytoattenuationz;
1612 R_Mesh_TextureState(&m);
1613 GL_ColorMask(0,0,0,1);
1614 GL_BlendFunc(GL_ONE, GL_ZERO);
1615 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1618 memset(&m, 0, sizeof(m));
1619 m.tex[0] = R_GetTexture(basetexture);
1620 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1621 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1622 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1623 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1624 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1626 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1627 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1628 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1629 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1630 m.texmatrix[1] = rsurface.entitytolight;
1632 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1634 // this final code is shared
1635 R_Mesh_TextureState(&m);
1636 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1639 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)
1642 // colorscale accounts for how much we multiply the brightness
1645 // mult is how many times the final pass of the lighting will be
1646 // performed to get more brightness than otherwise possible.
1648 // Limit mult to 64 for sanity sake.
1650 // generate normalization cubemap texcoords
1651 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
1652 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1654 // 3/2 3D combine path (Geforce3, Radeon 8500)
1655 memset(&m, 0, sizeof(m));
1656 m.tex[0] = R_GetTexture(normalmaptexture);
1657 m.texcombinergb[0] = GL_REPLACE;
1658 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1659 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1660 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1661 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1662 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1663 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1664 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1665 m.pointer_texcoord_bufferobject[1] = 0;
1666 m.pointer_texcoord_bufferoffset[1] = 0;
1667 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1668 m.pointer_texcoord3f[2] = rsurface.vertex3f;
1669 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
1670 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
1671 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
1672 R_Mesh_TextureState(&m);
1673 GL_ColorMask(0,0,0,1);
1674 GL_BlendFunc(GL_ONE, GL_ZERO);
1675 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1678 memset(&m, 0, sizeof(m));
1679 m.tex[0] = R_GetTexture(basetexture);
1680 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1681 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1682 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1683 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1684 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1686 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1687 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1688 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1689 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1690 m.texmatrix[1] = rsurface.entitytolight;
1692 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1694 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
1696 // 1/2/2 3D combine path (original Radeon)
1697 memset(&m, 0, sizeof(m));
1698 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1699 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1700 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1701 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1702 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1703 R_Mesh_TextureState(&m);
1704 GL_ColorMask(0,0,0,1);
1705 GL_BlendFunc(GL_ONE, GL_ZERO);
1706 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1709 memset(&m, 0, sizeof(m));
1710 m.tex[0] = R_GetTexture(normalmaptexture);
1711 m.texcombinergb[0] = GL_REPLACE;
1712 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1713 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1714 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1715 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1716 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1717 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1718 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1719 m.pointer_texcoord_bufferobject[1] = 0;
1720 m.pointer_texcoord_bufferoffset[1] = 0;
1721 R_Mesh_TextureState(&m);
1722 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1723 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1726 memset(&m, 0, sizeof(m));
1727 m.tex[0] = R_GetTexture(basetexture);
1728 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1729 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1730 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1731 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1732 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1734 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1735 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1736 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1737 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1738 m.texmatrix[1] = rsurface.entitytolight;
1740 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1742 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
1744 // 2/2 3D combine path (original Radeon)
1745 memset(&m, 0, sizeof(m));
1746 m.tex[0] = R_GetTexture(normalmaptexture);
1747 m.texcombinergb[0] = GL_REPLACE;
1748 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1749 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1750 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1751 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1752 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1753 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1754 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1755 m.pointer_texcoord_bufferobject[1] = 0;
1756 m.pointer_texcoord_bufferoffset[1] = 0;
1757 R_Mesh_TextureState(&m);
1758 GL_ColorMask(0,0,0,1);
1759 GL_BlendFunc(GL_ONE, GL_ZERO);
1760 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1763 memset(&m, 0, sizeof(m));
1764 m.tex[0] = R_GetTexture(basetexture);
1765 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1766 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1767 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1768 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1769 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1770 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1771 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1772 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1773 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
1774 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1776 else if (r_textureunits.integer >= 4)
1778 // 4/2 2D combine path (Geforce3, Radeon 8500)
1779 memset(&m, 0, sizeof(m));
1780 m.tex[0] = R_GetTexture(normalmaptexture);
1781 m.texcombinergb[0] = GL_REPLACE;
1782 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1783 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1784 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1785 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1786 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1787 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1788 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1789 m.pointer_texcoord_bufferobject[1] = 0;
1790 m.pointer_texcoord_bufferoffset[1] = 0;
1791 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1792 m.pointer_texcoord3f[2] = rsurface.vertex3f;
1793 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
1794 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
1795 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
1796 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1797 m.pointer_texcoord3f[3] = rsurface.vertex3f;
1798 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
1799 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
1800 m.texmatrix[3] = rsurface.entitytoattenuationz;
1801 R_Mesh_TextureState(&m);
1802 GL_ColorMask(0,0,0,1);
1803 GL_BlendFunc(GL_ONE, GL_ZERO);
1804 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1807 memset(&m, 0, sizeof(m));
1808 m.tex[0] = R_GetTexture(basetexture);
1809 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1810 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1811 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1812 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1813 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1815 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1816 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1817 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1818 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1819 m.texmatrix[1] = rsurface.entitytolight;
1821 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1825 // 2/2/2 2D combine path (any dot3 card)
1826 memset(&m, 0, sizeof(m));
1827 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1828 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1829 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1830 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1831 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1832 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1833 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1834 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1835 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1836 m.texmatrix[1] = rsurface.entitytoattenuationz;
1837 R_Mesh_TextureState(&m);
1838 GL_ColorMask(0,0,0,1);
1839 GL_BlendFunc(GL_ONE, GL_ZERO);
1840 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1843 memset(&m, 0, sizeof(m));
1844 m.tex[0] = R_GetTexture(normalmaptexture);
1845 m.texcombinergb[0] = GL_REPLACE;
1846 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1847 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1848 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1849 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1850 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1851 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1852 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1853 m.pointer_texcoord_bufferobject[1] = 0;
1854 m.pointer_texcoord_bufferoffset[1] = 0;
1855 R_Mesh_TextureState(&m);
1856 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1857 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1860 memset(&m, 0, sizeof(m));
1861 m.tex[0] = R_GetTexture(basetexture);
1862 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1863 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1864 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1865 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1866 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1868 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1869 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1870 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1871 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1872 m.texmatrix[1] = rsurface.entitytolight;
1874 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1876 // this final code is shared
1877 R_Mesh_TextureState(&m);
1878 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1881 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)
1883 float glossexponent;
1885 // FIXME: detect blendsquare!
1886 //if (!gl_support_blendsquare)
1889 // generate normalization cubemap texcoords
1890 R_Shadow_GenTexCoords_Specular_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
1891 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
1893 // 2/0/0/1/2 3D combine blendsquare path
1894 memset(&m, 0, sizeof(m));
1895 m.tex[0] = R_GetTexture(normalmaptexture);
1896 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1897 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1898 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1899 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1900 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1901 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1902 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1903 m.pointer_texcoord_bufferobject[1] = 0;
1904 m.pointer_texcoord_bufferoffset[1] = 0;
1905 R_Mesh_TextureState(&m);
1906 GL_ColorMask(0,0,0,1);
1907 // this squares the result
1908 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1909 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1911 // second and third pass
1912 R_Mesh_ResetTextureState();
1913 // square alpha in framebuffer a few times to make it shiny
1914 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1915 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
1916 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1919 memset(&m, 0, sizeof(m));
1920 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1921 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1922 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1923 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1924 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1925 R_Mesh_TextureState(&m);
1926 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1927 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1930 memset(&m, 0, sizeof(m));
1931 m.tex[0] = R_GetTexture(glosstexture);
1932 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1933 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1934 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1935 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1936 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1938 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1939 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1940 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1941 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1942 m.texmatrix[1] = rsurface.entitytolight;
1944 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1946 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
1948 // 2/0/0/2 3D combine blendsquare path
1949 memset(&m, 0, sizeof(m));
1950 m.tex[0] = R_GetTexture(normalmaptexture);
1951 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1952 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1953 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1954 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1955 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1956 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1957 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1958 m.pointer_texcoord_bufferobject[1] = 0;
1959 m.pointer_texcoord_bufferoffset[1] = 0;
1960 R_Mesh_TextureState(&m);
1961 GL_ColorMask(0,0,0,1);
1962 // this squares the result
1963 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1964 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1966 // second and third pass
1967 R_Mesh_ResetTextureState();
1968 // square alpha in framebuffer a few times to make it shiny
1969 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1970 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
1971 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1974 memset(&m, 0, sizeof(m));
1975 m.tex[0] = R_GetTexture(glosstexture);
1976 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1977 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1978 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1979 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1980 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1981 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1982 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1983 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1984 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
1985 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1989 // 2/0/0/2/2 2D combine blendsquare path
1990 memset(&m, 0, sizeof(m));
1991 m.tex[0] = R_GetTexture(normalmaptexture);
1992 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1993 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1994 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1995 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1996 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1997 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1998 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1999 m.pointer_texcoord_bufferobject[1] = 0;
2000 m.pointer_texcoord_bufferoffset[1] = 0;
2001 R_Mesh_TextureState(&m);
2002 GL_ColorMask(0,0,0,1);
2003 // this squares the result
2004 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2005 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2007 // second and third pass
2008 R_Mesh_ResetTextureState();
2009 // square alpha in framebuffer a few times to make it shiny
2010 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2011 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2012 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2015 memset(&m, 0, sizeof(m));
2016 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2017 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2018 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2019 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2020 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2021 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2022 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2023 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2024 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2025 m.texmatrix[1] = rsurface.entitytoattenuationz;
2026 R_Mesh_TextureState(&m);
2027 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2028 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2031 memset(&m, 0, sizeof(m));
2032 m.tex[0] = R_GetTexture(glosstexture);
2033 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2034 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2035 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2036 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2037 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2039 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2040 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2041 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2042 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2043 m.texmatrix[1] = rsurface.entitytolight;
2045 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2047 // this final code is shared
2048 R_Mesh_TextureState(&m);
2049 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
2052 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)
2054 // ARB path (any Geforce, any Radeon)
2055 qboolean doambient = ambientscale > 0;
2056 qboolean dodiffuse = diffusescale > 0;
2057 qboolean dospecular = specularscale > 0;
2058 if (!doambient && !dodiffuse && !dospecular)
2060 R_Mesh_ColorPointer(NULL, 0, 0);
2062 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, basetexture, ambientscale * r_view.colorscale);
2064 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, basetexture, normalmaptexture, diffusescale * r_view.colorscale);
2068 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorpants, pantstexture, ambientscale * r_view.colorscale);
2070 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorpants, pantstexture, normalmaptexture, diffusescale * r_view.colorscale);
2075 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorshirt, shirttexture, ambientscale * r_view.colorscale);
2077 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorshirt, shirttexture, normalmaptexture, diffusescale * r_view.colorscale);
2080 R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_view.colorscale);
2083 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)
2090 int newnumtriangles;
2094 int newelements[4096*3];
2095 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
2096 for (renders = 0;renders < 64;renders++)
2101 newnumtriangles = 0;
2103 // due to low fillrate on the cards this vertex lighting path is
2104 // designed for, we manually cull all triangles that do not
2105 // contain a lit vertex
2106 // this builds batches of triangles from multiple surfaces and
2107 // renders them at once
2108 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2110 if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
2112 if (newnumtriangles)
2114 newfirstvertex = min(newfirstvertex, e[0]);
2115 newlastvertex = max(newlastvertex, e[0]);
2119 newfirstvertex = e[0];
2120 newlastvertex = e[0];
2122 newfirstvertex = min(newfirstvertex, e[1]);
2123 newlastvertex = max(newlastvertex, e[1]);
2124 newfirstvertex = min(newfirstvertex, e[2]);
2125 newlastvertex = max(newlastvertex, e[2]);
2131 if (newnumtriangles >= (int)(sizeof(newelements)/sizeof(float[3])))
2133 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, newnumtriangles, newelements, 0, 0);
2134 newnumtriangles = 0;
2140 if (newnumtriangles >= 1)
2142 // if all triangles are included, use the original array to take advantage of the bufferobject if possible
2143 if (newnumtriangles == numtriangles)
2144 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2146 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, newnumtriangles, newelements, 0, 0);
2149 // if we couldn't find any lit triangles, exit early
2152 // now reduce the intensity for the next overbright pass
2153 // we have to clamp to 0 here incase the drivers have improper
2154 // handling of negative colors
2155 // (some old drivers even have improper handling of >1 color)
2157 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2159 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2161 c[0] = max(0, c[0] - 1);
2162 c[1] = max(0, c[1] - 1);
2163 c[2] = max(0, c[2] - 1);
2175 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)
2177 // OpenGL 1.1 path (anything)
2178 float ambientcolorbase[3], diffusecolorbase[3];
2179 float ambientcolorpants[3], diffusecolorpants[3];
2180 float ambientcolorshirt[3], diffusecolorshirt[3];
2182 VectorScale(lightcolorbase, ambientscale * 2 * r_view.colorscale, ambientcolorbase);
2183 VectorScale(lightcolorbase, diffusescale * 2 * r_view.colorscale, diffusecolorbase);
2184 VectorScale(lightcolorpants, ambientscale * 2 * r_view.colorscale, ambientcolorpants);
2185 VectorScale(lightcolorpants, diffusescale * 2 * r_view.colorscale, diffusecolorpants);
2186 VectorScale(lightcolorshirt, ambientscale * 2 * r_view.colorscale, ambientcolorshirt);
2187 VectorScale(lightcolorshirt, diffusescale * 2 * r_view.colorscale, diffusecolorshirt);
2188 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2189 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
2190 memset(&m, 0, sizeof(m));
2191 m.tex[0] = R_GetTexture(basetexture);
2192 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2193 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2194 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2195 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2196 if (r_textureunits.integer >= 2)
2199 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2200 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2201 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2202 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2203 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2204 if (r_textureunits.integer >= 3)
2206 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
2207 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2208 m.texmatrix[2] = rsurface.entitytoattenuationz;
2209 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2210 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2211 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2214 R_Mesh_TextureState(&m);
2215 //R_Mesh_TexBind(0, R_GetTexture(basetexture));
2216 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, diffusecolorbase, ambientcolorbase);
2219 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
2220 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, diffusecolorpants, ambientcolorpants);
2224 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
2225 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, diffusecolorshirt, ambientcolorshirt);
2229 extern cvar_t gl_lightmaps;
2230 void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset)
2232 float ambientscale, diffusescale, specularscale;
2233 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
2235 // calculate colors to render this texture with
2236 lightcolorbase[0] = rsurface.rtlight->currentcolor[0] * rsurface.texture->dlightcolor[0];
2237 lightcolorbase[1] = rsurface.rtlight->currentcolor[1] * rsurface.texture->dlightcolor[1];
2238 lightcolorbase[2] = rsurface.rtlight->currentcolor[2] * rsurface.texture->dlightcolor[2];
2239 ambientscale = rsurface.rtlight->ambientscale;
2240 diffusescale = rsurface.rtlight->diffusescale;
2241 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2242 if (!r_shadow_usenormalmap.integer)
2244 ambientscale += 1.0f * diffusescale;
2248 if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
2250 GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
2251 GL_PolygonOffset(rsurface.texture->currentpolygonfactor, rsurface.texture->currentpolygonoffset);
2252 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
2253 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_view.cullface_back);
2254 nmap = rsurface.texture->currentskinframe->nmap;
2255 if (gl_lightmaps.integer)
2256 nmap = r_texture_blanknormalmap;
2257 if (rsurface.texture->colormapping && !gl_lightmaps.integer)
2259 qboolean dopants = rsurface.texture->currentskinframe->pants != NULL && VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f);
2260 qboolean doshirt = rsurface.texture->currentskinframe->shirt != NULL && VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f);
2263 lightcolorpants[0] = lightcolorbase[0] * rsurface.colormap_pantscolor[0];
2264 lightcolorpants[1] = lightcolorbase[1] * rsurface.colormap_pantscolor[1];
2265 lightcolorpants[2] = lightcolorbase[2] * rsurface.colormap_pantscolor[2];
2268 VectorClear(lightcolorpants);
2271 lightcolorshirt[0] = lightcolorbase[0] * rsurface.colormap_shirtcolor[0];
2272 lightcolorshirt[1] = lightcolorbase[1] * rsurface.colormap_shirtcolor[1];
2273 lightcolorshirt[2] = lightcolorbase[2] * rsurface.colormap_shirtcolor[2];
2276 VectorClear(lightcolorshirt);
2277 switch (r_shadow_rendermode)
2279 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2280 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2281 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);
2283 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2284 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);
2286 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2287 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);
2289 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2290 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);
2293 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2299 switch (r_shadow_rendermode)
2301 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2302 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2303 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);
2305 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2306 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);
2308 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2309 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);
2311 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2312 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);
2315 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2321 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)
2323 matrix4x4_t tempmatrix = *matrix;
2324 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2326 // if this light has been compiled before, free the associated data
2327 R_RTLight_Uncompile(rtlight);
2329 // clear it completely to avoid any lingering data
2330 memset(rtlight, 0, sizeof(*rtlight));
2332 // copy the properties
2333 rtlight->matrix_lighttoworld = tempmatrix;
2334 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2335 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2336 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2337 VectorCopy(color, rtlight->color);
2338 rtlight->cubemapname[0] = 0;
2339 if (cubemapname && cubemapname[0])
2340 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2341 rtlight->shadow = shadow;
2342 rtlight->corona = corona;
2343 rtlight->style = style;
2344 rtlight->isstatic = isstatic;
2345 rtlight->coronasizescale = coronasizescale;
2346 rtlight->ambientscale = ambientscale;
2347 rtlight->diffusescale = diffusescale;
2348 rtlight->specularscale = specularscale;
2349 rtlight->flags = flags;
2351 // compute derived data
2352 //rtlight->cullradius = rtlight->radius;
2353 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2354 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2355 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2356 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2357 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2358 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2359 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2362 // compiles rtlight geometry
2363 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2364 void R_RTLight_Compile(rtlight_t *rtlight)
2367 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2368 int lighttris, shadowtris, shadowmeshes, shadowmeshtris;
2369 entity_render_t *ent = r_refdef.worldentity;
2370 model_t *model = r_refdef.worldmodel;
2371 unsigned char *data;
2373 // compile the light
2374 rtlight->compiled = true;
2375 rtlight->static_numleafs = 0;
2376 rtlight->static_numleafpvsbytes = 0;
2377 rtlight->static_leaflist = NULL;
2378 rtlight->static_leafpvs = NULL;
2379 rtlight->static_numsurfaces = 0;
2380 rtlight->static_surfacelist = NULL;
2381 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2382 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2383 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2384 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2385 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2386 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2388 if (model && model->GetLightInfo)
2390 // this variable must be set for the CompileShadowVolume code
2391 r_shadow_compilingrtlight = rtlight;
2392 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);
2393 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);
2394 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2395 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
2396 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
2397 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
2398 rtlight->static_numsurfaces = numsurfaces;
2399 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2400 rtlight->static_numleafs = numleafs;
2401 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2402 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2403 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2404 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
2405 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
2406 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
2407 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
2408 if (rtlight->static_numsurfaces)
2409 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2410 if (rtlight->static_numleafs)
2411 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2412 if (rtlight->static_numleafpvsbytes)
2413 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2414 if (rtlight->static_numshadowtrispvsbytes)
2415 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
2416 if (rtlight->static_numlighttrispvsbytes)
2417 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
2418 if (model->CompileShadowVolume && rtlight->shadow)
2419 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2420 // now we're done compiling the rtlight
2421 r_shadow_compilingrtlight = NULL;
2425 // use smallest available cullradius - box radius or light radius
2426 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2427 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2431 if (rtlight->static_meshchain_shadow)
2434 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2437 shadowmeshtris += mesh->numtriangles;
2442 if (rtlight->static_numlighttrispvsbytes)
2443 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
2444 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
2448 if (rtlight->static_numlighttrispvsbytes)
2449 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
2450 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
2453 if (developer.integer >= 10)
2454 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);
2457 void R_RTLight_Uncompile(rtlight_t *rtlight)
2459 if (rtlight->compiled)
2461 if (rtlight->static_meshchain_shadow)
2462 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2463 rtlight->static_meshchain_shadow = NULL;
2464 // these allocations are grouped
2465 if (rtlight->static_surfacelist)
2466 Mem_Free(rtlight->static_surfacelist);
2467 rtlight->static_numleafs = 0;
2468 rtlight->static_numleafpvsbytes = 0;
2469 rtlight->static_leaflist = NULL;
2470 rtlight->static_leafpvs = NULL;
2471 rtlight->static_numsurfaces = 0;
2472 rtlight->static_surfacelist = NULL;
2473 rtlight->static_numshadowtrispvsbytes = 0;
2474 rtlight->static_shadowtrispvs = NULL;
2475 rtlight->static_numlighttrispvsbytes = 0;
2476 rtlight->static_lighttrispvs = NULL;
2477 rtlight->compiled = false;
2481 void R_Shadow_UncompileWorldLights(void)
2484 for (light = r_shadow_worldlightchain;light;light = light->next)
2485 R_RTLight_Uncompile(&light->rtlight);
2488 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
2492 // reset the count of frustum planes
2493 // see rsurface.rtlight_frustumplanes definition for how much this array
2495 rsurface.rtlight_numfrustumplanes = 0;
2497 // haven't implemented a culling path for ortho rendering
2498 if (!r_view.useperspective)
2500 // check if the light is on screen and copy the 4 planes if it is
2501 for (i = 0;i < 4;i++)
2502 if (PlaneDiff(rtlight->shadoworigin, &r_view.frustum[i]) < -0.03125)
2505 for (i = 0;i < 4;i++)
2506 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_view.frustum[i];
2511 // generate a deformed frustum that includes the light origin, this is
2512 // used to cull shadow casting surfaces that can not possibly cast a
2513 // shadow onto the visible light-receiving surfaces, which can be a
2516 // if the light origin is onscreen the result will be 4 planes exactly
2517 // if the light origin is offscreen on only one axis the result will
2518 // be exactly 5 planes (split-side case)
2519 // if the light origin is offscreen on two axes the result will be
2520 // exactly 4 planes (stretched corner case)
2521 for (i = 0;i < 4;i++)
2523 // quickly reject standard frustum planes that put the light
2524 // origin outside the frustum
2525 if (PlaneDiff(rtlight->shadoworigin, &r_view.frustum[i]) < -0.03125)
2528 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_view.frustum[i];
2530 // if all the standard frustum planes were accepted, the light is onscreen
2531 // otherwise we need to generate some more planes below...
2532 if (rsurface.rtlight_numfrustumplanes < 4)
2534 // at least one of the stock frustum planes failed, so we need to
2535 // create one or two custom planes to enclose the light origin
2536 for (i = 0;i < 4;i++)
2538 // create a plane using the view origin and light origin, and a
2539 // single point from the frustum corner set
2540 TriangleNormal(r_view.origin, r_view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
2541 VectorNormalize(plane.normal);
2542 plane.dist = DotProduct(r_view.origin, plane.normal);
2543 // see if this plane is backwards and flip it if so
2544 for (j = 0;j < 4;j++)
2545 if (j != i && DotProduct(r_view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
2549 VectorNegate(plane.normal, plane.normal);
2551 // flipped plane, test again to see if it is now valid
2552 for (j = 0;j < 4;j++)
2553 if (j != i && DotProduct(r_view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
2555 // if the plane is still not valid, then it is dividing the
2556 // frustum and has to be rejected
2560 // we have created a valid plane, compute extra info
2561 PlaneClassify(&plane);
2563 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
2565 // if we've found 5 frustum planes then we have constructed a
2566 // proper split-side case and do not need to keep searching for
2567 // planes to enclose the light origin
2568 if (rsurface.rtlight_numfrustumplanes == 5)
2576 for (i = 0;i < rsurface.rtlight_numfrustumplanes;i++)
2578 plane = rsurface.rtlight_frustumplanes[i];
2579 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));
2584 // now add the light-space box planes if the light box is rotated, as any
2585 // caster outside the oriented light box is irrelevant (even if it passed
2586 // the worldspace light box, which is axial)
2587 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
2589 for (i = 0;i < 6;i++)
2593 v[i >> 1] = (i & 1) ? -1 : 1;
2594 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
2595 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
2596 plane.dist = VectorNormalizeLength(plane.normal);
2597 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
2598 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
2604 // add the world-space reduced box planes
2605 for (i = 0;i < 6;i++)
2607 VectorClear(plane.normal);
2608 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
2609 plane.dist = (i & 1) ? -rsurface.rtlight_cullmaxs[i >> 1] : rsurface.rtlight_cullmins[i >> 1];
2610 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
2619 // reduce all plane distances to tightly fit the rtlight cull box, which
2621 VectorSet(points[0], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
2622 VectorSet(points[1], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
2623 VectorSet(points[2], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
2624 VectorSet(points[3], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
2625 VectorSet(points[4], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
2626 VectorSet(points[5], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
2627 VectorSet(points[6], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
2628 VectorSet(points[7], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
2629 oldnum = rsurface.rtlight_numfrustumplanes;
2630 rsurface.rtlight_numfrustumplanes = 0;
2631 for (j = 0;j < oldnum;j++)
2633 // find the nearest point on the box to this plane
2634 bestdist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[0]);
2635 for (i = 1;i < 8;i++)
2637 dist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[i]);
2638 if (bestdist > dist)
2641 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);
2642 // if the nearest point is near or behind the plane, we want this
2643 // plane, otherwise the plane is useless as it won't cull anything
2644 if (rsurface.rtlight_frustumplanes[j].dist < bestdist + 0.03125)
2646 PlaneClassify(&rsurface.rtlight_frustumplanes[j]);
2647 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = rsurface.rtlight_frustumplanes[j];
2654 void R_Shadow_DrawWorldShadow(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
2656 RSurf_ActiveWorldEntity();
2657 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2661 for (mesh = rsurface.rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2663 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
2664 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
2665 GL_LockArrays(0, mesh->numverts);
2666 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
2668 // decrement stencil if backface is behind depthbuffer
2669 GL_CullFace(r_view.cullface_front);
2670 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2671 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->ebo, 0);
2672 // increment stencil if frontface is behind depthbuffer
2673 GL_CullFace(r_view.cullface_back);
2674 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2676 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->ebo, 0);
2677 GL_LockArrays(0, 0);
2681 else if (numsurfaces && r_refdef.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
2684 int surfacelistindex;
2685 msurface_t *surface;
2686 R_Shadow_PrepareShadowMark(r_refdef.worldmodel->brush.shadowmesh->numtriangles);
2687 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
2689 surface = r_refdef.worldmodel->data_surfaces + surfacelist[surfacelistindex];
2690 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
2691 if (CHECKPVSBIT(trispvs, t))
2692 shadowmarklist[numshadowmark++] = t;
2694 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);
2696 else if (numsurfaces)
2697 r_refdef.worldmodel->DrawShadowVolume(r_refdef.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
2700 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
2702 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
2703 vec_t relativeshadowradius;
2704 RSurf_ActiveModelEntity(ent, false, false);
2705 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
2706 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
2707 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
2708 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
2709 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
2710 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
2711 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
2712 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
2713 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2716 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
2718 // set up properties for rendering light onto this entity
2719 RSurf_ActiveModelEntity(ent, true, true);
2720 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
2721 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
2722 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
2723 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
2724 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2725 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
2728 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
2730 if (!r_refdef.worldmodel->DrawLight)
2733 // set up properties for rendering light onto this entity
2734 RSurf_ActiveWorldEntity();
2735 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
2736 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
2737 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
2738 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
2739 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2740 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
2742 r_refdef.worldmodel->DrawLight(r_refdef.worldentity, numsurfaces, surfacelist, trispvs);
2745 void R_Shadow_DrawEntityLight(entity_render_t *ent, int numsurfaces, int *surfacelist)
2747 model_t *model = ent->model;
2748 if (!model->DrawLight)
2751 R_Shadow_SetupEntityLight(ent);
2753 model->DrawLight(ent, model->nummodelsurfaces, model->surfacelist, NULL);
2756 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
2760 int numleafs, numsurfaces;
2761 int *leaflist, *surfacelist;
2762 unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs;
2763 int numlightentities;
2764 int numlightentities_noselfshadow;
2765 int numshadowentities;
2766 int numshadowentities_noselfshadow;
2767 entity_render_t *lightentities[MAX_EDICTS];
2768 entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
2769 entity_render_t *shadowentities[MAX_EDICTS];
2770 entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
2772 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
2773 // skip lights that are basically invisible (color 0 0 0)
2774 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
2777 // loading is done before visibility checks because loading should happen
2778 // all at once at the start of a level, not when it stalls gameplay.
2779 // (especially important to benchmarks)
2781 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2782 R_RTLight_Compile(rtlight);
2784 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
2786 // look up the light style value at this time
2787 f = (rtlight->style >= 0 ? r_refdef.lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2788 VectorScale(rtlight->color, f, rtlight->currentcolor);
2790 if (rtlight->selected)
2792 f = 2 + sin(realtime * M_PI * 4.0);
2793 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
2797 // if lightstyle is currently off, don't draw the light
2798 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
2801 // if the light box is offscreen, skip it
2802 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2805 VectorCopy(rtlight->cullmins, rsurface.rtlight_cullmins);
2806 VectorCopy(rtlight->cullmaxs, rsurface.rtlight_cullmaxs);
2808 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2810 // compiled light, world available and can receive realtime lighting
2811 // retrieve leaf information
2812 numleafs = rtlight->static_numleafs;
2813 leaflist = rtlight->static_leaflist;
2814 leafpvs = rtlight->static_leafpvs;
2815 numsurfaces = rtlight->static_numsurfaces;
2816 surfacelist = rtlight->static_surfacelist;
2817 shadowtrispvs = rtlight->static_shadowtrispvs;
2818 lighttrispvs = rtlight->static_lighttrispvs;
2820 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2822 // dynamic light, world available and can receive realtime lighting
2823 // calculate lit surfaces and leafs
2824 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);
2825 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);
2826 leaflist = r_shadow_buffer_leaflist;
2827 leafpvs = r_shadow_buffer_leafpvs;
2828 surfacelist = r_shadow_buffer_surfacelist;
2829 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
2830 lighttrispvs = r_shadow_buffer_lighttrispvs;
2831 // if the reduced leaf bounds are offscreen, skip it
2832 if (R_CullBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
2843 shadowtrispvs = NULL;
2844 lighttrispvs = NULL;
2846 // check if light is illuminating any visible leafs
2849 for (i = 0;i < numleafs;i++)
2850 if (r_viewcache.world_leafvisible[leaflist[i]])
2855 // set up a scissor rectangle for this light
2856 if (R_Shadow_ScissorForBBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
2859 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
2861 // make a list of lit entities and shadow casting entities
2862 numlightentities = 0;
2863 numlightentities_noselfshadow = 0;
2864 numshadowentities = 0;
2865 numshadowentities_noselfshadow = 0;
2866 // add dynamic entities that are lit by the light
2867 if (r_drawentities.integer)
2869 for (i = 0;i < r_refdef.numentities;i++)
2872 entity_render_t *ent = r_refdef.entities[i];
2874 if (!BoxesOverlap(ent->mins, ent->maxs, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
2876 // skip the object entirely if it is not within the valid
2877 // shadow-casting region (which includes the lit region)
2878 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rsurface.rtlight_numfrustumplanes, rsurface.rtlight_frustumplanes))
2880 if (!(model = ent->model))
2882 if (r_viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
2884 // this entity wants to receive light, is visible, and is
2885 // inside the light box
2886 // TODO: check if the surfaces in the model can receive light
2887 // so now check if it's in a leaf seen by the light
2888 if (r_refdef.worldmodel && r_refdef.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs))
2890 if (ent->flags & RENDER_NOSELFSHADOW)
2891 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
2893 lightentities[numlightentities++] = ent;
2894 // since it is lit, it probably also casts a shadow...
2895 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2896 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
2897 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
2899 // note: exterior models without the RENDER_NOSELFSHADOW
2900 // flag still create a RENDER_NOSELFSHADOW shadow but
2901 // are lit normally, this means that they are
2902 // self-shadowing but do not shadow other
2903 // RENDER_NOSELFSHADOW entities such as the gun
2904 // (very weird, but keeps the player shadow off the gun)
2905 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
2906 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
2908 shadowentities[numshadowentities++] = ent;
2911 else if (ent->flags & RENDER_SHADOW)
2913 // this entity is not receiving light, but may still need to
2915 // TODO: check if the surfaces in the model can cast shadow
2916 // now check if it is in a leaf seen by the light
2917 if (r_refdef.worldmodel && r_refdef.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs))
2919 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2920 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
2921 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
2923 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
2924 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
2926 shadowentities[numshadowentities++] = ent;
2932 // return if there's nothing at all to light
2933 if (!numlightentities && !numsurfaces)
2936 // don't let sound skip if going slow
2937 if (r_refdef.extraupdate)
2940 // make this the active rtlight for rendering purposes
2941 R_Shadow_RenderMode_ActiveLight(rtlight);
2942 // count this light in the r_speeds
2943 r_refdef.stats.lights++;
2945 if (r_showshadowvolumes.integer && r_view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.rtworldshadows : r_refdef.rtdlightshadows))
2947 // optionally draw visible shape of the shadow volumes
2948 // for performance analysis by level designers
2949 R_Shadow_RenderMode_VisibleShadowVolumes();
2951 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
2952 for (i = 0;i < numshadowentities;i++)
2953 R_Shadow_DrawEntityShadow(shadowentities[i]);
2954 for (i = 0;i < numshadowentities_noselfshadow;i++)
2955 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
2958 if (gl_stencil && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.rtworldshadows : r_refdef.rtdlightshadows))
2960 // draw stencil shadow volumes to mask off pixels that are in shadow
2961 // so that they won't receive lighting
2962 R_Shadow_RenderMode_StencilShadowVolumes(true);
2964 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
2965 for (i = 0;i < numshadowentities;i++)
2966 R_Shadow_DrawEntityShadow(shadowentities[i]);
2967 if (numlightentities_noselfshadow)
2969 // draw lighting in the unmasked areas
2970 R_Shadow_RenderMode_Lighting(true, false);
2971 for (i = 0;i < numlightentities_noselfshadow;i++)
2972 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i], numsurfaces, surfacelist);
2974 // optionally draw the illuminated areas
2975 // for performance analysis by level designers
2976 if (r_showlighting.integer && r_view.showdebug)
2978 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
2979 for (i = 0;i < numlightentities_noselfshadow;i++)
2980 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i], numsurfaces, surfacelist);
2983 R_Shadow_RenderMode_StencilShadowVolumes(false);
2985 for (i = 0;i < numshadowentities_noselfshadow;i++)
2986 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
2988 if (numsurfaces + numlightentities)
2990 // draw lighting in the unmasked areas
2991 R_Shadow_RenderMode_Lighting(true, false);
2993 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
2994 for (i = 0;i < numlightentities;i++)
2995 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
2997 // optionally draw the illuminated areas
2998 // for performance analysis by level designers
2999 if (r_showlighting.integer && r_view.showdebug)
3001 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
3003 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3004 for (i = 0;i < numlightentities;i++)
3005 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
3011 if (numsurfaces + numlightentities)
3013 // draw lighting in the unmasked areas
3014 R_Shadow_RenderMode_Lighting(false, false);
3016 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3017 for (i = 0;i < numlightentities;i++)
3018 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
3019 for (i = 0;i < numlightentities_noselfshadow;i++)
3020 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i], numsurfaces, surfacelist);
3022 // optionally draw the illuminated areas
3023 // for performance analysis by level designers
3024 if (r_showlighting.integer && r_view.showdebug)
3026 R_Shadow_RenderMode_VisibleLighting(false, false);
3028 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3029 for (i = 0;i < numlightentities;i++)
3030 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
3031 for (i = 0;i < numlightentities_noselfshadow;i++)
3032 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i], numsurfaces, surfacelist);
3038 void R_Shadow_DrawLightSprites(void);
3039 void R_ShadowVolumeLighting(qboolean visible)
3044 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
3045 R_Shadow_EditLights_Reload_f();
3047 if (r_editlights.integer)
3048 R_Shadow_DrawLightSprites();
3050 R_Shadow_RenderMode_Begin();
3052 flag = r_refdef.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3053 if (r_shadow_debuglight.integer >= 0)
3055 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
3056 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
3057 R_DrawRTLight(&light->rtlight, visible);
3060 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
3061 if (light->flags & flag)
3062 R_DrawRTLight(&light->rtlight, visible);
3063 if (r_refdef.rtdlight)
3064 for (lnum = 0;lnum < r_refdef.numlights;lnum++)
3065 R_DrawRTLight(&r_refdef.lights[lnum], visible);
3067 R_Shadow_RenderMode_End();
3070 extern void R_SetupView(void);
3071 extern cvar_t r_shadows_throwdistance;
3072 void R_DrawModelShadows(void)
3075 float relativethrowdistance;
3076 entity_render_t *ent;
3077 vec3_t relativelightorigin;
3078 vec3_t relativelightdirection;
3079 vec3_t relativeshadowmins, relativeshadowmaxs;
3082 if (!r_drawentities.integer || !gl_stencil)
3086 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
3088 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
3090 if (gl_ext_separatestencil.integer)
3091 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
3092 else if (gl_ext_stenciltwoside.integer)
3093 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
3095 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
3097 R_Shadow_RenderMode_StencilShadowVolumes(true);
3099 for (i = 0;i < r_refdef.numentities;i++)
3101 ent = r_refdef.entities[i];
3102 // cast shadows from anything that is not a submodel of the map
3103 if (ent->model && ent->model->DrawShadowVolume != NULL && !ent->model->brush.submodel && (ent->flags & RENDER_SHADOW))
3105 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
3106 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
3107 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
3108 VectorNegate(ent->modellight_lightdir, relativelightdirection);
3109 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
3110 RSurf_ActiveModelEntity(ent, false, false);
3111 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
3115 // not really the right mode, but this will disable any silly stencil features
3116 R_Shadow_RenderMode_VisibleLighting(true, true);
3118 // vertex coordinates for a quad that covers the screen exactly
3119 vertex3f[0] = 0;vertex3f[1] = 0;vertex3f[2] = 0;
3120 vertex3f[3] = 1;vertex3f[4] = 0;vertex3f[5] = 0;
3121 vertex3f[6] = 1;vertex3f[7] = 1;vertex3f[8] = 0;
3122 vertex3f[9] = 0;vertex3f[10] = 1;vertex3f[11] = 0;
3124 // set up ortho view for rendering this pass
3125 GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
3126 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
3127 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
3128 GL_ScissorTest(true);
3129 R_Mesh_Matrix(&identitymatrix);
3130 R_Mesh_ResetTextureState();
3131 R_Mesh_VertexPointer(vertex3f, 0, 0);
3132 R_Mesh_ColorPointer(NULL, 0, 0);
3134 // set up a 50% darkening blend on shadowed areas
3135 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3136 GL_DepthRange(0, 1);
3137 GL_DepthTest(false);
3138 GL_DepthMask(false);
3139 GL_PolygonOffset(0, 0);CHECKGLERROR
3140 GL_Color(0, 0, 0, 0.5);
3141 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
3142 qglDepthFunc(GL_ALWAYS);CHECKGLERROR
3143 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
3144 qglStencilMask(~0);CHECKGLERROR
3145 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
3146 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
3148 // apply the blend to the shadowed areas
3149 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3151 // restoring the perspective view is done by R_RenderScene
3154 // restore other state to normal
3155 R_Shadow_RenderMode_End();
3159 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
3160 typedef struct suffixinfo_s
3163 qboolean flipx, flipy, flipdiagonal;
3166 static suffixinfo_t suffix[3][6] =
3169 {"px", false, false, false},
3170 {"nx", false, false, false},
3171 {"py", false, false, false},
3172 {"ny", false, false, false},
3173 {"pz", false, false, false},
3174 {"nz", false, false, false}
3177 {"posx", false, false, false},
3178 {"negx", false, false, false},
3179 {"posy", false, false, false},
3180 {"negy", false, false, false},
3181 {"posz", false, false, false},
3182 {"negz", false, false, false}
3185 {"rt", true, false, true},
3186 {"lf", false, true, true},
3187 {"ft", true, true, false},
3188 {"bk", false, false, false},
3189 {"up", true, false, true},
3190 {"dn", true, false, true}
3194 static int componentorder[4] = {0, 1, 2, 3};
3196 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
3198 int i, j, cubemapsize;
3199 unsigned char *cubemappixels, *image_buffer;
3200 rtexture_t *cubemaptexture;
3202 // must start 0 so the first loadimagepixels has no requested width/height
3204 cubemappixels = NULL;
3205 cubemaptexture = NULL;
3206 // keep trying different suffix groups (posx, px, rt) until one loads
3207 for (j = 0;j < 3 && !cubemappixels;j++)
3209 // load the 6 images in the suffix group
3210 for (i = 0;i < 6;i++)
3212 // generate an image name based on the base and and suffix
3213 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
3215 if ((image_buffer = loadimagepixelsbgra(name, false, false)))
3217 // an image loaded, make sure width and height are equal
3218 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
3220 // if this is the first image to load successfully, allocate the cubemap memory
3221 if (!cubemappixels && image_width >= 1)
3223 cubemapsize = image_width;
3224 // note this clears to black, so unavailable sides are black
3225 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
3227 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
3229 Image_CopyMux(cubemappixels+i*cubemapsize*cubemapsize*4, image_buffer, cubemapsize, cubemapsize, suffix[j][i].flipx, suffix[j][i].flipy, suffix[j][i].flipdiagonal, 4, 4, componentorder);
3232 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
3234 Mem_Free(image_buffer);
3238 // if a cubemap loaded, upload it
3241 if (!r_shadow_filters_texturepool)
3242 r_shadow_filters_texturepool = R_AllocTexturePool();
3243 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, TEXF_PRECACHE | (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0), NULL);
3244 Mem_Free(cubemappixels);
3248 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
3249 for (j = 0;j < 3;j++)
3250 for (i = 0;i < 6;i++)
3251 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
3252 Con_Print(" and was unable to find any of them.\n");
3254 return cubemaptexture;
3257 rtexture_t *R_Shadow_Cubemap(const char *basename)
3260 for (i = 0;i < numcubemaps;i++)
3261 if (!strcasecmp(cubemaps[i].basename, basename))
3262 return cubemaps[i].texture;
3263 if (i >= MAX_CUBEMAPS)
3264 return r_texture_whitecube;
3266 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
3267 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
3268 if (!cubemaps[i].texture)
3269 cubemaps[i].texture = r_texture_whitecube;
3270 return cubemaps[i].texture;
3273 void R_Shadow_FreeCubemaps(void)
3276 R_FreeTexturePool(&r_shadow_filters_texturepool);
3279 dlight_t *R_Shadow_NewWorldLight(void)
3282 light = (dlight_t *)Mem_Alloc(r_main_mempool, sizeof(dlight_t));
3283 light->next = r_shadow_worldlightchain;
3284 r_shadow_worldlightchain = light;
3288 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)
3291 // validate parameters
3292 if (style < 0 || style >= MAX_LIGHTSTYLES)
3294 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
3300 // copy to light properties
3301 VectorCopy(origin, light->origin);
3302 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
3303 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
3304 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
3305 light->color[0] = max(color[0], 0);
3306 light->color[1] = max(color[1], 0);
3307 light->color[2] = max(color[2], 0);
3308 light->radius = max(radius, 0);
3309 light->style = style;
3310 light->shadow = shadowenable;
3311 light->corona = corona;
3312 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
3313 light->coronasizescale = coronasizescale;
3314 light->ambientscale = ambientscale;
3315 light->diffusescale = diffusescale;
3316 light->specularscale = specularscale;
3317 light->flags = flags;
3319 // update renderable light data
3320 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
3321 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);
3324 void R_Shadow_FreeWorldLight(dlight_t *light)
3326 dlight_t **lightpointer;
3327 R_RTLight_Uncompile(&light->rtlight);
3328 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
3329 if (*lightpointer != light)
3330 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain");
3331 *lightpointer = light->next;
3335 void R_Shadow_ClearWorldLights(void)
3337 while (r_shadow_worldlightchain)
3338 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
3339 r_shadow_selectedlight = NULL;
3340 R_Shadow_FreeCubemaps();
3343 void R_Shadow_SelectLight(dlight_t *light)
3345 if (r_shadow_selectedlight)
3346 r_shadow_selectedlight->selected = false;
3347 r_shadow_selectedlight = light;
3348 if (r_shadow_selectedlight)
3349 r_shadow_selectedlight->selected = true;
3352 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
3354 // this is never batched (there can be only one)
3355 float scale = r_editlights_cursorgrid.value * 0.5f;
3356 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);
3359 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
3361 // this is never batched (due to the ent parameter changing every time)
3362 // so numsurfaces == 1 and surfacelist[0] == lightnumber
3364 const dlight_t *light = (dlight_t *)ent;
3366 if (light->selected)
3367 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
3370 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);
3373 void R_Shadow_DrawLightSprites(void)
3378 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
3379 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 1+(i % 5), &light->rtlight);
3380 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
3383 void R_Shadow_SelectLightInView(void)
3385 float bestrating, rating, temp[3];
3386 dlight_t *best, *light;
3389 for (light = r_shadow_worldlightchain;light;light = light->next)
3391 VectorSubtract(light->origin, r_view.origin, temp);
3392 rating = (DotProduct(temp, r_view.forward) / sqrt(DotProduct(temp, temp)));
3395 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
3396 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)
3398 bestrating = rating;
3403 R_Shadow_SelectLight(best);
3406 void R_Shadow_LoadWorldLights(void)
3408 int n, a, style, shadow, flags;
3409 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
3410 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
3411 if (r_refdef.worldmodel == NULL)
3413 Con_Print("No map loaded.\n");
3416 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3417 strlcat (name, ".rtlights", sizeof (name));
3418 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3428 for (;COM_Parse(t, true) && strcmp(
3429 if (COM_Parse(t, true))
3431 if (com_token[0] == '!')
3434 origin[0] = atof(com_token+1);
3437 origin[0] = atof(com_token);
3442 while (*s && *s != '\n' && *s != '\r')
3448 // check for modifier flags
3455 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);
3458 flags = LIGHTFLAG_REALTIMEMODE;
3466 coronasizescale = 0.25f;
3468 VectorClear(angles);
3471 if (a < 9 || !strcmp(cubemapname, "\"\""))
3473 // remove quotes on cubemapname
3474 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
3477 namelen = strlen(cubemapname) - 2;
3478 memmove(cubemapname, cubemapname + 1, namelen);
3479 cubemapname[namelen] = '\0';
3483 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);
3486 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3494 Con_Printf("invalid rtlights file \"%s\"\n", name);
3495 Mem_Free(lightsstring);
3499 void R_Shadow_SaveWorldLights(void)
3502 size_t bufchars, bufmaxchars;
3504 char name[MAX_QPATH];
3505 char line[MAX_INPUTLINE];
3506 if (!r_shadow_worldlightchain)
3508 if (r_refdef.worldmodel == NULL)
3510 Con_Print("No map loaded.\n");
3513 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3514 strlcat (name, ".rtlights", sizeof (name));
3515 bufchars = bufmaxchars = 0;
3517 for (light = r_shadow_worldlightchain;light;light = light->next)
3519 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3520 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);
3521 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3522 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]);
3524 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);
3525 if (bufchars + strlen(line) > bufmaxchars)
3527 bufmaxchars = bufchars + strlen(line) + 2048;
3529 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
3533 memcpy(buf, oldbuf, bufchars);
3539 memcpy(buf + bufchars, line, strlen(line));
3540 bufchars += strlen(line);
3544 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
3549 void R_Shadow_LoadLightsFile(void)
3552 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3553 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3554 if (r_refdef.worldmodel == NULL)
3556 Con_Print("No map loaded.\n");
3559 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3560 strlcat (name, ".lights", sizeof (name));
3561 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3569 while (*s && *s != '\n' && *s != '\r')
3575 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);
3579 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);
3582 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3583 radius = bound(15, radius, 4096);
3584 VectorScale(color, (2.0f / (8388608.0f)), color);
3585 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3593 Con_Printf("invalid lights file \"%s\"\n", name);
3594 Mem_Free(lightsstring);
3598 // tyrlite/hmap2 light types in the delay field
3599 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3601 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3603 int entnum, style, islight, skin, pflags, effects, type, n;
3606 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3607 char key[256], value[MAX_INPUTLINE];
3609 if (r_refdef.worldmodel == NULL)
3611 Con_Print("No map loaded.\n");
3614 // try to load a .ent file first
3615 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3616 strlcat (key, ".ent", sizeof (key));
3617 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
3618 // and if that is not found, fall back to the bsp file entity string
3620 data = r_refdef.worldmodel->brush.entities;
3623 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
3625 type = LIGHTTYPE_MINUSX;
3626 origin[0] = origin[1] = origin[2] = 0;
3627 originhack[0] = originhack[1] = originhack[2] = 0;
3628 angles[0] = angles[1] = angles[2] = 0;
3629 color[0] = color[1] = color[2] = 1;
3630 light[0] = light[1] = light[2] = 1;light[3] = 300;
3631 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3641 if (!COM_ParseToken_Simple(&data, false, false))
3643 if (com_token[0] == '}')
3644 break; // end of entity
3645 if (com_token[0] == '_')
3646 strlcpy(key, com_token + 1, sizeof(key));
3648 strlcpy(key, com_token, sizeof(key));
3649 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3650 key[strlen(key)-1] = 0;
3651 if (!COM_ParseToken_Simple(&data, false, false))
3653 strlcpy(value, com_token, sizeof(value));
3655 // now that we have the key pair worked out...
3656 if (!strcmp("light", key))
3658 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3662 light[0] = vec[0] * (1.0f / 256.0f);
3663 light[1] = vec[0] * (1.0f / 256.0f);
3664 light[2] = vec[0] * (1.0f / 256.0f);
3670 light[0] = vec[0] * (1.0f / 255.0f);
3671 light[1] = vec[1] * (1.0f / 255.0f);
3672 light[2] = vec[2] * (1.0f / 255.0f);
3676 else if (!strcmp("delay", key))
3678 else if (!strcmp("origin", key))
3679 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3680 else if (!strcmp("angle", key))
3681 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3682 else if (!strcmp("angles", key))
3683 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3684 else if (!strcmp("color", key))
3685 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3686 else if (!strcmp("wait", key))
3687 fadescale = atof(value);
3688 else if (!strcmp("classname", key))
3690 if (!strncmp(value, "light", 5))
3693 if (!strcmp(value, "light_fluoro"))
3698 overridecolor[0] = 1;
3699 overridecolor[1] = 1;
3700 overridecolor[2] = 1;
3702 if (!strcmp(value, "light_fluorospark"))
3707 overridecolor[0] = 1;
3708 overridecolor[1] = 1;
3709 overridecolor[2] = 1;
3711 if (!strcmp(value, "light_globe"))
3716 overridecolor[0] = 1;
3717 overridecolor[1] = 0.8;
3718 overridecolor[2] = 0.4;
3720 if (!strcmp(value, "light_flame_large_yellow"))
3725 overridecolor[0] = 1;
3726 overridecolor[1] = 0.5;
3727 overridecolor[2] = 0.1;
3729 if (!strcmp(value, "light_flame_small_yellow"))
3734 overridecolor[0] = 1;
3735 overridecolor[1] = 0.5;
3736 overridecolor[2] = 0.1;
3738 if (!strcmp(value, "light_torch_small_white"))
3743 overridecolor[0] = 1;
3744 overridecolor[1] = 0.5;
3745 overridecolor[2] = 0.1;
3747 if (!strcmp(value, "light_torch_small_walltorch"))
3752 overridecolor[0] = 1;
3753 overridecolor[1] = 0.5;
3754 overridecolor[2] = 0.1;
3758 else if (!strcmp("style", key))
3759 style = atoi(value);
3760 else if (!strcmp("skin", key))
3761 skin = (int)atof(value);
3762 else if (!strcmp("pflags", key))
3763 pflags = (int)atof(value);
3764 else if (!strcmp("effects", key))
3765 effects = (int)atof(value);
3766 else if (r_refdef.worldmodel->type == mod_brushq3)
3768 if (!strcmp("scale", key))
3769 lightscale = atof(value);
3770 if (!strcmp("fade", key))
3771 fadescale = atof(value);
3776 if (lightscale <= 0)
3780 if (color[0] == color[1] && color[0] == color[2])
3782 color[0] *= overridecolor[0];
3783 color[1] *= overridecolor[1];
3784 color[2] *= overridecolor[2];
3786 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3787 color[0] = color[0] * light[0];
3788 color[1] = color[1] * light[1];
3789 color[2] = color[2] * light[2];
3792 case LIGHTTYPE_MINUSX:
3794 case LIGHTTYPE_RECIPX:
3796 VectorScale(color, (1.0f / 16.0f), color);
3798 case LIGHTTYPE_RECIPXX:
3800 VectorScale(color, (1.0f / 16.0f), color);
3803 case LIGHTTYPE_NONE:
3807 case LIGHTTYPE_MINUSXX:
3810 VectorAdd(origin, originhack, origin);
3812 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);
3815 Mem_Free(entfiledata);
3819 void R_Shadow_SetCursorLocationForView(void)
3822 vec3_t dest, endpos;
3824 VectorMA(r_view.origin, r_editlights_cursordistance.value, r_view.forward, dest);
3825 trace = CL_Move(r_view.origin, vec3_origin, vec3_origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
3826 if (trace.fraction < 1)
3828 dist = trace.fraction * r_editlights_cursordistance.value;
3829 push = r_editlights_cursorpushback.value;
3833 VectorMA(trace.endpos, push, r_view.forward, endpos);
3834 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
3838 VectorClear( endpos );
3840 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3841 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3842 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3845 void R_Shadow_UpdateWorldLightSelection(void)
3847 if (r_editlights.integer)
3849 R_Shadow_SetCursorLocationForView();
3850 R_Shadow_SelectLightInView();
3853 R_Shadow_SelectLight(NULL);
3856 void R_Shadow_EditLights_Clear_f(void)
3858 R_Shadow_ClearWorldLights();
3861 void R_Shadow_EditLights_Reload_f(void)
3863 if (!r_refdef.worldmodel)
3865 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3866 R_Shadow_ClearWorldLights();
3867 R_Shadow_LoadWorldLights();
3868 if (r_shadow_worldlightchain == NULL)
3870 R_Shadow_LoadLightsFile();
3871 if (r_shadow_worldlightchain == NULL)
3872 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3876 void R_Shadow_EditLights_Save_f(void)
3878 if (!r_refdef.worldmodel)
3880 R_Shadow_SaveWorldLights();
3883 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3885 R_Shadow_ClearWorldLights();
3886 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3889 void R_Shadow_EditLights_ImportLightsFile_f(void)
3891 R_Shadow_ClearWorldLights();
3892 R_Shadow_LoadLightsFile();
3895 void R_Shadow_EditLights_Spawn_f(void)
3898 if (!r_editlights.integer)
3900 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3903 if (Cmd_Argc() != 1)
3905 Con_Print("r_editlights_spawn does not take parameters\n");
3908 color[0] = color[1] = color[2] = 1;
3909 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3912 void R_Shadow_EditLights_Edit_f(void)
3914 vec3_t origin, angles, color;
3915 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3916 int style, shadows, flags, normalmode, realtimemode;
3917 char cubemapname[MAX_INPUTLINE];
3918 if (!r_editlights.integer)
3920 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3923 if (!r_shadow_selectedlight)
3925 Con_Print("No selected light.\n");
3928 VectorCopy(r_shadow_selectedlight->origin, origin);
3929 VectorCopy(r_shadow_selectedlight->angles, angles);
3930 VectorCopy(r_shadow_selectedlight->color, color);
3931 radius = r_shadow_selectedlight->radius;
3932 style = r_shadow_selectedlight->style;
3933 if (r_shadow_selectedlight->cubemapname)
3934 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
3937 shadows = r_shadow_selectedlight->shadow;
3938 corona = r_shadow_selectedlight->corona;
3939 coronasizescale = r_shadow_selectedlight->coronasizescale;
3940 ambientscale = r_shadow_selectedlight->ambientscale;
3941 diffusescale = r_shadow_selectedlight->diffusescale;
3942 specularscale = r_shadow_selectedlight->specularscale;
3943 flags = r_shadow_selectedlight->flags;
3944 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3945 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3946 if (!strcmp(Cmd_Argv(1), "origin"))
3948 if (Cmd_Argc() != 5)
3950 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3953 origin[0] = atof(Cmd_Argv(2));
3954 origin[1] = atof(Cmd_Argv(3));
3955 origin[2] = atof(Cmd_Argv(4));
3957 else if (!strcmp(Cmd_Argv(1), "originx"))
3959 if (Cmd_Argc() != 3)
3961 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3964 origin[0] = atof(Cmd_Argv(2));
3966 else if (!strcmp(Cmd_Argv(1), "originy"))
3968 if (Cmd_Argc() != 3)
3970 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3973 origin[1] = atof(Cmd_Argv(2));
3975 else if (!strcmp(Cmd_Argv(1), "originz"))
3977 if (Cmd_Argc() != 3)
3979 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3982 origin[2] = atof(Cmd_Argv(2));
3984 else if (!strcmp(Cmd_Argv(1), "move"))
3986 if (Cmd_Argc() != 5)
3988 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3991 origin[0] += atof(Cmd_Argv(2));
3992 origin[1] += atof(Cmd_Argv(3));
3993 origin[2] += atof(Cmd_Argv(4));
3995 else if (!strcmp(Cmd_Argv(1), "movex"))
3997 if (Cmd_Argc() != 3)
3999 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4002 origin[0] += atof(Cmd_Argv(2));
4004 else if (!strcmp(Cmd_Argv(1), "movey"))
4006 if (Cmd_Argc() != 3)
4008 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4011 origin[1] += atof(Cmd_Argv(2));
4013 else if (!strcmp(Cmd_Argv(1), "movez"))
4015 if (Cmd_Argc() != 3)
4017 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4020 origin[2] += atof(Cmd_Argv(2));
4022 else if (!strcmp(Cmd_Argv(1), "angles"))
4024 if (Cmd_Argc() != 5)
4026 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
4029 angles[0] = atof(Cmd_Argv(2));
4030 angles[1] = atof(Cmd_Argv(3));
4031 angles[2] = atof(Cmd_Argv(4));
4033 else if (!strcmp(Cmd_Argv(1), "anglesx"))
4035 if (Cmd_Argc() != 3)
4037 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4040 angles[0] = atof(Cmd_Argv(2));
4042 else if (!strcmp(Cmd_Argv(1), "anglesy"))
4044 if (Cmd_Argc() != 3)
4046 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4049 angles[1] = atof(Cmd_Argv(2));
4051 else if (!strcmp(Cmd_Argv(1), "anglesz"))
4053 if (Cmd_Argc() != 3)
4055 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4058 angles[2] = atof(Cmd_Argv(2));
4060 else if (!strcmp(Cmd_Argv(1), "color"))
4062 if (Cmd_Argc() != 5)
4064 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
4067 color[0] = atof(Cmd_Argv(2));
4068 color[1] = atof(Cmd_Argv(3));
4069 color[2] = atof(Cmd_Argv(4));
4071 else if (!strcmp(Cmd_Argv(1), "radius"))
4073 if (Cmd_Argc() != 3)
4075 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4078 radius = atof(Cmd_Argv(2));
4080 else if (!strcmp(Cmd_Argv(1), "colorscale"))
4082 if (Cmd_Argc() == 3)
4084 double scale = atof(Cmd_Argv(2));
4091 if (Cmd_Argc() != 5)
4093 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
4096 color[0] *= atof(Cmd_Argv(2));
4097 color[1] *= atof(Cmd_Argv(3));
4098 color[2] *= atof(Cmd_Argv(4));
4101 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
4103 if (Cmd_Argc() != 3)
4105 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4108 radius *= atof(Cmd_Argv(2));
4110 else if (!strcmp(Cmd_Argv(1), "style"))
4112 if (Cmd_Argc() != 3)
4114 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4117 style = atoi(Cmd_Argv(2));
4119 else if (!strcmp(Cmd_Argv(1), "cubemap"))
4123 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4126 if (Cmd_Argc() == 3)
4127 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
4131 else if (!strcmp(Cmd_Argv(1), "shadows"))
4133 if (Cmd_Argc() != 3)
4135 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4138 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4140 else if (!strcmp(Cmd_Argv(1), "corona"))
4142 if (Cmd_Argc() != 3)
4144 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4147 corona = atof(Cmd_Argv(2));
4149 else if (!strcmp(Cmd_Argv(1), "coronasize"))
4151 if (Cmd_Argc() != 3)
4153 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4156 coronasizescale = atof(Cmd_Argv(2));
4158 else if (!strcmp(Cmd_Argv(1), "ambient"))
4160 if (Cmd_Argc() != 3)
4162 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4165 ambientscale = atof(Cmd_Argv(2));
4167 else if (!strcmp(Cmd_Argv(1), "diffuse"))
4169 if (Cmd_Argc() != 3)
4171 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4174 diffusescale = atof(Cmd_Argv(2));
4176 else if (!strcmp(Cmd_Argv(1), "specular"))
4178 if (Cmd_Argc() != 3)
4180 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4183 specularscale = atof(Cmd_Argv(2));
4185 else if (!strcmp(Cmd_Argv(1), "normalmode"))
4187 if (Cmd_Argc() != 3)
4189 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4192 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4194 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
4196 if (Cmd_Argc() != 3)
4198 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4201 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4205 Con_Print("usage: r_editlights_edit [property] [value]\n");
4206 Con_Print("Selected light's properties:\n");
4207 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
4208 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
4209 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
4210 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
4211 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
4212 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
4213 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
4214 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
4215 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
4216 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
4217 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
4218 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
4219 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
4220 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
4223 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
4224 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4227 void R_Shadow_EditLights_EditAll_f(void)
4231 if (!r_editlights.integer)
4233 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
4237 for (light = r_shadow_worldlightchain;light;light = light->next)
4239 R_Shadow_SelectLight(light);
4240 R_Shadow_EditLights_Edit_f();
4244 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
4246 int lightnumber, lightcount;
4250 if (!r_editlights.integer)
4256 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
4257 if (light == r_shadow_selectedlight)
4258 lightnumber = lightcount;
4259 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;
4260 if (r_shadow_selectedlight == NULL)
4262 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
4263 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;
4264 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;
4265 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;
4266 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;
4267 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;
4268 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;
4269 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;
4270 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;
4271 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;
4272 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;
4273 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;
4274 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;
4275 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;
4276 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;
4279 void R_Shadow_EditLights_ToggleShadow_f(void)
4281 if (!r_editlights.integer)
4283 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4286 if (!r_shadow_selectedlight)
4288 Con_Print("No selected light.\n");
4291 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);
4294 void R_Shadow_EditLights_ToggleCorona_f(void)
4296 if (!r_editlights.integer)
4298 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4301 if (!r_shadow_selectedlight)
4303 Con_Print("No selected light.\n");
4306 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);
4309 void R_Shadow_EditLights_Remove_f(void)
4311 if (!r_editlights.integer)
4313 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
4316 if (!r_shadow_selectedlight)
4318 Con_Print("No selected light.\n");
4321 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
4322 r_shadow_selectedlight = NULL;
4325 void R_Shadow_EditLights_Help_f(void)
4328 "Documentation on r_editlights system:\n"
4330 "r_editlights : enable/disable editing mode\n"
4331 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
4332 "r_editlights_cursorpushback : push back cursor this far from surface\n"
4333 "r_editlights_cursorpushoff : push cursor off surface this far\n"
4334 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
4335 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
4337 "r_editlights_help : this help\n"
4338 "r_editlights_clear : remove all lights\n"
4339 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
4340 "r_editlights_save : save to .rtlights file\n"
4341 "r_editlights_spawn : create a light with default settings\n"
4342 "r_editlights_edit command : edit selected light - more documentation below\n"
4343 "r_editlights_remove : remove selected light\n"
4344 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
4345 "r_editlights_importlightentitiesfrommap : reload light entities\n"
4346 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
4348 "origin x y z : set light location\n"
4349 "originx x: set x component of light location\n"
4350 "originy y: set y component of light location\n"
4351 "originz z: set z component of light location\n"
4352 "move x y z : adjust light location\n"
4353 "movex x: adjust x component of light location\n"
4354 "movey y: adjust y component of light location\n"
4355 "movez z: adjust z component of light location\n"
4356 "angles x y z : set light angles\n"
4357 "anglesx x: set x component of light angles\n"
4358 "anglesy y: set y component of light angles\n"
4359 "anglesz z: set z component of light angles\n"
4360 "color r g b : set color of light (can be brighter than 1 1 1)\n"
4361 "radius radius : set radius (size) of light\n"
4362 "colorscale grey : multiply color of light (1 does nothing)\n"
4363 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
4364 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
4365 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
4366 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
4367 "cubemap basename : set filter cubemap of light (not yet supported)\n"
4368 "shadows 1/0 : turn on/off shadows\n"
4369 "corona n : set corona intensity\n"
4370 "coronasize n : set corona size (0-1)\n"
4371 "ambient n : set ambient intensity (0-1)\n"
4372 "diffuse n : set diffuse intensity (0-1)\n"
4373 "specular n : set specular intensity (0-1)\n"
4374 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
4375 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
4376 "<nothing> : print light properties to console\n"
4380 void R_Shadow_EditLights_CopyInfo_f(void)
4382 if (!r_editlights.integer)
4384 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
4387 if (!r_shadow_selectedlight)
4389 Con_Print("No selected light.\n");
4392 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
4393 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
4394 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
4395 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
4396 if (r_shadow_selectedlight->cubemapname)
4397 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
4399 r_shadow_bufferlight.cubemapname[0] = 0;
4400 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
4401 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
4402 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
4403 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
4404 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
4405 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
4406 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
4409 void R_Shadow_EditLights_PasteInfo_f(void)
4411 if (!r_editlights.integer)
4413 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
4416 if (!r_shadow_selectedlight)
4418 Con_Print("No selected light.\n");
4421 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);
4424 void R_Shadow_EditLights_Init(void)
4426 Cvar_RegisterVariable(&r_editlights);
4427 Cvar_RegisterVariable(&r_editlights_cursordistance);
4428 Cvar_RegisterVariable(&r_editlights_cursorpushback);
4429 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
4430 Cvar_RegisterVariable(&r_editlights_cursorgrid);
4431 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
4432 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
4433 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
4434 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)");
4435 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
4436 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
4437 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
4438 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)");
4439 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
4440 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
4441 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
4442 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
4443 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
4444 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
4445 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)");