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 // current light's cull box (copied out of an rtlight or calculated by GetLightInfo)
194 vec3_t r_shadow_rtlight_cullmins;
195 vec3_t r_shadow_rtlight_cullmaxs;
196 // current light's culling planes
197 int r_shadow_rtlight_numfrustumplanes;
198 mplane_t r_shadow_rtlight_frustumplanes[12+6+6]; // see R_Shadow_ComputeShadowCasterCullingPlanes
200 rtexturepool_t *r_shadow_texturepool;
201 rtexture_t *r_shadow_attenuationgradienttexture;
202 rtexture_t *r_shadow_attenuation2dtexture;
203 rtexture_t *r_shadow_attenuation3dtexture;
205 // lights are reloaded when this changes
206 char r_shadow_mapname[MAX_QPATH];
208 // used only for light filters (cubemaps)
209 rtexturepool_t *r_shadow_filters_texturepool;
211 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"};
212 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"};
213 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
214 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
215 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)"};
216 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"};
217 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
218 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
219 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
220 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
221 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
222 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
223 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"};
224 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000", "how far to cast shadows"};
225 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)"};
226 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
227 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
228 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
229 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
230 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)"};
231 cvar_t r_shadow_realtime_world_dlightshadows = {CVAR_SAVE, "r_shadow_realtime_world_dlightshadows", "1", "enables shadows from dynamic lights when using full world lighting"};
232 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"};
233 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
234 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
235 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"};
236 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation"};
237 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation"};
238 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)"};
239 cvar_t r_shadow_culltriangles = {0, "r_shadow_culltriangles", "1", "performs more expensive tests to remove unnecessary triangles of lit surfaces"};
240 cvar_t r_shadow_shadow_polygonfactor = {0, "r_shadow_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
241 cvar_t r_shadow_shadow_polygonoffset = {0, "r_shadow_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)"};
242 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)"};
243 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
244 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
245 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
246 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
247 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
248 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
249 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
250 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
252 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
253 #define ATTENTABLESIZE 256
254 // 1D gradient, 2D circle and 3D sphere attenuation textures
255 #define ATTEN1DSIZE 32
256 #define ATTEN2DSIZE 64
257 #define ATTEN3DSIZE 32
259 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
260 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
261 static float r_shadow_attentable[ATTENTABLESIZE+1];
263 rtlight_t *r_shadow_compilingrtlight;
264 dlight_t *r_shadow_worldlightchain;
265 dlight_t *r_shadow_selectedlight;
266 dlight_t r_shadow_bufferlight;
267 vec3_t r_editlights_cursorlocation;
269 extern int con_vislines;
271 typedef struct cubemapinfo_s
278 #define MAX_CUBEMAPS 256
279 static int numcubemaps;
280 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
282 void R_Shadow_UncompileWorldLights(void);
283 void R_Shadow_ClearWorldLights(void);
284 void R_Shadow_SaveWorldLights(void);
285 void R_Shadow_LoadWorldLights(void);
286 void R_Shadow_LoadLightsFile(void);
287 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
288 void R_Shadow_EditLights_Reload_f(void);
289 void R_Shadow_ValidateCvars(void);
290 static void R_Shadow_MakeTextures(void);
292 void r_shadow_start(void)
294 // allocate vertex processing arrays
296 r_shadow_attenuationgradienttexture = NULL;
297 r_shadow_attenuation2dtexture = NULL;
298 r_shadow_attenuation3dtexture = NULL;
299 r_shadow_texturepool = NULL;
300 r_shadow_filters_texturepool = NULL;
301 R_Shadow_ValidateCvars();
302 R_Shadow_MakeTextures();
303 maxshadowtriangles = 0;
304 shadowelements = NULL;
305 maxshadowvertices = 0;
306 shadowvertex3f = NULL;
314 shadowmarklist = NULL;
316 r_shadow_buffer_numleafpvsbytes = 0;
317 r_shadow_buffer_leafpvs = NULL;
318 r_shadow_buffer_leaflist = NULL;
319 r_shadow_buffer_numsurfacepvsbytes = 0;
320 r_shadow_buffer_surfacepvs = NULL;
321 r_shadow_buffer_surfacelist = NULL;
322 r_shadow_buffer_numshadowtrispvsbytes = 0;
323 r_shadow_buffer_shadowtrispvs = NULL;
324 r_shadow_buffer_numlighttrispvsbytes = 0;
325 r_shadow_buffer_lighttrispvs = NULL;
328 void r_shadow_shutdown(void)
330 R_Shadow_UncompileWorldLights();
332 r_shadow_attenuationgradienttexture = NULL;
333 r_shadow_attenuation2dtexture = NULL;
334 r_shadow_attenuation3dtexture = NULL;
335 R_FreeTexturePool(&r_shadow_texturepool);
336 R_FreeTexturePool(&r_shadow_filters_texturepool);
337 maxshadowtriangles = 0;
339 Mem_Free(shadowelements);
340 shadowelements = NULL;
342 Mem_Free(shadowvertex3f);
343 shadowvertex3f = NULL;
346 Mem_Free(vertexupdate);
349 Mem_Free(vertexremap);
355 Mem_Free(shadowmark);
358 Mem_Free(shadowmarklist);
359 shadowmarklist = NULL;
361 r_shadow_buffer_numleafpvsbytes = 0;
362 if (r_shadow_buffer_leafpvs)
363 Mem_Free(r_shadow_buffer_leafpvs);
364 r_shadow_buffer_leafpvs = NULL;
365 if (r_shadow_buffer_leaflist)
366 Mem_Free(r_shadow_buffer_leaflist);
367 r_shadow_buffer_leaflist = NULL;
368 r_shadow_buffer_numsurfacepvsbytes = 0;
369 if (r_shadow_buffer_surfacepvs)
370 Mem_Free(r_shadow_buffer_surfacepvs);
371 r_shadow_buffer_surfacepvs = NULL;
372 if (r_shadow_buffer_surfacelist)
373 Mem_Free(r_shadow_buffer_surfacelist);
374 r_shadow_buffer_surfacelist = NULL;
375 r_shadow_buffer_numshadowtrispvsbytes = 0;
376 if (r_shadow_buffer_shadowtrispvs)
377 Mem_Free(r_shadow_buffer_shadowtrispvs);
378 r_shadow_buffer_numlighttrispvsbytes = 0;
379 if (r_shadow_buffer_lighttrispvs)
380 Mem_Free(r_shadow_buffer_lighttrispvs);
383 void r_shadow_newmap(void)
387 void R_Shadow_Help_f(void)
390 "Documentation on r_shadow system:\n"
392 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
393 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
394 "r_shadow_debuglight : render only this light number (-1 = all)\n"
395 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
396 "r_shadow_gloss2intensity : brightness of forced gloss\n"
397 "r_shadow_glossintensity : brightness of textured gloss\n"
398 "r_shadow_lightattenuationlinearscale : used to generate attenuation texture\n"
399 "r_shadow_lightattenuationdividebias : used to generate attenuation texture\n"
400 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
401 "r_shadow_lightradiusscale : scale rendering radius of all lights\n"
402 "r_shadow_portallight : use portal visibility for static light precomputation\n"
403 "r_shadow_projectdistance : shadow volume projection distance\n"
404 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
405 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
406 "r_shadow_realtime_world : use high quality world lighting mode\n"
407 "r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n"
408 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
409 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
410 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
411 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
412 "r_shadow_scissor : use scissor optimization\n"
413 "r_shadow_shadow_polygonfactor : nudge shadow volumes closer/further\n"
414 "r_shadow_shadow_polygonoffset : nudge shadow volumes closer/further\n"
415 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
416 "r_showlighting : useful for performance testing; bright = slow!\n"
417 "r_showshadowvolumes : useful for performance testing; bright = slow!\n"
419 "r_shadow_help : this help\n"
423 void R_Shadow_Init(void)
425 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
426 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
427 Cvar_RegisterVariable(&r_shadow_usenormalmap);
428 Cvar_RegisterVariable(&r_shadow_debuglight);
429 Cvar_RegisterVariable(&r_shadow_gloss);
430 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
431 Cvar_RegisterVariable(&r_shadow_glossintensity);
432 Cvar_RegisterVariable(&r_shadow_glossexponent);
433 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
434 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
435 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
436 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
437 Cvar_RegisterVariable(&r_shadow_portallight);
438 Cvar_RegisterVariable(&r_shadow_projectdistance);
439 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
440 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
441 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
442 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
443 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
444 Cvar_RegisterVariable(&r_shadow_realtime_world);
445 Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows);
446 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
447 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
448 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
449 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
450 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
451 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
452 Cvar_RegisterVariable(&r_shadow_scissor);
453 Cvar_RegisterVariable(&r_shadow_culltriangles);
454 Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor);
455 Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset);
456 Cvar_RegisterVariable(&r_shadow_texture3d);
457 Cvar_RegisterVariable(&gl_ext_separatestencil);
458 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
459 if (gamemode == GAME_TENEBRAE)
461 Cvar_SetValue("r_shadow_gloss", 2);
462 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
464 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f, "prints documentation on console commands and variables used by realtime lighting and shadowing system");
465 R_Shadow_EditLights_Init();
466 r_shadow_worldlightchain = NULL;
467 maxshadowtriangles = 0;
468 shadowelements = NULL;
469 maxshadowvertices = 0;
470 shadowvertex3f = NULL;
478 shadowmarklist = NULL;
480 r_shadow_buffer_numleafpvsbytes = 0;
481 r_shadow_buffer_leafpvs = NULL;
482 r_shadow_buffer_leaflist = NULL;
483 r_shadow_buffer_numsurfacepvsbytes = 0;
484 r_shadow_buffer_surfacepvs = NULL;
485 r_shadow_buffer_surfacelist = NULL;
486 r_shadow_buffer_shadowtrispvs = NULL;
487 r_shadow_buffer_lighttrispvs = NULL;
488 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
491 matrix4x4_t matrix_attenuationxyz =
494 {0.5, 0.0, 0.0, 0.5},
495 {0.0, 0.5, 0.0, 0.5},
496 {0.0, 0.0, 0.5, 0.5},
501 matrix4x4_t matrix_attenuationz =
504 {0.0, 0.0, 0.5, 0.5},
505 {0.0, 0.0, 0.0, 0.5},
506 {0.0, 0.0, 0.0, 0.5},
511 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles)
513 // make sure shadowelements is big enough for this volume
514 if (maxshadowtriangles < numtriangles)
516 maxshadowtriangles = numtriangles;
518 Mem_Free(shadowelements);
519 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[24]));
521 // make sure shadowvertex3f is big enough for this volume
522 if (maxshadowvertices < numvertices)
524 maxshadowvertices = numvertices;
526 Mem_Free(shadowvertex3f);
527 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[6]));
531 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
533 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
534 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
535 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
536 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
537 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
539 if (r_shadow_buffer_leafpvs)
540 Mem_Free(r_shadow_buffer_leafpvs);
541 if (r_shadow_buffer_leaflist)
542 Mem_Free(r_shadow_buffer_leaflist);
543 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
544 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
545 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
547 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
549 if (r_shadow_buffer_surfacepvs)
550 Mem_Free(r_shadow_buffer_surfacepvs);
551 if (r_shadow_buffer_surfacelist)
552 Mem_Free(r_shadow_buffer_surfacelist);
553 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
554 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
555 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
557 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
559 if (r_shadow_buffer_shadowtrispvs)
560 Mem_Free(r_shadow_buffer_shadowtrispvs);
561 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
562 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
564 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
566 if (r_shadow_buffer_lighttrispvs)
567 Mem_Free(r_shadow_buffer_lighttrispvs);
568 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
569 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
573 void R_Shadow_PrepareShadowMark(int numtris)
575 // make sure shadowmark is big enough for this volume
576 if (maxshadowmark < numtris)
578 maxshadowmark = numtris;
580 Mem_Free(shadowmark);
582 Mem_Free(shadowmarklist);
583 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
584 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
588 // if shadowmarkcount wrapped we clear the array and adjust accordingly
589 if (shadowmarkcount == 0)
592 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
597 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)
600 int outtriangles = 0, outvertices = 0;
603 float ratio, direction[3], projectvector[3];
605 if (projectdirection)
606 VectorScale(projectdirection, projectdistance, projectvector);
608 VectorClear(projectvector);
610 if (maxvertexupdate < innumvertices)
612 maxvertexupdate = innumvertices;
614 Mem_Free(vertexupdate);
616 Mem_Free(vertexremap);
617 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
618 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
622 if (vertexupdatenum == 0)
625 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
626 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
629 for (i = 0;i < numshadowmarktris;i++)
630 shadowmark[shadowmarktris[i]] = shadowmarkcount;
632 // create the vertices
633 if (projectdirection)
635 for (i = 0;i < numshadowmarktris;i++)
637 element = inelement3i + shadowmarktris[i] * 3;
638 for (j = 0;j < 3;j++)
640 if (vertexupdate[element[j]] != vertexupdatenum)
642 vertexupdate[element[j]] = vertexupdatenum;
643 vertexremap[element[j]] = outvertices;
644 vertex = invertex3f + element[j] * 3;
645 // project one copy of the vertex according to projectvector
646 VectorCopy(vertex, outvertex3f);
647 VectorAdd(vertex, projectvector, (outvertex3f + 3));
656 for (i = 0;i < numshadowmarktris;i++)
658 element = inelement3i + shadowmarktris[i] * 3;
659 for (j = 0;j < 3;j++)
661 if (vertexupdate[element[j]] != vertexupdatenum)
663 vertexupdate[element[j]] = vertexupdatenum;
664 vertexremap[element[j]] = outvertices;
665 vertex = invertex3f + element[j] * 3;
666 // project one copy of the vertex to the sphere radius of the light
667 // (FIXME: would projecting it to the light box be better?)
668 VectorSubtract(vertex, projectorigin, direction);
669 ratio = projectdistance / VectorLength(direction);
670 VectorCopy(vertex, outvertex3f);
671 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
679 if (r_shadow_frontsidecasting.integer)
681 for (i = 0;i < numshadowmarktris;i++)
683 int remappedelement[3];
685 const int *neighbortriangle;
687 markindex = shadowmarktris[i] * 3;
688 element = inelement3i + markindex;
689 neighbortriangle = inneighbor3i + markindex;
690 // output the front and back triangles
691 outelement3i[0] = vertexremap[element[0]];
692 outelement3i[1] = vertexremap[element[1]];
693 outelement3i[2] = vertexremap[element[2]];
694 outelement3i[3] = vertexremap[element[2]] + 1;
695 outelement3i[4] = vertexremap[element[1]] + 1;
696 outelement3i[5] = vertexremap[element[0]] + 1;
700 // output the sides (facing outward from this triangle)
701 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
703 remappedelement[0] = vertexremap[element[0]];
704 remappedelement[1] = vertexremap[element[1]];
705 outelement3i[0] = remappedelement[1];
706 outelement3i[1] = remappedelement[0];
707 outelement3i[2] = remappedelement[0] + 1;
708 outelement3i[3] = remappedelement[1];
709 outelement3i[4] = remappedelement[0] + 1;
710 outelement3i[5] = remappedelement[1] + 1;
715 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
717 remappedelement[1] = vertexremap[element[1]];
718 remappedelement[2] = vertexremap[element[2]];
719 outelement3i[0] = remappedelement[2];
720 outelement3i[1] = remappedelement[1];
721 outelement3i[2] = remappedelement[1] + 1;
722 outelement3i[3] = remappedelement[2];
723 outelement3i[4] = remappedelement[1] + 1;
724 outelement3i[5] = remappedelement[2] + 1;
729 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
731 remappedelement[0] = vertexremap[element[0]];
732 remappedelement[2] = vertexremap[element[2]];
733 outelement3i[0] = remappedelement[0];
734 outelement3i[1] = remappedelement[2];
735 outelement3i[2] = remappedelement[2] + 1;
736 outelement3i[3] = remappedelement[0];
737 outelement3i[4] = remappedelement[2] + 1;
738 outelement3i[5] = remappedelement[0] + 1;
747 for (i = 0;i < numshadowmarktris;i++)
749 int remappedelement[3];
751 const int *neighbortriangle;
753 markindex = shadowmarktris[i] * 3;
754 element = inelement3i + markindex;
755 neighbortriangle = inneighbor3i + markindex;
756 // output the front and back triangles
757 outelement3i[0] = vertexremap[element[2]];
758 outelement3i[1] = vertexremap[element[1]];
759 outelement3i[2] = vertexremap[element[0]];
760 outelement3i[3] = vertexremap[element[0]] + 1;
761 outelement3i[4] = vertexremap[element[1]] + 1;
762 outelement3i[5] = vertexremap[element[2]] + 1;
766 // output the sides (facing outward from this triangle)
767 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
769 remappedelement[0] = vertexremap[element[0]];
770 remappedelement[1] = vertexremap[element[1]];
771 outelement3i[0] = remappedelement[0];
772 outelement3i[1] = remappedelement[1];
773 outelement3i[2] = remappedelement[1] + 1;
774 outelement3i[3] = remappedelement[0];
775 outelement3i[4] = remappedelement[1] + 1;
776 outelement3i[5] = remappedelement[0] + 1;
781 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
783 remappedelement[1] = vertexremap[element[1]];
784 remappedelement[2] = vertexremap[element[2]];
785 outelement3i[0] = remappedelement[1];
786 outelement3i[1] = remappedelement[2];
787 outelement3i[2] = remappedelement[2] + 1;
788 outelement3i[3] = remappedelement[1];
789 outelement3i[4] = remappedelement[2] + 1;
790 outelement3i[5] = remappedelement[1] + 1;
795 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
797 remappedelement[0] = vertexremap[element[0]];
798 remappedelement[2] = vertexremap[element[2]];
799 outelement3i[0] = remappedelement[2];
800 outelement3i[1] = remappedelement[0];
801 outelement3i[2] = remappedelement[0] + 1;
802 outelement3i[3] = remappedelement[2];
803 outelement3i[4] = remappedelement[0] + 1;
804 outelement3i[5] = remappedelement[2] + 1;
812 *outnumvertices = outvertices;
816 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)
819 if (projectdistance < 0.1)
821 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
824 if (!numverts || !nummarktris)
826 // make sure shadowelements is big enough for this volume
827 if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
828 R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
829 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
830 r_refdef.stats.lights_dynamicshadowtriangles += tris;
831 R_Shadow_RenderVolume(outverts, tris, shadowvertex3f, shadowelements);
834 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)
840 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
842 tend = firsttriangle + numtris;
843 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
845 // surface box entirely inside light box, no box cull
846 if (projectdirection)
848 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
850 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
851 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
852 shadowmarklist[numshadowmark++] = t;
857 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
858 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
859 shadowmarklist[numshadowmark++] = t;
864 // surface box not entirely inside light box, cull each triangle
865 if (projectdirection)
867 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
869 v[0] = invertex3f + e[0] * 3;
870 v[1] = invertex3f + e[1] * 3;
871 v[2] = invertex3f + e[2] * 3;
872 TriangleNormal(v[0], v[1], v[2], normal);
873 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
874 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
875 shadowmarklist[numshadowmark++] = t;
880 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
882 v[0] = invertex3f + e[0] * 3;
883 v[1] = invertex3f + e[1] * 3;
884 v[2] = invertex3f + e[2] * 3;
885 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
886 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
887 shadowmarklist[numshadowmark++] = t;
893 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
895 if (r_shadow_compilingrtlight)
897 // if we're compiling an rtlight, capture the mesh
898 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
901 r_refdef.stats.lights_shadowtriangles += numtriangles;
903 R_Mesh_VertexPointer(vertex3f, 0, 0);
904 GL_LockArrays(0, numvertices);
905 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
907 // decrement stencil if backface is behind depthbuffer
908 GL_CullFace(GL_BACK); // quake is backwards, this culls front faces
909 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
910 R_Mesh_Draw(0, numvertices, numtriangles, element3i, 0, 0);
911 // increment stencil if frontface is behind depthbuffer
912 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
913 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
915 R_Mesh_Draw(0, numvertices, numtriangles, element3i, 0, 0);
920 static unsigned char R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
922 float dist = sqrt(x*x+y*y+z*z);
923 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
924 return (unsigned char)bound(0, intensity * 256.0f, 255);
927 static void R_Shadow_MakeTextures(void)
930 float intensity, dist;
932 unsigned int palette[256];
933 R_FreeTexturePool(&r_shadow_texturepool);
934 r_shadow_texturepool = R_AllocTexturePool();
935 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
936 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
937 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
938 for (x = 0;x < 256;x++)
939 palette[x] = x * 0x01010101;
940 data = (unsigned char *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE));
941 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
942 for (x = 0;x <= ATTENTABLESIZE;x++)
944 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
945 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
946 r_shadow_attentable[x] = bound(0, intensity, 1);
948 // 1D gradient texture
949 for (x = 0;x < ATTEN1DSIZE;x++)
950 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
951 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, data, TEXTYPE_PALETTE, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, palette);
953 for (y = 0;y < ATTEN2DSIZE;y++)
954 for (x = 0;x < ATTEN2DSIZE;x++)
955 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);
956 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_PALETTE, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, palette);
958 if (r_shadow_texture3d.integer && gl_texture3d)
960 for (z = 0;z < ATTEN3DSIZE;z++)
961 for (y = 0;y < ATTEN3DSIZE;y++)
962 for (x = 0;x < ATTEN3DSIZE;x++)
963 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));
964 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_PALETTE, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, palette);
967 r_shadow_attenuation3dtexture = NULL;
971 void R_Shadow_ValidateCvars(void)
973 if (r_shadow_texture3d.integer && !gl_texture3d)
974 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
975 if (gl_ext_separatestencil.integer && !gl_support_separatestencil)
976 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
977 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
978 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
981 // light currently being rendered
982 rtlight_t *r_shadow_rtlight;
984 // this is the location of the light in entity space
985 vec3_t r_shadow_entitylightorigin;
986 // this transforms entity coordinates to light filter cubemap coordinates
987 // (also often used for other purposes)
988 matrix4x4_t r_shadow_entitytolight;
989 // based on entitytolight this transforms -1 to +1 to 0 to 1 for purposes
990 // of attenuation texturing in full 3D (Z result often ignored)
991 matrix4x4_t r_shadow_entitytoattenuationxyz;
992 // this transforms only the Z to S, and T is always 0.5
993 matrix4x4_t r_shadow_entitytoattenuationz;
995 void R_Shadow_RenderMode_Begin(void)
997 R_Shadow_ValidateCvars();
999 if (!r_shadow_attenuation2dtexture
1000 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1001 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1002 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1003 R_Shadow_MakeTextures();
1006 R_Mesh_ColorPointer(NULL, 0, 0);
1007 R_Mesh_ResetTextureState();
1008 GL_BlendFunc(GL_ONE, GL_ZERO);
1009 GL_DepthRange(0, 1);
1011 GL_DepthMask(false);
1012 GL_Color(0, 0, 0, 1);
1013 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
1015 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1017 if (gl_ext_separatestencil.integer)
1018 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
1019 else if (gl_ext_stenciltwoside.integer)
1020 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
1022 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
1024 if (r_glsl.integer && gl_support_fragment_shader)
1025 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1026 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
1027 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
1029 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1032 void R_Shadow_RenderMode_ActiveLight(rtlight_t *rtlight)
1034 r_shadow_rtlight = rtlight;
1037 void R_Shadow_RenderMode_Reset(void)
1040 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1042 qglUseProgramObjectARB(0);CHECKGLERROR
1044 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
1046 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1048 R_Mesh_ColorPointer(NULL, 0, 0);
1049 R_Mesh_ResetTextureState();
1050 GL_DepthRange(0, 1);
1052 GL_DepthMask(false);
1053 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1054 qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1055 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1056 qglStencilMask(~0);CHECKGLERROR
1057 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1058 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1059 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
1060 GL_Color(1, 1, 1, 1);
1061 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
1062 GL_BlendFunc(GL_ONE, GL_ZERO);
1065 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean clearstencil)
1068 R_Shadow_RenderMode_Reset();
1069 GL_ColorMask(0, 0, 0, 0);
1070 qglPolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1071 qglDepthFunc(GL_LESS);CHECKGLERROR
1072 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1073 r_shadow_rendermode = r_shadow_shadowingrendermode;
1074 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SEPARATESTENCIL)
1076 GL_CullFace(GL_NONE);
1077 qglStencilOpSeparate(GL_BACK, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR // quake is backwards, this is front faces
1078 qglStencilOpSeparate(GL_FRONT, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR // quake is backwards, this is back faces
1080 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
1082 GL_CullFace(GL_NONE);
1083 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1084 qglActiveStencilFaceEXT(GL_BACK);CHECKGLERROR // quake is backwards, this is front faces
1085 qglStencilMask(~0);CHECKGLERROR
1086 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1087 qglActiveStencilFaceEXT(GL_FRONT);CHECKGLERROR // quake is backwards, this is back faces
1088 qglStencilMask(~0);CHECKGLERROR
1089 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1092 GL_Clear(GL_STENCIL_BUFFER_BIT);
1093 r_refdef.stats.lights_clears++;
1096 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent)
1099 R_Shadow_RenderMode_Reset();
1100 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1103 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1107 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1108 // only draw light where this geometry was already rendered AND the
1109 // stencil is 128 (values other than this mean shadow)
1110 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1112 r_shadow_rendermode = r_shadow_lightingrendermode;
1113 // do global setup needed for the chosen lighting mode
1114 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1116 R_Mesh_TexBind(0, R_GetTexture(r_texture_blanknormalmap)); // normal
1117 R_Mesh_TexBind(1, R_GetTexture(r_texture_white)); // diffuse
1118 R_Mesh_TexBind(2, R_GetTexture(r_texture_white)); // gloss
1119 R_Mesh_TexBindCubeMap(3, R_GetTexture(r_shadow_rtlight->currentcubemap)); // light filter
1120 R_Mesh_TexBind(4, R_GetTexture(r_texture_fogattenuation)); // fog
1121 R_Mesh_TexBind(5, R_GetTexture(r_texture_white)); // pants
1122 R_Mesh_TexBind(6, R_GetTexture(r_texture_white)); // shirt
1123 R_Mesh_TexBind(7, R_GetTexture(r_texture_white)); // lightmap
1124 R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap)); // deluxemap
1125 R_Mesh_TexBind(9, R_GetTexture(r_texture_black)); // glow
1126 //R_Mesh_TexMatrix(3, r_shadow_entitytolight); // light filter matrix
1127 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1128 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 0);
1133 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
1136 R_Shadow_RenderMode_Reset();
1137 GL_BlendFunc(GL_ONE, GL_ONE);
1138 GL_DepthRange(0, 1);
1139 GL_DepthTest(r_showshadowvolumes.integer < 2);
1140 GL_Color(0.0, 0.0125 * r_view.colorscale, 0.1 * r_view.colorscale, 1);
1141 qglPolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1142 GL_CullFace(GL_NONE);
1143 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
1146 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
1149 R_Shadow_RenderMode_Reset();
1150 GL_BlendFunc(GL_ONE, GL_ONE);
1151 GL_DepthRange(0, 1);
1152 GL_DepthTest(r_showlighting.integer < 2);
1153 GL_Color(0.1 * r_view.colorscale, 0.0125 * r_view.colorscale, 0, 1);
1156 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1160 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1161 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1163 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
1166 void R_Shadow_RenderMode_End(void)
1169 R_Shadow_RenderMode_Reset();
1170 R_Shadow_RenderMode_ActiveLight(NULL);
1172 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
1173 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1176 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1178 int i, ix1, iy1, ix2, iy2;
1179 float x1, y1, x2, y2;
1182 mplane_t planes[11];
1183 float vertex3f[256*3];
1185 // if view is inside the light box, just say yes it's visible
1186 if (BoxesOverlap(r_view.origin, r_view.origin, mins, maxs))
1188 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
1192 // create a temporary brush describing the area the light can affect in worldspace
1193 VectorNegate(r_view.frustum[0].normal, planes[ 0].normal);planes[ 0].dist = -r_view.frustum[0].dist;
1194 VectorNegate(r_view.frustum[1].normal, planes[ 1].normal);planes[ 1].dist = -r_view.frustum[1].dist;
1195 VectorNegate(r_view.frustum[2].normal, planes[ 2].normal);planes[ 2].dist = -r_view.frustum[2].dist;
1196 VectorNegate(r_view.frustum[3].normal, planes[ 3].normal);planes[ 3].dist = -r_view.frustum[3].dist;
1197 VectorNegate(r_view.frustum[4].normal, planes[ 4].normal);planes[ 4].dist = -r_view.frustum[4].dist;
1198 VectorSet (planes[ 5].normal, 1, 0, 0); planes[ 5].dist = maxs[0];
1199 VectorSet (planes[ 6].normal, -1, 0, 0); planes[ 6].dist = -mins[0];
1200 VectorSet (planes[ 7].normal, 0, 1, 0); planes[ 7].dist = maxs[1];
1201 VectorSet (planes[ 8].normal, 0, -1, 0); planes[ 8].dist = -mins[1];
1202 VectorSet (planes[ 9].normal, 0, 0, 1); planes[ 9].dist = maxs[2];
1203 VectorSet (planes[10].normal, 0, 0, -1); planes[10].dist = -mins[2];
1205 // turn the brush into a mesh
1206 memset(&mesh, 0, sizeof(rmesh_t));
1207 mesh.maxvertices = 256;
1208 mesh.vertex3f = vertex3f;
1209 mesh.epsilon2 = (1.0f / (32.0f * 32.0f));
1210 R_Mesh_AddBrushMeshFromPlanes(&mesh, 11, planes);
1212 // if that mesh is empty, the light is not visible at all
1213 if (!mesh.numvertices)
1216 if (!r_shadow_scissor.integer)
1219 // if that mesh is not empty, check what area of the screen it covers
1220 x1 = y1 = x2 = y2 = 0;
1222 //Con_Printf("%i vertices to transform...\n", mesh.numvertices);
1223 for (i = 0;i < mesh.numvertices;i++)
1225 VectorCopy(mesh.vertex3f + i * 3, v);
1226 GL_TransformToScreen(v, v2);
1227 //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]);
1230 if (x1 > v2[0]) x1 = v2[0];
1231 if (x2 < v2[0]) x2 = v2[0];
1232 if (y1 > v2[1]) y1 = v2[1];
1233 if (y2 < v2[1]) y2 = v2[1];
1242 // now convert the scissor rectangle to integer screen coordinates
1243 ix1 = (int)(x1 - 1.0f);
1244 iy1 = (int)(y1 - 1.0f);
1245 ix2 = (int)(x2 + 1.0f);
1246 iy2 = (int)(y2 + 1.0f);
1247 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1249 // clamp it to the screen
1250 if (ix1 < r_view.x) ix1 = r_view.x;
1251 if (iy1 < r_view.y) iy1 = r_view.y;
1252 if (ix2 > r_view.x + r_view.width) ix2 = r_view.x + r_view.width;
1253 if (iy2 > r_view.y + r_view.height) iy2 = r_view.y + r_view.height;
1255 // if it is inside out, it's not visible
1256 if (ix2 <= ix1 || iy2 <= iy1)
1259 // the light area is visible, set up the scissor rectangle
1260 GL_Scissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1261 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);CHECKGLERROR
1262 //qglEnable(GL_SCISSOR_TEST);CHECKGLERROR
1263 r_refdef.stats.lights_scissored++;
1267 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
1269 float *vertex3f = rsurface_vertex3f + 3 * firstvertex;
1270 float *normal3f = rsurface_normal3f + 3 * firstvertex;
1271 float *color4f = rsurface_array_color4f + 4 * firstvertex;
1272 float dist, dot, distintensity, shadeintensity, v[3], n[3];
1273 if (r_textureunits.integer >= 3)
1275 if (VectorLength2(diffusecolor) > 0)
1277 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1279 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1280 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1281 if ((dot = DotProduct(n, v)) < 0)
1283 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1284 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
1287 VectorCopy(ambientcolor, color4f);
1288 if (r_refdef.fogenabled)
1290 float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
1291 VectorScale(color4f, f, color4f);
1298 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1300 VectorCopy(ambientcolor, color4f);
1301 if (r_refdef.fogenabled)
1304 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1305 f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
1306 VectorScale(color4f, f, color4f);
1312 else if (r_textureunits.integer >= 2)
1314 if (VectorLength2(diffusecolor) > 0)
1316 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1318 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1319 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1321 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1322 if ((dot = DotProduct(n, v)) < 0)
1324 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1325 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1326 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1327 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1331 color4f[0] = ambientcolor[0] * distintensity;
1332 color4f[1] = ambientcolor[1] * distintensity;
1333 color4f[2] = ambientcolor[2] * distintensity;
1335 if (r_refdef.fogenabled)
1337 float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
1338 VectorScale(color4f, f, color4f);
1342 VectorClear(color4f);
1348 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1350 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1351 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1353 color4f[0] = ambientcolor[0] * distintensity;
1354 color4f[1] = ambientcolor[1] * distintensity;
1355 color4f[2] = ambientcolor[2] * distintensity;
1356 if (r_refdef.fogenabled)
1358 float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
1359 VectorScale(color4f, f, color4f);
1363 VectorClear(color4f);
1370 if (VectorLength2(diffusecolor) > 0)
1372 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1374 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1375 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1377 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
1378 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1379 if ((dot = DotProduct(n, v)) < 0)
1381 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1382 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1383 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1384 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1388 color4f[0] = ambientcolor[0] * distintensity;
1389 color4f[1] = ambientcolor[1] * distintensity;
1390 color4f[2] = ambientcolor[2] * distintensity;
1392 if (r_refdef.fogenabled)
1394 float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
1395 VectorScale(color4f, f, color4f);
1399 VectorClear(color4f);
1405 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1407 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1408 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1410 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
1411 color4f[0] = ambientcolor[0] * distintensity;
1412 color4f[1] = ambientcolor[1] * distintensity;
1413 color4f[2] = ambientcolor[2] * distintensity;
1414 if (r_refdef.fogenabled)
1416 float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
1417 VectorScale(color4f, f, color4f);
1421 VectorClear(color4f);
1428 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1430 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
1433 float *out3f = rsurface_array_texcoord3f + 3 * firstvertex;
1434 const float *vertex3f = rsurface_vertex3f + 3 * firstvertex;
1435 const float *svector3f = rsurface_svector3f + 3 * firstvertex;
1436 const float *tvector3f = rsurface_tvector3f + 3 * firstvertex;
1437 const float *normal3f = rsurface_normal3f + 3 * firstvertex;
1439 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1441 VectorSubtract(r_shadow_entitylightorigin, vertex3f, lightdir);
1442 // the cubemap normalizes this for us
1443 out3f[0] = DotProduct(svector3f, lightdir);
1444 out3f[1] = DotProduct(tvector3f, lightdir);
1445 out3f[2] = DotProduct(normal3f, lightdir);
1449 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
1452 float *out3f = rsurface_array_texcoord3f + 3 * firstvertex;
1453 const float *vertex3f = rsurface_vertex3f + 3 * firstvertex;
1454 const float *svector3f = rsurface_svector3f + 3 * firstvertex;
1455 const float *tvector3f = rsurface_tvector3f + 3 * firstvertex;
1456 const float *normal3f = rsurface_normal3f + 3 * firstvertex;
1457 float lightdir[3], eyedir[3], halfdir[3];
1458 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1460 VectorSubtract(r_shadow_entitylightorigin, vertex3f, lightdir);
1461 VectorNormalize(lightdir);
1462 VectorSubtract(rsurface_modelorg, vertex3f, eyedir);
1463 VectorNormalize(eyedir);
1464 VectorAdd(lightdir, eyedir, halfdir);
1465 // the cubemap normalizes this for us
1466 out3f[0] = DotProduct(svector3f, halfdir);
1467 out3f[1] = DotProduct(tvector3f, halfdir);
1468 out3f[2] = DotProduct(normal3f, halfdir);
1472 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)
1474 // used to display how many times a surface is lit for level design purposes
1475 GL_Color(0.1 * r_view.colorscale, 0.025 * r_view.colorscale, 0, 1);
1476 R_Mesh_ColorPointer(NULL, 0, 0);
1477 R_Mesh_ResetTextureState();
1478 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1481 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)
1483 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
1484 R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale);
1485 R_Mesh_TexCoordPointer(0, 2, rsurface_model->surfmesh.data_texcoordtexture2f, rsurface_model->surfmesh.vbo, rsurface_model->surfmesh.vbooffset_texcoordtexture2f);
1486 R_Mesh_TexCoordPointer(1, 3, rsurface_svector3f, rsurface_svector3f_bufferobject, rsurface_svector3f_bufferoffset);
1487 R_Mesh_TexCoordPointer(2, 3, rsurface_tvector3f, rsurface_tvector3f_bufferobject, rsurface_tvector3f_bufferoffset);
1488 R_Mesh_TexCoordPointer(3, 3, rsurface_normal3f, rsurface_normal3f_bufferobject, rsurface_normal3f_bufferoffset);
1489 if (rsurface_texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1491 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1493 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1494 if (rsurface_texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1496 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1500 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)
1502 // shared final code for all the dot3 layers
1504 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 0);
1505 for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
1507 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
1508 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1512 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)
1515 // colorscale accounts for how much we multiply the brightness
1518 // mult is how many times the final pass of the lighting will be
1519 // performed to get more brightness than otherwise possible.
1521 // Limit mult to 64 for sanity sake.
1523 if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1525 // 3 3D combine path (Geforce3, Radeon 8500)
1526 memset(&m, 0, sizeof(m));
1527 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1528 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1529 m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
1530 m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
1531 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1532 m.tex[1] = R_GetTexture(basetexture);
1533 m.pointer_texcoord[1] = rsurface_model->surfmesh.data_texcoordtexture2f;
1534 m.pointer_texcoord_bufferobject[1] = rsurface_model->surfmesh.vbo;
1535 m.pointer_texcoord_bufferoffset[1] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1536 m.texmatrix[1] = rsurface_texture->currenttexmatrix;
1537 m.texcubemap[2] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1538 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1539 m.pointer_texcoord_bufferobject[2] = rsurface_vertex3f_bufferobject;
1540 m.pointer_texcoord_bufferoffset[2] = rsurface_vertex3f_bufferoffset;
1541 m.texmatrix[2] = r_shadow_entitytolight;
1542 GL_BlendFunc(GL_ONE, GL_ONE);
1544 else if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1546 // 2 3D combine path (Geforce3, original Radeon)
1547 memset(&m, 0, sizeof(m));
1548 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1549 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1550 m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
1551 m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
1552 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1553 m.tex[1] = R_GetTexture(basetexture);
1554 m.pointer_texcoord[1] = rsurface_model->surfmesh.data_texcoordtexture2f;
1555 m.pointer_texcoord_bufferobject[1] = rsurface_model->surfmesh.vbo;
1556 m.pointer_texcoord_bufferoffset[1] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1557 m.texmatrix[1] = rsurface_texture->currenttexmatrix;
1558 GL_BlendFunc(GL_ONE, GL_ONE);
1560 else if (r_textureunits.integer >= 4 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1562 // 4 2D combine path (Geforce3, Radeon 8500)
1563 memset(&m, 0, sizeof(m));
1564 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1565 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1566 m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
1567 m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
1568 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1569 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1570 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1571 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1572 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1573 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1574 m.tex[2] = R_GetTexture(basetexture);
1575 m.pointer_texcoord[2] = rsurface_model->surfmesh.data_texcoordtexture2f;
1576 m.pointer_texcoord_bufferobject[2] = rsurface_model->surfmesh.vbo;
1577 m.pointer_texcoord_bufferoffset[2] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1578 m.texmatrix[2] = rsurface_texture->currenttexmatrix;
1579 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1581 m.texcubemap[3] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1582 m.pointer_texcoord3f[3] = rsurface_vertex3f;
1583 m.pointer_texcoord_bufferobject[3] = rsurface_vertex3f_bufferobject;
1584 m.pointer_texcoord_bufferoffset[3] = rsurface_vertex3f_bufferoffset;
1585 m.texmatrix[3] = r_shadow_entitytolight;
1587 GL_BlendFunc(GL_ONE, GL_ONE);
1589 else if (r_textureunits.integer >= 3 && r_shadow_rtlight->currentcubemap == r_texture_whitecube)
1591 // 3 2D combine path (Geforce3, original Radeon)
1592 memset(&m, 0, sizeof(m));
1593 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1594 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1595 m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
1596 m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
1597 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1598 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1599 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1600 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1601 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1602 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1603 m.tex[2] = R_GetTexture(basetexture);
1604 m.pointer_texcoord[2] = rsurface_model->surfmesh.data_texcoordtexture2f;
1605 m.pointer_texcoord_bufferobject[2] = rsurface_model->surfmesh.vbo;
1606 m.pointer_texcoord_bufferoffset[2] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1607 m.texmatrix[2] = rsurface_texture->currenttexmatrix;
1608 GL_BlendFunc(GL_ONE, GL_ONE);
1612 // 2/2/2 2D combine path (any dot3 card)
1613 memset(&m, 0, sizeof(m));
1614 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1615 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1616 m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
1617 m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
1618 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1619 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1620 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1621 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1622 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1623 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1624 R_Mesh_TextureState(&m);
1625 GL_ColorMask(0,0,0,1);
1626 GL_BlendFunc(GL_ONE, GL_ZERO);
1627 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1630 memset(&m, 0, sizeof(m));
1631 m.tex[0] = R_GetTexture(basetexture);
1632 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1633 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1634 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1635 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1636 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1638 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1639 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1640 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1641 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1642 m.texmatrix[1] = r_shadow_entitytolight;
1644 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1646 // this final code is shared
1647 R_Mesh_TextureState(&m);
1648 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1651 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)
1654 // colorscale accounts for how much we multiply the brightness
1657 // mult is how many times the final pass of the lighting will be
1658 // performed to get more brightness than otherwise possible.
1660 // Limit mult to 64 for sanity sake.
1662 // generate normalization cubemap texcoords
1663 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
1664 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1666 // 3/2 3D combine path (Geforce3, Radeon 8500)
1667 memset(&m, 0, sizeof(m));
1668 m.tex[0] = R_GetTexture(normalmaptexture);
1669 m.texcombinergb[0] = GL_REPLACE;
1670 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1671 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1672 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1673 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1674 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1675 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1676 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1677 m.pointer_texcoord_bufferobject[1] = 0;
1678 m.pointer_texcoord_bufferoffset[1] = 0;
1679 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1680 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1681 m.pointer_texcoord_bufferobject[2] = rsurface_vertex3f_bufferobject;
1682 m.pointer_texcoord_bufferoffset[2] = rsurface_vertex3f_bufferoffset;
1683 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
1684 R_Mesh_TextureState(&m);
1685 GL_ColorMask(0,0,0,1);
1686 GL_BlendFunc(GL_ONE, GL_ZERO);
1687 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1690 memset(&m, 0, sizeof(m));
1691 m.tex[0] = R_GetTexture(basetexture);
1692 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1693 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1694 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1695 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1696 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1698 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1699 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1700 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1701 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1702 m.texmatrix[1] = r_shadow_entitytolight;
1704 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1706 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1708 // 1/2/2 3D combine path (original Radeon)
1709 memset(&m, 0, sizeof(m));
1710 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1711 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1712 m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
1713 m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
1714 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1715 R_Mesh_TextureState(&m);
1716 GL_ColorMask(0,0,0,1);
1717 GL_BlendFunc(GL_ONE, GL_ZERO);
1718 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1721 memset(&m, 0, sizeof(m));
1722 m.tex[0] = R_GetTexture(normalmaptexture);
1723 m.texcombinergb[0] = GL_REPLACE;
1724 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1725 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1726 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1727 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1728 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1729 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1730 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1731 m.pointer_texcoord_bufferobject[1] = 0;
1732 m.pointer_texcoord_bufferoffset[1] = 0;
1733 R_Mesh_TextureState(&m);
1734 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1735 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1738 memset(&m, 0, sizeof(m));
1739 m.tex[0] = R_GetTexture(basetexture);
1740 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1741 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1742 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1743 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1744 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1746 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1747 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1748 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1749 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1750 m.texmatrix[1] = r_shadow_entitytolight;
1752 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1754 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap == r_texture_whitecube)
1756 // 2/2 3D combine path (original Radeon)
1757 memset(&m, 0, sizeof(m));
1758 m.tex[0] = R_GetTexture(normalmaptexture);
1759 m.texcombinergb[0] = GL_REPLACE;
1760 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1761 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1762 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1763 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1764 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1765 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1766 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1767 m.pointer_texcoord_bufferobject[1] = 0;
1768 m.pointer_texcoord_bufferoffset[1] = 0;
1769 R_Mesh_TextureState(&m);
1770 GL_ColorMask(0,0,0,1);
1771 GL_BlendFunc(GL_ONE, GL_ZERO);
1772 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1775 memset(&m, 0, sizeof(m));
1776 m.tex[0] = R_GetTexture(basetexture);
1777 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1778 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1779 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1780 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1781 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1782 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1783 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1784 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1785 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
1786 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1788 else if (r_textureunits.integer >= 4)
1790 // 4/2 2D combine path (Geforce3, Radeon 8500)
1791 memset(&m, 0, sizeof(m));
1792 m.tex[0] = R_GetTexture(normalmaptexture);
1793 m.texcombinergb[0] = GL_REPLACE;
1794 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1795 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1796 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1797 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1798 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1799 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1800 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1801 m.pointer_texcoord_bufferobject[1] = 0;
1802 m.pointer_texcoord_bufferoffset[1] = 0;
1803 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1804 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1805 m.pointer_texcoord_bufferobject[2] = rsurface_vertex3f_bufferobject;
1806 m.pointer_texcoord_bufferoffset[2] = rsurface_vertex3f_bufferoffset;
1807 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
1808 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1809 m.pointer_texcoord3f[3] = rsurface_vertex3f;
1810 m.pointer_texcoord_bufferobject[3] = rsurface_vertex3f_bufferobject;
1811 m.pointer_texcoord_bufferoffset[3] = rsurface_vertex3f_bufferoffset;
1812 m.texmatrix[3] = r_shadow_entitytoattenuationz;
1813 R_Mesh_TextureState(&m);
1814 GL_ColorMask(0,0,0,1);
1815 GL_BlendFunc(GL_ONE, GL_ZERO);
1816 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1819 memset(&m, 0, sizeof(m));
1820 m.tex[0] = R_GetTexture(basetexture);
1821 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1822 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1823 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1824 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1825 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1827 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1828 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1829 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1830 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1831 m.texmatrix[1] = r_shadow_entitytolight;
1833 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1837 // 2/2/2 2D combine path (any dot3 card)
1838 memset(&m, 0, sizeof(m));
1839 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1840 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1841 m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
1842 m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
1843 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1844 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1845 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1846 m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
1847 m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
1848 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1849 R_Mesh_TextureState(&m);
1850 GL_ColorMask(0,0,0,1);
1851 GL_BlendFunc(GL_ONE, GL_ZERO);
1852 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1855 memset(&m, 0, sizeof(m));
1856 m.tex[0] = R_GetTexture(normalmaptexture);
1857 m.texcombinergb[0] = GL_REPLACE;
1858 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1859 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1860 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1861 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1862 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1863 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1864 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1865 m.pointer_texcoord_bufferobject[1] = 0;
1866 m.pointer_texcoord_bufferoffset[1] = 0;
1867 R_Mesh_TextureState(&m);
1868 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1869 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1872 memset(&m, 0, sizeof(m));
1873 m.tex[0] = R_GetTexture(basetexture);
1874 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1875 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1876 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1877 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1878 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1880 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1881 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1882 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1883 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1884 m.texmatrix[1] = r_shadow_entitytolight;
1886 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1888 // this final code is shared
1889 R_Mesh_TextureState(&m);
1890 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1893 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)
1895 float glossexponent;
1897 // FIXME: detect blendsquare!
1898 //if (!gl_support_blendsquare)
1901 // generate normalization cubemap texcoords
1902 R_Shadow_GenTexCoords_Specular_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
1903 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1905 // 2/0/0/1/2 3D combine blendsquare path
1906 memset(&m, 0, sizeof(m));
1907 m.tex[0] = R_GetTexture(normalmaptexture);
1908 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1909 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1910 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1911 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1912 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1913 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1914 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1915 m.pointer_texcoord_bufferobject[1] = 0;
1916 m.pointer_texcoord_bufferoffset[1] = 0;
1917 R_Mesh_TextureState(&m);
1918 GL_ColorMask(0,0,0,1);
1919 // this squares the result
1920 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1921 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1923 // second and third pass
1924 R_Mesh_ResetTextureState();
1925 // square alpha in framebuffer a few times to make it shiny
1926 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1927 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
1928 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1931 memset(&m, 0, sizeof(m));
1932 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1933 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1934 m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
1935 m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
1936 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1937 R_Mesh_TextureState(&m);
1938 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1939 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1942 memset(&m, 0, sizeof(m));
1943 m.tex[0] = R_GetTexture(glosstexture);
1944 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1945 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1946 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1947 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1948 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1950 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1951 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1952 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1953 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1954 m.texmatrix[1] = r_shadow_entitytolight;
1956 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1958 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
1960 // 2/0/0/2 3D combine blendsquare path
1961 memset(&m, 0, sizeof(m));
1962 m.tex[0] = R_GetTexture(normalmaptexture);
1963 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1964 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1965 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1966 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1967 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1968 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1969 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1970 m.pointer_texcoord_bufferobject[1] = 0;
1971 m.pointer_texcoord_bufferoffset[1] = 0;
1972 R_Mesh_TextureState(&m);
1973 GL_ColorMask(0,0,0,1);
1974 // this squares the result
1975 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1976 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1978 // second and third pass
1979 R_Mesh_ResetTextureState();
1980 // square alpha in framebuffer a few times to make it shiny
1981 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1982 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
1983 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1986 memset(&m, 0, sizeof(m));
1987 m.tex[0] = R_GetTexture(glosstexture);
1988 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1989 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1990 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1991 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1992 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1993 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1994 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1995 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1996 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
1997 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2001 // 2/0/0/2/2 2D combine blendsquare path
2002 memset(&m, 0, sizeof(m));
2003 m.tex[0] = R_GetTexture(normalmaptexture);
2004 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
2005 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
2006 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
2007 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
2008 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2009 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2010 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
2011 m.pointer_texcoord_bufferobject[1] = 0;
2012 m.pointer_texcoord_bufferoffset[1] = 0;
2013 R_Mesh_TextureState(&m);
2014 GL_ColorMask(0,0,0,1);
2015 // this squares the result
2016 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2017 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2019 // second and third pass
2020 R_Mesh_ResetTextureState();
2021 // square alpha in framebuffer a few times to make it shiny
2022 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2023 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2024 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2027 memset(&m, 0, sizeof(m));
2028 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2029 m.pointer_texcoord3f[0] = rsurface_vertex3f;
2030 m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
2031 m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
2032 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2033 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
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] = r_shadow_entitytoattenuationz;
2038 R_Mesh_TextureState(&m);
2039 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2040 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2043 memset(&m, 0, sizeof(m));
2044 m.tex[0] = R_GetTexture(glosstexture);
2045 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
2046 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
2047 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
2048 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
2049 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
2051 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
2052 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2053 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
2054 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
2055 m.texmatrix[1] = r_shadow_entitytolight;
2057 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2059 // this final code is shared
2060 R_Mesh_TextureState(&m);
2061 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
2064 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)
2066 // ARB path (any Geforce, any Radeon)
2067 qboolean doambient = ambientscale > 0;
2068 qboolean dodiffuse = diffusescale > 0;
2069 qboolean dospecular = specularscale > 0;
2070 if (!doambient && !dodiffuse && !dospecular)
2072 R_Mesh_ColorPointer(NULL, 0, 0);
2074 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, basetexture, ambientscale * r_view.colorscale);
2076 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, basetexture, normalmaptexture, diffusescale * r_view.colorscale);
2080 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorpants, pantstexture, ambientscale * r_view.colorscale);
2082 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorpants, pantstexture, normalmaptexture, diffusescale * r_view.colorscale);
2087 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorshirt, shirttexture, ambientscale * r_view.colorscale);
2089 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorshirt, shirttexture, normalmaptexture, diffusescale * r_view.colorscale);
2092 R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_view.colorscale);
2095 void R_Shadow_RenderLighting_Light_Vertex_Pass(const model_t *model, int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset, vec3_t diffusecolor2, vec3_t ambientcolor2)
2102 int newnumtriangles;
2106 int newelements[4096*3];
2107 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
2108 for (renders = 0;renders < 64;renders++)
2113 newnumtriangles = 0;
2115 // due to low fillrate on the cards this vertex lighting path is
2116 // designed for, we manually cull all triangles that do not
2117 // contain a lit vertex
2118 // this builds batches of triangles from multiple surfaces and
2119 // renders them at once
2120 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2122 if (VectorLength2(rsurface_array_color4f + e[0] * 4) + VectorLength2(rsurface_array_color4f + e[1] * 4) + VectorLength2(rsurface_array_color4f + e[2] * 4) >= 0.01)
2124 if (newnumtriangles)
2126 newfirstvertex = min(newfirstvertex, e[0]);
2127 newlastvertex = max(newlastvertex, e[0]);
2131 newfirstvertex = e[0];
2132 newlastvertex = e[0];
2134 newfirstvertex = min(newfirstvertex, e[1]);
2135 newlastvertex = max(newlastvertex, e[1]);
2136 newfirstvertex = min(newfirstvertex, e[2]);
2137 newlastvertex = max(newlastvertex, e[2]);
2143 if (newnumtriangles >= (int)(sizeof(newelements)/sizeof(float[3])))
2145 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, newnumtriangles, newelements, 0, 0);
2146 newnumtriangles = 0;
2152 if (newnumtriangles >= 1)
2154 // if all triangles are included, use the original array to take advantage of the bufferobject if possible
2155 if (newnumtriangles == numtriangles)
2156 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2158 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, newnumtriangles, newelements, 0, 0);
2161 // if we couldn't find any lit triangles, exit early
2164 // now reduce the intensity for the next overbright pass
2165 // we have to clamp to 0 here incase the drivers have improper
2166 // handling of negative colors
2167 // (some old drivers even have improper handling of >1 color)
2169 for (i = 0, c = rsurface_array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2171 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2173 c[0] = max(0, c[0] - 1);
2174 c[1] = max(0, c[1] - 1);
2175 c[2] = max(0, c[2] - 1);
2187 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)
2189 // OpenGL 1.1 path (anything)
2190 model_t *model = rsurface_entity->model;
2191 float ambientcolorbase[3], diffusecolorbase[3];
2192 float ambientcolorpants[3], diffusecolorpants[3];
2193 float ambientcolorshirt[3], diffusecolorshirt[3];
2195 VectorScale(lightcolorbase, ambientscale * 2 * r_view.colorscale, ambientcolorbase);
2196 VectorScale(lightcolorbase, diffusescale * 2 * r_view.colorscale, diffusecolorbase);
2197 VectorScale(lightcolorpants, ambientscale * 2 * r_view.colorscale, ambientcolorpants);
2198 VectorScale(lightcolorpants, diffusescale * 2 * r_view.colorscale, diffusecolorpants);
2199 VectorScale(lightcolorshirt, ambientscale * 2 * r_view.colorscale, ambientcolorshirt);
2200 VectorScale(lightcolorshirt, diffusescale * 2 * r_view.colorscale, diffusecolorshirt);
2201 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2202 R_Mesh_ColorPointer(rsurface_array_color4f, 0, 0);
2203 memset(&m, 0, sizeof(m));
2204 m.tex[0] = R_GetTexture(basetexture);
2205 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
2206 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
2207 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
2208 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
2209 if (r_textureunits.integer >= 2)
2212 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2213 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2214 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2215 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
2216 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
2217 if (r_textureunits.integer >= 3)
2219 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
2220 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2221 m.texmatrix[2] = r_shadow_entitytoattenuationz;
2222 m.pointer_texcoord3f[2] = rsurface_vertex3f;
2223 m.pointer_texcoord_bufferobject[2] = rsurface_vertex3f_bufferobject;
2224 m.pointer_texcoord_bufferoffset[2] = rsurface_vertex3f_bufferoffset;
2227 R_Mesh_TextureState(&m);
2228 //R_Mesh_TexBind(0, R_GetTexture(basetexture));
2229 R_Shadow_RenderLighting_Light_Vertex_Pass(model, firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, diffusecolorbase, ambientcolorbase);
2232 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
2233 R_Shadow_RenderLighting_Light_Vertex_Pass(model, firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, diffusecolorpants, ambientcolorpants);
2237 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
2238 R_Shadow_RenderLighting_Light_Vertex_Pass(model, firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, diffusecolorshirt, ambientcolorshirt);
2242 void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset)
2244 float ambientscale, diffusescale, specularscale;
2245 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
2246 // calculate colors to render this texture with
2247 lightcolorbase[0] = r_shadow_rtlight->currentcolor[0] * rsurface_entity->colormod[0] * rsurface_texture->currentalpha;
2248 lightcolorbase[1] = r_shadow_rtlight->currentcolor[1] * rsurface_entity->colormod[1] * rsurface_texture->currentalpha;
2249 lightcolorbase[2] = r_shadow_rtlight->currentcolor[2] * rsurface_entity->colormod[2] * rsurface_texture->currentalpha;
2250 ambientscale = r_shadow_rtlight->ambientscale;
2251 diffusescale = r_shadow_rtlight->diffusescale;
2252 specularscale = r_shadow_rtlight->specularscale * rsurface_texture->specularscale;
2253 if (!r_shadow_usenormalmap.integer)
2255 ambientscale += 1.0f * diffusescale;
2259 if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
2261 GL_DepthRange(0, (rsurface_texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
2262 GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
2263 GL_CullFace((rsurface_texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
2264 if (rsurface_texture->colormapping)
2266 qboolean dopants = rsurface_texture->currentskinframe->pants != NULL && VectorLength2(rsurface_entity->colormap_pantscolor) >= (1.0f / 1048576.0f);
2267 qboolean doshirt = rsurface_texture->currentskinframe->shirt != NULL && VectorLength2(rsurface_entity->colormap_shirtcolor) >= (1.0f / 1048576.0f);
2270 lightcolorpants[0] = lightcolorbase[0] * rsurface_entity->colormap_pantscolor[0];
2271 lightcolorpants[1] = lightcolorbase[1] * rsurface_entity->colormap_pantscolor[1];
2272 lightcolorpants[2] = lightcolorbase[2] * rsurface_entity->colormap_pantscolor[2];
2275 VectorClear(lightcolorpants);
2278 lightcolorshirt[0] = lightcolorbase[0] * rsurface_entity->colormap_shirtcolor[0];
2279 lightcolorshirt[1] = lightcolorbase[1] * rsurface_entity->colormap_shirtcolor[1];
2280 lightcolorshirt[2] = lightcolorbase[2] * rsurface_entity->colormap_shirtcolor[2];
2283 VectorClear(lightcolorshirt);
2284 switch (r_shadow_rendermode)
2286 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2287 GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2288 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);
2290 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2291 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);
2293 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2294 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);
2296 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2297 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);
2300 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2306 switch (r_shadow_rendermode)
2308 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2309 GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2310 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);
2312 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2313 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);
2315 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2316 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);
2318 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2319 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);
2322 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2328 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)
2330 matrix4x4_t tempmatrix = *matrix;
2331 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2333 // if this light has been compiled before, free the associated data
2334 R_RTLight_Uncompile(rtlight);
2336 // clear it completely to avoid any lingering data
2337 memset(rtlight, 0, sizeof(*rtlight));
2339 // copy the properties
2340 rtlight->matrix_lighttoworld = tempmatrix;
2341 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2342 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2343 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2344 VectorCopy(color, rtlight->color);
2345 rtlight->cubemapname[0] = 0;
2346 if (cubemapname && cubemapname[0])
2347 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2348 rtlight->shadow = shadow;
2349 rtlight->corona = corona;
2350 rtlight->style = style;
2351 rtlight->isstatic = isstatic;
2352 rtlight->coronasizescale = coronasizescale;
2353 rtlight->ambientscale = ambientscale;
2354 rtlight->diffusescale = diffusescale;
2355 rtlight->specularscale = specularscale;
2356 rtlight->flags = flags;
2358 // compute derived data
2359 //rtlight->cullradius = rtlight->radius;
2360 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2361 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2362 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2363 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2364 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2365 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2366 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2369 // compiles rtlight geometry
2370 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2371 void R_RTLight_Compile(rtlight_t *rtlight)
2374 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2375 int lighttris, shadowtris, shadowmeshes, shadowmeshtris;
2376 entity_render_t *ent = r_refdef.worldentity;
2377 model_t *model = r_refdef.worldmodel;
2378 unsigned char *data;
2380 // compile the light
2381 rtlight->compiled = true;
2382 rtlight->static_numleafs = 0;
2383 rtlight->static_numleafpvsbytes = 0;
2384 rtlight->static_leaflist = NULL;
2385 rtlight->static_leafpvs = NULL;
2386 rtlight->static_numsurfaces = 0;
2387 rtlight->static_surfacelist = NULL;
2388 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2389 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2390 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2391 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2392 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2393 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2395 if (model && model->GetLightInfo)
2397 // this variable must be set for the CompileShadowVolume code
2398 r_shadow_compilingrtlight = rtlight;
2399 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);
2400 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);
2401 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2402 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
2403 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
2404 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
2405 rtlight->static_numsurfaces = numsurfaces;
2406 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2407 rtlight->static_numleafs = numleafs;
2408 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2409 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2410 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2411 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
2412 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
2413 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
2414 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
2415 if (rtlight->static_numsurfaces)
2416 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2417 if (rtlight->static_numleafs)
2418 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2419 if (rtlight->static_numleafpvsbytes)
2420 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2421 if (rtlight->static_numshadowtrispvsbytes)
2422 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
2423 if (rtlight->static_numlighttrispvsbytes)
2424 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
2425 if (model->CompileShadowVolume && rtlight->shadow)
2426 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2427 // now we're done compiling the rtlight
2428 r_shadow_compilingrtlight = NULL;
2432 // use smallest available cullradius - box radius or light radius
2433 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2434 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2438 if (rtlight->static_meshchain_shadow)
2441 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2444 shadowmeshtris += mesh->numtriangles;
2449 if (rtlight->static_numlighttrispvsbytes)
2450 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
2451 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
2455 if (rtlight->static_numlighttrispvsbytes)
2456 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
2457 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
2460 if (developer.integer >= 10)
2461 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);
2464 void R_RTLight_Uncompile(rtlight_t *rtlight)
2466 if (rtlight->compiled)
2468 if (rtlight->static_meshchain_shadow)
2469 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2470 rtlight->static_meshchain_shadow = NULL;
2471 // these allocations are grouped
2472 if (rtlight->static_surfacelist)
2473 Mem_Free(rtlight->static_surfacelist);
2474 rtlight->static_numleafs = 0;
2475 rtlight->static_numleafpvsbytes = 0;
2476 rtlight->static_leaflist = NULL;
2477 rtlight->static_leafpvs = NULL;
2478 rtlight->static_numsurfaces = 0;
2479 rtlight->static_surfacelist = NULL;
2480 rtlight->static_numshadowtrispvsbytes = 0;
2481 rtlight->static_shadowtrispvs = NULL;
2482 rtlight->static_numlighttrispvsbytes = 0;
2483 rtlight->static_lighttrispvs = NULL;
2484 rtlight->compiled = false;
2488 void R_Shadow_UncompileWorldLights(void)
2491 for (light = r_shadow_worldlightchain;light;light = light->next)
2492 R_RTLight_Uncompile(&light->rtlight);
2495 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
2499 // reset the count of frustum planes
2500 // see r_shadow_rtlight_frustumplanes definition for how much this array
2502 r_shadow_rtlight_numfrustumplanes = 0;
2505 // generate a deformed frustum that includes the light origin, this is
2506 // used to cull shadow casting surfaces that can not possibly cast a
2507 // shadow onto the visible light-receiving surfaces, which can be a
2510 // if the light origin is onscreen the result will be 4 planes exactly
2511 // if the light origin is offscreen on only one axis the result will
2512 // be exactly 5 planes (split-side case)
2513 // if the light origin is offscreen on two axes the result will be
2514 // exactly 4 planes (stretched corner case)
2515 for (i = 0;i < 4;i++)
2517 // quickly reject standard frustum planes that put the light
2518 // origin outside the frustum
2519 if (PlaneDiff(rtlight->shadoworigin, &r_view.frustum[i]) < -0.03125)
2522 r_shadow_rtlight_frustumplanes[r_shadow_rtlight_numfrustumplanes++] = r_view.frustum[i];
2524 // if all the standard frustum planes were accepted, the light is onscreen
2525 // otherwise we need to generate some more planes below...
2526 if (r_shadow_rtlight_numfrustumplanes < 4)
2528 // at least one of the stock frustum planes failed, so we need to
2529 // create one or two custom planes to enclose the light origin
2530 for (i = 0;i < 4;i++)
2532 // create a plane using the view origin and light origin, and a
2533 // single point from the frustum corner set
2534 TriangleNormal(r_view.origin, r_view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
2535 VectorNormalize(plane.normal);
2536 plane.dist = DotProduct(r_view.origin, plane.normal);
2537 // see if this plane is backwards and flip it if so
2538 for (j = 0;j < 4;j++)
2539 if (j != i && DotProduct(r_view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
2543 VectorNegate(plane.normal, plane.normal);
2545 // flipped plane, test again to see if it is now valid
2546 for (j = 0;j < 4;j++)
2547 if (j != i && DotProduct(r_view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
2549 // if the plane is still not valid, then it is dividing the
2550 // frustum and has to be rejected
2554 // we have created a valid plane, compute extra info
2555 PlaneClassify(&plane);
2557 r_shadow_rtlight_frustumplanes[r_shadow_rtlight_numfrustumplanes++] = plane;
2559 // if we've found 5 frustum planes then we have constructed a
2560 // proper split-side case and do not need to keep searching for
2561 // planes to enclose the light origin
2562 if (r_shadow_rtlight_numfrustumplanes == 5)
2570 for (i = 0;i < r_shadow_rtlight_numfrustumplanes;i++)
2572 plane = r_shadow_rtlight_frustumplanes[i];
2573 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));
2578 // now add the light-space box planes if the light box is rotated, as any
2579 // caster outside the oriented light box is irrelevant (even if it passed
2580 // the worldspace light box, which is axial)
2581 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
2583 for (i = 0;i < 6;i++)
2587 v[i >> 1] = (i & 1) ? -1 : 1;
2588 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
2589 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
2590 plane.dist = VectorNormalizeLength(plane.normal);
2591 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
2592 r_shadow_rtlight_frustumplanes[r_shadow_rtlight_numfrustumplanes++] = plane;
2598 // add the world-space reduced box planes
2599 for (i = 0;i < 6;i++)
2601 VectorClear(plane.normal);
2602 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
2603 plane.dist = (i & 1) ? -r_shadow_rtlight_cullmaxs[i >> 1] : r_shadow_rtlight_cullmins[i >> 1];
2604 r_shadow_rtlight_frustumplanes[r_shadow_rtlight_numfrustumplanes++] = plane;
2613 // reduce all plane distances to tightly fit the rtlight cull box, which
2615 VectorSet(points[0], r_shadow_rtlight_cullmins[0], r_shadow_rtlight_cullmins[1], r_shadow_rtlight_cullmins[2]);
2616 VectorSet(points[1], r_shadow_rtlight_cullmaxs[0], r_shadow_rtlight_cullmins[1], r_shadow_rtlight_cullmins[2]);
2617 VectorSet(points[2], r_shadow_rtlight_cullmins[0], r_shadow_rtlight_cullmaxs[1], r_shadow_rtlight_cullmins[2]);
2618 VectorSet(points[3], r_shadow_rtlight_cullmaxs[0], r_shadow_rtlight_cullmaxs[1], r_shadow_rtlight_cullmins[2]);
2619 VectorSet(points[4], r_shadow_rtlight_cullmins[0], r_shadow_rtlight_cullmins[1], r_shadow_rtlight_cullmaxs[2]);
2620 VectorSet(points[5], r_shadow_rtlight_cullmaxs[0], r_shadow_rtlight_cullmins[1], r_shadow_rtlight_cullmaxs[2]);
2621 VectorSet(points[6], r_shadow_rtlight_cullmins[0], r_shadow_rtlight_cullmaxs[1], r_shadow_rtlight_cullmaxs[2]);
2622 VectorSet(points[7], r_shadow_rtlight_cullmaxs[0], r_shadow_rtlight_cullmaxs[1], r_shadow_rtlight_cullmaxs[2]);
2623 oldnum = r_shadow_rtlight_numfrustumplanes;
2624 r_shadow_rtlight_numfrustumplanes = 0;
2625 for (j = 0;j < oldnum;j++)
2627 // find the nearest point on the box to this plane
2628 bestdist = DotProduct(r_shadow_rtlight_frustumplanes[j].normal, points[0]);
2629 for (i = 1;i < 8;i++)
2631 dist = DotProduct(r_shadow_rtlight_frustumplanes[j].normal, points[i]);
2632 if (bestdist > dist)
2635 Con_Printf("light %p %splane #%i %f %f %f : %f < %f\n", rtlight, r_shadow_rtlight_frustumplanes[j].dist < bestdist + 0.03125 ? "^2" : "^1", j, r_shadow_rtlight_frustumplanes[j].normal[0], r_shadow_rtlight_frustumplanes[j].normal[1], r_shadow_rtlight_frustumplanes[j].normal[2], r_shadow_rtlight_frustumplanes[j].dist, bestdist);
2636 // if the nearest point is near or behind the plane, we want this
2637 // plane, otherwise the plane is useless as it won't cull anything
2638 if (r_shadow_rtlight_frustumplanes[j].dist < bestdist + 0.03125)
2640 PlaneClassify(&r_shadow_rtlight_frustumplanes[j]);
2641 r_shadow_rtlight_frustumplanes[r_shadow_rtlight_numfrustumplanes++] = r_shadow_rtlight_frustumplanes[j];
2648 void R_Shadow_DrawWorldShadow(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
2650 RSurf_ActiveWorldEntity();
2651 if (r_shadow_rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2655 for (mesh = r_shadow_rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2657 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
2658 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
2659 GL_LockArrays(0, mesh->numverts);
2660 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
2662 // decrement stencil if backface is behind depthbuffer
2663 GL_CullFace(GL_BACK); // quake is backwards, this culls front faces
2664 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2665 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->ebo, 0);
2666 // increment stencil if frontface is behind depthbuffer
2667 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
2668 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2670 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->ebo, 0);
2671 GL_LockArrays(0, 0);
2675 else if (numsurfaces && r_refdef.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
2678 int surfacelistindex;
2679 msurface_t *surface;
2680 R_Shadow_PrepareShadowMark(r_refdef.worldmodel->brush.shadowmesh->numtriangles);
2681 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
2683 surface = r_refdef.worldmodel->data_surfaces + surfacelist[surfacelistindex];
2684 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
2685 if (CHECKPVSBIT(trispvs, t))
2686 shadowmarklist[numshadowmark++] = t;
2688 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, r_shadow_rtlight->shadoworigin, NULL, r_shadow_rtlight->radius + r_refdef.worldmodel->radius*2 + r_shadow_projectdistance.value, numshadowmark, shadowmarklist);
2690 else if (numsurfaces)
2691 r_refdef.worldmodel->DrawShadowVolume(r_refdef.worldentity, r_shadow_rtlight->shadoworigin, NULL, r_shadow_rtlight->radius, numsurfaces, surfacelist, r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs);
2694 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
2696 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
2697 vec_t relativeshadowradius;
2698 RSurf_ActiveModelEntity(ent, false, false);
2699 Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, relativeshadoworigin);
2700 relativeshadowradius = r_shadow_rtlight->radius / ent->scale;
2701 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
2702 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
2703 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
2704 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
2705 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
2706 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
2707 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2710 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
2712 // set up properties for rendering light onto this entity
2713 RSurf_ActiveModelEntity(ent, true, true);
2714 Matrix4x4_Concat(&r_shadow_entitytolight, &r_shadow_rtlight->matrix_worldtolight, &ent->matrix);
2715 Matrix4x4_Concat(&r_shadow_entitytoattenuationxyz, &matrix_attenuationxyz, &r_shadow_entitytolight);
2716 Matrix4x4_Concat(&r_shadow_entitytoattenuationz, &matrix_attenuationz, &r_shadow_entitytolight);
2717 Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, r_shadow_entitylightorigin);
2718 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2719 R_Mesh_TexMatrix(3, &r_shadow_entitytolight);
2722 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
2724 if (!r_refdef.worldmodel->DrawLight)
2727 // set up properties for rendering light onto this entity
2728 RSurf_ActiveWorldEntity();
2729 r_shadow_entitytolight = r_shadow_rtlight->matrix_worldtolight;
2730 Matrix4x4_Concat(&r_shadow_entitytoattenuationxyz, &matrix_attenuationxyz, &r_shadow_entitytolight);
2731 Matrix4x4_Concat(&r_shadow_entitytoattenuationz, &matrix_attenuationz, &r_shadow_entitytolight);
2732 VectorCopy(r_shadow_rtlight->shadoworigin, r_shadow_entitylightorigin);
2733 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2734 R_Mesh_TexMatrix(3, &r_shadow_entitytolight);
2736 r_refdef.worldmodel->DrawLight(r_refdef.worldentity, numsurfaces, surfacelist, trispvs);
2739 void R_Shadow_DrawEntityLight(entity_render_t *ent, int numsurfaces, int *surfacelist)
2741 model_t *model = ent->model;
2742 if (!model->DrawLight)
2745 R_Shadow_SetupEntityLight(ent);
2747 model->DrawLight(ent, model->nummodelsurfaces, model->surfacelist, NULL);
2750 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
2754 int numleafs, numsurfaces;
2755 int *leaflist, *surfacelist;
2756 unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs;
2757 int numlightentities;
2758 int numlightentities_noselfshadow;
2759 int numshadowentities;
2760 int numshadowentities_noselfshadow;
2761 entity_render_t *lightentities[MAX_EDICTS];
2762 entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
2763 entity_render_t *shadowentities[MAX_EDICTS];
2764 entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
2766 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
2767 // skip lights that are basically invisible (color 0 0 0)
2768 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
2771 // loading is done before visibility checks because loading should happen
2772 // all at once at the start of a level, not when it stalls gameplay.
2773 // (especially important to benchmarks)
2775 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2776 R_RTLight_Compile(rtlight);
2778 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
2780 // look up the light style value at this time
2781 f = (rtlight->style >= 0 ? r_refdef.lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2782 VectorScale(rtlight->color, f, rtlight->currentcolor);
2784 if (rtlight->selected)
2786 f = 2 + sin(realtime * M_PI * 4.0);
2787 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
2791 // if lightstyle is currently off, don't draw the light
2792 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
2795 // if the light box is offscreen, skip it
2796 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2799 VectorCopy(rtlight->cullmins, r_shadow_rtlight_cullmins);
2800 VectorCopy(rtlight->cullmaxs, r_shadow_rtlight_cullmaxs);
2802 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2804 // compiled light, world available and can receive realtime lighting
2805 // retrieve leaf information
2806 numleafs = rtlight->static_numleafs;
2807 leaflist = rtlight->static_leaflist;
2808 leafpvs = rtlight->static_leafpvs;
2809 numsurfaces = rtlight->static_numsurfaces;
2810 surfacelist = rtlight->static_surfacelist;
2811 shadowtrispvs = rtlight->static_shadowtrispvs;
2812 lighttrispvs = rtlight->static_lighttrispvs;
2814 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2816 // dynamic light, world available and can receive realtime lighting
2817 // calculate lit surfaces and leafs
2818 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);
2819 r_refdef.worldmodel->GetLightInfo(r_refdef.worldentity, rtlight->shadoworigin, rtlight->radius, r_shadow_rtlight_cullmins, r_shadow_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);
2820 leaflist = r_shadow_buffer_leaflist;
2821 leafpvs = r_shadow_buffer_leafpvs;
2822 surfacelist = r_shadow_buffer_surfacelist;
2823 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
2824 lighttrispvs = r_shadow_buffer_lighttrispvs;
2825 // if the reduced leaf bounds are offscreen, skip it
2826 if (R_CullBox(r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs))
2837 shadowtrispvs = NULL;
2838 lighttrispvs = NULL;
2840 // check if light is illuminating any visible leafs
2843 for (i = 0;i < numleafs;i++)
2844 if (r_viewcache.world_leafvisible[leaflist[i]])
2849 // set up a scissor rectangle for this light
2850 if (R_Shadow_ScissorForBBox(r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs))
2853 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
2855 // make a list of lit entities and shadow casting entities
2856 numlightentities = 0;
2857 numlightentities_noselfshadow = 0;
2858 numshadowentities = 0;
2859 numshadowentities_noselfshadow = 0;
2860 // add dynamic entities that are lit by the light
2861 if (r_drawentities.integer)
2863 for (i = 0;i < r_refdef.numentities;i++)
2866 entity_render_t *ent = r_refdef.entities[i];
2868 if (!BoxesOverlap(ent->mins, ent->maxs, r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs))
2870 // skip the object entirely if it is not within the valid
2871 // shadow-casting region (which includes the lit region)
2872 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, r_shadow_rtlight_numfrustumplanes, r_shadow_rtlight_frustumplanes))
2874 if (!(model = ent->model))
2876 if (r_viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
2878 // this entity wants to receive light, is visible, and is
2879 // inside the light box
2880 // TODO: check if the surfaces in the model can receive light
2881 // so now check if it's in a leaf seen by the light
2882 if (r_refdef.worldmodel && r_refdef.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs))
2884 if (ent->flags & RENDER_NOSELFSHADOW)
2885 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
2887 lightentities[numlightentities++] = ent;
2888 // since it is lit, it probably also casts a shadow...
2889 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2890 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
2891 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
2893 // note: exterior models without the RENDER_NOSELFSHADOW
2894 // flag still create a RENDER_NOSELFSHADOW shadow but
2895 // are lit normally, this means that they are
2896 // self-shadowing but do not shadow other
2897 // RENDER_NOSELFSHADOW entities such as the gun
2898 // (very weird, but keeps the player shadow off the gun)
2899 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
2900 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
2902 shadowentities[numshadowentities++] = ent;
2905 else if (ent->flags & RENDER_SHADOW)
2907 // this entity is not receiving light, but may still need to
2909 // TODO: check if the surfaces in the model can cast shadow
2910 // now check if it is in a leaf seen by the light
2911 if (r_refdef.worldmodel && r_refdef.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs))
2913 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2914 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
2915 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
2917 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
2918 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
2920 shadowentities[numshadowentities++] = ent;
2926 // return if there's nothing at all to light
2927 if (!numlightentities && !numsurfaces)
2930 // don't let sound skip if going slow
2931 if (r_refdef.extraupdate)
2934 // make this the active rtlight for rendering purposes
2935 R_Shadow_RenderMode_ActiveLight(rtlight);
2936 // count this light in the r_speeds
2937 r_refdef.stats.lights++;
2939 if (r_showshadowvolumes.integer && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.rtworldshadows : r_refdef.rtdlightshadows))
2941 // optionally draw visible shape of the shadow volumes
2942 // for performance analysis by level designers
2943 R_Shadow_RenderMode_VisibleShadowVolumes();
2945 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
2946 for (i = 0;i < numshadowentities;i++)
2947 R_Shadow_DrawEntityShadow(shadowentities[i]);
2948 for (i = 0;i < numshadowentities_noselfshadow;i++)
2949 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
2952 if (gl_stencil && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.rtworldshadows : r_refdef.rtdlightshadows))
2954 // draw stencil shadow volumes to mask off pixels that are in shadow
2955 // so that they won't receive lighting
2956 R_Shadow_RenderMode_StencilShadowVolumes(true);
2958 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
2959 for (i = 0;i < numshadowentities;i++)
2960 R_Shadow_DrawEntityShadow(shadowentities[i]);
2961 if (numlightentities_noselfshadow)
2963 // draw lighting in the unmasked areas
2964 R_Shadow_RenderMode_Lighting(true, false);
2965 for (i = 0;i < numlightentities_noselfshadow;i++)
2966 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i], numsurfaces, surfacelist);
2968 // optionally draw the illuminated areas
2969 // for performance analysis by level designers
2970 if (r_showlighting.integer)
2972 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
2973 for (i = 0;i < numlightentities_noselfshadow;i++)
2974 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i], numsurfaces, surfacelist);
2977 R_Shadow_RenderMode_StencilShadowVolumes(false);
2979 for (i = 0;i < numshadowentities_noselfshadow;i++)
2980 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
2982 if (numsurfaces + numlightentities)
2984 // draw lighting in the unmasked areas
2985 R_Shadow_RenderMode_Lighting(true, false);
2987 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
2988 for (i = 0;i < numlightentities;i++)
2989 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
2991 // optionally draw the illuminated areas
2992 // for performance analysis by level designers
2993 if (r_showlighting.integer)
2995 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
2997 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
2998 for (i = 0;i < numlightentities;i++)
2999 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
3005 if (numsurfaces + numlightentities)
3007 // draw lighting in the unmasked areas
3008 R_Shadow_RenderMode_Lighting(false, false);
3010 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3011 for (i = 0;i < numlightentities;i++)
3012 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
3013 for (i = 0;i < numlightentities_noselfshadow;i++)
3014 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i], numsurfaces, surfacelist);
3016 // optionally draw the illuminated areas
3017 // for performance analysis by level designers
3018 if (r_showlighting.integer)
3020 R_Shadow_RenderMode_VisibleLighting(false, false);
3022 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3023 for (i = 0;i < numlightentities;i++)
3024 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
3025 for (i = 0;i < numlightentities_noselfshadow;i++)
3026 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i], numsurfaces, surfacelist);
3032 void R_Shadow_DrawLightSprites(void);
3033 void R_ShadowVolumeLighting(qboolean visible)
3038 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
3039 R_Shadow_EditLights_Reload_f();
3041 if (r_editlights.integer)
3042 R_Shadow_DrawLightSprites();
3044 R_Shadow_RenderMode_Begin();
3046 flag = r_refdef.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3047 if (r_shadow_debuglight.integer >= 0)
3049 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
3050 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
3051 R_DrawRTLight(&light->rtlight, visible);
3054 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
3055 if (light->flags & flag)
3056 R_DrawRTLight(&light->rtlight, visible);
3057 if (r_refdef.rtdlight)
3058 for (lnum = 0;lnum < r_refdef.numlights;lnum++)
3059 R_DrawRTLight(&r_refdef.lights[lnum], visible);
3061 R_Shadow_RenderMode_End();
3064 extern void R_SetupView(const matrix4x4_t *matrix);
3065 extern cvar_t r_shadows_throwdistance;
3066 void R_DrawModelShadows(void)
3069 float relativethrowdistance;
3070 entity_render_t *ent;
3071 vec3_t relativelightorigin;
3072 vec3_t relativelightdirection;
3073 vec3_t relativeshadowmins, relativeshadowmaxs;
3076 if (!r_drawentities.integer || !gl_stencil)
3080 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
3082 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
3084 if (gl_ext_separatestencil.integer)
3085 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
3086 else if (gl_ext_stenciltwoside.integer)
3087 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
3089 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
3091 R_Shadow_RenderMode_StencilShadowVolumes(true);
3093 for (i = 0;i < r_refdef.numentities;i++)
3095 ent = r_refdef.entities[i];
3096 // cast shadows from anything that is not a submodel of the map
3097 if (ent->model && ent->model->DrawShadowVolume != NULL && !ent->model->brush.submodel && (ent->flags & RENDER_SHADOW))
3099 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
3100 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
3101 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
3102 VectorNegate(ent->modellight_lightdir, relativelightdirection);
3103 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
3104 RSurf_ActiveModelEntity(ent, false, false);
3105 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
3109 // not really the right mode, but this will disable any silly stencil features
3110 R_Shadow_RenderMode_VisibleLighting(true, true);
3112 // vertex coordinates for a quad that covers the screen exactly
3113 vertex3f[0] = 0;vertex3f[1] = 0;vertex3f[2] = 0;
3114 vertex3f[3] = 1;vertex3f[4] = 0;vertex3f[5] = 0;
3115 vertex3f[6] = 1;vertex3f[7] = 1;vertex3f[8] = 0;
3116 vertex3f[9] = 0;vertex3f[10] = 1;vertex3f[11] = 0;
3118 // set up ortho view for rendering this pass
3119 GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
3120 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
3121 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
3122 GL_ScissorTest(true);
3123 R_Mesh_Matrix(&identitymatrix);
3124 R_Mesh_ResetTextureState();
3125 R_Mesh_VertexPointer(vertex3f, 0, 0);
3126 R_Mesh_ColorPointer(NULL, 0, 0);
3128 // set up a 50% darkening blend on shadowed areas
3129 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3130 GL_DepthRange(0, 1);
3131 GL_DepthTest(false);
3132 GL_DepthMask(false);
3133 qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
3134 GL_Color(0, 0, 0, 0.5);
3135 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
3136 qglDepthFunc(GL_ALWAYS);CHECKGLERROR
3137 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
3138 qglStencilMask(~0);CHECKGLERROR
3139 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
3140 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
3142 // apply the blend to the shadowed areas
3143 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3145 // restoring the perspective view is done by R_RenderScene
3146 //R_SetupView(&r_view.matrix);
3148 // restore other state to normal
3149 R_Shadow_RenderMode_End();
3153 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
3154 typedef struct suffixinfo_s
3157 qboolean flipx, flipy, flipdiagonal;
3160 static suffixinfo_t suffix[3][6] =
3163 {"px", false, false, false},
3164 {"nx", false, false, false},
3165 {"py", false, false, false},
3166 {"ny", false, false, false},
3167 {"pz", false, false, false},
3168 {"nz", false, false, false}
3171 {"posx", false, false, false},
3172 {"negx", false, false, false},
3173 {"posy", false, false, false},
3174 {"negy", false, false, false},
3175 {"posz", false, false, false},
3176 {"negz", false, false, false}
3179 {"rt", true, false, true},
3180 {"lf", false, true, true},
3181 {"ft", true, true, false},
3182 {"bk", false, false, false},
3183 {"up", true, false, true},
3184 {"dn", true, false, true}
3188 static int componentorder[4] = {0, 1, 2, 3};
3190 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
3192 int i, j, cubemapsize;
3193 unsigned char *cubemappixels, *image_rgba;
3194 rtexture_t *cubemaptexture;
3196 // must start 0 so the first loadimagepixels has no requested width/height
3198 cubemappixels = NULL;
3199 cubemaptexture = NULL;
3200 // keep trying different suffix groups (posx, px, rt) until one loads
3201 for (j = 0;j < 3 && !cubemappixels;j++)
3203 // load the 6 images in the suffix group
3204 for (i = 0;i < 6;i++)
3206 // generate an image name based on the base and and suffix
3207 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
3209 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
3211 // an image loaded, make sure width and height are equal
3212 if (image_width == image_height)
3214 // if this is the first image to load successfully, allocate the cubemap memory
3215 if (!cubemappixels && image_width >= 1)
3217 cubemapsize = image_width;
3218 // note this clears to black, so unavailable sides are black
3219 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
3221 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
3223 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);
3226 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
3228 Mem_Free(image_rgba);
3232 // if a cubemap loaded, upload it
3235 if (!r_shadow_filters_texturepool)
3236 r_shadow_filters_texturepool = R_AllocTexturePool();
3237 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
3238 Mem_Free(cubemappixels);
3242 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
3243 for (j = 0;j < 3;j++)
3244 for (i = 0;i < 6;i++)
3245 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
3246 Con_Print(" and was unable to find any of them.\n");
3248 return cubemaptexture;
3251 rtexture_t *R_Shadow_Cubemap(const char *basename)
3254 for (i = 0;i < numcubemaps;i++)
3255 if (!strcasecmp(cubemaps[i].basename, basename))
3256 return cubemaps[i].texture;
3257 if (i >= MAX_CUBEMAPS)
3258 return r_texture_whitecube;
3260 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
3261 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
3262 if (!cubemaps[i].texture)
3263 cubemaps[i].texture = r_texture_whitecube;
3264 return cubemaps[i].texture;
3267 void R_Shadow_FreeCubemaps(void)
3270 R_FreeTexturePool(&r_shadow_filters_texturepool);
3273 dlight_t *R_Shadow_NewWorldLight(void)
3276 light = (dlight_t *)Mem_Alloc(r_main_mempool, sizeof(dlight_t));
3277 light->next = r_shadow_worldlightchain;
3278 r_shadow_worldlightchain = light;
3282 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)
3285 // validate parameters
3286 if (style < 0 || style >= MAX_LIGHTSTYLES)
3288 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
3294 // copy to light properties
3295 VectorCopy(origin, light->origin);
3296 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
3297 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
3298 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
3299 light->color[0] = max(color[0], 0);
3300 light->color[1] = max(color[1], 0);
3301 light->color[2] = max(color[2], 0);
3302 light->radius = max(radius, 0);
3303 light->style = style;
3304 light->shadow = shadowenable;
3305 light->corona = corona;
3306 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
3307 light->coronasizescale = coronasizescale;
3308 light->ambientscale = ambientscale;
3309 light->diffusescale = diffusescale;
3310 light->specularscale = specularscale;
3311 light->flags = flags;
3313 // update renderable light data
3314 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
3315 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);
3318 void R_Shadow_FreeWorldLight(dlight_t *light)
3320 dlight_t **lightpointer;
3321 R_RTLight_Uncompile(&light->rtlight);
3322 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
3323 if (*lightpointer != light)
3324 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain");
3325 *lightpointer = light->next;
3329 void R_Shadow_ClearWorldLights(void)
3331 while (r_shadow_worldlightchain)
3332 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
3333 r_shadow_selectedlight = NULL;
3334 R_Shadow_FreeCubemaps();
3337 void R_Shadow_SelectLight(dlight_t *light)
3339 if (r_shadow_selectedlight)
3340 r_shadow_selectedlight->selected = false;
3341 r_shadow_selectedlight = light;
3342 if (r_shadow_selectedlight)
3343 r_shadow_selectedlight->selected = true;
3346 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
3348 // this is never batched (there can be only one)
3349 float scale = r_editlights_cursorgrid.value * 0.5f;
3350 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);
3353 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
3355 // this is never batched (due to the ent parameter changing every time)
3356 // so numsurfaces == 1 and surfacelist[0] == lightnumber
3358 const dlight_t *light = (dlight_t *)ent;
3360 if (light->selected)
3361 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
3364 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);
3367 void R_Shadow_DrawLightSprites(void)
3372 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
3373 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 1+(i % 5), &light->rtlight);
3374 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
3377 void R_Shadow_SelectLightInView(void)
3379 float bestrating, rating, temp[3];
3380 dlight_t *best, *light;
3383 for (light = r_shadow_worldlightchain;light;light = light->next)
3385 VectorSubtract(light->origin, r_view.origin, temp);
3386 rating = (DotProduct(temp, r_view.forward) / sqrt(DotProduct(temp, temp)));
3389 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
3390 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)
3392 bestrating = rating;
3397 R_Shadow_SelectLight(best);
3400 void R_Shadow_LoadWorldLights(void)
3402 int n, a, style, shadow, flags;
3403 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
3404 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
3405 if (r_refdef.worldmodel == NULL)
3407 Con_Print("No map loaded.\n");
3410 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3411 strlcat (name, ".rtlights", sizeof (name));
3412 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3422 for (;COM_Parse(t, true) && strcmp(
3423 if (COM_Parse(t, true))
3425 if (com_token[0] == '!')
3428 origin[0] = atof(com_token+1);
3431 origin[0] = atof(com_token);
3436 while (*s && *s != '\n' && *s != '\r')
3442 // check for modifier flags
3449 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);
3452 flags = LIGHTFLAG_REALTIMEMODE;
3460 coronasizescale = 0.25f;
3462 VectorClear(angles);
3465 if (a < 9 || !strcmp(cubemapname, "\"\""))
3467 // remove quotes on cubemapname
3468 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
3471 namelen = strlen(cubemapname) - 2;
3472 memmove(cubemapname, cubemapname + 1, namelen);
3473 cubemapname[namelen] = '\0';
3477 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);
3480 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3488 Con_Printf("invalid rtlights file \"%s\"\n", name);
3489 Mem_Free(lightsstring);
3493 void R_Shadow_SaveWorldLights(void)
3496 size_t bufchars, bufmaxchars;
3498 char name[MAX_QPATH];
3499 char line[MAX_INPUTLINE];
3500 if (!r_shadow_worldlightchain)
3502 if (r_refdef.worldmodel == NULL)
3504 Con_Print("No map loaded.\n");
3507 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3508 strlcat (name, ".rtlights", sizeof (name));
3509 bufchars = bufmaxchars = 0;
3511 for (light = r_shadow_worldlightchain;light;light = light->next)
3513 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3514 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);
3515 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3516 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]);
3518 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);
3519 if (bufchars + strlen(line) > bufmaxchars)
3521 bufmaxchars = bufchars + strlen(line) + 2048;
3523 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
3527 memcpy(buf, oldbuf, bufchars);
3533 memcpy(buf + bufchars, line, strlen(line));
3534 bufchars += strlen(line);
3538 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
3543 void R_Shadow_LoadLightsFile(void)
3546 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3547 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3548 if (r_refdef.worldmodel == NULL)
3550 Con_Print("No map loaded.\n");
3553 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3554 strlcat (name, ".lights", sizeof (name));
3555 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3563 while (*s && *s != '\n' && *s != '\r')
3569 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);
3573 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);
3576 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3577 radius = bound(15, radius, 4096);
3578 VectorScale(color, (2.0f / (8388608.0f)), color);
3579 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3587 Con_Printf("invalid lights file \"%s\"\n", name);
3588 Mem_Free(lightsstring);
3592 // tyrlite/hmap2 light types in the delay field
3593 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3595 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3597 int entnum, style, islight, skin, pflags, effects, type, n;
3600 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3601 char key[256], value[MAX_INPUTLINE];
3603 if (r_refdef.worldmodel == NULL)
3605 Con_Print("No map loaded.\n");
3608 // try to load a .ent file first
3609 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3610 strlcat (key, ".ent", sizeof (key));
3611 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
3612 // and if that is not found, fall back to the bsp file entity string
3614 data = r_refdef.worldmodel->brush.entities;
3617 for (entnum = 0;COM_ParseTokenConsole(&data) && com_token[0] == '{';entnum++)
3619 type = LIGHTTYPE_MINUSX;
3620 origin[0] = origin[1] = origin[2] = 0;
3621 originhack[0] = originhack[1] = originhack[2] = 0;
3622 angles[0] = angles[1] = angles[2] = 0;
3623 color[0] = color[1] = color[2] = 1;
3624 light[0] = light[1] = light[2] = 1;light[3] = 300;
3625 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3635 if (!COM_ParseTokenConsole(&data))
3637 if (com_token[0] == '}')
3638 break; // end of entity
3639 if (com_token[0] == '_')
3640 strlcpy(key, com_token + 1, sizeof(key));
3642 strlcpy(key, com_token, sizeof(key));
3643 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3644 key[strlen(key)-1] = 0;
3645 if (!COM_ParseTokenConsole(&data))
3647 strlcpy(value, com_token, sizeof(value));
3649 // now that we have the key pair worked out...
3650 if (!strcmp("light", key))
3652 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3656 light[0] = vec[0] * (1.0f / 256.0f);
3657 light[1] = vec[0] * (1.0f / 256.0f);
3658 light[2] = vec[0] * (1.0f / 256.0f);
3664 light[0] = vec[0] * (1.0f / 255.0f);
3665 light[1] = vec[1] * (1.0f / 255.0f);
3666 light[2] = vec[2] * (1.0f / 255.0f);
3670 else if (!strcmp("delay", key))
3672 else if (!strcmp("origin", key))
3673 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3674 else if (!strcmp("angle", key))
3675 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3676 else if (!strcmp("angles", key))
3677 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3678 else if (!strcmp("color", key))
3679 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3680 else if (!strcmp("wait", key))
3681 fadescale = atof(value);
3682 else if (!strcmp("classname", key))
3684 if (!strncmp(value, "light", 5))
3687 if (!strcmp(value, "light_fluoro"))
3692 overridecolor[0] = 1;
3693 overridecolor[1] = 1;
3694 overridecolor[2] = 1;
3696 if (!strcmp(value, "light_fluorospark"))
3701 overridecolor[0] = 1;
3702 overridecolor[1] = 1;
3703 overridecolor[2] = 1;
3705 if (!strcmp(value, "light_globe"))
3710 overridecolor[0] = 1;
3711 overridecolor[1] = 0.8;
3712 overridecolor[2] = 0.4;
3714 if (!strcmp(value, "light_flame_large_yellow"))
3719 overridecolor[0] = 1;
3720 overridecolor[1] = 0.5;
3721 overridecolor[2] = 0.1;
3723 if (!strcmp(value, "light_flame_small_yellow"))
3728 overridecolor[0] = 1;
3729 overridecolor[1] = 0.5;
3730 overridecolor[2] = 0.1;
3732 if (!strcmp(value, "light_torch_small_white"))
3737 overridecolor[0] = 1;
3738 overridecolor[1] = 0.5;
3739 overridecolor[2] = 0.1;
3741 if (!strcmp(value, "light_torch_small_walltorch"))
3746 overridecolor[0] = 1;
3747 overridecolor[1] = 0.5;
3748 overridecolor[2] = 0.1;
3752 else if (!strcmp("style", key))
3753 style = atoi(value);
3754 else if (!strcmp("skin", key))
3755 skin = (int)atof(value);
3756 else if (!strcmp("pflags", key))
3757 pflags = (int)atof(value);
3758 else if (!strcmp("effects", key))
3759 effects = (int)atof(value);
3760 else if (r_refdef.worldmodel->type == mod_brushq3)
3762 if (!strcmp("scale", key))
3763 lightscale = atof(value);
3764 if (!strcmp("fade", key))
3765 fadescale = atof(value);
3770 if (lightscale <= 0)
3774 if (color[0] == color[1] && color[0] == color[2])
3776 color[0] *= overridecolor[0];
3777 color[1] *= overridecolor[1];
3778 color[2] *= overridecolor[2];
3780 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3781 color[0] = color[0] * light[0];
3782 color[1] = color[1] * light[1];
3783 color[2] = color[2] * light[2];
3786 case LIGHTTYPE_MINUSX:
3788 case LIGHTTYPE_RECIPX:
3790 VectorScale(color, (1.0f / 16.0f), color);
3792 case LIGHTTYPE_RECIPXX:
3794 VectorScale(color, (1.0f / 16.0f), color);
3797 case LIGHTTYPE_NONE:
3801 case LIGHTTYPE_MINUSXX:
3804 VectorAdd(origin, originhack, origin);
3806 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);
3809 Mem_Free(entfiledata);
3813 void R_Shadow_SetCursorLocationForView(void)
3816 vec3_t dest, endpos;
3818 VectorMA(r_view.origin, r_editlights_cursordistance.value, r_view.forward, dest);
3819 trace = CL_Move(r_view.origin, vec3_origin, vec3_origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
3820 if (trace.fraction < 1)
3822 dist = trace.fraction * r_editlights_cursordistance.value;
3823 push = r_editlights_cursorpushback.value;
3827 VectorMA(trace.endpos, push, r_view.forward, endpos);
3828 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
3832 VectorClear( endpos );
3834 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3835 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3836 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3839 void R_Shadow_UpdateWorldLightSelection(void)
3841 if (r_editlights.integer)
3843 R_Shadow_SetCursorLocationForView();
3844 R_Shadow_SelectLightInView();
3847 R_Shadow_SelectLight(NULL);
3850 void R_Shadow_EditLights_Clear_f(void)
3852 R_Shadow_ClearWorldLights();
3855 void R_Shadow_EditLights_Reload_f(void)
3857 if (!r_refdef.worldmodel)
3859 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3860 R_Shadow_ClearWorldLights();
3861 R_Shadow_LoadWorldLights();
3862 if (r_shadow_worldlightchain == NULL)
3864 R_Shadow_LoadLightsFile();
3865 if (r_shadow_worldlightchain == NULL)
3866 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3870 void R_Shadow_EditLights_Save_f(void)
3872 if (!r_refdef.worldmodel)
3874 R_Shadow_SaveWorldLights();
3877 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3879 R_Shadow_ClearWorldLights();
3880 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3883 void R_Shadow_EditLights_ImportLightsFile_f(void)
3885 R_Shadow_ClearWorldLights();
3886 R_Shadow_LoadLightsFile();
3889 void R_Shadow_EditLights_Spawn_f(void)
3892 if (!r_editlights.integer)
3894 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3897 if (Cmd_Argc() != 1)
3899 Con_Print("r_editlights_spawn does not take parameters\n");
3902 color[0] = color[1] = color[2] = 1;
3903 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3906 void R_Shadow_EditLights_Edit_f(void)
3908 vec3_t origin, angles, color;
3909 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3910 int style, shadows, flags, normalmode, realtimemode;
3911 char cubemapname[MAX_INPUTLINE];
3912 if (!r_editlights.integer)
3914 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3917 if (!r_shadow_selectedlight)
3919 Con_Print("No selected light.\n");
3922 VectorCopy(r_shadow_selectedlight->origin, origin);
3923 VectorCopy(r_shadow_selectedlight->angles, angles);
3924 VectorCopy(r_shadow_selectedlight->color, color);
3925 radius = r_shadow_selectedlight->radius;
3926 style = r_shadow_selectedlight->style;
3927 if (r_shadow_selectedlight->cubemapname)
3928 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
3931 shadows = r_shadow_selectedlight->shadow;
3932 corona = r_shadow_selectedlight->corona;
3933 coronasizescale = r_shadow_selectedlight->coronasizescale;
3934 ambientscale = r_shadow_selectedlight->ambientscale;
3935 diffusescale = r_shadow_selectedlight->diffusescale;
3936 specularscale = r_shadow_selectedlight->specularscale;
3937 flags = r_shadow_selectedlight->flags;
3938 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3939 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3940 if (!strcmp(Cmd_Argv(1), "origin"))
3942 if (Cmd_Argc() != 5)
3944 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3947 origin[0] = atof(Cmd_Argv(2));
3948 origin[1] = atof(Cmd_Argv(3));
3949 origin[2] = atof(Cmd_Argv(4));
3951 else if (!strcmp(Cmd_Argv(1), "originx"))
3953 if (Cmd_Argc() != 3)
3955 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3958 origin[0] = atof(Cmd_Argv(2));
3960 else if (!strcmp(Cmd_Argv(1), "originy"))
3962 if (Cmd_Argc() != 3)
3964 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3967 origin[1] = atof(Cmd_Argv(2));
3969 else if (!strcmp(Cmd_Argv(1), "originz"))
3971 if (Cmd_Argc() != 3)
3973 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3976 origin[2] = atof(Cmd_Argv(2));
3978 else if (!strcmp(Cmd_Argv(1), "move"))
3980 if (Cmd_Argc() != 5)
3982 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3985 origin[0] += atof(Cmd_Argv(2));
3986 origin[1] += atof(Cmd_Argv(3));
3987 origin[2] += atof(Cmd_Argv(4));
3989 else if (!strcmp(Cmd_Argv(1), "movex"))
3991 if (Cmd_Argc() != 3)
3993 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3996 origin[0] += atof(Cmd_Argv(2));
3998 else if (!strcmp(Cmd_Argv(1), "movey"))
4000 if (Cmd_Argc() != 3)
4002 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4005 origin[1] += atof(Cmd_Argv(2));
4007 else if (!strcmp(Cmd_Argv(1), "movez"))
4009 if (Cmd_Argc() != 3)
4011 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4014 origin[2] += atof(Cmd_Argv(2));
4016 else if (!strcmp(Cmd_Argv(1), "angles"))
4018 if (Cmd_Argc() != 5)
4020 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
4023 angles[0] = atof(Cmd_Argv(2));
4024 angles[1] = atof(Cmd_Argv(3));
4025 angles[2] = atof(Cmd_Argv(4));
4027 else if (!strcmp(Cmd_Argv(1), "anglesx"))
4029 if (Cmd_Argc() != 3)
4031 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4034 angles[0] = atof(Cmd_Argv(2));
4036 else if (!strcmp(Cmd_Argv(1), "anglesy"))
4038 if (Cmd_Argc() != 3)
4040 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4043 angles[1] = atof(Cmd_Argv(2));
4045 else if (!strcmp(Cmd_Argv(1), "anglesz"))
4047 if (Cmd_Argc() != 3)
4049 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4052 angles[2] = atof(Cmd_Argv(2));
4054 else if (!strcmp(Cmd_Argv(1), "color"))
4056 if (Cmd_Argc() != 5)
4058 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
4061 color[0] = atof(Cmd_Argv(2));
4062 color[1] = atof(Cmd_Argv(3));
4063 color[2] = atof(Cmd_Argv(4));
4065 else if (!strcmp(Cmd_Argv(1), "radius"))
4067 if (Cmd_Argc() != 3)
4069 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4072 radius = atof(Cmd_Argv(2));
4074 else if (!strcmp(Cmd_Argv(1), "colorscale"))
4076 if (Cmd_Argc() == 3)
4078 double scale = atof(Cmd_Argv(2));
4085 if (Cmd_Argc() != 5)
4087 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
4090 color[0] *= atof(Cmd_Argv(2));
4091 color[1] *= atof(Cmd_Argv(3));
4092 color[2] *= atof(Cmd_Argv(4));
4095 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
4097 if (Cmd_Argc() != 3)
4099 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4102 radius *= atof(Cmd_Argv(2));
4104 else if (!strcmp(Cmd_Argv(1), "style"))
4106 if (Cmd_Argc() != 3)
4108 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4111 style = atoi(Cmd_Argv(2));
4113 else if (!strcmp(Cmd_Argv(1), "cubemap"))
4117 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4120 if (Cmd_Argc() == 3)
4121 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
4125 else if (!strcmp(Cmd_Argv(1), "shadows"))
4127 if (Cmd_Argc() != 3)
4129 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4132 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4134 else if (!strcmp(Cmd_Argv(1), "corona"))
4136 if (Cmd_Argc() != 3)
4138 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4141 corona = atof(Cmd_Argv(2));
4143 else if (!strcmp(Cmd_Argv(1), "coronasize"))
4145 if (Cmd_Argc() != 3)
4147 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4150 coronasizescale = atof(Cmd_Argv(2));
4152 else if (!strcmp(Cmd_Argv(1), "ambient"))
4154 if (Cmd_Argc() != 3)
4156 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4159 ambientscale = atof(Cmd_Argv(2));
4161 else if (!strcmp(Cmd_Argv(1), "diffuse"))
4163 if (Cmd_Argc() != 3)
4165 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4168 diffusescale = atof(Cmd_Argv(2));
4170 else if (!strcmp(Cmd_Argv(1), "specular"))
4172 if (Cmd_Argc() != 3)
4174 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4177 specularscale = atof(Cmd_Argv(2));
4179 else if (!strcmp(Cmd_Argv(1), "normalmode"))
4181 if (Cmd_Argc() != 3)
4183 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4186 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4188 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
4190 if (Cmd_Argc() != 3)
4192 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4195 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4199 Con_Print("usage: r_editlights_edit [property] [value]\n");
4200 Con_Print("Selected light's properties:\n");
4201 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
4202 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
4203 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
4204 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
4205 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
4206 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
4207 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
4208 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
4209 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
4210 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
4211 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
4212 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
4213 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
4214 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
4217 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
4218 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4221 void R_Shadow_EditLights_EditAll_f(void)
4225 if (!r_editlights.integer)
4227 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
4231 for (light = r_shadow_worldlightchain;light;light = light->next)
4233 R_Shadow_SelectLight(light);
4234 R_Shadow_EditLights_Edit_f();
4238 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
4240 int lightnumber, lightcount;
4244 if (!r_editlights.integer)
4250 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
4251 if (light == r_shadow_selectedlight)
4252 lightnumber = lightcount;
4253 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;
4254 if (r_shadow_selectedlight == NULL)
4256 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
4257 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;
4258 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;
4259 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;
4260 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;
4261 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;
4262 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;
4263 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;
4264 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;
4265 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;
4266 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;
4267 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;
4268 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;
4269 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;
4270 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;
4273 void R_Shadow_EditLights_ToggleShadow_f(void)
4275 if (!r_editlights.integer)
4277 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4280 if (!r_shadow_selectedlight)
4282 Con_Print("No selected light.\n");
4285 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);
4288 void R_Shadow_EditLights_ToggleCorona_f(void)
4290 if (!r_editlights.integer)
4292 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4295 if (!r_shadow_selectedlight)
4297 Con_Print("No selected light.\n");
4300 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);
4303 void R_Shadow_EditLights_Remove_f(void)
4305 if (!r_editlights.integer)
4307 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
4310 if (!r_shadow_selectedlight)
4312 Con_Print("No selected light.\n");
4315 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
4316 r_shadow_selectedlight = NULL;
4319 void R_Shadow_EditLights_Help_f(void)
4322 "Documentation on r_editlights system:\n"
4324 "r_editlights : enable/disable editing mode\n"
4325 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
4326 "r_editlights_cursorpushback : push back cursor this far from surface\n"
4327 "r_editlights_cursorpushoff : push cursor off surface this far\n"
4328 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
4329 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
4331 "r_editlights_help : this help\n"
4332 "r_editlights_clear : remove all lights\n"
4333 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
4334 "r_editlights_save : save to .rtlights file\n"
4335 "r_editlights_spawn : create a light with default settings\n"
4336 "r_editlights_edit command : edit selected light - more documentation below\n"
4337 "r_editlights_remove : remove selected light\n"
4338 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
4339 "r_editlights_importlightentitiesfrommap : reload light entities\n"
4340 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
4342 "origin x y z : set light location\n"
4343 "originx x: set x component of light location\n"
4344 "originy y: set y component of light location\n"
4345 "originz z: set z component of light location\n"
4346 "move x y z : adjust light location\n"
4347 "movex x: adjust x component of light location\n"
4348 "movey y: adjust y component of light location\n"
4349 "movez z: adjust z component of light location\n"
4350 "angles x y z : set light angles\n"
4351 "anglesx x: set x component of light angles\n"
4352 "anglesy y: set y component of light angles\n"
4353 "anglesz z: set z component of light angles\n"
4354 "color r g b : set color of light (can be brighter than 1 1 1)\n"
4355 "radius radius : set radius (size) of light\n"
4356 "colorscale grey : multiply color of light (1 does nothing)\n"
4357 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
4358 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
4359 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
4360 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
4361 "cubemap basename : set filter cubemap of light (not yet supported)\n"
4362 "shadows 1/0 : turn on/off shadows\n"
4363 "corona n : set corona intensity\n"
4364 "coronasize n : set corona size (0-1)\n"
4365 "ambient n : set ambient intensity (0-1)\n"
4366 "diffuse n : set diffuse intensity (0-1)\n"
4367 "specular n : set specular intensity (0-1)\n"
4368 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
4369 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
4370 "<nothing> : print light properties to console\n"
4374 void R_Shadow_EditLights_CopyInfo_f(void)
4376 if (!r_editlights.integer)
4378 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
4381 if (!r_shadow_selectedlight)
4383 Con_Print("No selected light.\n");
4386 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
4387 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
4388 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
4389 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
4390 if (r_shadow_selectedlight->cubemapname)
4391 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
4393 r_shadow_bufferlight.cubemapname[0] = 0;
4394 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
4395 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
4396 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
4397 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
4398 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
4399 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
4400 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
4403 void R_Shadow_EditLights_PasteInfo_f(void)
4405 if (!r_editlights.integer)
4407 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
4410 if (!r_shadow_selectedlight)
4412 Con_Print("No selected light.\n");
4415 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);
4418 void R_Shadow_EditLights_Init(void)
4420 Cvar_RegisterVariable(&r_editlights);
4421 Cvar_RegisterVariable(&r_editlights_cursordistance);
4422 Cvar_RegisterVariable(&r_editlights_cursorpushback);
4423 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
4424 Cvar_RegisterVariable(&r_editlights_cursorgrid);
4425 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
4426 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
4427 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
4428 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)");
4429 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
4430 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
4431 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
4432 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)");
4433 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
4434 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
4435 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
4436 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
4437 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
4438 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
4439 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)");