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);
986 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
989 GL_Color(0, 0, 0, 1);
990 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
992 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
994 if (gl_ext_separatestencil.integer)
995 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
996 else if (gl_ext_stenciltwoside.integer)
997 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
999 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
1001 if (r_glsl.integer && gl_support_fragment_shader)
1002 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1003 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
1004 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
1006 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1009 void R_Shadow_RenderMode_ActiveLight(rtlight_t *rtlight)
1011 rsurface.rtlight = rtlight;
1014 void R_Shadow_RenderMode_Reset(void)
1017 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1019 qglUseProgramObjectARB(0);CHECKGLERROR
1021 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
1023 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1025 R_Mesh_ColorPointer(NULL, 0, 0);
1026 R_Mesh_ResetTextureState();
1027 GL_DepthRange(0, 1);
1029 GL_DepthMask(false);
1030 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1031 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1032 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1033 qglStencilMask(~0);CHECKGLERROR
1034 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1035 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1036 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
1037 GL_Color(1, 1, 1, 1);
1038 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
1039 GL_BlendFunc(GL_ONE, GL_ZERO);
1042 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean clearstencil)
1045 R_Shadow_RenderMode_Reset();
1046 GL_ColorMask(0, 0, 0, 0);
1047 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1048 qglDepthFunc(GL_LESS);CHECKGLERROR
1049 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1050 r_shadow_rendermode = r_shadow_shadowingrendermode;
1051 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SEPARATESTENCIL)
1053 GL_CullFace(GL_NONE);
1054 qglStencilOpSeparate(GL_BACK, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR // quake is backwards, this is front faces
1055 qglStencilOpSeparate(GL_FRONT, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR // quake is backwards, this is back faces
1057 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
1059 GL_CullFace(GL_NONE);
1060 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1061 qglActiveStencilFaceEXT(GL_BACK);CHECKGLERROR // quake is backwards, this is front faces
1062 qglStencilMask(~0);CHECKGLERROR
1063 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1064 qglActiveStencilFaceEXT(GL_FRONT);CHECKGLERROR // quake is backwards, this is back faces
1065 qglStencilMask(~0);CHECKGLERROR
1066 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1069 GL_Clear(GL_STENCIL_BUFFER_BIT);
1070 r_refdef.stats.lights_clears++;
1073 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent)
1076 R_Shadow_RenderMode_Reset();
1077 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1080 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1084 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1085 // only draw light where this geometry was already rendered AND the
1086 // stencil is 128 (values other than this mean shadow)
1087 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1089 r_shadow_rendermode = r_shadow_lightingrendermode;
1090 // do global setup needed for the chosen lighting mode
1091 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1093 R_Mesh_TexBind(0, R_GetTexture(r_texture_blanknormalmap)); // normal
1094 R_Mesh_TexBind(1, R_GetTexture(r_texture_white)); // diffuse
1095 R_Mesh_TexBind(2, R_GetTexture(r_texture_white)); // gloss
1096 R_Mesh_TexBindCubeMap(3, R_GetTexture(rsurface.rtlight->currentcubemap)); // light filter
1097 R_Mesh_TexBind(4, R_GetTexture(r_texture_fogattenuation)); // fog
1098 R_Mesh_TexBind(5, R_GetTexture(r_texture_white)); // pants
1099 R_Mesh_TexBind(6, R_GetTexture(r_texture_white)); // shirt
1100 R_Mesh_TexBind(7, R_GetTexture(r_texture_white)); // lightmap
1101 R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap)); // deluxemap
1102 R_Mesh_TexBind(9, R_GetTexture(r_texture_black)); // glow
1103 //R_Mesh_TexMatrix(3, rsurface.entitytolight); // light filter matrix
1104 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1105 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 0);
1110 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
1113 R_Shadow_RenderMode_Reset();
1114 GL_BlendFunc(GL_ONE, GL_ONE);
1115 GL_DepthRange(0, 1);
1116 GL_DepthTest(r_showshadowvolumes.integer < 2);
1117 GL_Color(0.0, 0.0125 * r_view.colorscale, 0.1 * r_view.colorscale, 1);
1118 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1119 GL_CullFace(GL_NONE);
1120 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
1123 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
1126 R_Shadow_RenderMode_Reset();
1127 GL_BlendFunc(GL_ONE, GL_ONE);
1128 GL_DepthRange(0, 1);
1129 GL_DepthTest(r_showlighting.integer < 2);
1130 GL_Color(0.1 * r_view.colorscale, 0.0125 * r_view.colorscale, 0, 1);
1133 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1137 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1138 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1140 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
1143 void R_Shadow_RenderMode_End(void)
1146 R_Shadow_RenderMode_Reset();
1147 R_Shadow_RenderMode_ActiveLight(NULL);
1149 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
1150 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1153 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1155 int i, ix1, iy1, ix2, iy2;
1156 float x1, y1, x2, y2;
1159 mplane_t planes[11];
1160 float vertex3f[256*3];
1162 // if view is inside the light box, just say yes it's visible
1163 if (BoxesOverlap(r_view.origin, r_view.origin, mins, maxs))
1165 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
1169 // create a temporary brush describing the area the light can affect in worldspace
1170 VectorNegate(r_view.frustum[0].normal, planes[ 0].normal);planes[ 0].dist = -r_view.frustum[0].dist;
1171 VectorNegate(r_view.frustum[1].normal, planes[ 1].normal);planes[ 1].dist = -r_view.frustum[1].dist;
1172 VectorNegate(r_view.frustum[2].normal, planes[ 2].normal);planes[ 2].dist = -r_view.frustum[2].dist;
1173 VectorNegate(r_view.frustum[3].normal, planes[ 3].normal);planes[ 3].dist = -r_view.frustum[3].dist;
1174 VectorNegate(r_view.frustum[4].normal, planes[ 4].normal);planes[ 4].dist = -r_view.frustum[4].dist;
1175 VectorSet (planes[ 5].normal, 1, 0, 0); planes[ 5].dist = maxs[0];
1176 VectorSet (planes[ 6].normal, -1, 0, 0); planes[ 6].dist = -mins[0];
1177 VectorSet (planes[ 7].normal, 0, 1, 0); planes[ 7].dist = maxs[1];
1178 VectorSet (planes[ 8].normal, 0, -1, 0); planes[ 8].dist = -mins[1];
1179 VectorSet (planes[ 9].normal, 0, 0, 1); planes[ 9].dist = maxs[2];
1180 VectorSet (planes[10].normal, 0, 0, -1); planes[10].dist = -mins[2];
1182 // turn the brush into a mesh
1183 memset(&mesh, 0, sizeof(rmesh_t));
1184 mesh.maxvertices = 256;
1185 mesh.vertex3f = vertex3f;
1186 mesh.epsilon2 = (1.0f / (32.0f * 32.0f));
1187 R_Mesh_AddBrushMeshFromPlanes(&mesh, 11, planes);
1189 // if that mesh is empty, the light is not visible at all
1190 if (!mesh.numvertices)
1193 if (!r_shadow_scissor.integer)
1196 // if that mesh is not empty, check what area of the screen it covers
1197 x1 = y1 = x2 = y2 = 0;
1199 //Con_Printf("%i vertices to transform...\n", mesh.numvertices);
1200 for (i = 0;i < mesh.numvertices;i++)
1202 VectorCopy(mesh.vertex3f + i * 3, v);
1203 GL_TransformToScreen(v, v2);
1204 //Con_Printf("%.3f %.3f %.3f %.3f transformed to %.3f %.3f %.3f %.3f\n", v[0], v[1], v[2], v[3], v2[0], v2[1], v2[2], v2[3]);
1207 if (x1 > v2[0]) x1 = v2[0];
1208 if (x2 < v2[0]) x2 = v2[0];
1209 if (y1 > v2[1]) y1 = v2[1];
1210 if (y2 < v2[1]) y2 = v2[1];
1219 // now convert the scissor rectangle to integer screen coordinates
1220 ix1 = (int)(x1 - 1.0f);
1221 iy1 = (int)(y1 - 1.0f);
1222 ix2 = (int)(x2 + 1.0f);
1223 iy2 = (int)(y2 + 1.0f);
1224 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1226 // clamp it to the screen
1227 if (ix1 < r_view.x) ix1 = r_view.x;
1228 if (iy1 < r_view.y) iy1 = r_view.y;
1229 if (ix2 > r_view.x + r_view.width) ix2 = r_view.x + r_view.width;
1230 if (iy2 > r_view.y + r_view.height) iy2 = r_view.y + r_view.height;
1232 // if it is inside out, it's not visible
1233 if (ix2 <= ix1 || iy2 <= iy1)
1236 // the light area is visible, set up the scissor rectangle
1237 GL_Scissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1238 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);CHECKGLERROR
1239 //qglEnable(GL_SCISSOR_TEST);CHECKGLERROR
1240 r_refdef.stats.lights_scissored++;
1244 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
1246 float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1247 float *normal3f = rsurface.normal3f + 3 * firstvertex;
1248 float *color4f = rsurface.array_color4f + 4 * firstvertex;
1249 float dist, dot, distintensity, shadeintensity, v[3], n[3];
1250 if (r_textureunits.integer >= 3)
1252 if (VectorLength2(diffusecolor) > 0)
1254 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1256 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1257 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1258 if ((dot = DotProduct(n, v)) < 0)
1260 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1261 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
1264 VectorCopy(ambientcolor, color4f);
1265 if (r_refdef.fogenabled)
1268 f = FogPoint_Model(vertex3f);
1269 VectorScale(color4f, f, color4f);
1276 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1278 VectorCopy(ambientcolor, color4f);
1279 if (r_refdef.fogenabled)
1282 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1283 f = FogPoint_Model(vertex3f);
1284 VectorScale(color4f, f, color4f);
1290 else if (r_textureunits.integer >= 2)
1292 if (VectorLength2(diffusecolor) > 0)
1294 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1296 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1297 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1299 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1300 if ((dot = DotProduct(n, v)) < 0)
1302 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1303 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1304 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1305 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1309 color4f[0] = ambientcolor[0] * distintensity;
1310 color4f[1] = ambientcolor[1] * distintensity;
1311 color4f[2] = ambientcolor[2] * distintensity;
1313 if (r_refdef.fogenabled)
1316 f = FogPoint_Model(vertex3f);
1317 VectorScale(color4f, f, color4f);
1321 VectorClear(color4f);
1327 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1329 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1330 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1332 color4f[0] = ambientcolor[0] * distintensity;
1333 color4f[1] = ambientcolor[1] * distintensity;
1334 color4f[2] = ambientcolor[2] * distintensity;
1335 if (r_refdef.fogenabled)
1338 f = FogPoint_Model(vertex3f);
1339 VectorScale(color4f, f, color4f);
1343 VectorClear(color4f);
1350 if (VectorLength2(diffusecolor) > 0)
1352 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1354 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1355 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1357 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
1358 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1359 if ((dot = DotProduct(n, v)) < 0)
1361 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1362 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1363 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1364 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1368 color4f[0] = ambientcolor[0] * distintensity;
1369 color4f[1] = ambientcolor[1] * distintensity;
1370 color4f[2] = ambientcolor[2] * distintensity;
1372 if (r_refdef.fogenabled)
1375 f = FogPoint_Model(vertex3f);
1376 VectorScale(color4f, f, color4f);
1380 VectorClear(color4f);
1386 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1388 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1389 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1391 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
1392 color4f[0] = ambientcolor[0] * distintensity;
1393 color4f[1] = ambientcolor[1] * distintensity;
1394 color4f[2] = ambientcolor[2] * distintensity;
1395 if (r_refdef.fogenabled)
1398 f = FogPoint_Model(vertex3f);
1399 VectorScale(color4f, f, color4f);
1403 VectorClear(color4f);
1410 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1412 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
1415 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
1416 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1417 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
1418 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
1419 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
1421 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1423 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
1424 // the cubemap normalizes this for us
1425 out3f[0] = DotProduct(svector3f, lightdir);
1426 out3f[1] = DotProduct(tvector3f, lightdir);
1427 out3f[2] = DotProduct(normal3f, lightdir);
1431 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
1434 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
1435 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1436 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
1437 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
1438 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
1439 float lightdir[3], eyedir[3], halfdir[3];
1440 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1442 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
1443 VectorNormalize(lightdir);
1444 VectorSubtract(rsurface.modelorg, vertex3f, eyedir);
1445 VectorNormalize(eyedir);
1446 VectorAdd(lightdir, eyedir, halfdir);
1447 // the cubemap normalizes this for us
1448 out3f[0] = DotProduct(svector3f, halfdir);
1449 out3f[1] = DotProduct(tvector3f, halfdir);
1450 out3f[2] = DotProduct(normal3f, halfdir);
1454 static void R_Shadow_RenderLighting_VisibleLighting(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float ambientscale, float diffusescale, float specularscale, qboolean dopants, qboolean doshirt)
1456 // used to display how many times a surface is lit for level design purposes
1457 GL_Color(0.1 * r_view.colorscale, 0.025 * r_view.colorscale, 0, 1);
1458 R_Mesh_ColorPointer(NULL, 0, 0);
1459 R_Mesh_ResetTextureState();
1460 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1463 static void R_Shadow_RenderLighting_Light_GLSL(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float ambientscale, float diffusescale, float specularscale, qboolean dopants, qboolean doshirt)
1465 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
1466 R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale);
1467 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
1468 R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
1469 R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
1470 R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
1471 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1473 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1475 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1476 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1478 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1482 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)
1484 // shared final code for all the dot3 layers
1486 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 0);
1487 for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
1489 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
1490 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1494 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)
1497 // colorscale accounts for how much we multiply the brightness
1500 // mult is how many times the final pass of the lighting will be
1501 // performed to get more brightness than otherwise possible.
1503 // Limit mult to 64 for sanity sake.
1505 if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1507 // 3 3D combine path (Geforce3, Radeon 8500)
1508 memset(&m, 0, sizeof(m));
1509 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1510 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1511 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1512 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1513 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1514 m.tex[1] = R_GetTexture(basetexture);
1515 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
1516 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
1517 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
1518 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
1519 m.texcubemap[2] = R_GetTexture(rsurface.rtlight->currentcubemap);
1520 m.pointer_texcoord3f[2] = rsurface.vertex3f;
1521 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
1522 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
1523 m.texmatrix[2] = rsurface.entitytolight;
1524 GL_BlendFunc(GL_ONE, GL_ONE);
1526 else if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1528 // 2 3D combine path (Geforce3, original Radeon)
1529 memset(&m, 0, sizeof(m));
1530 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1531 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1532 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1533 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1534 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1535 m.tex[1] = R_GetTexture(basetexture);
1536 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
1537 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
1538 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
1539 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
1540 GL_BlendFunc(GL_ONE, GL_ONE);
1542 else if (r_textureunits.integer >= 4 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
1544 // 4 2D combine path (Geforce3, Radeon 8500)
1545 memset(&m, 0, sizeof(m));
1546 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1547 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1548 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1549 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1550 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1551 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1552 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1553 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1554 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1555 m.texmatrix[1] = rsurface.entitytoattenuationz;
1556 m.tex[2] = R_GetTexture(basetexture);
1557 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
1558 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
1559 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
1560 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
1561 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1563 m.texcubemap[3] = R_GetTexture(rsurface.rtlight->currentcubemap);
1564 m.pointer_texcoord3f[3] = rsurface.vertex3f;
1565 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
1566 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
1567 m.texmatrix[3] = rsurface.entitytolight;
1569 GL_BlendFunc(GL_ONE, GL_ONE);
1571 else if (r_textureunits.integer >= 3 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
1573 // 3 2D combine path (Geforce3, original Radeon)
1574 memset(&m, 0, sizeof(m));
1575 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1576 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1577 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1578 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1579 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1580 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1581 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1582 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1583 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1584 m.texmatrix[1] = rsurface.entitytoattenuationz;
1585 m.tex[2] = R_GetTexture(basetexture);
1586 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
1587 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
1588 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
1589 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
1590 GL_BlendFunc(GL_ONE, GL_ONE);
1594 // 2/2/2 2D combine path (any dot3 card)
1595 memset(&m, 0, sizeof(m));
1596 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1597 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1598 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1599 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1600 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1601 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1602 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1603 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1604 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1605 m.texmatrix[1] = rsurface.entitytoattenuationz;
1606 R_Mesh_TextureState(&m);
1607 GL_ColorMask(0,0,0,1);
1608 GL_BlendFunc(GL_ONE, GL_ZERO);
1609 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1612 memset(&m, 0, sizeof(m));
1613 m.tex[0] = R_GetTexture(basetexture);
1614 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1615 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1616 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1617 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1618 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1620 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1621 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1622 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1623 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1624 m.texmatrix[1] = rsurface.entitytolight;
1626 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1628 // this final code is shared
1629 R_Mesh_TextureState(&m);
1630 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1633 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)
1636 // colorscale accounts for how much we multiply the brightness
1639 // mult is how many times the final pass of the lighting will be
1640 // performed to get more brightness than otherwise possible.
1642 // Limit mult to 64 for sanity sake.
1644 // generate normalization cubemap texcoords
1645 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
1646 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1648 // 3/2 3D combine path (Geforce3, Radeon 8500)
1649 memset(&m, 0, sizeof(m));
1650 m.tex[0] = R_GetTexture(normalmaptexture);
1651 m.texcombinergb[0] = GL_REPLACE;
1652 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1653 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1654 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1655 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1656 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1657 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1658 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1659 m.pointer_texcoord_bufferobject[1] = 0;
1660 m.pointer_texcoord_bufferoffset[1] = 0;
1661 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1662 m.pointer_texcoord3f[2] = rsurface.vertex3f;
1663 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
1664 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
1665 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
1666 R_Mesh_TextureState(&m);
1667 GL_ColorMask(0,0,0,1);
1668 GL_BlendFunc(GL_ONE, GL_ZERO);
1669 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1672 memset(&m, 0, sizeof(m));
1673 m.tex[0] = R_GetTexture(basetexture);
1674 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1675 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1676 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1677 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1678 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1680 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1681 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1682 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1683 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1684 m.texmatrix[1] = rsurface.entitytolight;
1686 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1688 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
1690 // 1/2/2 3D combine path (original Radeon)
1691 memset(&m, 0, sizeof(m));
1692 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1693 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1694 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1695 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1696 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1697 R_Mesh_TextureState(&m);
1698 GL_ColorMask(0,0,0,1);
1699 GL_BlendFunc(GL_ONE, GL_ZERO);
1700 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1703 memset(&m, 0, sizeof(m));
1704 m.tex[0] = R_GetTexture(normalmaptexture);
1705 m.texcombinergb[0] = GL_REPLACE;
1706 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1707 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1708 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1709 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1710 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1711 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1712 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1713 m.pointer_texcoord_bufferobject[1] = 0;
1714 m.pointer_texcoord_bufferoffset[1] = 0;
1715 R_Mesh_TextureState(&m);
1716 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1717 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1720 memset(&m, 0, sizeof(m));
1721 m.tex[0] = R_GetTexture(basetexture);
1722 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1723 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1724 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1725 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1726 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1728 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1729 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1730 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1731 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1732 m.texmatrix[1] = rsurface.entitytolight;
1734 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1736 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
1738 // 2/2 3D combine path (original Radeon)
1739 memset(&m, 0, sizeof(m));
1740 m.tex[0] = R_GetTexture(normalmaptexture);
1741 m.texcombinergb[0] = GL_REPLACE;
1742 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1743 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1744 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1745 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1746 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1747 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1748 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1749 m.pointer_texcoord_bufferobject[1] = 0;
1750 m.pointer_texcoord_bufferoffset[1] = 0;
1751 R_Mesh_TextureState(&m);
1752 GL_ColorMask(0,0,0,1);
1753 GL_BlendFunc(GL_ONE, GL_ZERO);
1754 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1757 memset(&m, 0, sizeof(m));
1758 m.tex[0] = R_GetTexture(basetexture);
1759 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1760 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1761 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1762 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1763 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1764 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1765 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1766 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1767 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
1768 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1770 else if (r_textureunits.integer >= 4)
1772 // 4/2 2D combine path (Geforce3, Radeon 8500)
1773 memset(&m, 0, sizeof(m));
1774 m.tex[0] = R_GetTexture(normalmaptexture);
1775 m.texcombinergb[0] = GL_REPLACE;
1776 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1777 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1778 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1779 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1780 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1781 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1782 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1783 m.pointer_texcoord_bufferobject[1] = 0;
1784 m.pointer_texcoord_bufferoffset[1] = 0;
1785 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1786 m.pointer_texcoord3f[2] = rsurface.vertex3f;
1787 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
1788 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
1789 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
1790 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1791 m.pointer_texcoord3f[3] = rsurface.vertex3f;
1792 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
1793 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
1794 m.texmatrix[3] = rsurface.entitytoattenuationz;
1795 R_Mesh_TextureState(&m);
1796 GL_ColorMask(0,0,0,1);
1797 GL_BlendFunc(GL_ONE, GL_ZERO);
1798 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1801 memset(&m, 0, sizeof(m));
1802 m.tex[0] = R_GetTexture(basetexture);
1803 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1804 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1805 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1806 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1807 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1809 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1810 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1811 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1812 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1813 m.texmatrix[1] = rsurface.entitytolight;
1815 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1819 // 2/2/2 2D combine path (any dot3 card)
1820 memset(&m, 0, sizeof(m));
1821 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1822 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1823 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1824 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1825 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1826 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1827 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1828 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1829 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1830 m.texmatrix[1] = rsurface.entitytoattenuationz;
1831 R_Mesh_TextureState(&m);
1832 GL_ColorMask(0,0,0,1);
1833 GL_BlendFunc(GL_ONE, GL_ZERO);
1834 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1837 memset(&m, 0, sizeof(m));
1838 m.tex[0] = R_GetTexture(normalmaptexture);
1839 m.texcombinergb[0] = GL_REPLACE;
1840 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1841 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1842 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1843 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1844 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1845 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1846 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1847 m.pointer_texcoord_bufferobject[1] = 0;
1848 m.pointer_texcoord_bufferoffset[1] = 0;
1849 R_Mesh_TextureState(&m);
1850 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1851 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1854 memset(&m, 0, sizeof(m));
1855 m.tex[0] = R_GetTexture(basetexture);
1856 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1857 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1858 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1859 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1860 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1862 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1863 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1864 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1865 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1866 m.texmatrix[1] = rsurface.entitytolight;
1868 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1870 // this final code is shared
1871 R_Mesh_TextureState(&m);
1872 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1875 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)
1877 float glossexponent;
1879 // FIXME: detect blendsquare!
1880 //if (!gl_support_blendsquare)
1883 // generate normalization cubemap texcoords
1884 R_Shadow_GenTexCoords_Specular_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
1885 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
1887 // 2/0/0/1/2 3D combine blendsquare path
1888 memset(&m, 0, sizeof(m));
1889 m.tex[0] = R_GetTexture(normalmaptexture);
1890 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1891 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1892 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1893 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1894 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1895 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1896 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1897 m.pointer_texcoord_bufferobject[1] = 0;
1898 m.pointer_texcoord_bufferoffset[1] = 0;
1899 R_Mesh_TextureState(&m);
1900 GL_ColorMask(0,0,0,1);
1901 // this squares the result
1902 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1903 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1905 // second and third pass
1906 R_Mesh_ResetTextureState();
1907 // square alpha in framebuffer a few times to make it shiny
1908 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1909 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
1910 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1913 memset(&m, 0, sizeof(m));
1914 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1915 m.pointer_texcoord3f[0] = rsurface.vertex3f;
1916 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
1917 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
1918 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
1919 R_Mesh_TextureState(&m);
1920 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1921 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1924 memset(&m, 0, sizeof(m));
1925 m.tex[0] = R_GetTexture(glosstexture);
1926 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1927 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1928 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1929 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1930 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1932 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
1933 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1934 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1935 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1936 m.texmatrix[1] = rsurface.entitytolight;
1938 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1940 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
1942 // 2/0/0/2 3D combine blendsquare path
1943 memset(&m, 0, sizeof(m));
1944 m.tex[0] = R_GetTexture(normalmaptexture);
1945 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1946 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1947 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1948 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1949 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1950 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1951 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1952 m.pointer_texcoord_bufferobject[1] = 0;
1953 m.pointer_texcoord_bufferoffset[1] = 0;
1954 R_Mesh_TextureState(&m);
1955 GL_ColorMask(0,0,0,1);
1956 // this squares the result
1957 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1958 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1960 // second and third pass
1961 R_Mesh_ResetTextureState();
1962 // square alpha in framebuffer a few times to make it shiny
1963 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1964 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
1965 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1968 memset(&m, 0, sizeof(m));
1969 m.tex[0] = R_GetTexture(glosstexture);
1970 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1971 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1972 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1973 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1974 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1975 m.pointer_texcoord3f[1] = rsurface.vertex3f;
1976 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
1977 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
1978 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
1979 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1983 // 2/0/0/2/2 2D combine blendsquare path
1984 memset(&m, 0, sizeof(m));
1985 m.tex[0] = R_GetTexture(normalmaptexture);
1986 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
1987 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
1988 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
1989 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
1990 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1991 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1992 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
1993 m.pointer_texcoord_bufferobject[1] = 0;
1994 m.pointer_texcoord_bufferoffset[1] = 0;
1995 R_Mesh_TextureState(&m);
1996 GL_ColorMask(0,0,0,1);
1997 // this squares the result
1998 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1999 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2001 // second and third pass
2002 R_Mesh_ResetTextureState();
2003 // square alpha in framebuffer a few times to make it shiny
2004 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2005 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2006 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2009 memset(&m, 0, sizeof(m));
2010 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2011 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2012 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2013 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2014 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2015 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2016 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2017 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2018 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2019 m.texmatrix[1] = rsurface.entitytoattenuationz;
2020 R_Mesh_TextureState(&m);
2021 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2022 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2025 memset(&m, 0, sizeof(m));
2026 m.tex[0] = R_GetTexture(glosstexture);
2027 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2028 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2029 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2030 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2031 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2033 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2034 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2035 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2036 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2037 m.texmatrix[1] = rsurface.entitytolight;
2039 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2041 // this final code is shared
2042 R_Mesh_TextureState(&m);
2043 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
2046 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)
2048 // ARB path (any Geforce, any Radeon)
2049 qboolean doambient = ambientscale > 0;
2050 qboolean dodiffuse = diffusescale > 0;
2051 qboolean dospecular = specularscale > 0;
2052 if (!doambient && !dodiffuse && !dospecular)
2054 R_Mesh_ColorPointer(NULL, 0, 0);
2056 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, basetexture, ambientscale * r_view.colorscale);
2058 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, basetexture, normalmaptexture, diffusescale * r_view.colorscale);
2062 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorpants, pantstexture, ambientscale * r_view.colorscale);
2064 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorpants, pantstexture, normalmaptexture, diffusescale * r_view.colorscale);
2069 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorshirt, shirttexture, ambientscale * r_view.colorscale);
2071 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorshirt, shirttexture, normalmaptexture, diffusescale * r_view.colorscale);
2074 R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_view.colorscale);
2077 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)
2084 int newnumtriangles;
2088 int newelements[4096*3];
2089 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
2090 for (renders = 0;renders < 64;renders++)
2095 newnumtriangles = 0;
2097 // due to low fillrate on the cards this vertex lighting path is
2098 // designed for, we manually cull all triangles that do not
2099 // contain a lit vertex
2100 // this builds batches of triangles from multiple surfaces and
2101 // renders them at once
2102 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2104 if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
2106 if (newnumtriangles)
2108 newfirstvertex = min(newfirstvertex, e[0]);
2109 newlastvertex = max(newlastvertex, e[0]);
2113 newfirstvertex = e[0];
2114 newlastvertex = e[0];
2116 newfirstvertex = min(newfirstvertex, e[1]);
2117 newlastvertex = max(newlastvertex, e[1]);
2118 newfirstvertex = min(newfirstvertex, e[2]);
2119 newlastvertex = max(newlastvertex, e[2]);
2125 if (newnumtriangles >= (int)(sizeof(newelements)/sizeof(float[3])))
2127 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, newnumtriangles, newelements, 0, 0);
2128 newnumtriangles = 0;
2134 if (newnumtriangles >= 1)
2136 // if all triangles are included, use the original array to take advantage of the bufferobject if possible
2137 if (newnumtriangles == numtriangles)
2138 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2140 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, newnumtriangles, newelements, 0, 0);
2143 // if we couldn't find any lit triangles, exit early
2146 // now reduce the intensity for the next overbright pass
2147 // we have to clamp to 0 here incase the drivers have improper
2148 // handling of negative colors
2149 // (some old drivers even have improper handling of >1 color)
2151 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2153 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2155 c[0] = max(0, c[0] - 1);
2156 c[1] = max(0, c[1] - 1);
2157 c[2] = max(0, c[2] - 1);
2169 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)
2171 // OpenGL 1.1 path (anything)
2172 float ambientcolorbase[3], diffusecolorbase[3];
2173 float ambientcolorpants[3], diffusecolorpants[3];
2174 float ambientcolorshirt[3], diffusecolorshirt[3];
2176 VectorScale(lightcolorbase, ambientscale * 2 * r_view.colorscale, ambientcolorbase);
2177 VectorScale(lightcolorbase, diffusescale * 2 * r_view.colorscale, diffusecolorbase);
2178 VectorScale(lightcolorpants, ambientscale * 2 * r_view.colorscale, ambientcolorpants);
2179 VectorScale(lightcolorpants, diffusescale * 2 * r_view.colorscale, diffusecolorpants);
2180 VectorScale(lightcolorshirt, ambientscale * 2 * r_view.colorscale, ambientcolorshirt);
2181 VectorScale(lightcolorshirt, diffusescale * 2 * r_view.colorscale, diffusecolorshirt);
2182 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2183 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
2184 memset(&m, 0, sizeof(m));
2185 m.tex[0] = R_GetTexture(basetexture);
2186 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2187 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2188 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2189 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2190 if (r_textureunits.integer >= 2)
2193 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2194 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2195 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2196 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2197 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2198 if (r_textureunits.integer >= 3)
2200 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
2201 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2202 m.texmatrix[2] = rsurface.entitytoattenuationz;
2203 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2204 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2205 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2208 R_Mesh_TextureState(&m);
2209 //R_Mesh_TexBind(0, R_GetTexture(basetexture));
2210 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, diffusecolorbase, ambientcolorbase);
2213 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
2214 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, diffusecolorpants, ambientcolorpants);
2218 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
2219 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, diffusecolorshirt, ambientcolorshirt);
2223 void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset)
2225 float ambientscale, diffusescale, specularscale;
2226 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
2227 // calculate colors to render this texture with
2228 lightcolorbase[0] = rsurface.rtlight->currentcolor[0] * rsurface.texture->dlightcolor[0];
2229 lightcolorbase[1] = rsurface.rtlight->currentcolor[1] * rsurface.texture->dlightcolor[1];
2230 lightcolorbase[2] = rsurface.rtlight->currentcolor[2] * rsurface.texture->dlightcolor[2];
2231 ambientscale = rsurface.rtlight->ambientscale;
2232 diffusescale = rsurface.rtlight->diffusescale;
2233 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2234 if (!r_shadow_usenormalmap.integer)
2236 ambientscale += 1.0f * diffusescale;
2240 if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
2242 GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
2243 GL_PolygonOffset(rsurface.texture->currentpolygonfactor, rsurface.texture->currentpolygonoffset);
2244 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
2245 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
2246 if (rsurface.texture->colormapping)
2248 qboolean dopants = rsurface.texture->currentskinframe->pants != NULL && VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f);
2249 qboolean doshirt = rsurface.texture->currentskinframe->shirt != NULL && VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f);
2252 lightcolorpants[0] = lightcolorbase[0] * rsurface.colormap_pantscolor[0];
2253 lightcolorpants[1] = lightcolorbase[1] * rsurface.colormap_pantscolor[1];
2254 lightcolorpants[2] = lightcolorbase[2] * rsurface.colormap_pantscolor[2];
2257 VectorClear(lightcolorpants);
2260 lightcolorshirt[0] = lightcolorbase[0] * rsurface.colormap_shirtcolor[0];
2261 lightcolorshirt[1] = lightcolorbase[1] * rsurface.colormap_shirtcolor[1];
2262 lightcolorshirt[2] = lightcolorbase[2] * rsurface.colormap_shirtcolor[2];
2265 VectorClear(lightcolorshirt);
2266 switch (r_shadow_rendermode)
2268 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2269 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2270 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);
2272 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2273 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);
2275 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2276 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);
2278 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2279 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);
2282 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2288 switch (r_shadow_rendermode)
2290 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2291 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2292 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);
2294 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2295 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);
2297 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2298 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);
2300 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2301 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);
2304 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2310 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)
2312 matrix4x4_t tempmatrix = *matrix;
2313 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2315 // if this light has been compiled before, free the associated data
2316 R_RTLight_Uncompile(rtlight);
2318 // clear it completely to avoid any lingering data
2319 memset(rtlight, 0, sizeof(*rtlight));
2321 // copy the properties
2322 rtlight->matrix_lighttoworld = tempmatrix;
2323 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2324 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2325 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2326 VectorCopy(color, rtlight->color);
2327 rtlight->cubemapname[0] = 0;
2328 if (cubemapname && cubemapname[0])
2329 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2330 rtlight->shadow = shadow;
2331 rtlight->corona = corona;
2332 rtlight->style = style;
2333 rtlight->isstatic = isstatic;
2334 rtlight->coronasizescale = coronasizescale;
2335 rtlight->ambientscale = ambientscale;
2336 rtlight->diffusescale = diffusescale;
2337 rtlight->specularscale = specularscale;
2338 rtlight->flags = flags;
2340 // compute derived data
2341 //rtlight->cullradius = rtlight->radius;
2342 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2343 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2344 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2345 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2346 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2347 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2348 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2351 // compiles rtlight geometry
2352 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2353 void R_RTLight_Compile(rtlight_t *rtlight)
2356 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2357 int lighttris, shadowtris, shadowmeshes, shadowmeshtris;
2358 entity_render_t *ent = r_refdef.worldentity;
2359 model_t *model = r_refdef.worldmodel;
2360 unsigned char *data;
2362 // compile the light
2363 rtlight->compiled = true;
2364 rtlight->static_numleafs = 0;
2365 rtlight->static_numleafpvsbytes = 0;
2366 rtlight->static_leaflist = NULL;
2367 rtlight->static_leafpvs = NULL;
2368 rtlight->static_numsurfaces = 0;
2369 rtlight->static_surfacelist = NULL;
2370 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2371 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2372 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2373 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2374 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2375 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2377 if (model && model->GetLightInfo)
2379 // this variable must be set for the CompileShadowVolume code
2380 r_shadow_compilingrtlight = rtlight;
2381 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);
2382 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);
2383 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2384 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
2385 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
2386 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
2387 rtlight->static_numsurfaces = numsurfaces;
2388 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2389 rtlight->static_numleafs = numleafs;
2390 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2391 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2392 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2393 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
2394 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
2395 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
2396 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
2397 if (rtlight->static_numsurfaces)
2398 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2399 if (rtlight->static_numleafs)
2400 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2401 if (rtlight->static_numleafpvsbytes)
2402 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2403 if (rtlight->static_numshadowtrispvsbytes)
2404 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
2405 if (rtlight->static_numlighttrispvsbytes)
2406 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
2407 if (model->CompileShadowVolume && rtlight->shadow)
2408 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2409 // now we're done compiling the rtlight
2410 r_shadow_compilingrtlight = NULL;
2414 // use smallest available cullradius - box radius or light radius
2415 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2416 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2420 if (rtlight->static_meshchain_shadow)
2423 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2426 shadowmeshtris += mesh->numtriangles;
2431 if (rtlight->static_numlighttrispvsbytes)
2432 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
2433 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
2437 if (rtlight->static_numlighttrispvsbytes)
2438 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
2439 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
2442 if (developer.integer >= 10)
2443 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);
2446 void R_RTLight_Uncompile(rtlight_t *rtlight)
2448 if (rtlight->compiled)
2450 if (rtlight->static_meshchain_shadow)
2451 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2452 rtlight->static_meshchain_shadow = NULL;
2453 // these allocations are grouped
2454 if (rtlight->static_surfacelist)
2455 Mem_Free(rtlight->static_surfacelist);
2456 rtlight->static_numleafs = 0;
2457 rtlight->static_numleafpvsbytes = 0;
2458 rtlight->static_leaflist = NULL;
2459 rtlight->static_leafpvs = NULL;
2460 rtlight->static_numsurfaces = 0;
2461 rtlight->static_surfacelist = NULL;
2462 rtlight->static_numshadowtrispvsbytes = 0;
2463 rtlight->static_shadowtrispvs = NULL;
2464 rtlight->static_numlighttrispvsbytes = 0;
2465 rtlight->static_lighttrispvs = NULL;
2466 rtlight->compiled = false;
2470 void R_Shadow_UncompileWorldLights(void)
2473 for (light = r_shadow_worldlightchain;light;light = light->next)
2474 R_RTLight_Uncompile(&light->rtlight);
2477 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
2481 // reset the count of frustum planes
2482 // see rsurface.rtlight_frustumplanes definition for how much this array
2484 rsurface.rtlight_numfrustumplanes = 0;
2486 // haven't implemented a culling path for ortho rendering
2487 if (!r_view.useperspective)
2489 // check if the light is on screen and copy the 4 planes if it is
2490 for (i = 0;i < 4;i++)
2491 if (PlaneDiff(rtlight->shadoworigin, &r_view.frustum[i]) < -0.03125)
2494 for (i = 0;i < 4;i++)
2495 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_view.frustum[i];
2500 // generate a deformed frustum that includes the light origin, this is
2501 // used to cull shadow casting surfaces that can not possibly cast a
2502 // shadow onto the visible light-receiving surfaces, which can be a
2505 // if the light origin is onscreen the result will be 4 planes exactly
2506 // if the light origin is offscreen on only one axis the result will
2507 // be exactly 5 planes (split-side case)
2508 // if the light origin is offscreen on two axes the result will be
2509 // exactly 4 planes (stretched corner case)
2510 for (i = 0;i < 4;i++)
2512 // quickly reject standard frustum planes that put the light
2513 // origin outside the frustum
2514 if (PlaneDiff(rtlight->shadoworigin, &r_view.frustum[i]) < -0.03125)
2517 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_view.frustum[i];
2519 // if all the standard frustum planes were accepted, the light is onscreen
2520 // otherwise we need to generate some more planes below...
2521 if (rsurface.rtlight_numfrustumplanes < 4)
2523 // at least one of the stock frustum planes failed, so we need to
2524 // create one or two custom planes to enclose the light origin
2525 for (i = 0;i < 4;i++)
2527 // create a plane using the view origin and light origin, and a
2528 // single point from the frustum corner set
2529 TriangleNormal(r_view.origin, r_view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
2530 VectorNormalize(plane.normal);
2531 plane.dist = DotProduct(r_view.origin, plane.normal);
2532 // see if this plane is backwards and flip it if so
2533 for (j = 0;j < 4;j++)
2534 if (j != i && DotProduct(r_view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
2538 VectorNegate(plane.normal, plane.normal);
2540 // flipped plane, test again to see if it is now valid
2541 for (j = 0;j < 4;j++)
2542 if (j != i && DotProduct(r_view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
2544 // if the plane is still not valid, then it is dividing the
2545 // frustum and has to be rejected
2549 // we have created a valid plane, compute extra info
2550 PlaneClassify(&plane);
2552 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
2554 // if we've found 5 frustum planes then we have constructed a
2555 // proper split-side case and do not need to keep searching for
2556 // planes to enclose the light origin
2557 if (rsurface.rtlight_numfrustumplanes == 5)
2565 for (i = 0;i < rsurface.rtlight_numfrustumplanes;i++)
2567 plane = rsurface.rtlight_frustumplanes[i];
2568 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));
2573 // now add the light-space box planes if the light box is rotated, as any
2574 // caster outside the oriented light box is irrelevant (even if it passed
2575 // the worldspace light box, which is axial)
2576 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
2578 for (i = 0;i < 6;i++)
2582 v[i >> 1] = (i & 1) ? -1 : 1;
2583 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
2584 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
2585 plane.dist = VectorNormalizeLength(plane.normal);
2586 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
2587 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
2593 // add the world-space reduced box planes
2594 for (i = 0;i < 6;i++)
2596 VectorClear(plane.normal);
2597 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
2598 plane.dist = (i & 1) ? -rsurface.rtlight_cullmaxs[i >> 1] : rsurface.rtlight_cullmins[i >> 1];
2599 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
2608 // reduce all plane distances to tightly fit the rtlight cull box, which
2610 VectorSet(points[0], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
2611 VectorSet(points[1], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
2612 VectorSet(points[2], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
2613 VectorSet(points[3], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
2614 VectorSet(points[4], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
2615 VectorSet(points[5], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
2616 VectorSet(points[6], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
2617 VectorSet(points[7], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
2618 oldnum = rsurface.rtlight_numfrustumplanes;
2619 rsurface.rtlight_numfrustumplanes = 0;
2620 for (j = 0;j < oldnum;j++)
2622 // find the nearest point on the box to this plane
2623 bestdist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[0]);
2624 for (i = 1;i < 8;i++)
2626 dist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[i]);
2627 if (bestdist > dist)
2630 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);
2631 // if the nearest point is near or behind the plane, we want this
2632 // plane, otherwise the plane is useless as it won't cull anything
2633 if (rsurface.rtlight_frustumplanes[j].dist < bestdist + 0.03125)
2635 PlaneClassify(&rsurface.rtlight_frustumplanes[j]);
2636 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = rsurface.rtlight_frustumplanes[j];
2643 void R_Shadow_DrawWorldShadow(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
2645 RSurf_ActiveWorldEntity();
2646 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2650 for (mesh = rsurface.rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2652 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
2653 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
2654 GL_LockArrays(0, mesh->numverts);
2655 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
2657 // decrement stencil if backface is behind depthbuffer
2658 GL_CullFace(GL_BACK); // quake is backwards, this culls front faces
2659 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2660 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->ebo, 0);
2661 // increment stencil if frontface is behind depthbuffer
2662 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
2663 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2665 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->ebo, 0);
2666 GL_LockArrays(0, 0);
2670 else if (numsurfaces && r_refdef.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
2673 int surfacelistindex;
2674 msurface_t *surface;
2675 R_Shadow_PrepareShadowMark(r_refdef.worldmodel->brush.shadowmesh->numtriangles);
2676 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
2678 surface = r_refdef.worldmodel->data_surfaces + surfacelist[surfacelistindex];
2679 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
2680 if (CHECKPVSBIT(trispvs, t))
2681 shadowmarklist[numshadowmark++] = t;
2683 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);
2685 else if (numsurfaces)
2686 r_refdef.worldmodel->DrawShadowVolume(r_refdef.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
2689 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
2691 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
2692 vec_t relativeshadowradius;
2693 RSurf_ActiveModelEntity(ent, false, false);
2694 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
2695 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
2696 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
2697 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
2698 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
2699 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
2700 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
2701 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
2702 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2705 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
2707 // set up properties for rendering light onto this entity
2708 RSurf_ActiveModelEntity(ent, true, true);
2709 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
2710 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
2711 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
2712 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
2713 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2714 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
2717 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
2719 if (!r_refdef.worldmodel->DrawLight)
2722 // set up properties for rendering light onto this entity
2723 RSurf_ActiveWorldEntity();
2724 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
2725 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
2726 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
2727 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
2728 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2729 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
2731 r_refdef.worldmodel->DrawLight(r_refdef.worldentity, numsurfaces, surfacelist, trispvs);
2734 void R_Shadow_DrawEntityLight(entity_render_t *ent, int numsurfaces, int *surfacelist)
2736 model_t *model = ent->model;
2737 if (!model->DrawLight)
2740 R_Shadow_SetupEntityLight(ent);
2742 model->DrawLight(ent, model->nummodelsurfaces, model->surfacelist, NULL);
2745 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
2749 int numleafs, numsurfaces;
2750 int *leaflist, *surfacelist;
2751 unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs;
2752 int numlightentities;
2753 int numlightentities_noselfshadow;
2754 int numshadowentities;
2755 int numshadowentities_noselfshadow;
2756 entity_render_t *lightentities[MAX_EDICTS];
2757 entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
2758 entity_render_t *shadowentities[MAX_EDICTS];
2759 entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
2761 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
2762 // skip lights that are basically invisible (color 0 0 0)
2763 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
2766 // loading is done before visibility checks because loading should happen
2767 // all at once at the start of a level, not when it stalls gameplay.
2768 // (especially important to benchmarks)
2770 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2771 R_RTLight_Compile(rtlight);
2773 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
2775 // look up the light style value at this time
2776 f = (rtlight->style >= 0 ? r_refdef.lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2777 VectorScale(rtlight->color, f, rtlight->currentcolor);
2779 if (rtlight->selected)
2781 f = 2 + sin(realtime * M_PI * 4.0);
2782 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
2786 // if lightstyle is currently off, don't draw the light
2787 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
2790 // if the light box is offscreen, skip it
2791 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2794 VectorCopy(rtlight->cullmins, rsurface.rtlight_cullmins);
2795 VectorCopy(rtlight->cullmaxs, rsurface.rtlight_cullmaxs);
2797 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2799 // compiled light, world available and can receive realtime lighting
2800 // retrieve leaf information
2801 numleafs = rtlight->static_numleafs;
2802 leaflist = rtlight->static_leaflist;
2803 leafpvs = rtlight->static_leafpvs;
2804 numsurfaces = rtlight->static_numsurfaces;
2805 surfacelist = rtlight->static_surfacelist;
2806 shadowtrispvs = rtlight->static_shadowtrispvs;
2807 lighttrispvs = rtlight->static_lighttrispvs;
2809 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2811 // dynamic light, world available and can receive realtime lighting
2812 // calculate lit surfaces and leafs
2813 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);
2814 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);
2815 leaflist = r_shadow_buffer_leaflist;
2816 leafpvs = r_shadow_buffer_leafpvs;
2817 surfacelist = r_shadow_buffer_surfacelist;
2818 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
2819 lighttrispvs = r_shadow_buffer_lighttrispvs;
2820 // if the reduced leaf bounds are offscreen, skip it
2821 if (R_CullBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
2832 shadowtrispvs = NULL;
2833 lighttrispvs = NULL;
2835 // check if light is illuminating any visible leafs
2838 for (i = 0;i < numleafs;i++)
2839 if (r_viewcache.world_leafvisible[leaflist[i]])
2844 // set up a scissor rectangle for this light
2845 if (R_Shadow_ScissorForBBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
2848 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
2850 // make a list of lit entities and shadow casting entities
2851 numlightentities = 0;
2852 numlightentities_noselfshadow = 0;
2853 numshadowentities = 0;
2854 numshadowentities_noselfshadow = 0;
2855 // add dynamic entities that are lit by the light
2856 if (r_drawentities.integer)
2858 for (i = 0;i < r_refdef.numentities;i++)
2861 entity_render_t *ent = r_refdef.entities[i];
2863 if (!BoxesOverlap(ent->mins, ent->maxs, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
2865 // skip the object entirely if it is not within the valid
2866 // shadow-casting region (which includes the lit region)
2867 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rsurface.rtlight_numfrustumplanes, rsurface.rtlight_frustumplanes))
2869 if (!(model = ent->model))
2871 if (r_viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
2873 // this entity wants to receive light, is visible, and is
2874 // inside the light box
2875 // TODO: check if the surfaces in the model can receive light
2876 // so now check if it's in a leaf seen by the light
2877 if (r_refdef.worldmodel && r_refdef.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs))
2879 if (ent->flags & RENDER_NOSELFSHADOW)
2880 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
2882 lightentities[numlightentities++] = ent;
2883 // since it is lit, it probably also casts a shadow...
2884 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2885 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
2886 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
2888 // note: exterior models without the RENDER_NOSELFSHADOW
2889 // flag still create a RENDER_NOSELFSHADOW shadow but
2890 // are lit normally, this means that they are
2891 // self-shadowing but do not shadow other
2892 // RENDER_NOSELFSHADOW entities such as the gun
2893 // (very weird, but keeps the player shadow off the gun)
2894 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
2895 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
2897 shadowentities[numshadowentities++] = ent;
2900 else if (ent->flags & RENDER_SHADOW)
2902 // this entity is not receiving light, but may still need to
2904 // TODO: check if the surfaces in the model can cast shadow
2905 // now check if it is in a leaf seen by the light
2906 if (r_refdef.worldmodel && r_refdef.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs))
2908 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2909 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
2910 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
2912 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
2913 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
2915 shadowentities[numshadowentities++] = ent;
2921 // return if there's nothing at all to light
2922 if (!numlightentities && !numsurfaces)
2925 // don't let sound skip if going slow
2926 if (r_refdef.extraupdate)
2929 // make this the active rtlight for rendering purposes
2930 R_Shadow_RenderMode_ActiveLight(rtlight);
2931 // count this light in the r_speeds
2932 r_refdef.stats.lights++;
2934 if (r_showshadowvolumes.integer && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.rtworldshadows : r_refdef.rtdlightshadows))
2936 // optionally draw visible shape of the shadow volumes
2937 // for performance analysis by level designers
2938 R_Shadow_RenderMode_VisibleShadowVolumes();
2940 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
2941 for (i = 0;i < numshadowentities;i++)
2942 R_Shadow_DrawEntityShadow(shadowentities[i]);
2943 for (i = 0;i < numshadowentities_noselfshadow;i++)
2944 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
2947 if (gl_stencil && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.rtworldshadows : r_refdef.rtdlightshadows))
2949 // draw stencil shadow volumes to mask off pixels that are in shadow
2950 // so that they won't receive lighting
2951 R_Shadow_RenderMode_StencilShadowVolumes(true);
2953 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
2954 for (i = 0;i < numshadowentities;i++)
2955 R_Shadow_DrawEntityShadow(shadowentities[i]);
2956 if (numlightentities_noselfshadow)
2958 // draw lighting in the unmasked areas
2959 R_Shadow_RenderMode_Lighting(true, false);
2960 for (i = 0;i < numlightentities_noselfshadow;i++)
2961 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i], numsurfaces, surfacelist);
2963 // optionally draw the illuminated areas
2964 // for performance analysis by level designers
2965 if (r_showlighting.integer)
2967 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
2968 for (i = 0;i < numlightentities_noselfshadow;i++)
2969 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i], numsurfaces, surfacelist);
2972 R_Shadow_RenderMode_StencilShadowVolumes(false);
2974 for (i = 0;i < numshadowentities_noselfshadow;i++)
2975 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
2977 if (numsurfaces + numlightentities)
2979 // draw lighting in the unmasked areas
2980 R_Shadow_RenderMode_Lighting(true, false);
2982 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
2983 for (i = 0;i < numlightentities;i++)
2984 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
2986 // optionally draw the illuminated areas
2987 // for performance analysis by level designers
2988 if (r_showlighting.integer)
2990 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
2992 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
2993 for (i = 0;i < numlightentities;i++)
2994 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
3000 if (numsurfaces + numlightentities)
3002 // draw lighting in the unmasked areas
3003 R_Shadow_RenderMode_Lighting(false, false);
3005 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3006 for (i = 0;i < numlightentities;i++)
3007 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
3008 for (i = 0;i < numlightentities_noselfshadow;i++)
3009 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i], numsurfaces, surfacelist);
3011 // optionally draw the illuminated areas
3012 // for performance analysis by level designers
3013 if (r_showlighting.integer)
3015 R_Shadow_RenderMode_VisibleLighting(false, false);
3017 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3018 for (i = 0;i < numlightentities;i++)
3019 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
3020 for (i = 0;i < numlightentities_noselfshadow;i++)
3021 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i], numsurfaces, surfacelist);
3027 void R_Shadow_DrawLightSprites(void);
3028 void R_ShadowVolumeLighting(qboolean visible)
3033 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
3034 R_Shadow_EditLights_Reload_f();
3036 if (r_editlights.integer)
3037 R_Shadow_DrawLightSprites();
3039 R_Shadow_RenderMode_Begin();
3041 flag = r_refdef.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3042 if (r_shadow_debuglight.integer >= 0)
3044 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
3045 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
3046 R_DrawRTLight(&light->rtlight, visible);
3049 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
3050 if (light->flags & flag)
3051 R_DrawRTLight(&light->rtlight, visible);
3052 if (r_refdef.rtdlight)
3053 for (lnum = 0;lnum < r_refdef.numlights;lnum++)
3054 R_DrawRTLight(&r_refdef.lights[lnum], visible);
3056 R_Shadow_RenderMode_End();
3059 extern void R_SetupView(const matrix4x4_t *matrix);
3060 extern cvar_t r_shadows_throwdistance;
3061 void R_DrawModelShadows(void)
3064 float relativethrowdistance;
3065 entity_render_t *ent;
3066 vec3_t relativelightorigin;
3067 vec3_t relativelightdirection;
3068 vec3_t relativeshadowmins, relativeshadowmaxs;
3071 if (!r_drawentities.integer || !gl_stencil)
3075 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
3077 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
3079 if (gl_ext_separatestencil.integer)
3080 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
3081 else if (gl_ext_stenciltwoside.integer)
3082 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
3084 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
3086 R_Shadow_RenderMode_StencilShadowVolumes(true);
3088 for (i = 0;i < r_refdef.numentities;i++)
3090 ent = r_refdef.entities[i];
3091 // cast shadows from anything that is not a submodel of the map
3092 if (ent->model && ent->model->DrawShadowVolume != NULL && !ent->model->brush.submodel && (ent->flags & RENDER_SHADOW))
3094 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
3095 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
3096 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
3097 VectorNegate(ent->modellight_lightdir, relativelightdirection);
3098 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
3099 RSurf_ActiveModelEntity(ent, false, false);
3100 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
3104 // not really the right mode, but this will disable any silly stencil features
3105 R_Shadow_RenderMode_VisibleLighting(true, true);
3107 // vertex coordinates for a quad that covers the screen exactly
3108 vertex3f[0] = 0;vertex3f[1] = 0;vertex3f[2] = 0;
3109 vertex3f[3] = 1;vertex3f[4] = 0;vertex3f[5] = 0;
3110 vertex3f[6] = 1;vertex3f[7] = 1;vertex3f[8] = 0;
3111 vertex3f[9] = 0;vertex3f[10] = 1;vertex3f[11] = 0;
3113 // set up ortho view for rendering this pass
3114 GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
3115 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
3116 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
3117 GL_ScissorTest(true);
3118 R_Mesh_Matrix(&identitymatrix);
3119 R_Mesh_ResetTextureState();
3120 R_Mesh_VertexPointer(vertex3f, 0, 0);
3121 R_Mesh_ColorPointer(NULL, 0, 0);
3123 // set up a 50% darkening blend on shadowed areas
3124 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3125 GL_DepthRange(0, 1);
3126 GL_DepthTest(false);
3127 GL_DepthMask(false);
3128 GL_PolygonOffset(0, 0);CHECKGLERROR
3129 GL_Color(0, 0, 0, 0.5);
3130 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
3131 qglDepthFunc(GL_ALWAYS);CHECKGLERROR
3132 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
3133 qglStencilMask(~0);CHECKGLERROR
3134 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
3135 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
3137 // apply the blend to the shadowed areas
3138 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3140 // restoring the perspective view is done by R_RenderScene
3141 //R_SetupView(&r_view.matrix);
3143 // restore other state to normal
3144 R_Shadow_RenderMode_End();
3148 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
3149 typedef struct suffixinfo_s
3152 qboolean flipx, flipy, flipdiagonal;
3155 static suffixinfo_t suffix[3][6] =
3158 {"px", false, false, false},
3159 {"nx", false, false, false},
3160 {"py", false, false, false},
3161 {"ny", false, false, false},
3162 {"pz", false, false, false},
3163 {"nz", false, false, false}
3166 {"posx", false, false, false},
3167 {"negx", false, false, false},
3168 {"posy", false, false, false},
3169 {"negy", false, false, false},
3170 {"posz", false, false, false},
3171 {"negz", false, false, false}
3174 {"rt", true, false, true},
3175 {"lf", false, true, true},
3176 {"ft", true, true, false},
3177 {"bk", false, false, false},
3178 {"up", true, false, true},
3179 {"dn", true, false, true}
3183 static int componentorder[4] = {0, 1, 2, 3};
3185 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
3187 int i, j, cubemapsize;
3188 unsigned char *cubemappixels, *image_rgba;
3189 rtexture_t *cubemaptexture;
3191 // must start 0 so the first loadimagepixels has no requested width/height
3193 cubemappixels = NULL;
3194 cubemaptexture = NULL;
3195 // keep trying different suffix groups (posx, px, rt) until one loads
3196 for (j = 0;j < 3 && !cubemappixels;j++)
3198 // load the 6 images in the suffix group
3199 for (i = 0;i < 6;i++)
3201 // generate an image name based on the base and and suffix
3202 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
3204 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
3206 // an image loaded, make sure width and height are equal
3207 if (image_width == image_height)
3209 // if this is the first image to load successfully, allocate the cubemap memory
3210 if (!cubemappixels && image_width >= 1)
3212 cubemapsize = image_width;
3213 // note this clears to black, so unavailable sides are black
3214 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
3216 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
3218 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);
3221 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
3223 Mem_Free(image_rgba);
3227 // if a cubemap loaded, upload it
3230 if (!r_shadow_filters_texturepool)
3231 r_shadow_filters_texturepool = R_AllocTexturePool();
3232 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
3233 Mem_Free(cubemappixels);
3237 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
3238 for (j = 0;j < 3;j++)
3239 for (i = 0;i < 6;i++)
3240 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
3241 Con_Print(" and was unable to find any of them.\n");
3243 return cubemaptexture;
3246 rtexture_t *R_Shadow_Cubemap(const char *basename)
3249 for (i = 0;i < numcubemaps;i++)
3250 if (!strcasecmp(cubemaps[i].basename, basename))
3251 return cubemaps[i].texture;
3252 if (i >= MAX_CUBEMAPS)
3253 return r_texture_whitecube;
3255 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
3256 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
3257 if (!cubemaps[i].texture)
3258 cubemaps[i].texture = r_texture_whitecube;
3259 return cubemaps[i].texture;
3262 void R_Shadow_FreeCubemaps(void)
3265 R_FreeTexturePool(&r_shadow_filters_texturepool);
3268 dlight_t *R_Shadow_NewWorldLight(void)
3271 light = (dlight_t *)Mem_Alloc(r_main_mempool, sizeof(dlight_t));
3272 light->next = r_shadow_worldlightchain;
3273 r_shadow_worldlightchain = light;
3277 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)
3280 // validate parameters
3281 if (style < 0 || style >= MAX_LIGHTSTYLES)
3283 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
3289 // copy to light properties
3290 VectorCopy(origin, light->origin);
3291 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
3292 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
3293 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
3294 light->color[0] = max(color[0], 0);
3295 light->color[1] = max(color[1], 0);
3296 light->color[2] = max(color[2], 0);
3297 light->radius = max(radius, 0);
3298 light->style = style;
3299 light->shadow = shadowenable;
3300 light->corona = corona;
3301 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
3302 light->coronasizescale = coronasizescale;
3303 light->ambientscale = ambientscale;
3304 light->diffusescale = diffusescale;
3305 light->specularscale = specularscale;
3306 light->flags = flags;
3308 // update renderable light data
3309 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
3310 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);
3313 void R_Shadow_FreeWorldLight(dlight_t *light)
3315 dlight_t **lightpointer;
3316 R_RTLight_Uncompile(&light->rtlight);
3317 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
3318 if (*lightpointer != light)
3319 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain");
3320 *lightpointer = light->next;
3324 void R_Shadow_ClearWorldLights(void)
3326 while (r_shadow_worldlightchain)
3327 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
3328 r_shadow_selectedlight = NULL;
3329 R_Shadow_FreeCubemaps();
3332 void R_Shadow_SelectLight(dlight_t *light)
3334 if (r_shadow_selectedlight)
3335 r_shadow_selectedlight->selected = false;
3336 r_shadow_selectedlight = light;
3337 if (r_shadow_selectedlight)
3338 r_shadow_selectedlight->selected = true;
3341 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
3343 // this is never batched (there can be only one)
3344 float scale = r_editlights_cursorgrid.value * 0.5f;
3345 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);
3348 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
3350 // this is never batched (due to the ent parameter changing every time)
3351 // so numsurfaces == 1 and surfacelist[0] == lightnumber
3353 const dlight_t *light = (dlight_t *)ent;
3355 if (light->selected)
3356 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
3359 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);
3362 void R_Shadow_DrawLightSprites(void)
3367 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
3368 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 1+(i % 5), &light->rtlight);
3369 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
3372 void R_Shadow_SelectLightInView(void)
3374 float bestrating, rating, temp[3];
3375 dlight_t *best, *light;
3378 for (light = r_shadow_worldlightchain;light;light = light->next)
3380 VectorSubtract(light->origin, r_view.origin, temp);
3381 rating = (DotProduct(temp, r_view.forward) / sqrt(DotProduct(temp, temp)));
3384 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
3385 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)
3387 bestrating = rating;
3392 R_Shadow_SelectLight(best);
3395 void R_Shadow_LoadWorldLights(void)
3397 int n, a, style, shadow, flags;
3398 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
3399 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
3400 if (r_refdef.worldmodel == NULL)
3402 Con_Print("No map loaded.\n");
3405 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3406 strlcat (name, ".rtlights", sizeof (name));
3407 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3417 for (;COM_Parse(t, true) && strcmp(
3418 if (COM_Parse(t, true))
3420 if (com_token[0] == '!')
3423 origin[0] = atof(com_token+1);
3426 origin[0] = atof(com_token);
3431 while (*s && *s != '\n' && *s != '\r')
3437 // check for modifier flags
3444 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);
3447 flags = LIGHTFLAG_REALTIMEMODE;
3455 coronasizescale = 0.25f;
3457 VectorClear(angles);
3460 if (a < 9 || !strcmp(cubemapname, "\"\""))
3462 // remove quotes on cubemapname
3463 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
3466 namelen = strlen(cubemapname) - 2;
3467 memmove(cubemapname, cubemapname + 1, namelen);
3468 cubemapname[namelen] = '\0';
3472 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);
3475 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3483 Con_Printf("invalid rtlights file \"%s\"\n", name);
3484 Mem_Free(lightsstring);
3488 void R_Shadow_SaveWorldLights(void)
3491 size_t bufchars, bufmaxchars;
3493 char name[MAX_QPATH];
3494 char line[MAX_INPUTLINE];
3495 if (!r_shadow_worldlightchain)
3497 if (r_refdef.worldmodel == NULL)
3499 Con_Print("No map loaded.\n");
3502 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3503 strlcat (name, ".rtlights", sizeof (name));
3504 bufchars = bufmaxchars = 0;
3506 for (light = r_shadow_worldlightchain;light;light = light->next)
3508 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3509 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);
3510 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3511 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]);
3513 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);
3514 if (bufchars + strlen(line) > bufmaxchars)
3516 bufmaxchars = bufchars + strlen(line) + 2048;
3518 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
3522 memcpy(buf, oldbuf, bufchars);
3528 memcpy(buf + bufchars, line, strlen(line));
3529 bufchars += strlen(line);
3533 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
3538 void R_Shadow_LoadLightsFile(void)
3541 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3542 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3543 if (r_refdef.worldmodel == NULL)
3545 Con_Print("No map loaded.\n");
3548 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3549 strlcat (name, ".lights", sizeof (name));
3550 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3558 while (*s && *s != '\n' && *s != '\r')
3564 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);
3568 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);
3571 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3572 radius = bound(15, radius, 4096);
3573 VectorScale(color, (2.0f / (8388608.0f)), color);
3574 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3582 Con_Printf("invalid lights file \"%s\"\n", name);
3583 Mem_Free(lightsstring);
3587 // tyrlite/hmap2 light types in the delay field
3588 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3590 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3592 int entnum, style, islight, skin, pflags, effects, type, n;
3595 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3596 char key[256], value[MAX_INPUTLINE];
3598 if (r_refdef.worldmodel == NULL)
3600 Con_Print("No map loaded.\n");
3603 // try to load a .ent file first
3604 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3605 strlcat (key, ".ent", sizeof (key));
3606 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
3607 // and if that is not found, fall back to the bsp file entity string
3609 data = r_refdef.worldmodel->brush.entities;
3612 for (entnum = 0;COM_ParseToken_Simple(&data, false) && com_token[0] == '{';entnum++)
3614 type = LIGHTTYPE_MINUSX;
3615 origin[0] = origin[1] = origin[2] = 0;
3616 originhack[0] = originhack[1] = originhack[2] = 0;
3617 angles[0] = angles[1] = angles[2] = 0;
3618 color[0] = color[1] = color[2] = 1;
3619 light[0] = light[1] = light[2] = 1;light[3] = 300;
3620 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3630 if (!COM_ParseToken_Simple(&data, false))
3632 if (com_token[0] == '}')
3633 break; // end of entity
3634 if (com_token[0] == '_')
3635 strlcpy(key, com_token + 1, sizeof(key));
3637 strlcpy(key, com_token, sizeof(key));
3638 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3639 key[strlen(key)-1] = 0;
3640 if (!COM_ParseToken_Simple(&data, false))
3642 strlcpy(value, com_token, sizeof(value));
3644 // now that we have the key pair worked out...
3645 if (!strcmp("light", key))
3647 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3651 light[0] = vec[0] * (1.0f / 256.0f);
3652 light[1] = vec[0] * (1.0f / 256.0f);
3653 light[2] = vec[0] * (1.0f / 256.0f);
3659 light[0] = vec[0] * (1.0f / 255.0f);
3660 light[1] = vec[1] * (1.0f / 255.0f);
3661 light[2] = vec[2] * (1.0f / 255.0f);
3665 else if (!strcmp("delay", key))
3667 else if (!strcmp("origin", key))
3668 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3669 else if (!strcmp("angle", key))
3670 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3671 else if (!strcmp("angles", key))
3672 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3673 else if (!strcmp("color", key))
3674 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3675 else if (!strcmp("wait", key))
3676 fadescale = atof(value);
3677 else if (!strcmp("classname", key))
3679 if (!strncmp(value, "light", 5))
3682 if (!strcmp(value, "light_fluoro"))
3687 overridecolor[0] = 1;
3688 overridecolor[1] = 1;
3689 overridecolor[2] = 1;
3691 if (!strcmp(value, "light_fluorospark"))
3696 overridecolor[0] = 1;
3697 overridecolor[1] = 1;
3698 overridecolor[2] = 1;
3700 if (!strcmp(value, "light_globe"))
3705 overridecolor[0] = 1;
3706 overridecolor[1] = 0.8;
3707 overridecolor[2] = 0.4;
3709 if (!strcmp(value, "light_flame_large_yellow"))
3714 overridecolor[0] = 1;
3715 overridecolor[1] = 0.5;
3716 overridecolor[2] = 0.1;
3718 if (!strcmp(value, "light_flame_small_yellow"))
3723 overridecolor[0] = 1;
3724 overridecolor[1] = 0.5;
3725 overridecolor[2] = 0.1;
3727 if (!strcmp(value, "light_torch_small_white"))
3732 overridecolor[0] = 1;
3733 overridecolor[1] = 0.5;
3734 overridecolor[2] = 0.1;
3736 if (!strcmp(value, "light_torch_small_walltorch"))
3741 overridecolor[0] = 1;
3742 overridecolor[1] = 0.5;
3743 overridecolor[2] = 0.1;
3747 else if (!strcmp("style", key))
3748 style = atoi(value);
3749 else if (!strcmp("skin", key))
3750 skin = (int)atof(value);
3751 else if (!strcmp("pflags", key))
3752 pflags = (int)atof(value);
3753 else if (!strcmp("effects", key))
3754 effects = (int)atof(value);
3755 else if (r_refdef.worldmodel->type == mod_brushq3)
3757 if (!strcmp("scale", key))
3758 lightscale = atof(value);
3759 if (!strcmp("fade", key))
3760 fadescale = atof(value);
3765 if (lightscale <= 0)
3769 if (color[0] == color[1] && color[0] == color[2])
3771 color[0] *= overridecolor[0];
3772 color[1] *= overridecolor[1];
3773 color[2] *= overridecolor[2];
3775 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3776 color[0] = color[0] * light[0];
3777 color[1] = color[1] * light[1];
3778 color[2] = color[2] * light[2];
3781 case LIGHTTYPE_MINUSX:
3783 case LIGHTTYPE_RECIPX:
3785 VectorScale(color, (1.0f / 16.0f), color);
3787 case LIGHTTYPE_RECIPXX:
3789 VectorScale(color, (1.0f / 16.0f), color);
3792 case LIGHTTYPE_NONE:
3796 case LIGHTTYPE_MINUSXX:
3799 VectorAdd(origin, originhack, origin);
3801 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);
3804 Mem_Free(entfiledata);
3808 void R_Shadow_SetCursorLocationForView(void)
3811 vec3_t dest, endpos;
3813 VectorMA(r_view.origin, r_editlights_cursordistance.value, r_view.forward, dest);
3814 trace = CL_Move(r_view.origin, vec3_origin, vec3_origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
3815 if (trace.fraction < 1)
3817 dist = trace.fraction * r_editlights_cursordistance.value;
3818 push = r_editlights_cursorpushback.value;
3822 VectorMA(trace.endpos, push, r_view.forward, endpos);
3823 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
3827 VectorClear( endpos );
3829 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3830 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3831 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3834 void R_Shadow_UpdateWorldLightSelection(void)
3836 if (r_editlights.integer)
3838 R_Shadow_SetCursorLocationForView();
3839 R_Shadow_SelectLightInView();
3842 R_Shadow_SelectLight(NULL);
3845 void R_Shadow_EditLights_Clear_f(void)
3847 R_Shadow_ClearWorldLights();
3850 void R_Shadow_EditLights_Reload_f(void)
3852 if (!r_refdef.worldmodel)
3854 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3855 R_Shadow_ClearWorldLights();
3856 R_Shadow_LoadWorldLights();
3857 if (r_shadow_worldlightchain == NULL)
3859 R_Shadow_LoadLightsFile();
3860 if (r_shadow_worldlightchain == NULL)
3861 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3865 void R_Shadow_EditLights_Save_f(void)
3867 if (!r_refdef.worldmodel)
3869 R_Shadow_SaveWorldLights();
3872 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3874 R_Shadow_ClearWorldLights();
3875 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3878 void R_Shadow_EditLights_ImportLightsFile_f(void)
3880 R_Shadow_ClearWorldLights();
3881 R_Shadow_LoadLightsFile();
3884 void R_Shadow_EditLights_Spawn_f(void)
3887 if (!r_editlights.integer)
3889 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3892 if (Cmd_Argc() != 1)
3894 Con_Print("r_editlights_spawn does not take parameters\n");
3897 color[0] = color[1] = color[2] = 1;
3898 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3901 void R_Shadow_EditLights_Edit_f(void)
3903 vec3_t origin, angles, color;
3904 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3905 int style, shadows, flags, normalmode, realtimemode;
3906 char cubemapname[MAX_INPUTLINE];
3907 if (!r_editlights.integer)
3909 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3912 if (!r_shadow_selectedlight)
3914 Con_Print("No selected light.\n");
3917 VectorCopy(r_shadow_selectedlight->origin, origin);
3918 VectorCopy(r_shadow_selectedlight->angles, angles);
3919 VectorCopy(r_shadow_selectedlight->color, color);
3920 radius = r_shadow_selectedlight->radius;
3921 style = r_shadow_selectedlight->style;
3922 if (r_shadow_selectedlight->cubemapname)
3923 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
3926 shadows = r_shadow_selectedlight->shadow;
3927 corona = r_shadow_selectedlight->corona;
3928 coronasizescale = r_shadow_selectedlight->coronasizescale;
3929 ambientscale = r_shadow_selectedlight->ambientscale;
3930 diffusescale = r_shadow_selectedlight->diffusescale;
3931 specularscale = r_shadow_selectedlight->specularscale;
3932 flags = r_shadow_selectedlight->flags;
3933 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3934 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3935 if (!strcmp(Cmd_Argv(1), "origin"))
3937 if (Cmd_Argc() != 5)
3939 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3942 origin[0] = atof(Cmd_Argv(2));
3943 origin[1] = atof(Cmd_Argv(3));
3944 origin[2] = atof(Cmd_Argv(4));
3946 else if (!strcmp(Cmd_Argv(1), "originx"))
3948 if (Cmd_Argc() != 3)
3950 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3953 origin[0] = atof(Cmd_Argv(2));
3955 else if (!strcmp(Cmd_Argv(1), "originy"))
3957 if (Cmd_Argc() != 3)
3959 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3962 origin[1] = atof(Cmd_Argv(2));
3964 else if (!strcmp(Cmd_Argv(1), "originz"))
3966 if (Cmd_Argc() != 3)
3968 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3971 origin[2] = atof(Cmd_Argv(2));
3973 else if (!strcmp(Cmd_Argv(1), "move"))
3975 if (Cmd_Argc() != 5)
3977 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3980 origin[0] += atof(Cmd_Argv(2));
3981 origin[1] += atof(Cmd_Argv(3));
3982 origin[2] += atof(Cmd_Argv(4));
3984 else if (!strcmp(Cmd_Argv(1), "movex"))
3986 if (Cmd_Argc() != 3)
3988 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3991 origin[0] += atof(Cmd_Argv(2));
3993 else if (!strcmp(Cmd_Argv(1), "movey"))
3995 if (Cmd_Argc() != 3)
3997 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4000 origin[1] += atof(Cmd_Argv(2));
4002 else if (!strcmp(Cmd_Argv(1), "movez"))
4004 if (Cmd_Argc() != 3)
4006 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4009 origin[2] += atof(Cmd_Argv(2));
4011 else if (!strcmp(Cmd_Argv(1), "angles"))
4013 if (Cmd_Argc() != 5)
4015 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
4018 angles[0] = atof(Cmd_Argv(2));
4019 angles[1] = atof(Cmd_Argv(3));
4020 angles[2] = atof(Cmd_Argv(4));
4022 else if (!strcmp(Cmd_Argv(1), "anglesx"))
4024 if (Cmd_Argc() != 3)
4026 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4029 angles[0] = atof(Cmd_Argv(2));
4031 else if (!strcmp(Cmd_Argv(1), "anglesy"))
4033 if (Cmd_Argc() != 3)
4035 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4038 angles[1] = atof(Cmd_Argv(2));
4040 else if (!strcmp(Cmd_Argv(1), "anglesz"))
4042 if (Cmd_Argc() != 3)
4044 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4047 angles[2] = atof(Cmd_Argv(2));
4049 else if (!strcmp(Cmd_Argv(1), "color"))
4051 if (Cmd_Argc() != 5)
4053 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
4056 color[0] = atof(Cmd_Argv(2));
4057 color[1] = atof(Cmd_Argv(3));
4058 color[2] = atof(Cmd_Argv(4));
4060 else if (!strcmp(Cmd_Argv(1), "radius"))
4062 if (Cmd_Argc() != 3)
4064 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4067 radius = atof(Cmd_Argv(2));
4069 else if (!strcmp(Cmd_Argv(1), "colorscale"))
4071 if (Cmd_Argc() == 3)
4073 double scale = atof(Cmd_Argv(2));
4080 if (Cmd_Argc() != 5)
4082 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
4085 color[0] *= atof(Cmd_Argv(2));
4086 color[1] *= atof(Cmd_Argv(3));
4087 color[2] *= atof(Cmd_Argv(4));
4090 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
4092 if (Cmd_Argc() != 3)
4094 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4097 radius *= atof(Cmd_Argv(2));
4099 else if (!strcmp(Cmd_Argv(1), "style"))
4101 if (Cmd_Argc() != 3)
4103 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4106 style = atoi(Cmd_Argv(2));
4108 else if (!strcmp(Cmd_Argv(1), "cubemap"))
4112 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4115 if (Cmd_Argc() == 3)
4116 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
4120 else if (!strcmp(Cmd_Argv(1), "shadows"))
4122 if (Cmd_Argc() != 3)
4124 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4127 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4129 else if (!strcmp(Cmd_Argv(1), "corona"))
4131 if (Cmd_Argc() != 3)
4133 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4136 corona = atof(Cmd_Argv(2));
4138 else if (!strcmp(Cmd_Argv(1), "coronasize"))
4140 if (Cmd_Argc() != 3)
4142 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4145 coronasizescale = atof(Cmd_Argv(2));
4147 else if (!strcmp(Cmd_Argv(1), "ambient"))
4149 if (Cmd_Argc() != 3)
4151 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4154 ambientscale = atof(Cmd_Argv(2));
4156 else if (!strcmp(Cmd_Argv(1), "diffuse"))
4158 if (Cmd_Argc() != 3)
4160 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4163 diffusescale = atof(Cmd_Argv(2));
4165 else if (!strcmp(Cmd_Argv(1), "specular"))
4167 if (Cmd_Argc() != 3)
4169 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4172 specularscale = atof(Cmd_Argv(2));
4174 else if (!strcmp(Cmd_Argv(1), "normalmode"))
4176 if (Cmd_Argc() != 3)
4178 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4181 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4183 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
4185 if (Cmd_Argc() != 3)
4187 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4190 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4194 Con_Print("usage: r_editlights_edit [property] [value]\n");
4195 Con_Print("Selected light's properties:\n");
4196 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
4197 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
4198 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
4199 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
4200 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
4201 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
4202 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
4203 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
4204 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
4205 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
4206 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
4207 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
4208 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
4209 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
4212 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
4213 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4216 void R_Shadow_EditLights_EditAll_f(void)
4220 if (!r_editlights.integer)
4222 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
4226 for (light = r_shadow_worldlightchain;light;light = light->next)
4228 R_Shadow_SelectLight(light);
4229 R_Shadow_EditLights_Edit_f();
4233 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
4235 int lightnumber, lightcount;
4239 if (!r_editlights.integer)
4245 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
4246 if (light == r_shadow_selectedlight)
4247 lightnumber = lightcount;
4248 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;
4249 if (r_shadow_selectedlight == NULL)
4251 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
4252 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;
4253 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;
4254 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;
4255 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;
4256 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;
4257 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;
4258 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;
4259 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;
4260 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;
4261 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;
4262 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;
4263 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;
4264 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;
4265 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;
4268 void R_Shadow_EditLights_ToggleShadow_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_ToggleCorona_f(void)
4285 if (!r_editlights.integer)
4287 Con_Print("Cannot spawn 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_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);
4298 void R_Shadow_EditLights_Remove_f(void)
4300 if (!r_editlights.integer)
4302 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
4305 if (!r_shadow_selectedlight)
4307 Con_Print("No selected light.\n");
4310 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
4311 r_shadow_selectedlight = NULL;
4314 void R_Shadow_EditLights_Help_f(void)
4317 "Documentation on r_editlights system:\n"
4319 "r_editlights : enable/disable editing mode\n"
4320 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
4321 "r_editlights_cursorpushback : push back cursor this far from surface\n"
4322 "r_editlights_cursorpushoff : push cursor off surface this far\n"
4323 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
4324 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
4326 "r_editlights_help : this help\n"
4327 "r_editlights_clear : remove all lights\n"
4328 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
4329 "r_editlights_save : save to .rtlights file\n"
4330 "r_editlights_spawn : create a light with default settings\n"
4331 "r_editlights_edit command : edit selected light - more documentation below\n"
4332 "r_editlights_remove : remove selected light\n"
4333 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
4334 "r_editlights_importlightentitiesfrommap : reload light entities\n"
4335 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
4337 "origin x y z : set light location\n"
4338 "originx x: set x component of light location\n"
4339 "originy y: set y component of light location\n"
4340 "originz z: set z component of light location\n"
4341 "move x y z : adjust light location\n"
4342 "movex x: adjust x component of light location\n"
4343 "movey y: adjust y component of light location\n"
4344 "movez z: adjust z component of light location\n"
4345 "angles x y z : set light angles\n"
4346 "anglesx x: set x component of light angles\n"
4347 "anglesy y: set y component of light angles\n"
4348 "anglesz z: set z component of light angles\n"
4349 "color r g b : set color of light (can be brighter than 1 1 1)\n"
4350 "radius radius : set radius (size) of light\n"
4351 "colorscale grey : multiply color of light (1 does nothing)\n"
4352 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
4353 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
4354 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
4355 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
4356 "cubemap basename : set filter cubemap of light (not yet supported)\n"
4357 "shadows 1/0 : turn on/off shadows\n"
4358 "corona n : set corona intensity\n"
4359 "coronasize n : set corona size (0-1)\n"
4360 "ambient n : set ambient intensity (0-1)\n"
4361 "diffuse n : set diffuse intensity (0-1)\n"
4362 "specular n : set specular intensity (0-1)\n"
4363 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
4364 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
4365 "<nothing> : print light properties to console\n"
4369 void R_Shadow_EditLights_CopyInfo_f(void)
4371 if (!r_editlights.integer)
4373 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
4376 if (!r_shadow_selectedlight)
4378 Con_Print("No selected light.\n");
4381 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
4382 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
4383 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
4384 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
4385 if (r_shadow_selectedlight->cubemapname)
4386 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
4388 r_shadow_bufferlight.cubemapname[0] = 0;
4389 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
4390 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
4391 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
4392 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
4393 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
4394 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
4395 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
4398 void R_Shadow_EditLights_PasteInfo_f(void)
4400 if (!r_editlights.integer)
4402 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
4405 if (!r_shadow_selectedlight)
4407 Con_Print("No selected light.\n");
4410 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);
4413 void R_Shadow_EditLights_Init(void)
4415 Cvar_RegisterVariable(&r_editlights);
4416 Cvar_RegisterVariable(&r_editlights_cursordistance);
4417 Cvar_RegisterVariable(&r_editlights_cursorpushback);
4418 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
4419 Cvar_RegisterVariable(&r_editlights_cursorgrid);
4420 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
4421 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
4422 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
4423 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)");
4424 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
4425 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
4426 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
4427 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)");
4428 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
4429 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
4430 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
4431 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
4432 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
4433 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
4434 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)");