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(GL_BACK); // quake is backwards, this culls front faces
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(GL_FRONT); // quake is backwards, this culls back faces
903 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
905 R_Mesh_Draw(0, numvertices, numtriangles, element3i, 0, 0);
910 static unsigned char R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
912 float dist = sqrt(x*x+y*y+z*z);
913 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
914 return (unsigned char)bound(0, intensity * 256.0f, 255);
917 static void R_Shadow_MakeTextures(void)
920 float intensity, dist;
922 unsigned int palette[256];
923 R_FreeTexturePool(&r_shadow_texturepool);
924 r_shadow_texturepool = R_AllocTexturePool();
925 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
926 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
927 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
928 for (x = 0;x < 256;x++)
929 palette[x] = x * 0x01010101;
930 data = (unsigned char *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE));
931 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
932 for (x = 0;x <= ATTENTABLESIZE;x++)
934 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
935 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
936 r_shadow_attentable[x] = bound(0, intensity, 1);
938 // 1D gradient texture
939 for (x = 0;x < ATTEN1DSIZE;x++)
940 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
941 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, data, TEXTYPE_PALETTE, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, palette);
943 for (y = 0;y < ATTEN2DSIZE;y++)
944 for (x = 0;x < ATTEN2DSIZE;x++)
945 data[y*ATTEN2DSIZE+x] = R_Shadow_MakeTextures_SamplePoint(((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375), ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375), 0);
946 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_PALETTE, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, palette);
948 if (r_shadow_texture3d.integer && gl_texture3d)
950 for (z = 0;z < ATTEN3DSIZE;z++)
951 for (y = 0;y < ATTEN3DSIZE;y++)
952 for (x = 0;x < ATTEN3DSIZE;x++)
953 data[(z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x] = R_Shadow_MakeTextures_SamplePoint(((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375), ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375), ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375));
954 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_PALETTE, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, palette);
957 r_shadow_attenuation3dtexture = NULL;
961 void R_Shadow_ValidateCvars(void)
963 if (r_shadow_texture3d.integer && !gl_texture3d)
964 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
965 if (gl_ext_separatestencil.integer && !gl_support_separatestencil)
966 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
967 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
968 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
971 void R_Shadow_RenderMode_Begin(void)
973 R_Shadow_ValidateCvars();
975 if (!r_shadow_attenuation2dtexture
976 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
977 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
978 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
979 R_Shadow_MakeTextures();
982 R_Mesh_ColorPointer(NULL, 0, 0);
983 R_Mesh_ResetTextureState();
984 GL_BlendFunc(GL_ONE, GL_ZERO);
988 GL_Color(0, 0, 0, 1);
989 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
991 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
993 if (gl_ext_separatestencil.integer)
994 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
995 else if (gl_ext_stenciltwoside.integer)
996 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
998 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
1000 if (r_glsl.integer && gl_support_fragment_shader)
1001 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1002 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
1003 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
1005 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1008 void R_Shadow_RenderMode_ActiveLight(rtlight_t *rtlight)
1010 rsurface.rtlight = rtlight;
1013 void R_Shadow_RenderMode_Reset(void)
1016 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1018 qglUseProgramObjectARB(0);CHECKGLERROR
1020 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
1022 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1024 R_Mesh_ColorPointer(NULL, 0, 0);
1025 R_Mesh_ResetTextureState();
1026 GL_DepthRange(0, 1);
1028 GL_DepthMask(false);
1029 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1030 qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1031 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1032 qglStencilMask(~0);CHECKGLERROR
1033 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1034 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1035 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
1036 GL_Color(1, 1, 1, 1);
1037 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
1038 GL_BlendFunc(GL_ONE, GL_ZERO);
1041 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean clearstencil)
1044 R_Shadow_RenderMode_Reset();
1045 GL_ColorMask(0, 0, 0, 0);
1046 qglPolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1047 qglDepthFunc(GL_LESS);CHECKGLERROR
1048 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1049 r_shadow_rendermode = r_shadow_shadowingrendermode;
1050 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SEPARATESTENCIL)
1052 GL_CullFace(GL_NONE);
1053 qglStencilOpSeparate(GL_BACK, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR // quake is backwards, this is front faces
1054 qglStencilOpSeparate(GL_FRONT, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR // quake is backwards, this is back faces
1056 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
1058 GL_CullFace(GL_NONE);
1059 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1060 qglActiveStencilFaceEXT(GL_BACK);CHECKGLERROR // quake is backwards, this is front faces
1061 qglStencilMask(~0);CHECKGLERROR
1062 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1063 qglActiveStencilFaceEXT(GL_FRONT);CHECKGLERROR // quake is backwards, this is back faces
1064 qglStencilMask(~0);CHECKGLERROR
1065 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1068 GL_Clear(GL_STENCIL_BUFFER_BIT);
1069 r_refdef.stats.lights_clears++;
1072 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent)
1075 R_Shadow_RenderMode_Reset();
1076 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1079 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1083 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1084 // only draw light where this geometry was already rendered AND the
1085 // stencil is 128 (values other than this mean shadow)
1086 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1088 r_shadow_rendermode = r_shadow_lightingrendermode;
1089 // do global setup needed for the chosen lighting mode
1090 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1092 R_Mesh_TexBind(0, R_GetTexture(r_texture_blanknormalmap)); // normal
1093 R_Mesh_TexBind(1, R_GetTexture(r_texture_white)); // diffuse
1094 R_Mesh_TexBind(2, R_GetTexture(r_texture_white)); // gloss
1095 R_Mesh_TexBindCubeMap(3, R_GetTexture(rsurface.rtlight->currentcubemap)); // light filter
1096 R_Mesh_TexBind(4, R_GetTexture(r_texture_fogattenuation)); // fog
1097 R_Mesh_TexBind(5, R_GetTexture(r_texture_white)); // pants
1098 R_Mesh_TexBind(6, R_GetTexture(r_texture_white)); // shirt
1099 R_Mesh_TexBind(7, R_GetTexture(r_texture_white)); // lightmap
1100 R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap)); // deluxemap
1101 R_Mesh_TexBind(9, R_GetTexture(r_texture_black)); // glow
1102 //R_Mesh_TexMatrix(3, rsurface.entitytolight); // light filter matrix
1103 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1104 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 0);
1109 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
1112 R_Shadow_RenderMode_Reset();
1113 GL_BlendFunc(GL_ONE, GL_ONE);
1114 GL_DepthRange(0, 1);
1115 GL_DepthTest(r_showshadowvolumes.integer < 2);
1116 GL_Color(0.0, 0.0125 * r_view.colorscale, 0.1 * r_view.colorscale, 1);
1117 qglPolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1118 GL_CullFace(GL_NONE);
1119 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
1122 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
1125 R_Shadow_RenderMode_Reset();
1126 GL_BlendFunc(GL_ONE, GL_ONE);
1127 GL_DepthRange(0, 1);
1128 GL_DepthTest(r_showlighting.integer < 2);
1129 GL_Color(0.1 * r_view.colorscale, 0.0125 * r_view.colorscale, 0, 1);
1132 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1136 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1137 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1139 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
1142 void R_Shadow_RenderMode_End(void)
1145 R_Shadow_RenderMode_Reset();
1146 R_Shadow_RenderMode_ActiveLight(NULL);
1148 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
1149 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1152 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1154 int i, ix1, iy1, ix2, iy2;
1155 float x1, y1, x2, y2;
1158 mplane_t planes[11];
1159 float vertex3f[256*3];
1161 // if view is inside the light box, just say yes it's visible
1162 if (BoxesOverlap(r_view.origin, r_view.origin, mins, maxs))
1164 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
1168 // create a temporary brush describing the area the light can affect in worldspace
1169 VectorNegate(r_view.frustum[0].normal, planes[ 0].normal);planes[ 0].dist = -r_view.frustum[0].dist;
1170 VectorNegate(r_view.frustum[1].normal, planes[ 1].normal);planes[ 1].dist = -r_view.frustum[1].dist;
1171 VectorNegate(r_view.frustum[2].normal, planes[ 2].normal);planes[ 2].dist = -r_view.frustum[2].dist;
1172 VectorNegate(r_view.frustum[3].normal, planes[ 3].normal);planes[ 3].dist = -r_view.frustum[3].dist;
1173 VectorNegate(r_view.frustum[4].normal, planes[ 4].normal);planes[ 4].dist = -r_view.frustum[4].dist;
1174 VectorSet (planes[ 5].normal, 1, 0, 0); planes[ 5].dist = maxs[0];
1175 VectorSet (planes[ 6].normal, -1, 0, 0); planes[ 6].dist = -mins[0];
1176 VectorSet (planes[ 7].normal, 0, 1, 0); planes[ 7].dist = maxs[1];
1177 VectorSet (planes[ 8].normal, 0, -1, 0); planes[ 8].dist = -mins[1];
1178 VectorSet (planes[ 9].normal, 0, 0, 1); planes[ 9].dist = maxs[2];
1179 VectorSet (planes[10].normal, 0, 0, -1); planes[10].dist = -mins[2];
1181 // turn the brush into a mesh
1182 memset(&mesh, 0, sizeof(rmesh_t));
1183 mesh.maxvertices = 256;
1184 mesh.vertex3f = vertex3f;
1185 mesh.epsilon2 = (1.0f / (32.0f * 32.0f));
1186 R_Mesh_AddBrushMeshFromPlanes(&mesh, 11, planes);
1188 // if that mesh is empty, the light is not visible at all
1189 if (!mesh.numvertices)
1192 if (!r_shadow_scissor.integer)
1195 // if that mesh is not empty, check what area of the screen it covers
1196 x1 = y1 = x2 = y2 = 0;
1198 //Con_Printf("%i vertices to transform...\n", mesh.numvertices);
1199 for (i = 0;i < mesh.numvertices;i++)
1201 VectorCopy(mesh.vertex3f + i * 3, v);
1202 GL_TransformToScreen(v, v2);
1203 //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]);
1206 if (x1 > v2[0]) x1 = v2[0];
1207 if (x2 < v2[0]) x2 = v2[0];
1208 if (y1 > v2[1]) y1 = v2[1];
1209 if (y2 < v2[1]) y2 = v2[1];
1218 // now convert the scissor rectangle to integer screen coordinates
1219 ix1 = (int)(x1 - 1.0f);
1220 iy1 = (int)(y1 - 1.0f);
1221 ix2 = (int)(x2 + 1.0f);
1222 iy2 = (int)(y2 + 1.0f);
1223 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1225 // clamp it to the screen
1226 if (ix1 < r_view.x) ix1 = r_view.x;
1227 if (iy1 < r_view.y) iy1 = r_view.y;
1228 if (ix2 > r_view.x + r_view.width) ix2 = r_view.x + r_view.width;
1229 if (iy2 > r_view.y + r_view.height) iy2 = r_view.y + r_view.height;
1231 // if it is inside out, it's not visible
1232 if (ix2 <= ix1 || iy2 <= iy1)
1235 // the light area is visible, set up the scissor rectangle
1236 GL_Scissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1237 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);CHECKGLERROR
1238 //qglEnable(GL_SCISSOR_TEST);CHECKGLERROR
1239 r_refdef.stats.lights_scissored++;
1243 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
1245 float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1246 float *normal3f = rsurface.normal3f + 3 * firstvertex;
1247 float *color4f = rsurface.array_color4f + 4 * firstvertex;
1248 float dist, dot, distintensity, shadeintensity, v[3], n[3];
1249 if (r_textureunits.integer >= 3)
1251 if (VectorLength2(diffusecolor) > 0)
1253 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1255 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1256 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1257 if ((dot = DotProduct(n, v)) < 0)
1259 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1260 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
1263 VectorCopy(ambientcolor, color4f);
1264 if (r_refdef.fogenabled)
1267 f = FogPoint_Model(vertex3f);
1268 VectorScale(color4f, f, color4f);
1275 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1277 VectorCopy(ambientcolor, color4f);
1278 if (r_refdef.fogenabled)
1281 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1282 f = FogPoint_Model(vertex3f);
1283 VectorScale(color4f, f, color4f);
1289 else if (r_textureunits.integer >= 2)
1291 if (VectorLength2(diffusecolor) > 0)
1293 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1295 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1296 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1298 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1299 if ((dot = DotProduct(n, v)) < 0)
1301 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1302 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1303 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1304 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1308 color4f[0] = ambientcolor[0] * distintensity;
1309 color4f[1] = ambientcolor[1] * distintensity;
1310 color4f[2] = ambientcolor[2] * distintensity;
1312 if (r_refdef.fogenabled)
1315 f = FogPoint_Model(vertex3f);
1316 VectorScale(color4f, f, color4f);
1320 VectorClear(color4f);
1326 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1328 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1329 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1331 color4f[0] = ambientcolor[0] * distintensity;
1332 color4f[1] = ambientcolor[1] * distintensity;
1333 color4f[2] = ambientcolor[2] * distintensity;
1334 if (r_refdef.fogenabled)
1337 f = FogPoint_Model(vertex3f);
1338 VectorScale(color4f, f, color4f);
1342 VectorClear(color4f);
1349 if (VectorLength2(diffusecolor) > 0)
1351 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1353 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1354 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1356 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
1357 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1358 if ((dot = DotProduct(n, v)) < 0)
1360 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1361 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1362 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1363 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1367 color4f[0] = ambientcolor[0] * distintensity;
1368 color4f[1] = ambientcolor[1] * distintensity;
1369 color4f[2] = ambientcolor[2] * distintensity;
1371 if (r_refdef.fogenabled)
1374 f = FogPoint_Model(vertex3f);
1375 VectorScale(color4f, f, color4f);
1379 VectorClear(color4f);
1385 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1387 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1388 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1390 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
1391 color4f[0] = ambientcolor[0] * distintensity;
1392 color4f[1] = ambientcolor[1] * distintensity;
1393 color4f[2] = ambientcolor[2] * distintensity;
1394 if (r_refdef.fogenabled)
1397 f = FogPoint_Model(vertex3f);
1398 VectorScale(color4f, f, color4f);
1402 VectorClear(color4f);
1409 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1411 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
1414 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
1415 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1416 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
1417 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
1418 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
1420 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1422 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
1423 // the cubemap normalizes this for us
1424 out3f[0] = DotProduct(svector3f, lightdir);
1425 out3f[1] = DotProduct(tvector3f, lightdir);
1426 out3f[2] = DotProduct(normal3f, lightdir);
1430 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
1433 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
1434 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1435 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
1436 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
1437 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
1438 float lightdir[3], eyedir[3], halfdir[3];
1439 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1441 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
1442 VectorNormalize(lightdir);
1443 VectorSubtract(rsurface.modelorg, vertex3f, eyedir);
1444 VectorNormalize(eyedir);
1445 VectorAdd(lightdir, eyedir, halfdir);
1446 // the cubemap normalizes this for us
1447 out3f[0] = DotProduct(svector3f, halfdir);
1448 out3f[1] = DotProduct(tvector3f, halfdir);
1449 out3f[2] = DotProduct(normal3f, halfdir);
1453 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)
1455 // used to display how many times a surface is lit for level design purposes
1456 GL_Color(0.1 * r_view.colorscale, 0.025 * r_view.colorscale, 0, 1);
1457 R_Mesh_ColorPointer(NULL, 0, 0);
1458 R_Mesh_ResetTextureState();
1459 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1462 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)
1464 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
1465 R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale);
1466 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
1467 R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
1468 R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
1469 R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
1470 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1472 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1474 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1475 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1477 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1481 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)
1483 // shared final code for all the dot3 layers
1485 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 0);
1486 for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
1488 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
1489 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1493 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)
1496 // colorscale accounts for how much we multiply the brightness
1499 // mult is how many times the final pass of the lighting will be
1500 // performed to get more brightness than otherwise possible.
1502 // Limit mult to 64 for sanity sake.
1504 if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1506 // 3 3D combine path (Geforce3, Radeon 8500)
1507 memset(&m, 0, sizeof(m));
1508 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1509 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1510 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1511 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1512 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1513 m.tex[1] = R_GetTexture(basetexture);
1514 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
1515 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
1516 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
1517 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
1518 m.texcubemap[2] = R_GetTexture(rsurface.rtlight->currentcubemap);
1519 m.pointer_texcoord3f[2] = rsurface.vertex3f;
1520 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
1521 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
1522 m.texmatrix[2] = rsurface.entitytolight;
1523 GL_BlendFunc(GL_ONE, GL_ONE);
1525 else if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1527 // 2 3D combine path (Geforce3, original Radeon)
1528 memset(&m, 0, sizeof(m));
1529 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1530 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1531 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1532 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1533 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1534 m.tex[1] = R_GetTexture(basetexture);
1535 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
1536 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
1537 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
1538 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
1539 GL_BlendFunc(GL_ONE, GL_ONE);
1541 else if (r_textureunits.integer >= 4 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
1543 // 4 2D combine path (Geforce3, Radeon 8500)
1544 memset(&m, 0, sizeof(m));
1545 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1546 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1547 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1548 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1549 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1550 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1551 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1552 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1553 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1554 m.texmatrix[1] = rsurface.entitytoattenuationz;
1555 m.tex[2] = R_GetTexture(basetexture);
1556 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
1557 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
1558 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
1559 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
1560 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1562 m.texcubemap[3] = R_GetTexture(rsurface.rtlight->currentcubemap);
1563 m.pointer_texcoord3f[3] = rsurface.vertex3f;
1564 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
1565 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
1566 m.texmatrix[3] = rsurface.entitytolight;
1568 GL_BlendFunc(GL_ONE, GL_ONE);
1570 else if (r_textureunits.integer >= 3 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
1572 // 3 2D combine path (Geforce3, original Radeon)
1573 memset(&m, 0, sizeof(m));
1574 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1575 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1576 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1577 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1578 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1579 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1580 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1581 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1582 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1583 m.texmatrix[1] = rsurface.entitytoattenuationz;
1584 m.tex[2] = R_GetTexture(basetexture);
1585 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
1586 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
1587 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
1588 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
1589 GL_BlendFunc(GL_ONE, GL_ONE);
1593 // 2/2/2 2D combine path (any dot3 card)
1594 memset(&m, 0, sizeof(m));
1595 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1596 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1597 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1598 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1599 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1600 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1601 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1602 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1603 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1604 m.texmatrix[1] = rsurface.entitytoattenuationz;
1605 R_Mesh_TextureState(&m);
1606 GL_ColorMask(0,0,0,1);
1607 GL_BlendFunc(GL_ONE, GL_ZERO);
1608 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1611 memset(&m, 0, sizeof(m));
1612 m.tex[0] = R_GetTexture(basetexture);
1613 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1614 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1615 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1616 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1617 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1619 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1620 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1621 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1622 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1623 m.texmatrix[1] = rsurface.entitytolight;
1625 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1627 // this final code is shared
1628 R_Mesh_TextureState(&m);
1629 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1632 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)
1635 // colorscale accounts for how much we multiply the brightness
1638 // mult is how many times the final pass of the lighting will be
1639 // performed to get more brightness than otherwise possible.
1641 // Limit mult to 64 for sanity sake.
1643 // generate normalization cubemap texcoords
1644 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
1645 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1647 // 3/2 3D combine path (Geforce3, Radeon 8500)
1648 memset(&m, 0, sizeof(m));
1649 m.tex[0] = R_GetTexture(normalmaptexture);
1650 m.texcombinergb[0] = GL_REPLACE;
1651 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1652 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1653 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1654 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1655 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1656 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1657 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1658 m.pointer_texcoord_bufferobject[1] = 0;
1659 m.pointer_texcoord_bufferoffset[1] = 0;
1660 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1661 m.pointer_texcoord3f[2] = rsurface.vertex3f;
1662 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
1663 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
1664 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
1665 R_Mesh_TextureState(&m);
1666 GL_ColorMask(0,0,0,1);
1667 GL_BlendFunc(GL_ONE, GL_ZERO);
1668 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1671 memset(&m, 0, sizeof(m));
1672 m.tex[0] = R_GetTexture(basetexture);
1673 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1674 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1675 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1676 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1677 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1679 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1680 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1681 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1682 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1683 m.texmatrix[1] = rsurface.entitytolight;
1685 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1687 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
1689 // 1/2/2 3D combine path (original Radeon)
1690 memset(&m, 0, sizeof(m));
1691 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1692 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1693 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1694 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1695 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1696 R_Mesh_TextureState(&m);
1697 GL_ColorMask(0,0,0,1);
1698 GL_BlendFunc(GL_ONE, GL_ZERO);
1699 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1702 memset(&m, 0, sizeof(m));
1703 m.tex[0] = R_GetTexture(normalmaptexture);
1704 m.texcombinergb[0] = GL_REPLACE;
1705 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1706 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1707 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1708 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1709 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1710 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1711 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1712 m.pointer_texcoord_bufferobject[1] = 0;
1713 m.pointer_texcoord_bufferoffset[1] = 0;
1714 R_Mesh_TextureState(&m);
1715 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1716 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1719 memset(&m, 0, sizeof(m));
1720 m.tex[0] = R_GetTexture(basetexture);
1721 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1722 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1723 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1724 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1725 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1727 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1728 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1729 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1730 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1731 m.texmatrix[1] = rsurface.entitytolight;
1733 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1735 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
1737 // 2/2 3D combine path (original Radeon)
1738 memset(&m, 0, sizeof(m));
1739 m.tex[0] = R_GetTexture(normalmaptexture);
1740 m.texcombinergb[0] = GL_REPLACE;
1741 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1742 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1743 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1744 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1745 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1746 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1747 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1748 m.pointer_texcoord_bufferobject[1] = 0;
1749 m.pointer_texcoord_bufferoffset[1] = 0;
1750 R_Mesh_TextureState(&m);
1751 GL_ColorMask(0,0,0,1);
1752 GL_BlendFunc(GL_ONE, GL_ZERO);
1753 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1756 memset(&m, 0, sizeof(m));
1757 m.tex[0] = R_GetTexture(basetexture);
1758 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1759 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1760 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1761 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1762 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1763 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1764 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1765 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1766 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
1767 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1769 else if (r_textureunits.integer >= 4)
1771 // 4/2 2D combine path (Geforce3, Radeon 8500)
1772 memset(&m, 0, sizeof(m));
1773 m.tex[0] = R_GetTexture(normalmaptexture);
1774 m.texcombinergb[0] = GL_REPLACE;
1775 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1776 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1777 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1778 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1779 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1780 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1781 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1782 m.pointer_texcoord_bufferobject[1] = 0;
1783 m.pointer_texcoord_bufferoffset[1] = 0;
1784 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1785 m.pointer_texcoord3f[2] = rsurface.vertex3f;
1786 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
1787 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
1788 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
1789 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1790 m.pointer_texcoord3f[3] = rsurface.vertex3f;
1791 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
1792 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
1793 m.texmatrix[3] = rsurface.entitytoattenuationz;
1794 R_Mesh_TextureState(&m);
1795 GL_ColorMask(0,0,0,1);
1796 GL_BlendFunc(GL_ONE, GL_ZERO);
1797 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1800 memset(&m, 0, sizeof(m));
1801 m.tex[0] = R_GetTexture(basetexture);
1802 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1803 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1804 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1805 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1806 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1808 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1809 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1810 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1811 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1812 m.texmatrix[1] = rsurface.entitytolight;
1814 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1818 // 2/2/2 2D combine path (any dot3 card)
1819 memset(&m, 0, sizeof(m));
1820 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1821 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1822 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1823 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1824 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1825 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1826 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1827 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1828 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1829 m.texmatrix[1] = rsurface.entitytoattenuationz;
1830 R_Mesh_TextureState(&m);
1831 GL_ColorMask(0,0,0,1);
1832 GL_BlendFunc(GL_ONE, GL_ZERO);
1833 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1836 memset(&m, 0, sizeof(m));
1837 m.tex[0] = R_GetTexture(normalmaptexture);
1838 m.texcombinergb[0] = GL_REPLACE;
1839 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1840 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1841 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1842 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1843 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1844 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1845 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1846 m.pointer_texcoord_bufferobject[1] = 0;
1847 m.pointer_texcoord_bufferoffset[1] = 0;
1848 R_Mesh_TextureState(&m);
1849 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1850 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1853 memset(&m, 0, sizeof(m));
1854 m.tex[0] = R_GetTexture(basetexture);
1855 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1856 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1857 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1858 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1859 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1861 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1862 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1863 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1864 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1865 m.texmatrix[1] = rsurface.entitytolight;
1867 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1869 // this final code is shared
1870 R_Mesh_TextureState(&m);
1871 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1874 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)
1876 float glossexponent;
1878 // FIXME: detect blendsquare!
1879 //if (!gl_support_blendsquare)
1882 // generate normalization cubemap texcoords
1883 R_Shadow_GenTexCoords_Specular_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
1884 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
1886 // 2/0/0/1/2 3D combine blendsquare path
1887 memset(&m, 0, sizeof(m));
1888 m.tex[0] = R_GetTexture(normalmaptexture);
1889 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1890 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1891 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1892 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1893 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1894 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1895 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1896 m.pointer_texcoord_bufferobject[1] = 0;
1897 m.pointer_texcoord_bufferoffset[1] = 0;
1898 R_Mesh_TextureState(&m);
1899 GL_ColorMask(0,0,0,1);
1900 // this squares the result
1901 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1902 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1904 // second and third pass
1905 R_Mesh_ResetTextureState();
1906 // square alpha in framebuffer a few times to make it shiny
1907 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1908 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
1909 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1912 memset(&m, 0, sizeof(m));
1913 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1914 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1915 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1916 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1917 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1918 R_Mesh_TextureState(&m);
1919 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1920 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1923 memset(&m, 0, sizeof(m));
1924 m.tex[0] = R_GetTexture(glosstexture);
1925 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1926 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1927 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1928 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1929 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1931 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1932 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1933 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1934 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1935 m.texmatrix[1] = rsurface.entitytolight;
1937 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1939 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
1941 // 2/0/0/2 3D combine blendsquare path
1942 memset(&m, 0, sizeof(m));
1943 m.tex[0] = R_GetTexture(normalmaptexture);
1944 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1945 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1946 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1947 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1948 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1949 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1950 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1951 m.pointer_texcoord_bufferobject[1] = 0;
1952 m.pointer_texcoord_bufferoffset[1] = 0;
1953 R_Mesh_TextureState(&m);
1954 GL_ColorMask(0,0,0,1);
1955 // this squares the result
1956 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1957 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1959 // second and third pass
1960 R_Mesh_ResetTextureState();
1961 // square alpha in framebuffer a few times to make it shiny
1962 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1963 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
1964 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1967 memset(&m, 0, sizeof(m));
1968 m.tex[0] = R_GetTexture(glosstexture);
1969 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1970 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1971 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1972 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1973 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1974 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1975 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1976 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1977 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
1978 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1982 // 2/0/0/2/2 2D combine blendsquare path
1983 memset(&m, 0, sizeof(m));
1984 m.tex[0] = R_GetTexture(normalmaptexture);
1985 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1986 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1987 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1988 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1989 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1990 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1991 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1992 m.pointer_texcoord_bufferobject[1] = 0;
1993 m.pointer_texcoord_bufferoffset[1] = 0;
1994 R_Mesh_TextureState(&m);
1995 GL_ColorMask(0,0,0,1);
1996 // this squares the result
1997 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1998 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2000 // second and third pass
2001 R_Mesh_ResetTextureState();
2002 // square alpha in framebuffer a few times to make it shiny
2003 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2004 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2005 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2008 memset(&m, 0, sizeof(m));
2009 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2010 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2011 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2012 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2013 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2014 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2015 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2016 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2017 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2018 m.texmatrix[1] = rsurface.entitytoattenuationz;
2019 R_Mesh_TextureState(&m);
2020 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2021 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2024 memset(&m, 0, sizeof(m));
2025 m.tex[0] = R_GetTexture(glosstexture);
2026 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2027 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2028 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2029 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2030 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2032 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2033 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2034 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2035 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2036 m.texmatrix[1] = rsurface.entitytolight;
2038 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2040 // this final code is shared
2041 R_Mesh_TextureState(&m);
2042 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
2045 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)
2047 // ARB path (any Geforce, any Radeon)
2048 qboolean doambient = ambientscale > 0;
2049 qboolean dodiffuse = diffusescale > 0;
2050 qboolean dospecular = specularscale > 0;
2051 if (!doambient && !dodiffuse && !dospecular)
2053 R_Mesh_ColorPointer(NULL, 0, 0);
2055 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, basetexture, ambientscale * r_view.colorscale);
2057 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, basetexture, normalmaptexture, diffusescale * r_view.colorscale);
2061 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorpants, pantstexture, ambientscale * r_view.colorscale);
2063 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorpants, pantstexture, normalmaptexture, diffusescale * r_view.colorscale);
2068 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorshirt, shirttexture, ambientscale * r_view.colorscale);
2070 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorshirt, shirttexture, normalmaptexture, diffusescale * r_view.colorscale);
2073 R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_view.colorscale);
2076 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)
2083 int newnumtriangles;
2087 int newelements[4096*3];
2088 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
2089 for (renders = 0;renders < 64;renders++)
2094 newnumtriangles = 0;
2096 // due to low fillrate on the cards this vertex lighting path is
2097 // designed for, we manually cull all triangles that do not
2098 // contain a lit vertex
2099 // this builds batches of triangles from multiple surfaces and
2100 // renders them at once
2101 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2103 if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
2105 if (newnumtriangles)
2107 newfirstvertex = min(newfirstvertex, e[0]);
2108 newlastvertex = max(newlastvertex, e[0]);
2112 newfirstvertex = e[0];
2113 newlastvertex = e[0];
2115 newfirstvertex = min(newfirstvertex, e[1]);
2116 newlastvertex = max(newlastvertex, e[1]);
2117 newfirstvertex = min(newfirstvertex, e[2]);
2118 newlastvertex = max(newlastvertex, e[2]);
2124 if (newnumtriangles >= (int)(sizeof(newelements)/sizeof(float[3])))
2126 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, newnumtriangles, newelements, 0, 0);
2127 newnumtriangles = 0;
2133 if (newnumtriangles >= 1)
2135 // if all triangles are included, use the original array to take advantage of the bufferobject if possible
2136 if (newnumtriangles == numtriangles)
2137 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2139 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, newnumtriangles, newelements, 0, 0);
2142 // if we couldn't find any lit triangles, exit early
2145 // now reduce the intensity for the next overbright pass
2146 // we have to clamp to 0 here incase the drivers have improper
2147 // handling of negative colors
2148 // (some old drivers even have improper handling of >1 color)
2150 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2152 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2154 c[0] = max(0, c[0] - 1);
2155 c[1] = max(0, c[1] - 1);
2156 c[2] = max(0, c[2] - 1);
2168 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)
2170 // OpenGL 1.1 path (anything)
2171 float ambientcolorbase[3], diffusecolorbase[3];
2172 float ambientcolorpants[3], diffusecolorpants[3];
2173 float ambientcolorshirt[3], diffusecolorshirt[3];
2175 VectorScale(lightcolorbase, ambientscale * 2 * r_view.colorscale, ambientcolorbase);
2176 VectorScale(lightcolorbase, diffusescale * 2 * r_view.colorscale, diffusecolorbase);
2177 VectorScale(lightcolorpants, ambientscale * 2 * r_view.colorscale, ambientcolorpants);
2178 VectorScale(lightcolorpants, diffusescale * 2 * r_view.colorscale, diffusecolorpants);
2179 VectorScale(lightcolorshirt, ambientscale * 2 * r_view.colorscale, ambientcolorshirt);
2180 VectorScale(lightcolorshirt, diffusescale * 2 * r_view.colorscale, diffusecolorshirt);
2181 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2182 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
2183 memset(&m, 0, sizeof(m));
2184 m.tex[0] = R_GetTexture(basetexture);
2185 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2186 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2187 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2188 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2189 if (r_textureunits.integer >= 2)
2192 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2193 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2194 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2195 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2196 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2197 if (r_textureunits.integer >= 3)
2199 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
2200 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2201 m.texmatrix[2] = rsurface.entitytoattenuationz;
2202 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2203 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2204 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2207 R_Mesh_TextureState(&m);
2208 //R_Mesh_TexBind(0, R_GetTexture(basetexture));
2209 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, diffusecolorbase, ambientcolorbase);
2212 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
2213 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, diffusecolorpants, ambientcolorpants);
2217 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
2218 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, diffusecolorshirt, ambientcolorshirt);
2222 void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset)
2224 float ambientscale, diffusescale, specularscale;
2225 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
2226 // calculate colors to render this texture with
2227 lightcolorbase[0] = rsurface.rtlight->currentcolor[0] * rsurface.texture->currentlayers[0].color[0] * rsurface.texture->currentlayers[0].color[3];
2228 lightcolorbase[1] = rsurface.rtlight->currentcolor[1] * rsurface.texture->currentlayers[0].color[1] * rsurface.texture->currentlayers[0].color[3];
2229 lightcolorbase[2] = rsurface.rtlight->currentcolor[2] * rsurface.texture->currentlayers[0].color[2] * rsurface.texture->currentlayers[0].color[3];
2230 ambientscale = rsurface.rtlight->ambientscale;
2231 diffusescale = rsurface.rtlight->diffusescale;
2232 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2233 if (!r_shadow_usenormalmap.integer)
2235 ambientscale += 1.0f * diffusescale;
2239 if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
2241 GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
2242 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
2243 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
2244 if (rsurface.texture->colormapping)
2246 qboolean dopants = rsurface.texture->currentskinframe->pants != NULL && VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f);
2247 qboolean doshirt = rsurface.texture->currentskinframe->shirt != NULL && VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f);
2250 lightcolorpants[0] = lightcolorbase[0] * rsurface.colormap_pantscolor[0];
2251 lightcolorpants[1] = lightcolorbase[1] * rsurface.colormap_pantscolor[1];
2252 lightcolorpants[2] = lightcolorbase[2] * rsurface.colormap_pantscolor[2];
2255 VectorClear(lightcolorpants);
2258 lightcolorshirt[0] = lightcolorbase[0] * rsurface.colormap_shirtcolor[0];
2259 lightcolorshirt[1] = lightcolorbase[1] * rsurface.colormap_shirtcolor[1];
2260 lightcolorshirt[2] = lightcolorbase[2] * rsurface.colormap_shirtcolor[2];
2263 VectorClear(lightcolorshirt);
2264 switch (r_shadow_rendermode)
2266 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2267 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2268 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, rsurface.texture->currentskinframe->nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, dopants, doshirt);
2270 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2271 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, rsurface.texture->currentskinframe->nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, dopants, doshirt);
2273 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2274 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, rsurface.texture->currentskinframe->nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, dopants, doshirt);
2276 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2277 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, rsurface.texture->currentskinframe->nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, dopants, doshirt);
2280 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2286 switch (r_shadow_rendermode)
2288 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2289 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2290 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, rsurface.texture->currentskinframe->nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, false, false);
2292 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2293 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, rsurface.texture->currentskinframe->nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, false, false);
2295 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2296 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, rsurface.texture->currentskinframe->nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, false, false);
2298 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2299 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, rsurface.texture->currentskinframe->nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, false, false);
2302 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2308 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)
2310 matrix4x4_t tempmatrix = *matrix;
2311 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2313 // if this light has been compiled before, free the associated data
2314 R_RTLight_Uncompile(rtlight);
2316 // clear it completely to avoid any lingering data
2317 memset(rtlight, 0, sizeof(*rtlight));
2319 // copy the properties
2320 rtlight->matrix_lighttoworld = tempmatrix;
2321 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2322 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2323 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2324 VectorCopy(color, rtlight->color);
2325 rtlight->cubemapname[0] = 0;
2326 if (cubemapname && cubemapname[0])
2327 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2328 rtlight->shadow = shadow;
2329 rtlight->corona = corona;
2330 rtlight->style = style;
2331 rtlight->isstatic = isstatic;
2332 rtlight->coronasizescale = coronasizescale;
2333 rtlight->ambientscale = ambientscale;
2334 rtlight->diffusescale = diffusescale;
2335 rtlight->specularscale = specularscale;
2336 rtlight->flags = flags;
2338 // compute derived data
2339 //rtlight->cullradius = rtlight->radius;
2340 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2341 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2342 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2343 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2344 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2345 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2346 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2349 // compiles rtlight geometry
2350 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2351 void R_RTLight_Compile(rtlight_t *rtlight)
2354 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2355 int lighttris, shadowtris, shadowmeshes, shadowmeshtris;
2356 entity_render_t *ent = r_refdef.worldentity;
2357 model_t *model = r_refdef.worldmodel;
2358 unsigned char *data;
2360 // compile the light
2361 rtlight->compiled = true;
2362 rtlight->static_numleafs = 0;
2363 rtlight->static_numleafpvsbytes = 0;
2364 rtlight->static_leaflist = NULL;
2365 rtlight->static_leafpvs = NULL;
2366 rtlight->static_numsurfaces = 0;
2367 rtlight->static_surfacelist = NULL;
2368 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2369 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2370 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2371 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2372 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2373 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2375 if (model && model->GetLightInfo)
2377 // this variable must be set for the CompileShadowVolume code
2378 r_shadow_compilingrtlight = rtlight;
2379 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);
2380 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);
2381 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2382 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
2383 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
2384 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
2385 rtlight->static_numsurfaces = numsurfaces;
2386 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2387 rtlight->static_numleafs = numleafs;
2388 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2389 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2390 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2391 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
2392 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
2393 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
2394 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
2395 if (rtlight->static_numsurfaces)
2396 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2397 if (rtlight->static_numleafs)
2398 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2399 if (rtlight->static_numleafpvsbytes)
2400 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2401 if (rtlight->static_numshadowtrispvsbytes)
2402 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
2403 if (rtlight->static_numlighttrispvsbytes)
2404 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
2405 if (model->CompileShadowVolume && rtlight->shadow)
2406 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2407 // now we're done compiling the rtlight
2408 r_shadow_compilingrtlight = NULL;
2412 // use smallest available cullradius - box radius or light radius
2413 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2414 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2418 if (rtlight->static_meshchain_shadow)
2421 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2424 shadowmeshtris += mesh->numtriangles;
2429 if (rtlight->static_numlighttrispvsbytes)
2430 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
2431 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
2435 if (rtlight->static_numlighttrispvsbytes)
2436 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
2437 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
2440 if (developer.integer >= 10)
2441 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);
2444 void R_RTLight_Uncompile(rtlight_t *rtlight)
2446 if (rtlight->compiled)
2448 if (rtlight->static_meshchain_shadow)
2449 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2450 rtlight->static_meshchain_shadow = NULL;
2451 // these allocations are grouped
2452 if (rtlight->static_surfacelist)
2453 Mem_Free(rtlight->static_surfacelist);
2454 rtlight->static_numleafs = 0;
2455 rtlight->static_numleafpvsbytes = 0;
2456 rtlight->static_leaflist = NULL;
2457 rtlight->static_leafpvs = NULL;
2458 rtlight->static_numsurfaces = 0;
2459 rtlight->static_surfacelist = NULL;
2460 rtlight->static_numshadowtrispvsbytes = 0;
2461 rtlight->static_shadowtrispvs = NULL;
2462 rtlight->static_numlighttrispvsbytes = 0;
2463 rtlight->static_lighttrispvs = NULL;
2464 rtlight->compiled = false;
2468 void R_Shadow_UncompileWorldLights(void)
2471 for (light = r_shadow_worldlightchain;light;light = light->next)
2472 R_RTLight_Uncompile(&light->rtlight);
2475 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
2479 // reset the count of frustum planes
2480 // see rsurface.rtlight_frustumplanes definition for how much this array
2482 rsurface.rtlight_numfrustumplanes = 0;
2485 // generate a deformed frustum that includes the light origin, this is
2486 // used to cull shadow casting surfaces that can not possibly cast a
2487 // shadow onto the visible light-receiving surfaces, which can be a
2490 // if the light origin is onscreen the result will be 4 planes exactly
2491 // if the light origin is offscreen on only one axis the result will
2492 // be exactly 5 planes (split-side case)
2493 // if the light origin is offscreen on two axes the result will be
2494 // exactly 4 planes (stretched corner case)
2495 for (i = 0;i < 4;i++)
2497 // quickly reject standard frustum planes that put the light
2498 // origin outside the frustum
2499 if (PlaneDiff(rtlight->shadoworigin, &r_view.frustum[i]) < -0.03125)
2502 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_view.frustum[i];
2504 // if all the standard frustum planes were accepted, the light is onscreen
2505 // otherwise we need to generate some more planes below...
2506 if (rsurface.rtlight_numfrustumplanes < 4)
2508 // at least one of the stock frustum planes failed, so we need to
2509 // create one or two custom planes to enclose the light origin
2510 for (i = 0;i < 4;i++)
2512 // create a plane using the view origin and light origin, and a
2513 // single point from the frustum corner set
2514 TriangleNormal(r_view.origin, r_view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
2515 VectorNormalize(plane.normal);
2516 plane.dist = DotProduct(r_view.origin, plane.normal);
2517 // see if this plane is backwards and flip it if so
2518 for (j = 0;j < 4;j++)
2519 if (j != i && DotProduct(r_view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
2523 VectorNegate(plane.normal, plane.normal);
2525 // flipped plane, test again to see if it is now valid
2526 for (j = 0;j < 4;j++)
2527 if (j != i && DotProduct(r_view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
2529 // if the plane is still not valid, then it is dividing the
2530 // frustum and has to be rejected
2534 // we have created a valid plane, compute extra info
2535 PlaneClassify(&plane);
2537 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
2539 // if we've found 5 frustum planes then we have constructed a
2540 // proper split-side case and do not need to keep searching for
2541 // planes to enclose the light origin
2542 if (rsurface.rtlight_numfrustumplanes == 5)
2550 for (i = 0;i < rsurface.rtlight_numfrustumplanes;i++)
2552 plane = rsurface.rtlight_frustumplanes[i];
2553 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));
2558 // now add the light-space box planes if the light box is rotated, as any
2559 // caster outside the oriented light box is irrelevant (even if it passed
2560 // the worldspace light box, which is axial)
2561 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
2563 for (i = 0;i < 6;i++)
2567 v[i >> 1] = (i & 1) ? -1 : 1;
2568 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
2569 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
2570 plane.dist = VectorNormalizeLength(plane.normal);
2571 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
2572 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
2578 // add the world-space reduced box planes
2579 for (i = 0;i < 6;i++)
2581 VectorClear(plane.normal);
2582 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
2583 plane.dist = (i & 1) ? -rsurface.rtlight_cullmaxs[i >> 1] : rsurface.rtlight_cullmins[i >> 1];
2584 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
2593 // reduce all plane distances to tightly fit the rtlight cull box, which
2595 VectorSet(points[0], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
2596 VectorSet(points[1], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
2597 VectorSet(points[2], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
2598 VectorSet(points[3], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
2599 VectorSet(points[4], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
2600 VectorSet(points[5], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
2601 VectorSet(points[6], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
2602 VectorSet(points[7], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
2603 oldnum = rsurface.rtlight_numfrustumplanes;
2604 rsurface.rtlight_numfrustumplanes = 0;
2605 for (j = 0;j < oldnum;j++)
2607 // find the nearest point on the box to this plane
2608 bestdist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[0]);
2609 for (i = 1;i < 8;i++)
2611 dist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[i]);
2612 if (bestdist > dist)
2615 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);
2616 // if the nearest point is near or behind the plane, we want this
2617 // plane, otherwise the plane is useless as it won't cull anything
2618 if (rsurface.rtlight_frustumplanes[j].dist < bestdist + 0.03125)
2620 PlaneClassify(&rsurface.rtlight_frustumplanes[j]);
2621 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = rsurface.rtlight_frustumplanes[j];
2628 void R_Shadow_DrawWorldShadow(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
2630 RSurf_ActiveWorldEntity();
2631 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2635 for (mesh = rsurface.rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2637 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
2638 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
2639 GL_LockArrays(0, mesh->numverts);
2640 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
2642 // decrement stencil if backface is behind depthbuffer
2643 GL_CullFace(GL_BACK); // quake is backwards, this culls front faces
2644 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2645 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->ebo, 0);
2646 // increment stencil if frontface is behind depthbuffer
2647 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
2648 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2650 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->ebo, 0);
2651 GL_LockArrays(0, 0);
2655 else if (numsurfaces && r_refdef.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
2658 int surfacelistindex;
2659 msurface_t *surface;
2660 R_Shadow_PrepareShadowMark(r_refdef.worldmodel->brush.shadowmesh->numtriangles);
2661 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
2663 surface = r_refdef.worldmodel->data_surfaces + surfacelist[surfacelistindex];
2664 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
2665 if (CHECKPVSBIT(trispvs, t))
2666 shadowmarklist[numshadowmark++] = t;
2668 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);
2670 else if (numsurfaces)
2671 r_refdef.worldmodel->DrawShadowVolume(r_refdef.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
2674 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
2676 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
2677 vec_t relativeshadowradius;
2678 RSurf_ActiveModelEntity(ent, false, false);
2679 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
2680 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
2681 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
2682 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
2683 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
2684 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
2685 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
2686 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
2687 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2690 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
2692 // set up properties for rendering light onto this entity
2693 RSurf_ActiveModelEntity(ent, true, true);
2694 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
2695 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
2696 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
2697 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
2698 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2699 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
2702 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
2704 if (!r_refdef.worldmodel->DrawLight)
2707 // set up properties for rendering light onto this entity
2708 RSurf_ActiveWorldEntity();
2709 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
2710 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
2711 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
2712 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
2713 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2714 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
2716 r_refdef.worldmodel->DrawLight(r_refdef.worldentity, numsurfaces, surfacelist, trispvs);
2719 void R_Shadow_DrawEntityLight(entity_render_t *ent, int numsurfaces, int *surfacelist)
2721 model_t *model = ent->model;
2722 if (!model->DrawLight)
2725 R_Shadow_SetupEntityLight(ent);
2727 model->DrawLight(ent, model->nummodelsurfaces, model->surfacelist, NULL);
2730 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
2734 int numleafs, numsurfaces;
2735 int *leaflist, *surfacelist;
2736 unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs;
2737 int numlightentities;
2738 int numlightentities_noselfshadow;
2739 int numshadowentities;
2740 int numshadowentities_noselfshadow;
2741 entity_render_t *lightentities[MAX_EDICTS];
2742 entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
2743 entity_render_t *shadowentities[MAX_EDICTS];
2744 entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
2746 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
2747 // skip lights that are basically invisible (color 0 0 0)
2748 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
2751 // loading is done before visibility checks because loading should happen
2752 // all at once at the start of a level, not when it stalls gameplay.
2753 // (especially important to benchmarks)
2755 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2756 R_RTLight_Compile(rtlight);
2758 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
2760 // look up the light style value at this time
2761 f = (rtlight->style >= 0 ? r_refdef.lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2762 VectorScale(rtlight->color, f, rtlight->currentcolor);
2764 if (rtlight->selected)
2766 f = 2 + sin(realtime * M_PI * 4.0);
2767 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
2771 // if lightstyle is currently off, don't draw the light
2772 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
2775 // if the light box is offscreen, skip it
2776 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2779 VectorCopy(rtlight->cullmins, rsurface.rtlight_cullmins);
2780 VectorCopy(rtlight->cullmaxs, rsurface.rtlight_cullmaxs);
2782 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2784 // compiled light, world available and can receive realtime lighting
2785 // retrieve leaf information
2786 numleafs = rtlight->static_numleafs;
2787 leaflist = rtlight->static_leaflist;
2788 leafpvs = rtlight->static_leafpvs;
2789 numsurfaces = rtlight->static_numsurfaces;
2790 surfacelist = rtlight->static_surfacelist;
2791 shadowtrispvs = rtlight->static_shadowtrispvs;
2792 lighttrispvs = rtlight->static_lighttrispvs;
2794 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2796 // dynamic light, world available and can receive realtime lighting
2797 // calculate lit surfaces and leafs
2798 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);
2799 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);
2800 leaflist = r_shadow_buffer_leaflist;
2801 leafpvs = r_shadow_buffer_leafpvs;
2802 surfacelist = r_shadow_buffer_surfacelist;
2803 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
2804 lighttrispvs = r_shadow_buffer_lighttrispvs;
2805 // if the reduced leaf bounds are offscreen, skip it
2806 if (R_CullBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
2817 shadowtrispvs = NULL;
2818 lighttrispvs = NULL;
2820 // check if light is illuminating any visible leafs
2823 for (i = 0;i < numleafs;i++)
2824 if (r_viewcache.world_leafvisible[leaflist[i]])
2829 // set up a scissor rectangle for this light
2830 if (R_Shadow_ScissorForBBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
2833 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
2835 // make a list of lit entities and shadow casting entities
2836 numlightentities = 0;
2837 numlightentities_noselfshadow = 0;
2838 numshadowentities = 0;
2839 numshadowentities_noselfshadow = 0;
2840 // add dynamic entities that are lit by the light
2841 if (r_drawentities.integer)
2843 for (i = 0;i < r_refdef.numentities;i++)
2846 entity_render_t *ent = r_refdef.entities[i];
2848 if (!BoxesOverlap(ent->mins, ent->maxs, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
2850 // skip the object entirely if it is not within the valid
2851 // shadow-casting region (which includes the lit region)
2852 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rsurface.rtlight_numfrustumplanes, rsurface.rtlight_frustumplanes))
2854 if (!(model = ent->model))
2856 if (r_viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
2858 // this entity wants to receive light, is visible, and is
2859 // inside the light box
2860 // TODO: check if the surfaces in the model can receive light
2861 // so now check if it's in a leaf seen by the light
2862 if (r_refdef.worldmodel && r_refdef.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs))
2864 if (ent->flags & RENDER_NOSELFSHADOW)
2865 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
2867 lightentities[numlightentities++] = ent;
2868 // since it is lit, it probably also casts a shadow...
2869 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2870 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
2871 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
2873 // note: exterior models without the RENDER_NOSELFSHADOW
2874 // flag still create a RENDER_NOSELFSHADOW shadow but
2875 // are lit normally, this means that they are
2876 // self-shadowing but do not shadow other
2877 // RENDER_NOSELFSHADOW entities such as the gun
2878 // (very weird, but keeps the player shadow off the gun)
2879 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
2880 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
2882 shadowentities[numshadowentities++] = ent;
2885 else if (ent->flags & RENDER_SHADOW)
2887 // this entity is not receiving light, but may still need to
2889 // TODO: check if the surfaces in the model can cast shadow
2890 // now check if it is in a leaf seen by the light
2891 if (r_refdef.worldmodel && r_refdef.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs))
2893 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2894 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
2895 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
2897 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
2898 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
2900 shadowentities[numshadowentities++] = ent;
2906 // return if there's nothing at all to light
2907 if (!numlightentities && !numsurfaces)
2910 // don't let sound skip if going slow
2911 if (r_refdef.extraupdate)
2914 // make this the active rtlight for rendering purposes
2915 R_Shadow_RenderMode_ActiveLight(rtlight);
2916 // count this light in the r_speeds
2917 r_refdef.stats.lights++;
2919 if (r_showshadowvolumes.integer && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.rtworldshadows : r_refdef.rtdlightshadows))
2921 // optionally draw visible shape of the shadow volumes
2922 // for performance analysis by level designers
2923 R_Shadow_RenderMode_VisibleShadowVolumes();
2925 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
2926 for (i = 0;i < numshadowentities;i++)
2927 R_Shadow_DrawEntityShadow(shadowentities[i]);
2928 for (i = 0;i < numshadowentities_noselfshadow;i++)
2929 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
2932 if (gl_stencil && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.rtworldshadows : r_refdef.rtdlightshadows))
2934 // draw stencil shadow volumes to mask off pixels that are in shadow
2935 // so that they won't receive lighting
2936 R_Shadow_RenderMode_StencilShadowVolumes(true);
2938 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
2939 for (i = 0;i < numshadowentities;i++)
2940 R_Shadow_DrawEntityShadow(shadowentities[i]);
2941 if (numlightentities_noselfshadow)
2943 // draw lighting in the unmasked areas
2944 R_Shadow_RenderMode_Lighting(true, false);
2945 for (i = 0;i < numlightentities_noselfshadow;i++)
2946 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i], numsurfaces, surfacelist);
2948 // optionally draw the illuminated areas
2949 // for performance analysis by level designers
2950 if (r_showlighting.integer)
2952 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
2953 for (i = 0;i < numlightentities_noselfshadow;i++)
2954 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i], numsurfaces, surfacelist);
2957 R_Shadow_RenderMode_StencilShadowVolumes(false);
2959 for (i = 0;i < numshadowentities_noselfshadow;i++)
2960 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
2962 if (numsurfaces + numlightentities)
2964 // draw lighting in the unmasked areas
2965 R_Shadow_RenderMode_Lighting(true, false);
2967 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
2968 for (i = 0;i < numlightentities;i++)
2969 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
2971 // optionally draw the illuminated areas
2972 // for performance analysis by level designers
2973 if (r_showlighting.integer)
2975 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
2977 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
2978 for (i = 0;i < numlightentities;i++)
2979 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
2985 if (numsurfaces + numlightentities)
2987 // draw lighting in the unmasked areas
2988 R_Shadow_RenderMode_Lighting(false, false);
2990 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
2991 for (i = 0;i < numlightentities;i++)
2992 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
2993 for (i = 0;i < numlightentities_noselfshadow;i++)
2994 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i], numsurfaces, surfacelist);
2996 // optionally draw the illuminated areas
2997 // for performance analysis by level designers
2998 if (r_showlighting.integer)
3000 R_Shadow_RenderMode_VisibleLighting(false, false);
3002 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3003 for (i = 0;i < numlightentities;i++)
3004 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
3005 for (i = 0;i < numlightentities_noselfshadow;i++)
3006 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i], numsurfaces, surfacelist);
3012 void R_Shadow_DrawLightSprites(void);
3013 void R_ShadowVolumeLighting(qboolean visible)
3018 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
3019 R_Shadow_EditLights_Reload_f();
3021 if (r_editlights.integer)
3022 R_Shadow_DrawLightSprites();
3024 R_Shadow_RenderMode_Begin();
3026 flag = r_refdef.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3027 if (r_shadow_debuglight.integer >= 0)
3029 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
3030 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
3031 R_DrawRTLight(&light->rtlight, visible);
3034 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
3035 if (light->flags & flag)
3036 R_DrawRTLight(&light->rtlight, visible);
3037 if (r_refdef.rtdlight)
3038 for (lnum = 0;lnum < r_refdef.numlights;lnum++)
3039 R_DrawRTLight(&r_refdef.lights[lnum], visible);
3041 R_Shadow_RenderMode_End();
3044 extern void R_SetupView(const matrix4x4_t *matrix);
3045 extern cvar_t r_shadows_throwdistance;
3046 void R_DrawModelShadows(void)
3049 float relativethrowdistance;
3050 entity_render_t *ent;
3051 vec3_t relativelightorigin;
3052 vec3_t relativelightdirection;
3053 vec3_t relativeshadowmins, relativeshadowmaxs;
3056 if (!r_drawentities.integer || !gl_stencil)
3060 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
3062 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
3064 if (gl_ext_separatestencil.integer)
3065 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
3066 else if (gl_ext_stenciltwoside.integer)
3067 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
3069 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
3071 R_Shadow_RenderMode_StencilShadowVolumes(true);
3073 for (i = 0;i < r_refdef.numentities;i++)
3075 ent = r_refdef.entities[i];
3076 // cast shadows from anything that is not a submodel of the map
3077 if (ent->model && ent->model->DrawShadowVolume != NULL && !ent->model->brush.submodel && (ent->flags & RENDER_SHADOW))
3079 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
3080 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
3081 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
3082 VectorNegate(ent->modellight_lightdir, relativelightdirection);
3083 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
3084 RSurf_ActiveModelEntity(ent, false, false);
3085 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
3089 // not really the right mode, but this will disable any silly stencil features
3090 R_Shadow_RenderMode_VisibleLighting(true, true);
3092 // vertex coordinates for a quad that covers the screen exactly
3093 vertex3f[0] = 0;vertex3f[1] = 0;vertex3f[2] = 0;
3094 vertex3f[3] = 1;vertex3f[4] = 0;vertex3f[5] = 0;
3095 vertex3f[6] = 1;vertex3f[7] = 1;vertex3f[8] = 0;
3096 vertex3f[9] = 0;vertex3f[10] = 1;vertex3f[11] = 0;
3098 // set up ortho view for rendering this pass
3099 GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
3100 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
3101 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
3102 GL_ScissorTest(true);
3103 R_Mesh_Matrix(&identitymatrix);
3104 R_Mesh_ResetTextureState();
3105 R_Mesh_VertexPointer(vertex3f, 0, 0);
3106 R_Mesh_ColorPointer(NULL, 0, 0);
3108 // set up a 50% darkening blend on shadowed areas
3109 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3110 GL_DepthRange(0, 1);
3111 GL_DepthTest(false);
3112 GL_DepthMask(false);
3113 qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
3114 GL_Color(0, 0, 0, 0.5);
3115 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
3116 qglDepthFunc(GL_ALWAYS);CHECKGLERROR
3117 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
3118 qglStencilMask(~0);CHECKGLERROR
3119 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
3120 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
3122 // apply the blend to the shadowed areas
3123 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3125 // restoring the perspective view is done by R_RenderScene
3126 //R_SetupView(&r_view.matrix);
3128 // restore other state to normal
3129 R_Shadow_RenderMode_End();
3133 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
3134 typedef struct suffixinfo_s
3137 qboolean flipx, flipy, flipdiagonal;
3140 static suffixinfo_t suffix[3][6] =
3143 {"px", false, false, false},
3144 {"nx", false, false, false},
3145 {"py", false, false, false},
3146 {"ny", false, false, false},
3147 {"pz", false, false, false},
3148 {"nz", false, false, false}
3151 {"posx", false, false, false},
3152 {"negx", false, false, false},
3153 {"posy", false, false, false},
3154 {"negy", false, false, false},
3155 {"posz", false, false, false},
3156 {"negz", false, false, false}
3159 {"rt", true, false, true},
3160 {"lf", false, true, true},
3161 {"ft", true, true, false},
3162 {"bk", false, false, false},
3163 {"up", true, false, true},
3164 {"dn", true, false, true}
3168 static int componentorder[4] = {0, 1, 2, 3};
3170 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
3172 int i, j, cubemapsize;
3173 unsigned char *cubemappixels, *image_rgba;
3174 rtexture_t *cubemaptexture;
3176 // must start 0 so the first loadimagepixels has no requested width/height
3178 cubemappixels = NULL;
3179 cubemaptexture = NULL;
3180 // keep trying different suffix groups (posx, px, rt) until one loads
3181 for (j = 0;j < 3 && !cubemappixels;j++)
3183 // load the 6 images in the suffix group
3184 for (i = 0;i < 6;i++)
3186 // generate an image name based on the base and and suffix
3187 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
3189 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
3191 // an image loaded, make sure width and height are equal
3192 if (image_width == image_height)
3194 // if this is the first image to load successfully, allocate the cubemap memory
3195 if (!cubemappixels && image_width >= 1)
3197 cubemapsize = image_width;
3198 // note this clears to black, so unavailable sides are black
3199 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
3201 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
3203 Image_CopyMux(cubemappixels+i*cubemapsize*cubemapsize*4, image_rgba, cubemapsize, cubemapsize, suffix[j][i].flipx, suffix[j][i].flipy, suffix[j][i].flipdiagonal, 4, 4, componentorder);
3206 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
3208 Mem_Free(image_rgba);
3212 // if a cubemap loaded, upload it
3215 if (!r_shadow_filters_texturepool)
3216 r_shadow_filters_texturepool = R_AllocTexturePool();
3217 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
3218 Mem_Free(cubemappixels);
3222 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
3223 for (j = 0;j < 3;j++)
3224 for (i = 0;i < 6;i++)
3225 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
3226 Con_Print(" and was unable to find any of them.\n");
3228 return cubemaptexture;
3231 rtexture_t *R_Shadow_Cubemap(const char *basename)
3234 for (i = 0;i < numcubemaps;i++)
3235 if (!strcasecmp(cubemaps[i].basename, basename))
3236 return cubemaps[i].texture;
3237 if (i >= MAX_CUBEMAPS)
3238 return r_texture_whitecube;
3240 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
3241 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
3242 if (!cubemaps[i].texture)
3243 cubemaps[i].texture = r_texture_whitecube;
3244 return cubemaps[i].texture;
3247 void R_Shadow_FreeCubemaps(void)
3250 R_FreeTexturePool(&r_shadow_filters_texturepool);
3253 dlight_t *R_Shadow_NewWorldLight(void)
3256 light = (dlight_t *)Mem_Alloc(r_main_mempool, sizeof(dlight_t));
3257 light->next = r_shadow_worldlightchain;
3258 r_shadow_worldlightchain = light;
3262 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)
3265 // validate parameters
3266 if (style < 0 || style >= MAX_LIGHTSTYLES)
3268 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
3274 // copy to light properties
3275 VectorCopy(origin, light->origin);
3276 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
3277 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
3278 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
3279 light->color[0] = max(color[0], 0);
3280 light->color[1] = max(color[1], 0);
3281 light->color[2] = max(color[2], 0);
3282 light->radius = max(radius, 0);
3283 light->style = style;
3284 light->shadow = shadowenable;
3285 light->corona = corona;
3286 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
3287 light->coronasizescale = coronasizescale;
3288 light->ambientscale = ambientscale;
3289 light->diffusescale = diffusescale;
3290 light->specularscale = specularscale;
3291 light->flags = flags;
3293 // update renderable light data
3294 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
3295 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);
3298 void R_Shadow_FreeWorldLight(dlight_t *light)
3300 dlight_t **lightpointer;
3301 R_RTLight_Uncompile(&light->rtlight);
3302 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
3303 if (*lightpointer != light)
3304 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain");
3305 *lightpointer = light->next;
3309 void R_Shadow_ClearWorldLights(void)
3311 while (r_shadow_worldlightchain)
3312 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
3313 r_shadow_selectedlight = NULL;
3314 R_Shadow_FreeCubemaps();
3317 void R_Shadow_SelectLight(dlight_t *light)
3319 if (r_shadow_selectedlight)
3320 r_shadow_selectedlight->selected = false;
3321 r_shadow_selectedlight = light;
3322 if (r_shadow_selectedlight)
3323 r_shadow_selectedlight->selected = true;
3326 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
3328 // this is never batched (there can be only one)
3329 float scale = r_editlights_cursorgrid.value * 0.5f;
3330 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);
3333 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
3335 // this is never batched (due to the ent parameter changing every time)
3336 // so numsurfaces == 1 and surfacelist[0] == lightnumber
3338 const dlight_t *light = (dlight_t *)ent;
3340 if (light->selected)
3341 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
3344 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);
3347 void R_Shadow_DrawLightSprites(void)
3352 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
3353 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 1+(i % 5), &light->rtlight);
3354 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
3357 void R_Shadow_SelectLightInView(void)
3359 float bestrating, rating, temp[3];
3360 dlight_t *best, *light;
3363 for (light = r_shadow_worldlightchain;light;light = light->next)
3365 VectorSubtract(light->origin, r_view.origin, temp);
3366 rating = (DotProduct(temp, r_view.forward) / sqrt(DotProduct(temp, temp)));
3369 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
3370 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)
3372 bestrating = rating;
3377 R_Shadow_SelectLight(best);
3380 void R_Shadow_LoadWorldLights(void)
3382 int n, a, style, shadow, flags;
3383 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
3384 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
3385 if (r_refdef.worldmodel == NULL)
3387 Con_Print("No map loaded.\n");
3390 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3391 strlcat (name, ".rtlights", sizeof (name));
3392 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3402 for (;COM_Parse(t, true) && strcmp(
3403 if (COM_Parse(t, true))
3405 if (com_token[0] == '!')
3408 origin[0] = atof(com_token+1);
3411 origin[0] = atof(com_token);
3416 while (*s && *s != '\n' && *s != '\r')
3422 // check for modifier flags
3429 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);
3432 flags = LIGHTFLAG_REALTIMEMODE;
3440 coronasizescale = 0.25f;
3442 VectorClear(angles);
3445 if (a < 9 || !strcmp(cubemapname, "\"\""))
3447 // remove quotes on cubemapname
3448 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
3451 namelen = strlen(cubemapname) - 2;
3452 memmove(cubemapname, cubemapname + 1, namelen);
3453 cubemapname[namelen] = '\0';
3457 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);
3460 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3468 Con_Printf("invalid rtlights file \"%s\"\n", name);
3469 Mem_Free(lightsstring);
3473 void R_Shadow_SaveWorldLights(void)
3476 size_t bufchars, bufmaxchars;
3478 char name[MAX_QPATH];
3479 char line[MAX_INPUTLINE];
3480 if (!r_shadow_worldlightchain)
3482 if (r_refdef.worldmodel == NULL)
3484 Con_Print("No map loaded.\n");
3487 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3488 strlcat (name, ".rtlights", sizeof (name));
3489 bufchars = bufmaxchars = 0;
3491 for (light = r_shadow_worldlightchain;light;light = light->next)
3493 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3494 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);
3495 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3496 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]);
3498 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);
3499 if (bufchars + strlen(line) > bufmaxchars)
3501 bufmaxchars = bufchars + strlen(line) + 2048;
3503 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
3507 memcpy(buf, oldbuf, bufchars);
3513 memcpy(buf + bufchars, line, strlen(line));
3514 bufchars += strlen(line);
3518 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
3523 void R_Shadow_LoadLightsFile(void)
3526 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3527 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3528 if (r_refdef.worldmodel == NULL)
3530 Con_Print("No map loaded.\n");
3533 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3534 strlcat (name, ".lights", sizeof (name));
3535 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3543 while (*s && *s != '\n' && *s != '\r')
3549 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);
3553 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);
3556 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3557 radius = bound(15, radius, 4096);
3558 VectorScale(color, (2.0f / (8388608.0f)), color);
3559 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3567 Con_Printf("invalid lights file \"%s\"\n", name);
3568 Mem_Free(lightsstring);
3572 // tyrlite/hmap2 light types in the delay field
3573 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3575 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3577 int entnum, style, islight, skin, pflags, effects, type, n;
3580 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3581 char key[256], value[MAX_INPUTLINE];
3583 if (r_refdef.worldmodel == NULL)
3585 Con_Print("No map loaded.\n");
3588 // try to load a .ent file first
3589 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3590 strlcat (key, ".ent", sizeof (key));
3591 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
3592 // and if that is not found, fall back to the bsp file entity string
3594 data = r_refdef.worldmodel->brush.entities;
3597 for (entnum = 0;COM_ParseToken_Simple(&data, false) && com_token[0] == '{';entnum++)
3599 type = LIGHTTYPE_MINUSX;
3600 origin[0] = origin[1] = origin[2] = 0;
3601 originhack[0] = originhack[1] = originhack[2] = 0;
3602 angles[0] = angles[1] = angles[2] = 0;
3603 color[0] = color[1] = color[2] = 1;
3604 light[0] = light[1] = light[2] = 1;light[3] = 300;
3605 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3615 if (!COM_ParseToken_Simple(&data, false))
3617 if (com_token[0] == '}')
3618 break; // end of entity
3619 if (com_token[0] == '_')
3620 strlcpy(key, com_token + 1, sizeof(key));
3622 strlcpy(key, com_token, sizeof(key));
3623 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3624 key[strlen(key)-1] = 0;
3625 if (!COM_ParseToken_Simple(&data, false))
3627 strlcpy(value, com_token, sizeof(value));
3629 // now that we have the key pair worked out...
3630 if (!strcmp("light", key))
3632 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3636 light[0] = vec[0] * (1.0f / 256.0f);
3637 light[1] = vec[0] * (1.0f / 256.0f);
3638 light[2] = vec[0] * (1.0f / 256.0f);
3644 light[0] = vec[0] * (1.0f / 255.0f);
3645 light[1] = vec[1] * (1.0f / 255.0f);
3646 light[2] = vec[2] * (1.0f / 255.0f);
3650 else if (!strcmp("delay", key))
3652 else if (!strcmp("origin", key))
3653 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3654 else if (!strcmp("angle", key))
3655 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3656 else if (!strcmp("angles", key))
3657 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3658 else if (!strcmp("color", key))
3659 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3660 else if (!strcmp("wait", key))
3661 fadescale = atof(value);
3662 else if (!strcmp("classname", key))
3664 if (!strncmp(value, "light", 5))
3667 if (!strcmp(value, "light_fluoro"))
3672 overridecolor[0] = 1;
3673 overridecolor[1] = 1;
3674 overridecolor[2] = 1;
3676 if (!strcmp(value, "light_fluorospark"))
3681 overridecolor[0] = 1;
3682 overridecolor[1] = 1;
3683 overridecolor[2] = 1;
3685 if (!strcmp(value, "light_globe"))
3690 overridecolor[0] = 1;
3691 overridecolor[1] = 0.8;
3692 overridecolor[2] = 0.4;
3694 if (!strcmp(value, "light_flame_large_yellow"))
3699 overridecolor[0] = 1;
3700 overridecolor[1] = 0.5;
3701 overridecolor[2] = 0.1;
3703 if (!strcmp(value, "light_flame_small_yellow"))
3708 overridecolor[0] = 1;
3709 overridecolor[1] = 0.5;
3710 overridecolor[2] = 0.1;
3712 if (!strcmp(value, "light_torch_small_white"))
3717 overridecolor[0] = 1;
3718 overridecolor[1] = 0.5;
3719 overridecolor[2] = 0.1;
3721 if (!strcmp(value, "light_torch_small_walltorch"))
3726 overridecolor[0] = 1;
3727 overridecolor[1] = 0.5;
3728 overridecolor[2] = 0.1;
3732 else if (!strcmp("style", key))
3733 style = atoi(value);
3734 else if (!strcmp("skin", key))
3735 skin = (int)atof(value);
3736 else if (!strcmp("pflags", key))
3737 pflags = (int)atof(value);
3738 else if (!strcmp("effects", key))
3739 effects = (int)atof(value);
3740 else if (r_refdef.worldmodel->type == mod_brushq3)
3742 if (!strcmp("scale", key))
3743 lightscale = atof(value);
3744 if (!strcmp("fade", key))
3745 fadescale = atof(value);
3750 if (lightscale <= 0)
3754 if (color[0] == color[1] && color[0] == color[2])
3756 color[0] *= overridecolor[0];
3757 color[1] *= overridecolor[1];
3758 color[2] *= overridecolor[2];
3760 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3761 color[0] = color[0] * light[0];
3762 color[1] = color[1] * light[1];
3763 color[2] = color[2] * light[2];
3766 case LIGHTTYPE_MINUSX:
3768 case LIGHTTYPE_RECIPX:
3770 VectorScale(color, (1.0f / 16.0f), color);
3772 case LIGHTTYPE_RECIPXX:
3774 VectorScale(color, (1.0f / 16.0f), color);
3777 case LIGHTTYPE_NONE:
3781 case LIGHTTYPE_MINUSXX:
3784 VectorAdd(origin, originhack, origin);
3786 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);
3789 Mem_Free(entfiledata);
3793 void R_Shadow_SetCursorLocationForView(void)
3796 vec3_t dest, endpos;
3798 VectorMA(r_view.origin, r_editlights_cursordistance.value, r_view.forward, dest);
3799 trace = CL_Move(r_view.origin, vec3_origin, vec3_origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
3800 if (trace.fraction < 1)
3802 dist = trace.fraction * r_editlights_cursordistance.value;
3803 push = r_editlights_cursorpushback.value;
3807 VectorMA(trace.endpos, push, r_view.forward, endpos);
3808 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
3812 VectorClear( endpos );
3814 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3815 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3816 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3819 void R_Shadow_UpdateWorldLightSelection(void)
3821 if (r_editlights.integer)
3823 R_Shadow_SetCursorLocationForView();
3824 R_Shadow_SelectLightInView();
3827 R_Shadow_SelectLight(NULL);
3830 void R_Shadow_EditLights_Clear_f(void)
3832 R_Shadow_ClearWorldLights();
3835 void R_Shadow_EditLights_Reload_f(void)
3837 if (!r_refdef.worldmodel)
3839 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3840 R_Shadow_ClearWorldLights();
3841 R_Shadow_LoadWorldLights();
3842 if (r_shadow_worldlightchain == NULL)
3844 R_Shadow_LoadLightsFile();
3845 if (r_shadow_worldlightchain == NULL)
3846 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3850 void R_Shadow_EditLights_Save_f(void)
3852 if (!r_refdef.worldmodel)
3854 R_Shadow_SaveWorldLights();
3857 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3859 R_Shadow_ClearWorldLights();
3860 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3863 void R_Shadow_EditLights_ImportLightsFile_f(void)
3865 R_Shadow_ClearWorldLights();
3866 R_Shadow_LoadLightsFile();
3869 void R_Shadow_EditLights_Spawn_f(void)
3872 if (!r_editlights.integer)
3874 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3877 if (Cmd_Argc() != 1)
3879 Con_Print("r_editlights_spawn does not take parameters\n");
3882 color[0] = color[1] = color[2] = 1;
3883 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3886 void R_Shadow_EditLights_Edit_f(void)
3888 vec3_t origin, angles, color;
3889 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3890 int style, shadows, flags, normalmode, realtimemode;
3891 char cubemapname[MAX_INPUTLINE];
3892 if (!r_editlights.integer)
3894 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3897 if (!r_shadow_selectedlight)
3899 Con_Print("No selected light.\n");
3902 VectorCopy(r_shadow_selectedlight->origin, origin);
3903 VectorCopy(r_shadow_selectedlight->angles, angles);
3904 VectorCopy(r_shadow_selectedlight->color, color);
3905 radius = r_shadow_selectedlight->radius;
3906 style = r_shadow_selectedlight->style;
3907 if (r_shadow_selectedlight->cubemapname)
3908 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
3911 shadows = r_shadow_selectedlight->shadow;
3912 corona = r_shadow_selectedlight->corona;
3913 coronasizescale = r_shadow_selectedlight->coronasizescale;
3914 ambientscale = r_shadow_selectedlight->ambientscale;
3915 diffusescale = r_shadow_selectedlight->diffusescale;
3916 specularscale = r_shadow_selectedlight->specularscale;
3917 flags = r_shadow_selectedlight->flags;
3918 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3919 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3920 if (!strcmp(Cmd_Argv(1), "origin"))
3922 if (Cmd_Argc() != 5)
3924 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3927 origin[0] = atof(Cmd_Argv(2));
3928 origin[1] = atof(Cmd_Argv(3));
3929 origin[2] = atof(Cmd_Argv(4));
3931 else if (!strcmp(Cmd_Argv(1), "originx"))
3933 if (Cmd_Argc() != 3)
3935 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3938 origin[0] = atof(Cmd_Argv(2));
3940 else if (!strcmp(Cmd_Argv(1), "originy"))
3942 if (Cmd_Argc() != 3)
3944 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3947 origin[1] = atof(Cmd_Argv(2));
3949 else if (!strcmp(Cmd_Argv(1), "originz"))
3951 if (Cmd_Argc() != 3)
3953 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3956 origin[2] = atof(Cmd_Argv(2));
3958 else if (!strcmp(Cmd_Argv(1), "move"))
3960 if (Cmd_Argc() != 5)
3962 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3965 origin[0] += atof(Cmd_Argv(2));
3966 origin[1] += atof(Cmd_Argv(3));
3967 origin[2] += atof(Cmd_Argv(4));
3969 else if (!strcmp(Cmd_Argv(1), "movex"))
3971 if (Cmd_Argc() != 3)
3973 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3976 origin[0] += atof(Cmd_Argv(2));
3978 else if (!strcmp(Cmd_Argv(1), "movey"))
3980 if (Cmd_Argc() != 3)
3982 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3985 origin[1] += atof(Cmd_Argv(2));
3987 else if (!strcmp(Cmd_Argv(1), "movez"))
3989 if (Cmd_Argc() != 3)
3991 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3994 origin[2] += atof(Cmd_Argv(2));
3996 else if (!strcmp(Cmd_Argv(1), "angles"))
3998 if (Cmd_Argc() != 5)
4000 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
4003 angles[0] = atof(Cmd_Argv(2));
4004 angles[1] = atof(Cmd_Argv(3));
4005 angles[2] = atof(Cmd_Argv(4));
4007 else if (!strcmp(Cmd_Argv(1), "anglesx"))
4009 if (Cmd_Argc() != 3)
4011 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4014 angles[0] = atof(Cmd_Argv(2));
4016 else if (!strcmp(Cmd_Argv(1), "anglesy"))
4018 if (Cmd_Argc() != 3)
4020 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4023 angles[1] = atof(Cmd_Argv(2));
4025 else if (!strcmp(Cmd_Argv(1), "anglesz"))
4027 if (Cmd_Argc() != 3)
4029 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4032 angles[2] = atof(Cmd_Argv(2));
4034 else if (!strcmp(Cmd_Argv(1), "color"))
4036 if (Cmd_Argc() != 5)
4038 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
4041 color[0] = atof(Cmd_Argv(2));
4042 color[1] = atof(Cmd_Argv(3));
4043 color[2] = atof(Cmd_Argv(4));
4045 else if (!strcmp(Cmd_Argv(1), "radius"))
4047 if (Cmd_Argc() != 3)
4049 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4052 radius = atof(Cmd_Argv(2));
4054 else if (!strcmp(Cmd_Argv(1), "colorscale"))
4056 if (Cmd_Argc() == 3)
4058 double scale = atof(Cmd_Argv(2));
4065 if (Cmd_Argc() != 5)
4067 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
4070 color[0] *= atof(Cmd_Argv(2));
4071 color[1] *= atof(Cmd_Argv(3));
4072 color[2] *= atof(Cmd_Argv(4));
4075 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
4077 if (Cmd_Argc() != 3)
4079 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4082 radius *= atof(Cmd_Argv(2));
4084 else if (!strcmp(Cmd_Argv(1), "style"))
4086 if (Cmd_Argc() != 3)
4088 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4091 style = atoi(Cmd_Argv(2));
4093 else if (!strcmp(Cmd_Argv(1), "cubemap"))
4097 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4100 if (Cmd_Argc() == 3)
4101 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
4105 else if (!strcmp(Cmd_Argv(1), "shadows"))
4107 if (Cmd_Argc() != 3)
4109 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4112 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4114 else if (!strcmp(Cmd_Argv(1), "corona"))
4116 if (Cmd_Argc() != 3)
4118 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4121 corona = atof(Cmd_Argv(2));
4123 else if (!strcmp(Cmd_Argv(1), "coronasize"))
4125 if (Cmd_Argc() != 3)
4127 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4130 coronasizescale = atof(Cmd_Argv(2));
4132 else if (!strcmp(Cmd_Argv(1), "ambient"))
4134 if (Cmd_Argc() != 3)
4136 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4139 ambientscale = atof(Cmd_Argv(2));
4141 else if (!strcmp(Cmd_Argv(1), "diffuse"))
4143 if (Cmd_Argc() != 3)
4145 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4148 diffusescale = atof(Cmd_Argv(2));
4150 else if (!strcmp(Cmd_Argv(1), "specular"))
4152 if (Cmd_Argc() != 3)
4154 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4157 specularscale = atof(Cmd_Argv(2));
4159 else if (!strcmp(Cmd_Argv(1), "normalmode"))
4161 if (Cmd_Argc() != 3)
4163 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4166 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4168 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
4170 if (Cmd_Argc() != 3)
4172 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4175 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4179 Con_Print("usage: r_editlights_edit [property] [value]\n");
4180 Con_Print("Selected light's properties:\n");
4181 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
4182 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
4183 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
4184 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
4185 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
4186 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
4187 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
4188 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
4189 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
4190 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
4191 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
4192 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
4193 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
4194 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
4197 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
4198 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4201 void R_Shadow_EditLights_EditAll_f(void)
4205 if (!r_editlights.integer)
4207 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
4211 for (light = r_shadow_worldlightchain;light;light = light->next)
4213 R_Shadow_SelectLight(light);
4214 R_Shadow_EditLights_Edit_f();
4218 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
4220 int lightnumber, lightcount;
4224 if (!r_editlights.integer)
4230 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
4231 if (light == r_shadow_selectedlight)
4232 lightnumber = lightcount;
4233 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;
4234 if (r_shadow_selectedlight == NULL)
4236 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
4237 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;
4238 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;
4239 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;
4240 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;
4241 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;
4242 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;
4243 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;
4244 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;
4245 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;
4246 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;
4247 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;
4248 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;
4249 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;
4250 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;
4253 void R_Shadow_EditLights_ToggleShadow_f(void)
4255 if (!r_editlights.integer)
4257 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4260 if (!r_shadow_selectedlight)
4262 Con_Print("No selected light.\n");
4265 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);
4268 void R_Shadow_EditLights_ToggleCorona_f(void)
4270 if (!r_editlights.integer)
4272 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4275 if (!r_shadow_selectedlight)
4277 Con_Print("No selected light.\n");
4280 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);
4283 void R_Shadow_EditLights_Remove_f(void)
4285 if (!r_editlights.integer)
4287 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
4290 if (!r_shadow_selectedlight)
4292 Con_Print("No selected light.\n");
4295 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
4296 r_shadow_selectedlight = NULL;
4299 void R_Shadow_EditLights_Help_f(void)
4302 "Documentation on r_editlights system:\n"
4304 "r_editlights : enable/disable editing mode\n"
4305 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
4306 "r_editlights_cursorpushback : push back cursor this far from surface\n"
4307 "r_editlights_cursorpushoff : push cursor off surface this far\n"
4308 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
4309 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
4311 "r_editlights_help : this help\n"
4312 "r_editlights_clear : remove all lights\n"
4313 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
4314 "r_editlights_save : save to .rtlights file\n"
4315 "r_editlights_spawn : create a light with default settings\n"
4316 "r_editlights_edit command : edit selected light - more documentation below\n"
4317 "r_editlights_remove : remove selected light\n"
4318 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
4319 "r_editlights_importlightentitiesfrommap : reload light entities\n"
4320 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
4322 "origin x y z : set light location\n"
4323 "originx x: set x component of light location\n"
4324 "originy y: set y component of light location\n"
4325 "originz z: set z component of light location\n"
4326 "move x y z : adjust light location\n"
4327 "movex x: adjust x component of light location\n"
4328 "movey y: adjust y component of light location\n"
4329 "movez z: adjust z component of light location\n"
4330 "angles x y z : set light angles\n"
4331 "anglesx x: set x component of light angles\n"
4332 "anglesy y: set y component of light angles\n"
4333 "anglesz z: set z component of light angles\n"
4334 "color r g b : set color of light (can be brighter than 1 1 1)\n"
4335 "radius radius : set radius (size) of light\n"
4336 "colorscale grey : multiply color of light (1 does nothing)\n"
4337 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
4338 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
4339 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
4340 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
4341 "cubemap basename : set filter cubemap of light (not yet supported)\n"
4342 "shadows 1/0 : turn on/off shadows\n"
4343 "corona n : set corona intensity\n"
4344 "coronasize n : set corona size (0-1)\n"
4345 "ambient n : set ambient intensity (0-1)\n"
4346 "diffuse n : set diffuse intensity (0-1)\n"
4347 "specular n : set specular intensity (0-1)\n"
4348 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
4349 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
4350 "<nothing> : print light properties to console\n"
4354 void R_Shadow_EditLights_CopyInfo_f(void)
4356 if (!r_editlights.integer)
4358 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
4361 if (!r_shadow_selectedlight)
4363 Con_Print("No selected light.\n");
4366 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
4367 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
4368 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
4369 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
4370 if (r_shadow_selectedlight->cubemapname)
4371 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
4373 r_shadow_bufferlight.cubemapname[0] = 0;
4374 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
4375 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
4376 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
4377 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
4378 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
4379 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
4380 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
4383 void R_Shadow_EditLights_PasteInfo_f(void)
4385 if (!r_editlights.integer)
4387 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
4390 if (!r_shadow_selectedlight)
4392 Con_Print("No selected light.\n");
4395 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);
4398 void R_Shadow_EditLights_Init(void)
4400 Cvar_RegisterVariable(&r_editlights);
4401 Cvar_RegisterVariable(&r_editlights_cursordistance);
4402 Cvar_RegisterVariable(&r_editlights_cursorpushback);
4403 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
4404 Cvar_RegisterVariable(&r_editlights_cursorgrid);
4405 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
4406 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
4407 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
4408 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)");
4409 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
4410 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
4411 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
4412 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)");
4413 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
4414 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
4415 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
4416 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
4417 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
4418 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
4419 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)");