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)
1291 f = FogPoint_Model(vertex3f);
1292 VectorScale(color4f, f, color4f);
1299 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1301 VectorCopy(ambientcolor, color4f);
1302 if (r_refdef.fogenabled)
1305 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1306 f = FogPoint_Model(vertex3f);
1307 VectorScale(color4f, f, color4f);
1313 else if (r_textureunits.integer >= 2)
1315 if (VectorLength2(diffusecolor) > 0)
1317 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1319 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1320 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1322 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1323 if ((dot = DotProduct(n, v)) < 0)
1325 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1326 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1327 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1328 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1332 color4f[0] = ambientcolor[0] * distintensity;
1333 color4f[1] = ambientcolor[1] * distintensity;
1334 color4f[2] = ambientcolor[2] * distintensity;
1336 if (r_refdef.fogenabled)
1339 f = FogPoint_Model(vertex3f);
1340 VectorScale(color4f, f, color4f);
1344 VectorClear(color4f);
1350 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1352 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1353 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1355 color4f[0] = ambientcolor[0] * distintensity;
1356 color4f[1] = ambientcolor[1] * distintensity;
1357 color4f[2] = ambientcolor[2] * distintensity;
1358 if (r_refdef.fogenabled)
1361 f = FogPoint_Model(vertex3f);
1362 VectorScale(color4f, f, color4f);
1366 VectorClear(color4f);
1373 if (VectorLength2(diffusecolor) > 0)
1375 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1377 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1378 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1380 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
1381 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1382 if ((dot = DotProduct(n, v)) < 0)
1384 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1385 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1386 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1387 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1391 color4f[0] = ambientcolor[0] * distintensity;
1392 color4f[1] = ambientcolor[1] * distintensity;
1393 color4f[2] = ambientcolor[2] * distintensity;
1395 if (r_refdef.fogenabled)
1398 f = FogPoint_Model(vertex3f);
1399 VectorScale(color4f, f, color4f);
1403 VectorClear(color4f);
1409 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1411 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1412 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1414 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
1415 color4f[0] = ambientcolor[0] * distintensity;
1416 color4f[1] = ambientcolor[1] * distintensity;
1417 color4f[2] = ambientcolor[2] * distintensity;
1418 if (r_refdef.fogenabled)
1421 f = FogPoint_Model(vertex3f);
1422 VectorScale(color4f, f, color4f);
1426 VectorClear(color4f);
1433 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1435 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
1438 float *out3f = rsurface_array_texcoord3f + 3 * firstvertex;
1439 const float *vertex3f = rsurface_vertex3f + 3 * firstvertex;
1440 const float *svector3f = rsurface_svector3f + 3 * firstvertex;
1441 const float *tvector3f = rsurface_tvector3f + 3 * firstvertex;
1442 const float *normal3f = rsurface_normal3f + 3 * firstvertex;
1444 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1446 VectorSubtract(r_shadow_entitylightorigin, vertex3f, lightdir);
1447 // the cubemap normalizes this for us
1448 out3f[0] = DotProduct(svector3f, lightdir);
1449 out3f[1] = DotProduct(tvector3f, lightdir);
1450 out3f[2] = DotProduct(normal3f, lightdir);
1454 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
1457 float *out3f = rsurface_array_texcoord3f + 3 * firstvertex;
1458 const float *vertex3f = rsurface_vertex3f + 3 * firstvertex;
1459 const float *svector3f = rsurface_svector3f + 3 * firstvertex;
1460 const float *tvector3f = rsurface_tvector3f + 3 * firstvertex;
1461 const float *normal3f = rsurface_normal3f + 3 * firstvertex;
1462 float lightdir[3], eyedir[3], halfdir[3];
1463 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1465 VectorSubtract(r_shadow_entitylightorigin, vertex3f, lightdir);
1466 VectorNormalize(lightdir);
1467 VectorSubtract(rsurface_modelorg, vertex3f, eyedir);
1468 VectorNormalize(eyedir);
1469 VectorAdd(lightdir, eyedir, halfdir);
1470 // the cubemap normalizes this for us
1471 out3f[0] = DotProduct(svector3f, halfdir);
1472 out3f[1] = DotProduct(tvector3f, halfdir);
1473 out3f[2] = DotProduct(normal3f, halfdir);
1477 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)
1479 // used to display how many times a surface is lit for level design purposes
1480 GL_Color(0.1 * r_view.colorscale, 0.025 * r_view.colorscale, 0, 1);
1481 R_Mesh_ColorPointer(NULL, 0, 0);
1482 R_Mesh_ResetTextureState();
1483 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1486 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)
1488 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
1489 R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale);
1490 R_Mesh_TexCoordPointer(0, 2, rsurface_model->surfmesh.data_texcoordtexture2f, rsurface_model->surfmesh.vbo, rsurface_model->surfmesh.vbooffset_texcoordtexture2f);
1491 R_Mesh_TexCoordPointer(1, 3, rsurface_svector3f, rsurface_svector3f_bufferobject, rsurface_svector3f_bufferoffset);
1492 R_Mesh_TexCoordPointer(2, 3, rsurface_tvector3f, rsurface_tvector3f_bufferobject, rsurface_tvector3f_bufferoffset);
1493 R_Mesh_TexCoordPointer(3, 3, rsurface_normal3f, rsurface_normal3f_bufferobject, rsurface_normal3f_bufferoffset);
1494 if (rsurface_texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1496 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1498 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1499 if (rsurface_texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1501 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1505 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)
1507 // shared final code for all the dot3 layers
1509 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 0);
1510 for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
1512 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
1513 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1517 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)
1520 // colorscale accounts for how much we multiply the brightness
1523 // mult is how many times the final pass of the lighting will be
1524 // performed to get more brightness than otherwise possible.
1526 // Limit mult to 64 for sanity sake.
1528 if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1530 // 3 3D combine path (Geforce3, Radeon 8500)
1531 memset(&m, 0, sizeof(m));
1532 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1533 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1534 m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
1535 m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
1536 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1537 m.tex[1] = R_GetTexture(basetexture);
1538 m.pointer_texcoord[1] = rsurface_model->surfmesh.data_texcoordtexture2f;
1539 m.pointer_texcoord_bufferobject[1] = rsurface_model->surfmesh.vbo;
1540 m.pointer_texcoord_bufferoffset[1] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1541 m.texmatrix[1] = rsurface_texture->currenttexmatrix;
1542 m.texcubemap[2] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1543 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1544 m.pointer_texcoord_bufferobject[2] = rsurface_vertex3f_bufferobject;
1545 m.pointer_texcoord_bufferoffset[2] = rsurface_vertex3f_bufferoffset;
1546 m.texmatrix[2] = r_shadow_entitytolight;
1547 GL_BlendFunc(GL_ONE, GL_ONE);
1549 else if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1551 // 2 3D combine path (Geforce3, original Radeon)
1552 memset(&m, 0, sizeof(m));
1553 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1554 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1555 m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
1556 m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
1557 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1558 m.tex[1] = R_GetTexture(basetexture);
1559 m.pointer_texcoord[1] = rsurface_model->surfmesh.data_texcoordtexture2f;
1560 m.pointer_texcoord_bufferobject[1] = rsurface_model->surfmesh.vbo;
1561 m.pointer_texcoord_bufferoffset[1] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1562 m.texmatrix[1] = rsurface_texture->currenttexmatrix;
1563 GL_BlendFunc(GL_ONE, GL_ONE);
1565 else if (r_textureunits.integer >= 4 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1567 // 4 2D combine path (Geforce3, Radeon 8500)
1568 memset(&m, 0, sizeof(m));
1569 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1570 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1571 m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
1572 m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
1573 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1574 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1575 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1576 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1577 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1578 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1579 m.tex[2] = R_GetTexture(basetexture);
1580 m.pointer_texcoord[2] = rsurface_model->surfmesh.data_texcoordtexture2f;
1581 m.pointer_texcoord_bufferobject[2] = rsurface_model->surfmesh.vbo;
1582 m.pointer_texcoord_bufferoffset[2] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1583 m.texmatrix[2] = rsurface_texture->currenttexmatrix;
1584 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1586 m.texcubemap[3] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1587 m.pointer_texcoord3f[3] = rsurface_vertex3f;
1588 m.pointer_texcoord_bufferobject[3] = rsurface_vertex3f_bufferobject;
1589 m.pointer_texcoord_bufferoffset[3] = rsurface_vertex3f_bufferoffset;
1590 m.texmatrix[3] = r_shadow_entitytolight;
1592 GL_BlendFunc(GL_ONE, GL_ONE);
1594 else if (r_textureunits.integer >= 3 && r_shadow_rtlight->currentcubemap == r_texture_whitecube)
1596 // 3 2D combine path (Geforce3, original Radeon)
1597 memset(&m, 0, sizeof(m));
1598 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1599 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1600 m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
1601 m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
1602 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1603 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1604 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1605 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1606 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1607 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1608 m.tex[2] = R_GetTexture(basetexture);
1609 m.pointer_texcoord[2] = rsurface_model->surfmesh.data_texcoordtexture2f;
1610 m.pointer_texcoord_bufferobject[2] = rsurface_model->surfmesh.vbo;
1611 m.pointer_texcoord_bufferoffset[2] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1612 m.texmatrix[2] = rsurface_texture->currenttexmatrix;
1613 GL_BlendFunc(GL_ONE, GL_ONE);
1617 // 2/2/2 2D combine path (any dot3 card)
1618 memset(&m, 0, sizeof(m));
1619 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1620 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1621 m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
1622 m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
1623 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1624 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1625 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1626 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1627 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1628 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1629 R_Mesh_TextureState(&m);
1630 GL_ColorMask(0,0,0,1);
1631 GL_BlendFunc(GL_ONE, GL_ZERO);
1632 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1635 memset(&m, 0, sizeof(m));
1636 m.tex[0] = R_GetTexture(basetexture);
1637 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1638 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1639 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1640 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1641 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1643 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1644 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1645 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1646 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1647 m.texmatrix[1] = r_shadow_entitytolight;
1649 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1651 // this final code is shared
1652 R_Mesh_TextureState(&m);
1653 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1656 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)
1659 // colorscale accounts for how much we multiply the brightness
1662 // mult is how many times the final pass of the lighting will be
1663 // performed to get more brightness than otherwise possible.
1665 // Limit mult to 64 for sanity sake.
1667 // generate normalization cubemap texcoords
1668 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
1669 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1671 // 3/2 3D combine path (Geforce3, Radeon 8500)
1672 memset(&m, 0, sizeof(m));
1673 m.tex[0] = R_GetTexture(normalmaptexture);
1674 m.texcombinergb[0] = GL_REPLACE;
1675 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1676 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1677 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1678 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1679 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1680 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1681 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1682 m.pointer_texcoord_bufferobject[1] = 0;
1683 m.pointer_texcoord_bufferoffset[1] = 0;
1684 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1685 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1686 m.pointer_texcoord_bufferobject[2] = rsurface_vertex3f_bufferobject;
1687 m.pointer_texcoord_bufferoffset[2] = rsurface_vertex3f_bufferoffset;
1688 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
1689 R_Mesh_TextureState(&m);
1690 GL_ColorMask(0,0,0,1);
1691 GL_BlendFunc(GL_ONE, GL_ZERO);
1692 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1695 memset(&m, 0, sizeof(m));
1696 m.tex[0] = R_GetTexture(basetexture);
1697 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1698 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1699 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1700 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1701 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1703 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1704 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1705 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1706 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1707 m.texmatrix[1] = r_shadow_entitytolight;
1709 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1711 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1713 // 1/2/2 3D combine path (original Radeon)
1714 memset(&m, 0, sizeof(m));
1715 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1716 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1717 m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
1718 m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
1719 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1720 R_Mesh_TextureState(&m);
1721 GL_ColorMask(0,0,0,1);
1722 GL_BlendFunc(GL_ONE, GL_ZERO);
1723 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1726 memset(&m, 0, sizeof(m));
1727 m.tex[0] = R_GetTexture(normalmaptexture);
1728 m.texcombinergb[0] = GL_REPLACE;
1729 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1730 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1731 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1732 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1733 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1734 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1735 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1736 m.pointer_texcoord_bufferobject[1] = 0;
1737 m.pointer_texcoord_bufferoffset[1] = 0;
1738 R_Mesh_TextureState(&m);
1739 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1740 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1743 memset(&m, 0, sizeof(m));
1744 m.tex[0] = R_GetTexture(basetexture);
1745 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1746 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1747 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1748 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1749 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1751 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1752 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1753 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1754 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1755 m.texmatrix[1] = r_shadow_entitytolight;
1757 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1759 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap == r_texture_whitecube)
1761 // 2/2 3D combine path (original Radeon)
1762 memset(&m, 0, sizeof(m));
1763 m.tex[0] = R_GetTexture(normalmaptexture);
1764 m.texcombinergb[0] = GL_REPLACE;
1765 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1766 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1767 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1768 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1769 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1770 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1771 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1772 m.pointer_texcoord_bufferobject[1] = 0;
1773 m.pointer_texcoord_bufferoffset[1] = 0;
1774 R_Mesh_TextureState(&m);
1775 GL_ColorMask(0,0,0,1);
1776 GL_BlendFunc(GL_ONE, GL_ZERO);
1777 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1780 memset(&m, 0, sizeof(m));
1781 m.tex[0] = R_GetTexture(basetexture);
1782 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1783 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1784 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1785 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1786 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1787 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1788 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1789 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1790 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
1791 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1793 else if (r_textureunits.integer >= 4)
1795 // 4/2 2D combine path (Geforce3, Radeon 8500)
1796 memset(&m, 0, sizeof(m));
1797 m.tex[0] = R_GetTexture(normalmaptexture);
1798 m.texcombinergb[0] = GL_REPLACE;
1799 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1800 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1801 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1802 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1803 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1804 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1805 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1806 m.pointer_texcoord_bufferobject[1] = 0;
1807 m.pointer_texcoord_bufferoffset[1] = 0;
1808 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1809 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1810 m.pointer_texcoord_bufferobject[2] = rsurface_vertex3f_bufferobject;
1811 m.pointer_texcoord_bufferoffset[2] = rsurface_vertex3f_bufferoffset;
1812 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
1813 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1814 m.pointer_texcoord3f[3] = rsurface_vertex3f;
1815 m.pointer_texcoord_bufferobject[3] = rsurface_vertex3f_bufferobject;
1816 m.pointer_texcoord_bufferoffset[3] = rsurface_vertex3f_bufferoffset;
1817 m.texmatrix[3] = r_shadow_entitytoattenuationz;
1818 R_Mesh_TextureState(&m);
1819 GL_ColorMask(0,0,0,1);
1820 GL_BlendFunc(GL_ONE, GL_ZERO);
1821 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1824 memset(&m, 0, sizeof(m));
1825 m.tex[0] = R_GetTexture(basetexture);
1826 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1827 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1828 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1829 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1830 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1832 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1833 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1834 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1835 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1836 m.texmatrix[1] = r_shadow_entitytolight;
1838 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1842 // 2/2/2 2D combine path (any dot3 card)
1843 memset(&m, 0, sizeof(m));
1844 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1845 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1846 m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
1847 m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
1848 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1849 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1850 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1851 m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
1852 m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
1853 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1854 R_Mesh_TextureState(&m);
1855 GL_ColorMask(0,0,0,1);
1856 GL_BlendFunc(GL_ONE, GL_ZERO);
1857 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1860 memset(&m, 0, sizeof(m));
1861 m.tex[0] = R_GetTexture(normalmaptexture);
1862 m.texcombinergb[0] = GL_REPLACE;
1863 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1864 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1865 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1866 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1867 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1868 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1869 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1870 m.pointer_texcoord_bufferobject[1] = 0;
1871 m.pointer_texcoord_bufferoffset[1] = 0;
1872 R_Mesh_TextureState(&m);
1873 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1874 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1877 memset(&m, 0, sizeof(m));
1878 m.tex[0] = R_GetTexture(basetexture);
1879 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1880 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1881 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1882 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1883 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1885 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1886 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1887 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1888 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1889 m.texmatrix[1] = r_shadow_entitytolight;
1891 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1893 // this final code is shared
1894 R_Mesh_TextureState(&m);
1895 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1898 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)
1900 float glossexponent;
1902 // FIXME: detect blendsquare!
1903 //if (!gl_support_blendsquare)
1906 // generate normalization cubemap texcoords
1907 R_Shadow_GenTexCoords_Specular_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
1908 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1910 // 2/0/0/1/2 3D combine blendsquare path
1911 memset(&m, 0, sizeof(m));
1912 m.tex[0] = R_GetTexture(normalmaptexture);
1913 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1914 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1915 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1916 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1917 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1918 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1919 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1920 m.pointer_texcoord_bufferobject[1] = 0;
1921 m.pointer_texcoord_bufferoffset[1] = 0;
1922 R_Mesh_TextureState(&m);
1923 GL_ColorMask(0,0,0,1);
1924 // this squares the result
1925 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1926 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1928 // second and third pass
1929 R_Mesh_ResetTextureState();
1930 // square alpha in framebuffer a few times to make it shiny
1931 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1932 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
1933 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1936 memset(&m, 0, sizeof(m));
1937 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1938 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1939 m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
1940 m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
1941 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1942 R_Mesh_TextureState(&m);
1943 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1944 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1947 memset(&m, 0, sizeof(m));
1948 m.tex[0] = R_GetTexture(glosstexture);
1949 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1950 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1951 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1952 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1953 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1955 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1956 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1957 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1958 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1959 m.texmatrix[1] = r_shadow_entitytolight;
1961 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1963 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
1965 // 2/0/0/2 3D combine blendsquare path
1966 memset(&m, 0, sizeof(m));
1967 m.tex[0] = R_GetTexture(normalmaptexture);
1968 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1969 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1970 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1971 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1972 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1973 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1974 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1975 m.pointer_texcoord_bufferobject[1] = 0;
1976 m.pointer_texcoord_bufferoffset[1] = 0;
1977 R_Mesh_TextureState(&m);
1978 GL_ColorMask(0,0,0,1);
1979 // this squares the result
1980 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1981 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1983 // second and third pass
1984 R_Mesh_ResetTextureState();
1985 // square alpha in framebuffer a few times to make it shiny
1986 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1987 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
1988 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1991 memset(&m, 0, sizeof(m));
1992 m.tex[0] = R_GetTexture(glosstexture);
1993 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1994 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1995 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1996 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1997 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1998 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1999 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
2000 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
2001 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2002 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2006 // 2/0/0/2/2 2D combine blendsquare path
2007 memset(&m, 0, sizeof(m));
2008 m.tex[0] = R_GetTexture(normalmaptexture);
2009 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
2010 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
2011 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
2012 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
2013 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2014 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2015 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
2016 m.pointer_texcoord_bufferobject[1] = 0;
2017 m.pointer_texcoord_bufferoffset[1] = 0;
2018 R_Mesh_TextureState(&m);
2019 GL_ColorMask(0,0,0,1);
2020 // this squares the result
2021 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2022 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2024 // second and third pass
2025 R_Mesh_ResetTextureState();
2026 // square alpha in framebuffer a few times to make it shiny
2027 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2028 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2029 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2032 memset(&m, 0, sizeof(m));
2033 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2034 m.pointer_texcoord3f[0] = rsurface_vertex3f;
2035 m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
2036 m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
2037 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2038 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2039 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2040 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
2041 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
2042 m.texmatrix[1] = r_shadow_entitytoattenuationz;
2043 R_Mesh_TextureState(&m);
2044 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2045 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2048 memset(&m, 0, sizeof(m));
2049 m.tex[0] = R_GetTexture(glosstexture);
2050 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
2051 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
2052 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
2053 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
2054 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
2056 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
2057 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2058 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
2059 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
2060 m.texmatrix[1] = r_shadow_entitytolight;
2062 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2064 // this final code is shared
2065 R_Mesh_TextureState(&m);
2066 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
2069 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)
2071 // ARB path (any Geforce, any Radeon)
2072 qboolean doambient = ambientscale > 0;
2073 qboolean dodiffuse = diffusescale > 0;
2074 qboolean dospecular = specularscale > 0;
2075 if (!doambient && !dodiffuse && !dospecular)
2077 R_Mesh_ColorPointer(NULL, 0, 0);
2079 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, basetexture, ambientscale * r_view.colorscale);
2081 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, basetexture, normalmaptexture, diffusescale * r_view.colorscale);
2085 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorpants, pantstexture, ambientscale * r_view.colorscale);
2087 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorpants, pantstexture, normalmaptexture, diffusescale * r_view.colorscale);
2092 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorshirt, shirttexture, ambientscale * r_view.colorscale);
2094 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorshirt, shirttexture, normalmaptexture, diffusescale * r_view.colorscale);
2097 R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_view.colorscale);
2100 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)
2107 int newnumtriangles;
2111 int newelements[4096*3];
2112 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
2113 for (renders = 0;renders < 64;renders++)
2118 newnumtriangles = 0;
2120 // due to low fillrate on the cards this vertex lighting path is
2121 // designed for, we manually cull all triangles that do not
2122 // contain a lit vertex
2123 // this builds batches of triangles from multiple surfaces and
2124 // renders them at once
2125 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2127 if (VectorLength2(rsurface_array_color4f + e[0] * 4) + VectorLength2(rsurface_array_color4f + e[1] * 4) + VectorLength2(rsurface_array_color4f + e[2] * 4) >= 0.01)
2129 if (newnumtriangles)
2131 newfirstvertex = min(newfirstvertex, e[0]);
2132 newlastvertex = max(newlastvertex, e[0]);
2136 newfirstvertex = e[0];
2137 newlastvertex = e[0];
2139 newfirstvertex = min(newfirstvertex, e[1]);
2140 newlastvertex = max(newlastvertex, e[1]);
2141 newfirstvertex = min(newfirstvertex, e[2]);
2142 newlastvertex = max(newlastvertex, e[2]);
2148 if (newnumtriangles >= (int)(sizeof(newelements)/sizeof(float[3])))
2150 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, newnumtriangles, newelements, 0, 0);
2151 newnumtriangles = 0;
2157 if (newnumtriangles >= 1)
2159 // if all triangles are included, use the original array to take advantage of the bufferobject if possible
2160 if (newnumtriangles == numtriangles)
2161 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2163 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, newnumtriangles, newelements, 0, 0);
2166 // if we couldn't find any lit triangles, exit early
2169 // now reduce the intensity for the next overbright pass
2170 // we have to clamp to 0 here incase the drivers have improper
2171 // handling of negative colors
2172 // (some old drivers even have improper handling of >1 color)
2174 for (i = 0, c = rsurface_array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2176 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2178 c[0] = max(0, c[0] - 1);
2179 c[1] = max(0, c[1] - 1);
2180 c[2] = max(0, c[2] - 1);
2192 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)
2194 // OpenGL 1.1 path (anything)
2195 model_t *model = rsurface_entity->model;
2196 float ambientcolorbase[3], diffusecolorbase[3];
2197 float ambientcolorpants[3], diffusecolorpants[3];
2198 float ambientcolorshirt[3], diffusecolorshirt[3];
2200 VectorScale(lightcolorbase, ambientscale * 2 * r_view.colorscale, ambientcolorbase);
2201 VectorScale(lightcolorbase, diffusescale * 2 * r_view.colorscale, diffusecolorbase);
2202 VectorScale(lightcolorpants, ambientscale * 2 * r_view.colorscale, ambientcolorpants);
2203 VectorScale(lightcolorpants, diffusescale * 2 * r_view.colorscale, diffusecolorpants);
2204 VectorScale(lightcolorshirt, ambientscale * 2 * r_view.colorscale, ambientcolorshirt);
2205 VectorScale(lightcolorshirt, diffusescale * 2 * r_view.colorscale, diffusecolorshirt);
2206 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2207 R_Mesh_ColorPointer(rsurface_array_color4f, 0, 0);
2208 memset(&m, 0, sizeof(m));
2209 m.tex[0] = R_GetTexture(basetexture);
2210 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
2211 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
2212 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
2213 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
2214 if (r_textureunits.integer >= 2)
2217 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2218 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2219 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2220 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
2221 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
2222 if (r_textureunits.integer >= 3)
2224 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
2225 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2226 m.texmatrix[2] = r_shadow_entitytoattenuationz;
2227 m.pointer_texcoord3f[2] = rsurface_vertex3f;
2228 m.pointer_texcoord_bufferobject[2] = rsurface_vertex3f_bufferobject;
2229 m.pointer_texcoord_bufferoffset[2] = rsurface_vertex3f_bufferoffset;
2232 R_Mesh_TextureState(&m);
2233 //R_Mesh_TexBind(0, R_GetTexture(basetexture));
2234 R_Shadow_RenderLighting_Light_Vertex_Pass(model, firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, diffusecolorbase, ambientcolorbase);
2237 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
2238 R_Shadow_RenderLighting_Light_Vertex_Pass(model, firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, diffusecolorpants, ambientcolorpants);
2242 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
2243 R_Shadow_RenderLighting_Light_Vertex_Pass(model, firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, diffusecolorshirt, ambientcolorshirt);
2247 void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset)
2249 float ambientscale, diffusescale, specularscale;
2250 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
2251 // calculate colors to render this texture with
2252 lightcolorbase[0] = r_shadow_rtlight->currentcolor[0] * rsurface_entity->colormod[0] * rsurface_texture->currentalpha;
2253 lightcolorbase[1] = r_shadow_rtlight->currentcolor[1] * rsurface_entity->colormod[1] * rsurface_texture->currentalpha;
2254 lightcolorbase[2] = r_shadow_rtlight->currentcolor[2] * rsurface_entity->colormod[2] * rsurface_texture->currentalpha;
2255 ambientscale = r_shadow_rtlight->ambientscale;
2256 diffusescale = r_shadow_rtlight->diffusescale;
2257 specularscale = r_shadow_rtlight->specularscale * rsurface_texture->specularscale;
2258 if (!r_shadow_usenormalmap.integer)
2260 ambientscale += 1.0f * diffusescale;
2264 if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
2266 GL_DepthRange(0, (rsurface_texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
2267 GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
2268 GL_CullFace((rsurface_texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
2269 if (rsurface_texture->colormapping)
2271 qboolean dopants = rsurface_texture->currentskinframe->pants != NULL && VectorLength2(rsurface_entity->colormap_pantscolor) >= (1.0f / 1048576.0f);
2272 qboolean doshirt = rsurface_texture->currentskinframe->shirt != NULL && VectorLength2(rsurface_entity->colormap_shirtcolor) >= (1.0f / 1048576.0f);
2275 lightcolorpants[0] = lightcolorbase[0] * rsurface_entity->colormap_pantscolor[0];
2276 lightcolorpants[1] = lightcolorbase[1] * rsurface_entity->colormap_pantscolor[1];
2277 lightcolorpants[2] = lightcolorbase[2] * rsurface_entity->colormap_pantscolor[2];
2280 VectorClear(lightcolorpants);
2283 lightcolorshirt[0] = lightcolorbase[0] * rsurface_entity->colormap_shirtcolor[0];
2284 lightcolorshirt[1] = lightcolorbase[1] * rsurface_entity->colormap_shirtcolor[1];
2285 lightcolorshirt[2] = lightcolorbase[2] * rsurface_entity->colormap_shirtcolor[2];
2288 VectorClear(lightcolorshirt);
2289 switch (r_shadow_rendermode)
2291 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2292 GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2293 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);
2295 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2296 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);
2298 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2299 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);
2301 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2302 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);
2305 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2311 switch (r_shadow_rendermode)
2313 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2314 GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2315 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);
2317 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2318 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);
2320 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2321 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);
2323 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2324 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);
2327 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2333 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)
2335 matrix4x4_t tempmatrix = *matrix;
2336 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2338 // if this light has been compiled before, free the associated data
2339 R_RTLight_Uncompile(rtlight);
2341 // clear it completely to avoid any lingering data
2342 memset(rtlight, 0, sizeof(*rtlight));
2344 // copy the properties
2345 rtlight->matrix_lighttoworld = tempmatrix;
2346 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2347 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2348 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2349 VectorCopy(color, rtlight->color);
2350 rtlight->cubemapname[0] = 0;
2351 if (cubemapname && cubemapname[0])
2352 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2353 rtlight->shadow = shadow;
2354 rtlight->corona = corona;
2355 rtlight->style = style;
2356 rtlight->isstatic = isstatic;
2357 rtlight->coronasizescale = coronasizescale;
2358 rtlight->ambientscale = ambientscale;
2359 rtlight->diffusescale = diffusescale;
2360 rtlight->specularscale = specularscale;
2361 rtlight->flags = flags;
2363 // compute derived data
2364 //rtlight->cullradius = rtlight->radius;
2365 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2366 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2367 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2368 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2369 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2370 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2371 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2374 // compiles rtlight geometry
2375 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2376 void R_RTLight_Compile(rtlight_t *rtlight)
2379 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2380 int lighttris, shadowtris, shadowmeshes, shadowmeshtris;
2381 entity_render_t *ent = r_refdef.worldentity;
2382 model_t *model = r_refdef.worldmodel;
2383 unsigned char *data;
2385 // compile the light
2386 rtlight->compiled = true;
2387 rtlight->static_numleafs = 0;
2388 rtlight->static_numleafpvsbytes = 0;
2389 rtlight->static_leaflist = NULL;
2390 rtlight->static_leafpvs = NULL;
2391 rtlight->static_numsurfaces = 0;
2392 rtlight->static_surfacelist = NULL;
2393 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2394 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2395 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2396 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2397 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2398 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2400 if (model && model->GetLightInfo)
2402 // this variable must be set for the CompileShadowVolume code
2403 r_shadow_compilingrtlight = rtlight;
2404 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);
2405 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);
2406 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2407 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
2408 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
2409 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
2410 rtlight->static_numsurfaces = numsurfaces;
2411 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2412 rtlight->static_numleafs = numleafs;
2413 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2414 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2415 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2416 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
2417 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
2418 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
2419 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
2420 if (rtlight->static_numsurfaces)
2421 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2422 if (rtlight->static_numleafs)
2423 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2424 if (rtlight->static_numleafpvsbytes)
2425 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2426 if (rtlight->static_numshadowtrispvsbytes)
2427 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
2428 if (rtlight->static_numlighttrispvsbytes)
2429 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
2430 if (model->CompileShadowVolume && rtlight->shadow)
2431 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2432 // now we're done compiling the rtlight
2433 r_shadow_compilingrtlight = NULL;
2437 // use smallest available cullradius - box radius or light radius
2438 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2439 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2443 if (rtlight->static_meshchain_shadow)
2446 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2449 shadowmeshtris += mesh->numtriangles;
2454 if (rtlight->static_numlighttrispvsbytes)
2455 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
2456 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
2460 if (rtlight->static_numlighttrispvsbytes)
2461 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
2462 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
2465 if (developer.integer >= 10)
2466 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);
2469 void R_RTLight_Uncompile(rtlight_t *rtlight)
2471 if (rtlight->compiled)
2473 if (rtlight->static_meshchain_shadow)
2474 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2475 rtlight->static_meshchain_shadow = NULL;
2476 // these allocations are grouped
2477 if (rtlight->static_surfacelist)
2478 Mem_Free(rtlight->static_surfacelist);
2479 rtlight->static_numleafs = 0;
2480 rtlight->static_numleafpvsbytes = 0;
2481 rtlight->static_leaflist = NULL;
2482 rtlight->static_leafpvs = NULL;
2483 rtlight->static_numsurfaces = 0;
2484 rtlight->static_surfacelist = NULL;
2485 rtlight->static_numshadowtrispvsbytes = 0;
2486 rtlight->static_shadowtrispvs = NULL;
2487 rtlight->static_numlighttrispvsbytes = 0;
2488 rtlight->static_lighttrispvs = NULL;
2489 rtlight->compiled = false;
2493 void R_Shadow_UncompileWorldLights(void)
2496 for (light = r_shadow_worldlightchain;light;light = light->next)
2497 R_RTLight_Uncompile(&light->rtlight);
2500 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
2504 // reset the count of frustum planes
2505 // see r_shadow_rtlight_frustumplanes definition for how much this array
2507 r_shadow_rtlight_numfrustumplanes = 0;
2510 // generate a deformed frustum that includes the light origin, this is
2511 // used to cull shadow casting surfaces that can not possibly cast a
2512 // shadow onto the visible light-receiving surfaces, which can be a
2515 // if the light origin is onscreen the result will be 4 planes exactly
2516 // if the light origin is offscreen on only one axis the result will
2517 // be exactly 5 planes (split-side case)
2518 // if the light origin is offscreen on two axes the result will be
2519 // exactly 4 planes (stretched corner case)
2520 for (i = 0;i < 4;i++)
2522 // quickly reject standard frustum planes that put the light
2523 // origin outside the frustum
2524 if (PlaneDiff(rtlight->shadoworigin, &r_view.frustum[i]) < -0.03125)
2527 r_shadow_rtlight_frustumplanes[r_shadow_rtlight_numfrustumplanes++] = r_view.frustum[i];
2529 // if all the standard frustum planes were accepted, the light is onscreen
2530 // otherwise we need to generate some more planes below...
2531 if (r_shadow_rtlight_numfrustumplanes < 4)
2533 // at least one of the stock frustum planes failed, so we need to
2534 // create one or two custom planes to enclose the light origin
2535 for (i = 0;i < 4;i++)
2537 // create a plane using the view origin and light origin, and a
2538 // single point from the frustum corner set
2539 TriangleNormal(r_view.origin, r_view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
2540 VectorNormalize(plane.normal);
2541 plane.dist = DotProduct(r_view.origin, plane.normal);
2542 // see if this plane is backwards and flip it if so
2543 for (j = 0;j < 4;j++)
2544 if (j != i && DotProduct(r_view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
2548 VectorNegate(plane.normal, plane.normal);
2550 // flipped plane, test again to see if it is now valid
2551 for (j = 0;j < 4;j++)
2552 if (j != i && DotProduct(r_view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
2554 // if the plane is still not valid, then it is dividing the
2555 // frustum and has to be rejected
2559 // we have created a valid plane, compute extra info
2560 PlaneClassify(&plane);
2562 r_shadow_rtlight_frustumplanes[r_shadow_rtlight_numfrustumplanes++] = plane;
2564 // if we've found 5 frustum planes then we have constructed a
2565 // proper split-side case and do not need to keep searching for
2566 // planes to enclose the light origin
2567 if (r_shadow_rtlight_numfrustumplanes == 5)
2575 for (i = 0;i < r_shadow_rtlight_numfrustumplanes;i++)
2577 plane = r_shadow_rtlight_frustumplanes[i];
2578 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));
2583 // now add the light-space box planes if the light box is rotated, as any
2584 // caster outside the oriented light box is irrelevant (even if it passed
2585 // the worldspace light box, which is axial)
2586 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
2588 for (i = 0;i < 6;i++)
2592 v[i >> 1] = (i & 1) ? -1 : 1;
2593 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
2594 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
2595 plane.dist = VectorNormalizeLength(plane.normal);
2596 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
2597 r_shadow_rtlight_frustumplanes[r_shadow_rtlight_numfrustumplanes++] = plane;
2603 // add the world-space reduced box planes
2604 for (i = 0;i < 6;i++)
2606 VectorClear(plane.normal);
2607 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
2608 plane.dist = (i & 1) ? -r_shadow_rtlight_cullmaxs[i >> 1] : r_shadow_rtlight_cullmins[i >> 1];
2609 r_shadow_rtlight_frustumplanes[r_shadow_rtlight_numfrustumplanes++] = plane;
2618 // reduce all plane distances to tightly fit the rtlight cull box, which
2620 VectorSet(points[0], r_shadow_rtlight_cullmins[0], r_shadow_rtlight_cullmins[1], r_shadow_rtlight_cullmins[2]);
2621 VectorSet(points[1], r_shadow_rtlight_cullmaxs[0], r_shadow_rtlight_cullmins[1], r_shadow_rtlight_cullmins[2]);
2622 VectorSet(points[2], r_shadow_rtlight_cullmins[0], r_shadow_rtlight_cullmaxs[1], r_shadow_rtlight_cullmins[2]);
2623 VectorSet(points[3], r_shadow_rtlight_cullmaxs[0], r_shadow_rtlight_cullmaxs[1], r_shadow_rtlight_cullmins[2]);
2624 VectorSet(points[4], r_shadow_rtlight_cullmins[0], r_shadow_rtlight_cullmins[1], r_shadow_rtlight_cullmaxs[2]);
2625 VectorSet(points[5], r_shadow_rtlight_cullmaxs[0], r_shadow_rtlight_cullmins[1], r_shadow_rtlight_cullmaxs[2]);
2626 VectorSet(points[6], r_shadow_rtlight_cullmins[0], r_shadow_rtlight_cullmaxs[1], r_shadow_rtlight_cullmaxs[2]);
2627 VectorSet(points[7], r_shadow_rtlight_cullmaxs[0], r_shadow_rtlight_cullmaxs[1], r_shadow_rtlight_cullmaxs[2]);
2628 oldnum = r_shadow_rtlight_numfrustumplanes;
2629 r_shadow_rtlight_numfrustumplanes = 0;
2630 for (j = 0;j < oldnum;j++)
2632 // find the nearest point on the box to this plane
2633 bestdist = DotProduct(r_shadow_rtlight_frustumplanes[j].normal, points[0]);
2634 for (i = 1;i < 8;i++)
2636 dist = DotProduct(r_shadow_rtlight_frustumplanes[j].normal, points[i]);
2637 if (bestdist > dist)
2640 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);
2641 // if the nearest point is near or behind the plane, we want this
2642 // plane, otherwise the plane is useless as it won't cull anything
2643 if (r_shadow_rtlight_frustumplanes[j].dist < bestdist + 0.03125)
2645 PlaneClassify(&r_shadow_rtlight_frustumplanes[j]);
2646 r_shadow_rtlight_frustumplanes[r_shadow_rtlight_numfrustumplanes++] = r_shadow_rtlight_frustumplanes[j];
2653 void R_Shadow_DrawWorldShadow(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
2655 RSurf_ActiveWorldEntity();
2656 if (r_shadow_rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2660 for (mesh = r_shadow_rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2662 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
2663 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
2664 GL_LockArrays(0, mesh->numverts);
2665 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
2667 // decrement stencil if backface is behind depthbuffer
2668 GL_CullFace(GL_BACK); // quake is backwards, this culls front faces
2669 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2670 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->ebo, 0);
2671 // increment stencil if frontface is behind depthbuffer
2672 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
2673 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2675 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->ebo, 0);
2676 GL_LockArrays(0, 0);
2680 else if (numsurfaces && r_refdef.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
2683 int surfacelistindex;
2684 msurface_t *surface;
2685 R_Shadow_PrepareShadowMark(r_refdef.worldmodel->brush.shadowmesh->numtriangles);
2686 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
2688 surface = r_refdef.worldmodel->data_surfaces + surfacelist[surfacelistindex];
2689 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
2690 if (CHECKPVSBIT(trispvs, t))
2691 shadowmarklist[numshadowmark++] = t;
2693 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);
2695 else if (numsurfaces)
2696 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);
2699 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
2701 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
2702 vec_t relativeshadowradius;
2703 RSurf_ActiveModelEntity(ent, false, false);
2704 Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, relativeshadoworigin);
2705 relativeshadowradius = r_shadow_rtlight->radius / ent->scale;
2706 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
2707 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
2708 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
2709 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
2710 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
2711 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
2712 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2715 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
2717 // set up properties for rendering light onto this entity
2718 RSurf_ActiveModelEntity(ent, true, true);
2719 Matrix4x4_Concat(&r_shadow_entitytolight, &r_shadow_rtlight->matrix_worldtolight, &ent->matrix);
2720 Matrix4x4_Concat(&r_shadow_entitytoattenuationxyz, &matrix_attenuationxyz, &r_shadow_entitytolight);
2721 Matrix4x4_Concat(&r_shadow_entitytoattenuationz, &matrix_attenuationz, &r_shadow_entitytolight);
2722 Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, r_shadow_entitylightorigin);
2723 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2724 R_Mesh_TexMatrix(3, &r_shadow_entitytolight);
2727 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
2729 if (!r_refdef.worldmodel->DrawLight)
2732 // set up properties for rendering light onto this entity
2733 RSurf_ActiveWorldEntity();
2734 r_shadow_entitytolight = r_shadow_rtlight->matrix_worldtolight;
2735 Matrix4x4_Concat(&r_shadow_entitytoattenuationxyz, &matrix_attenuationxyz, &r_shadow_entitytolight);
2736 Matrix4x4_Concat(&r_shadow_entitytoattenuationz, &matrix_attenuationz, &r_shadow_entitytolight);
2737 VectorCopy(r_shadow_rtlight->shadoworigin, r_shadow_entitylightorigin);
2738 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2739 R_Mesh_TexMatrix(3, &r_shadow_entitytolight);
2741 r_refdef.worldmodel->DrawLight(r_refdef.worldentity, numsurfaces, surfacelist, trispvs);
2744 void R_Shadow_DrawEntityLight(entity_render_t *ent, int numsurfaces, int *surfacelist)
2746 model_t *model = ent->model;
2747 if (!model->DrawLight)
2750 R_Shadow_SetupEntityLight(ent);
2752 model->DrawLight(ent, model->nummodelsurfaces, model->surfacelist, NULL);
2755 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
2759 int numleafs, numsurfaces;
2760 int *leaflist, *surfacelist;
2761 unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs;
2762 int numlightentities;
2763 int numlightentities_noselfshadow;
2764 int numshadowentities;
2765 int numshadowentities_noselfshadow;
2766 entity_render_t *lightentities[MAX_EDICTS];
2767 entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
2768 entity_render_t *shadowentities[MAX_EDICTS];
2769 entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
2771 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
2772 // skip lights that are basically invisible (color 0 0 0)
2773 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
2776 // loading is done before visibility checks because loading should happen
2777 // all at once at the start of a level, not when it stalls gameplay.
2778 // (especially important to benchmarks)
2780 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2781 R_RTLight_Compile(rtlight);
2783 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
2785 // look up the light style value at this time
2786 f = (rtlight->style >= 0 ? r_refdef.lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2787 VectorScale(rtlight->color, f, rtlight->currentcolor);
2789 if (rtlight->selected)
2791 f = 2 + sin(realtime * M_PI * 4.0);
2792 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
2796 // if lightstyle is currently off, don't draw the light
2797 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
2800 // if the light box is offscreen, skip it
2801 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2804 VectorCopy(rtlight->cullmins, r_shadow_rtlight_cullmins);
2805 VectorCopy(rtlight->cullmaxs, r_shadow_rtlight_cullmaxs);
2807 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2809 // compiled light, world available and can receive realtime lighting
2810 // retrieve leaf information
2811 numleafs = rtlight->static_numleafs;
2812 leaflist = rtlight->static_leaflist;
2813 leafpvs = rtlight->static_leafpvs;
2814 numsurfaces = rtlight->static_numsurfaces;
2815 surfacelist = rtlight->static_surfacelist;
2816 shadowtrispvs = rtlight->static_shadowtrispvs;
2817 lighttrispvs = rtlight->static_lighttrispvs;
2819 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2821 // dynamic light, world available and can receive realtime lighting
2822 // calculate lit surfaces and leafs
2823 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);
2824 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);
2825 leaflist = r_shadow_buffer_leaflist;
2826 leafpvs = r_shadow_buffer_leafpvs;
2827 surfacelist = r_shadow_buffer_surfacelist;
2828 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
2829 lighttrispvs = r_shadow_buffer_lighttrispvs;
2830 // if the reduced leaf bounds are offscreen, skip it
2831 if (R_CullBox(r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs))
2842 shadowtrispvs = NULL;
2843 lighttrispvs = NULL;
2845 // check if light is illuminating any visible leafs
2848 for (i = 0;i < numleafs;i++)
2849 if (r_viewcache.world_leafvisible[leaflist[i]])
2854 // set up a scissor rectangle for this light
2855 if (R_Shadow_ScissorForBBox(r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs))
2858 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
2860 // make a list of lit entities and shadow casting entities
2861 numlightentities = 0;
2862 numlightentities_noselfshadow = 0;
2863 numshadowentities = 0;
2864 numshadowentities_noselfshadow = 0;
2865 // add dynamic entities that are lit by the light
2866 if (r_drawentities.integer)
2868 for (i = 0;i < r_refdef.numentities;i++)
2871 entity_render_t *ent = r_refdef.entities[i];
2873 if (!BoxesOverlap(ent->mins, ent->maxs, r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs))
2875 // skip the object entirely if it is not within the valid
2876 // shadow-casting region (which includes the lit region)
2877 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, r_shadow_rtlight_numfrustumplanes, r_shadow_rtlight_frustumplanes))
2879 if (!(model = ent->model))
2881 if (r_viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
2883 // this entity wants to receive light, is visible, and is
2884 // inside the light box
2885 // TODO: check if the surfaces in the model can receive light
2886 // so now check if it's in a leaf seen by the light
2887 if (r_refdef.worldmodel && r_refdef.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs))
2889 if (ent->flags & RENDER_NOSELFSHADOW)
2890 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
2892 lightentities[numlightentities++] = ent;
2893 // since it is lit, it probably also casts a shadow...
2894 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2895 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
2896 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
2898 // note: exterior models without the RENDER_NOSELFSHADOW
2899 // flag still create a RENDER_NOSELFSHADOW shadow but
2900 // are lit normally, this means that they are
2901 // self-shadowing but do not shadow other
2902 // RENDER_NOSELFSHADOW entities such as the gun
2903 // (very weird, but keeps the player shadow off the gun)
2904 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
2905 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
2907 shadowentities[numshadowentities++] = ent;
2910 else if (ent->flags & RENDER_SHADOW)
2912 // this entity is not receiving light, but may still need to
2914 // TODO: check if the surfaces in the model can cast shadow
2915 // now check if it is in a leaf seen by the light
2916 if (r_refdef.worldmodel && r_refdef.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs))
2918 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2919 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
2920 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
2922 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
2923 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
2925 shadowentities[numshadowentities++] = ent;
2931 // return if there's nothing at all to light
2932 if (!numlightentities && !numsurfaces)
2935 // don't let sound skip if going slow
2936 if (r_refdef.extraupdate)
2939 // make this the active rtlight for rendering purposes
2940 R_Shadow_RenderMode_ActiveLight(rtlight);
2941 // count this light in the r_speeds
2942 r_refdef.stats.lights++;
2944 if (r_showshadowvolumes.integer && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.rtworldshadows : r_refdef.rtdlightshadows))
2946 // optionally draw visible shape of the shadow volumes
2947 // for performance analysis by level designers
2948 R_Shadow_RenderMode_VisibleShadowVolumes();
2950 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
2951 for (i = 0;i < numshadowentities;i++)
2952 R_Shadow_DrawEntityShadow(shadowentities[i]);
2953 for (i = 0;i < numshadowentities_noselfshadow;i++)
2954 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
2957 if (gl_stencil && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.rtworldshadows : r_refdef.rtdlightshadows))
2959 // draw stencil shadow volumes to mask off pixels that are in shadow
2960 // so that they won't receive lighting
2961 R_Shadow_RenderMode_StencilShadowVolumes(true);
2963 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
2964 for (i = 0;i < numshadowentities;i++)
2965 R_Shadow_DrawEntityShadow(shadowentities[i]);
2966 if (numlightentities_noselfshadow)
2968 // draw lighting in the unmasked areas
2969 R_Shadow_RenderMode_Lighting(true, false);
2970 for (i = 0;i < numlightentities_noselfshadow;i++)
2971 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i], numsurfaces, surfacelist);
2973 // optionally draw the illuminated areas
2974 // for performance analysis by level designers
2975 if (r_showlighting.integer)
2977 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
2978 for (i = 0;i < numlightentities_noselfshadow;i++)
2979 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i], numsurfaces, surfacelist);
2982 R_Shadow_RenderMode_StencilShadowVolumes(false);
2984 for (i = 0;i < numshadowentities_noselfshadow;i++)
2985 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
2987 if (numsurfaces + numlightentities)
2989 // draw lighting in the unmasked areas
2990 R_Shadow_RenderMode_Lighting(true, false);
2992 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
2993 for (i = 0;i < numlightentities;i++)
2994 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
2996 // optionally draw the illuminated areas
2997 // for performance analysis by level designers
2998 if (r_showlighting.integer)
3000 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
3002 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3003 for (i = 0;i < numlightentities;i++)
3004 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
3010 if (numsurfaces + numlightentities)
3012 // draw lighting in the unmasked areas
3013 R_Shadow_RenderMode_Lighting(false, false);
3015 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3016 for (i = 0;i < numlightentities;i++)
3017 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
3018 for (i = 0;i < numlightentities_noselfshadow;i++)
3019 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i], numsurfaces, surfacelist);
3021 // optionally draw the illuminated areas
3022 // for performance analysis by level designers
3023 if (r_showlighting.integer)
3025 R_Shadow_RenderMode_VisibleLighting(false, false);
3027 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3028 for (i = 0;i < numlightentities;i++)
3029 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
3030 for (i = 0;i < numlightentities_noselfshadow;i++)
3031 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i], numsurfaces, surfacelist);
3037 void R_Shadow_DrawLightSprites(void);
3038 void R_ShadowVolumeLighting(qboolean visible)
3043 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
3044 R_Shadow_EditLights_Reload_f();
3046 if (r_editlights.integer)
3047 R_Shadow_DrawLightSprites();
3049 R_Shadow_RenderMode_Begin();
3051 flag = r_refdef.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3052 if (r_shadow_debuglight.integer >= 0)
3054 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
3055 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
3056 R_DrawRTLight(&light->rtlight, visible);
3059 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
3060 if (light->flags & flag)
3061 R_DrawRTLight(&light->rtlight, visible);
3062 if (r_refdef.rtdlight)
3063 for (lnum = 0;lnum < r_refdef.numlights;lnum++)
3064 R_DrawRTLight(&r_refdef.lights[lnum], visible);
3066 R_Shadow_RenderMode_End();
3069 extern void R_SetupView(const matrix4x4_t *matrix);
3070 extern cvar_t r_shadows_throwdistance;
3071 void R_DrawModelShadows(void)
3074 float relativethrowdistance;
3075 entity_render_t *ent;
3076 vec3_t relativelightorigin;
3077 vec3_t relativelightdirection;
3078 vec3_t relativeshadowmins, relativeshadowmaxs;
3081 if (!r_drawentities.integer || !gl_stencil)
3085 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
3087 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
3089 if (gl_ext_separatestencil.integer)
3090 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
3091 else if (gl_ext_stenciltwoside.integer)
3092 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
3094 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
3096 R_Shadow_RenderMode_StencilShadowVolumes(true);
3098 for (i = 0;i < r_refdef.numentities;i++)
3100 ent = r_refdef.entities[i];
3101 // cast shadows from anything that is not a submodel of the map
3102 if (ent->model && ent->model->DrawShadowVolume != NULL && !ent->model->brush.submodel && (ent->flags & RENDER_SHADOW))
3104 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
3105 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
3106 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
3107 VectorNegate(ent->modellight_lightdir, relativelightdirection);
3108 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
3109 RSurf_ActiveModelEntity(ent, false, false);
3110 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
3114 // not really the right mode, but this will disable any silly stencil features
3115 R_Shadow_RenderMode_VisibleLighting(true, true);
3117 // vertex coordinates for a quad that covers the screen exactly
3118 vertex3f[0] = 0;vertex3f[1] = 0;vertex3f[2] = 0;
3119 vertex3f[3] = 1;vertex3f[4] = 0;vertex3f[5] = 0;
3120 vertex3f[6] = 1;vertex3f[7] = 1;vertex3f[8] = 0;
3121 vertex3f[9] = 0;vertex3f[10] = 1;vertex3f[11] = 0;
3123 // set up ortho view for rendering this pass
3124 GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
3125 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
3126 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
3127 GL_ScissorTest(true);
3128 R_Mesh_Matrix(&identitymatrix);
3129 R_Mesh_ResetTextureState();
3130 R_Mesh_VertexPointer(vertex3f, 0, 0);
3131 R_Mesh_ColorPointer(NULL, 0, 0);
3133 // set up a 50% darkening blend on shadowed areas
3134 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3135 GL_DepthRange(0, 1);
3136 GL_DepthTest(false);
3137 GL_DepthMask(false);
3138 qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
3139 GL_Color(0, 0, 0, 0.5);
3140 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
3141 qglDepthFunc(GL_ALWAYS);CHECKGLERROR
3142 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
3143 qglStencilMask(~0);CHECKGLERROR
3144 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
3145 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
3147 // apply the blend to the shadowed areas
3148 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3150 // restoring the perspective view is done by R_RenderScene
3151 //R_SetupView(&r_view.matrix);
3153 // restore other state to normal
3154 R_Shadow_RenderMode_End();
3158 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
3159 typedef struct suffixinfo_s
3162 qboolean flipx, flipy, flipdiagonal;
3165 static suffixinfo_t suffix[3][6] =
3168 {"px", false, false, false},
3169 {"nx", false, false, false},
3170 {"py", false, false, false},
3171 {"ny", false, false, false},
3172 {"pz", false, false, false},
3173 {"nz", false, false, false}
3176 {"posx", false, false, false},
3177 {"negx", false, false, false},
3178 {"posy", false, false, false},
3179 {"negy", false, false, false},
3180 {"posz", false, false, false},
3181 {"negz", false, false, false}
3184 {"rt", true, false, true},
3185 {"lf", false, true, true},
3186 {"ft", true, true, false},
3187 {"bk", false, false, false},
3188 {"up", true, false, true},
3189 {"dn", true, false, true}
3193 static int componentorder[4] = {0, 1, 2, 3};
3195 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
3197 int i, j, cubemapsize;
3198 unsigned char *cubemappixels, *image_rgba;
3199 rtexture_t *cubemaptexture;
3201 // must start 0 so the first loadimagepixels has no requested width/height
3203 cubemappixels = NULL;
3204 cubemaptexture = NULL;
3205 // keep trying different suffix groups (posx, px, rt) until one loads
3206 for (j = 0;j < 3 && !cubemappixels;j++)
3208 // load the 6 images in the suffix group
3209 for (i = 0;i < 6;i++)
3211 // generate an image name based on the base and and suffix
3212 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
3214 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
3216 // an image loaded, make sure width and height are equal
3217 if (image_width == image_height)
3219 // if this is the first image to load successfully, allocate the cubemap memory
3220 if (!cubemappixels && image_width >= 1)
3222 cubemapsize = image_width;
3223 // note this clears to black, so unavailable sides are black
3224 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
3226 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
3228 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);
3231 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
3233 Mem_Free(image_rgba);
3237 // if a cubemap loaded, upload it
3240 if (!r_shadow_filters_texturepool)
3241 r_shadow_filters_texturepool = R_AllocTexturePool();
3242 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
3243 Mem_Free(cubemappixels);
3247 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
3248 for (j = 0;j < 3;j++)
3249 for (i = 0;i < 6;i++)
3250 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
3251 Con_Print(" and was unable to find any of them.\n");
3253 return cubemaptexture;
3256 rtexture_t *R_Shadow_Cubemap(const char *basename)
3259 for (i = 0;i < numcubemaps;i++)
3260 if (!strcasecmp(cubemaps[i].basename, basename))
3261 return cubemaps[i].texture;
3262 if (i >= MAX_CUBEMAPS)
3263 return r_texture_whitecube;
3265 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
3266 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
3267 if (!cubemaps[i].texture)
3268 cubemaps[i].texture = r_texture_whitecube;
3269 return cubemaps[i].texture;
3272 void R_Shadow_FreeCubemaps(void)
3275 R_FreeTexturePool(&r_shadow_filters_texturepool);
3278 dlight_t *R_Shadow_NewWorldLight(void)
3281 light = (dlight_t *)Mem_Alloc(r_main_mempool, sizeof(dlight_t));
3282 light->next = r_shadow_worldlightchain;
3283 r_shadow_worldlightchain = light;
3287 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)
3290 // validate parameters
3291 if (style < 0 || style >= MAX_LIGHTSTYLES)
3293 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
3299 // copy to light properties
3300 VectorCopy(origin, light->origin);
3301 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
3302 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
3303 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
3304 light->color[0] = max(color[0], 0);
3305 light->color[1] = max(color[1], 0);
3306 light->color[2] = max(color[2], 0);
3307 light->radius = max(radius, 0);
3308 light->style = style;
3309 light->shadow = shadowenable;
3310 light->corona = corona;
3311 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
3312 light->coronasizescale = coronasizescale;
3313 light->ambientscale = ambientscale;
3314 light->diffusescale = diffusescale;
3315 light->specularscale = specularscale;
3316 light->flags = flags;
3318 // update renderable light data
3319 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
3320 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);
3323 void R_Shadow_FreeWorldLight(dlight_t *light)
3325 dlight_t **lightpointer;
3326 R_RTLight_Uncompile(&light->rtlight);
3327 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
3328 if (*lightpointer != light)
3329 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain");
3330 *lightpointer = light->next;
3334 void R_Shadow_ClearWorldLights(void)
3336 while (r_shadow_worldlightchain)
3337 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
3338 r_shadow_selectedlight = NULL;
3339 R_Shadow_FreeCubemaps();
3342 void R_Shadow_SelectLight(dlight_t *light)
3344 if (r_shadow_selectedlight)
3345 r_shadow_selectedlight->selected = false;
3346 r_shadow_selectedlight = light;
3347 if (r_shadow_selectedlight)
3348 r_shadow_selectedlight->selected = true;
3351 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
3353 // this is never batched (there can be only one)
3354 float scale = r_editlights_cursorgrid.value * 0.5f;
3355 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);
3358 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
3360 // this is never batched (due to the ent parameter changing every time)
3361 // so numsurfaces == 1 and surfacelist[0] == lightnumber
3363 const dlight_t *light = (dlight_t *)ent;
3365 if (light->selected)
3366 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
3369 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);
3372 void R_Shadow_DrawLightSprites(void)
3377 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
3378 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 1+(i % 5), &light->rtlight);
3379 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
3382 void R_Shadow_SelectLightInView(void)
3384 float bestrating, rating, temp[3];
3385 dlight_t *best, *light;
3388 for (light = r_shadow_worldlightchain;light;light = light->next)
3390 VectorSubtract(light->origin, r_view.origin, temp);
3391 rating = (DotProduct(temp, r_view.forward) / sqrt(DotProduct(temp, temp)));
3394 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
3395 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)
3397 bestrating = rating;
3402 R_Shadow_SelectLight(best);
3405 void R_Shadow_LoadWorldLights(void)
3407 int n, a, style, shadow, flags;
3408 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
3409 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
3410 if (r_refdef.worldmodel == NULL)
3412 Con_Print("No map loaded.\n");
3415 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3416 strlcat (name, ".rtlights", sizeof (name));
3417 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3427 for (;COM_Parse(t, true) && strcmp(
3428 if (COM_Parse(t, true))
3430 if (com_token[0] == '!')
3433 origin[0] = atof(com_token+1);
3436 origin[0] = atof(com_token);
3441 while (*s && *s != '\n' && *s != '\r')
3447 // check for modifier flags
3454 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);
3457 flags = LIGHTFLAG_REALTIMEMODE;
3465 coronasizescale = 0.25f;
3467 VectorClear(angles);
3470 if (a < 9 || !strcmp(cubemapname, "\"\""))
3472 // remove quotes on cubemapname
3473 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
3476 namelen = strlen(cubemapname) - 2;
3477 memmove(cubemapname, cubemapname + 1, namelen);
3478 cubemapname[namelen] = '\0';
3482 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);
3485 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3493 Con_Printf("invalid rtlights file \"%s\"\n", name);
3494 Mem_Free(lightsstring);
3498 void R_Shadow_SaveWorldLights(void)
3501 size_t bufchars, bufmaxchars;
3503 char name[MAX_QPATH];
3504 char line[MAX_INPUTLINE];
3505 if (!r_shadow_worldlightchain)
3507 if (r_refdef.worldmodel == NULL)
3509 Con_Print("No map loaded.\n");
3512 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3513 strlcat (name, ".rtlights", sizeof (name));
3514 bufchars = bufmaxchars = 0;
3516 for (light = r_shadow_worldlightchain;light;light = light->next)
3518 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3519 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);
3520 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3521 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]);
3523 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);
3524 if (bufchars + strlen(line) > bufmaxchars)
3526 bufmaxchars = bufchars + strlen(line) + 2048;
3528 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
3532 memcpy(buf, oldbuf, bufchars);
3538 memcpy(buf + bufchars, line, strlen(line));
3539 bufchars += strlen(line);
3543 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
3548 void R_Shadow_LoadLightsFile(void)
3551 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3552 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3553 if (r_refdef.worldmodel == NULL)
3555 Con_Print("No map loaded.\n");
3558 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3559 strlcat (name, ".lights", sizeof (name));
3560 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3568 while (*s && *s != '\n' && *s != '\r')
3574 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);
3578 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);
3581 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3582 radius = bound(15, radius, 4096);
3583 VectorScale(color, (2.0f / (8388608.0f)), color);
3584 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3592 Con_Printf("invalid lights file \"%s\"\n", name);
3593 Mem_Free(lightsstring);
3597 // tyrlite/hmap2 light types in the delay field
3598 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3600 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3602 int entnum, style, islight, skin, pflags, effects, type, n;
3605 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3606 char key[256], value[MAX_INPUTLINE];
3608 if (r_refdef.worldmodel == NULL)
3610 Con_Print("No map loaded.\n");
3613 // try to load a .ent file first
3614 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3615 strlcat (key, ".ent", sizeof (key));
3616 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
3617 // and if that is not found, fall back to the bsp file entity string
3619 data = r_refdef.worldmodel->brush.entities;
3622 for (entnum = 0;COM_ParseToken_Simple(&data, false) && com_token[0] == '{';entnum++)
3624 type = LIGHTTYPE_MINUSX;
3625 origin[0] = origin[1] = origin[2] = 0;
3626 originhack[0] = originhack[1] = originhack[2] = 0;
3627 angles[0] = angles[1] = angles[2] = 0;
3628 color[0] = color[1] = color[2] = 1;
3629 light[0] = light[1] = light[2] = 1;light[3] = 300;
3630 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3640 if (!COM_ParseToken_Simple(&data, false))
3642 if (com_token[0] == '}')
3643 break; // end of entity
3644 if (com_token[0] == '_')
3645 strlcpy(key, com_token + 1, sizeof(key));
3647 strlcpy(key, com_token, sizeof(key));
3648 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3649 key[strlen(key)-1] = 0;
3650 if (!COM_ParseToken_Simple(&data, false))
3652 strlcpy(value, com_token, sizeof(value));
3654 // now that we have the key pair worked out...
3655 if (!strcmp("light", key))
3657 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3661 light[0] = vec[0] * (1.0f / 256.0f);
3662 light[1] = vec[0] * (1.0f / 256.0f);
3663 light[2] = vec[0] * (1.0f / 256.0f);
3669 light[0] = vec[0] * (1.0f / 255.0f);
3670 light[1] = vec[1] * (1.0f / 255.0f);
3671 light[2] = vec[2] * (1.0f / 255.0f);
3675 else if (!strcmp("delay", key))
3677 else if (!strcmp("origin", key))
3678 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3679 else if (!strcmp("angle", key))
3680 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3681 else if (!strcmp("angles", key))
3682 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3683 else if (!strcmp("color", key))
3684 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3685 else if (!strcmp("wait", key))
3686 fadescale = atof(value);
3687 else if (!strcmp("classname", key))
3689 if (!strncmp(value, "light", 5))
3692 if (!strcmp(value, "light_fluoro"))
3697 overridecolor[0] = 1;
3698 overridecolor[1] = 1;
3699 overridecolor[2] = 1;
3701 if (!strcmp(value, "light_fluorospark"))
3706 overridecolor[0] = 1;
3707 overridecolor[1] = 1;
3708 overridecolor[2] = 1;
3710 if (!strcmp(value, "light_globe"))
3715 overridecolor[0] = 1;
3716 overridecolor[1] = 0.8;
3717 overridecolor[2] = 0.4;
3719 if (!strcmp(value, "light_flame_large_yellow"))
3724 overridecolor[0] = 1;
3725 overridecolor[1] = 0.5;
3726 overridecolor[2] = 0.1;
3728 if (!strcmp(value, "light_flame_small_yellow"))
3733 overridecolor[0] = 1;
3734 overridecolor[1] = 0.5;
3735 overridecolor[2] = 0.1;
3737 if (!strcmp(value, "light_torch_small_white"))
3742 overridecolor[0] = 1;
3743 overridecolor[1] = 0.5;
3744 overridecolor[2] = 0.1;
3746 if (!strcmp(value, "light_torch_small_walltorch"))
3751 overridecolor[0] = 1;
3752 overridecolor[1] = 0.5;
3753 overridecolor[2] = 0.1;
3757 else if (!strcmp("style", key))
3758 style = atoi(value);
3759 else if (!strcmp("skin", key))
3760 skin = (int)atof(value);
3761 else if (!strcmp("pflags", key))
3762 pflags = (int)atof(value);
3763 else if (!strcmp("effects", key))
3764 effects = (int)atof(value);
3765 else if (r_refdef.worldmodel->type == mod_brushq3)
3767 if (!strcmp("scale", key))
3768 lightscale = atof(value);
3769 if (!strcmp("fade", key))
3770 fadescale = atof(value);
3775 if (lightscale <= 0)
3779 if (color[0] == color[1] && color[0] == color[2])
3781 color[0] *= overridecolor[0];
3782 color[1] *= overridecolor[1];
3783 color[2] *= overridecolor[2];
3785 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3786 color[0] = color[0] * light[0];
3787 color[1] = color[1] * light[1];
3788 color[2] = color[2] * light[2];
3791 case LIGHTTYPE_MINUSX:
3793 case LIGHTTYPE_RECIPX:
3795 VectorScale(color, (1.0f / 16.0f), color);
3797 case LIGHTTYPE_RECIPXX:
3799 VectorScale(color, (1.0f / 16.0f), color);
3802 case LIGHTTYPE_NONE:
3806 case LIGHTTYPE_MINUSXX:
3809 VectorAdd(origin, originhack, origin);
3811 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);
3814 Mem_Free(entfiledata);
3818 void R_Shadow_SetCursorLocationForView(void)
3821 vec3_t dest, endpos;
3823 VectorMA(r_view.origin, r_editlights_cursordistance.value, r_view.forward, dest);
3824 trace = CL_Move(r_view.origin, vec3_origin, vec3_origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
3825 if (trace.fraction < 1)
3827 dist = trace.fraction * r_editlights_cursordistance.value;
3828 push = r_editlights_cursorpushback.value;
3832 VectorMA(trace.endpos, push, r_view.forward, endpos);
3833 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
3837 VectorClear( endpos );
3839 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3840 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3841 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3844 void R_Shadow_UpdateWorldLightSelection(void)
3846 if (r_editlights.integer)
3848 R_Shadow_SetCursorLocationForView();
3849 R_Shadow_SelectLightInView();
3852 R_Shadow_SelectLight(NULL);
3855 void R_Shadow_EditLights_Clear_f(void)
3857 R_Shadow_ClearWorldLights();
3860 void R_Shadow_EditLights_Reload_f(void)
3862 if (!r_refdef.worldmodel)
3864 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3865 R_Shadow_ClearWorldLights();
3866 R_Shadow_LoadWorldLights();
3867 if (r_shadow_worldlightchain == NULL)
3869 R_Shadow_LoadLightsFile();
3870 if (r_shadow_worldlightchain == NULL)
3871 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3875 void R_Shadow_EditLights_Save_f(void)
3877 if (!r_refdef.worldmodel)
3879 R_Shadow_SaveWorldLights();
3882 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3884 R_Shadow_ClearWorldLights();
3885 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3888 void R_Shadow_EditLights_ImportLightsFile_f(void)
3890 R_Shadow_ClearWorldLights();
3891 R_Shadow_LoadLightsFile();
3894 void R_Shadow_EditLights_Spawn_f(void)
3897 if (!r_editlights.integer)
3899 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3902 if (Cmd_Argc() != 1)
3904 Con_Print("r_editlights_spawn does not take parameters\n");
3907 color[0] = color[1] = color[2] = 1;
3908 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3911 void R_Shadow_EditLights_Edit_f(void)
3913 vec3_t origin, angles, color;
3914 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3915 int style, shadows, flags, normalmode, realtimemode;
3916 char cubemapname[MAX_INPUTLINE];
3917 if (!r_editlights.integer)
3919 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3922 if (!r_shadow_selectedlight)
3924 Con_Print("No selected light.\n");
3927 VectorCopy(r_shadow_selectedlight->origin, origin);
3928 VectorCopy(r_shadow_selectedlight->angles, angles);
3929 VectorCopy(r_shadow_selectedlight->color, color);
3930 radius = r_shadow_selectedlight->radius;
3931 style = r_shadow_selectedlight->style;
3932 if (r_shadow_selectedlight->cubemapname)
3933 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
3936 shadows = r_shadow_selectedlight->shadow;
3937 corona = r_shadow_selectedlight->corona;
3938 coronasizescale = r_shadow_selectedlight->coronasizescale;
3939 ambientscale = r_shadow_selectedlight->ambientscale;
3940 diffusescale = r_shadow_selectedlight->diffusescale;
3941 specularscale = r_shadow_selectedlight->specularscale;
3942 flags = r_shadow_selectedlight->flags;
3943 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3944 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3945 if (!strcmp(Cmd_Argv(1), "origin"))
3947 if (Cmd_Argc() != 5)
3949 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3952 origin[0] = atof(Cmd_Argv(2));
3953 origin[1] = atof(Cmd_Argv(3));
3954 origin[2] = atof(Cmd_Argv(4));
3956 else if (!strcmp(Cmd_Argv(1), "originx"))
3958 if (Cmd_Argc() != 3)
3960 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3963 origin[0] = atof(Cmd_Argv(2));
3965 else if (!strcmp(Cmd_Argv(1), "originy"))
3967 if (Cmd_Argc() != 3)
3969 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3972 origin[1] = atof(Cmd_Argv(2));
3974 else if (!strcmp(Cmd_Argv(1), "originz"))
3976 if (Cmd_Argc() != 3)
3978 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3981 origin[2] = atof(Cmd_Argv(2));
3983 else if (!strcmp(Cmd_Argv(1), "move"))
3985 if (Cmd_Argc() != 5)
3987 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3990 origin[0] += atof(Cmd_Argv(2));
3991 origin[1] += atof(Cmd_Argv(3));
3992 origin[2] += atof(Cmd_Argv(4));
3994 else if (!strcmp(Cmd_Argv(1), "movex"))
3996 if (Cmd_Argc() != 3)
3998 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4001 origin[0] += atof(Cmd_Argv(2));
4003 else if (!strcmp(Cmd_Argv(1), "movey"))
4005 if (Cmd_Argc() != 3)
4007 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4010 origin[1] += atof(Cmd_Argv(2));
4012 else if (!strcmp(Cmd_Argv(1), "movez"))
4014 if (Cmd_Argc() != 3)
4016 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4019 origin[2] += atof(Cmd_Argv(2));
4021 else if (!strcmp(Cmd_Argv(1), "angles"))
4023 if (Cmd_Argc() != 5)
4025 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
4028 angles[0] = atof(Cmd_Argv(2));
4029 angles[1] = atof(Cmd_Argv(3));
4030 angles[2] = atof(Cmd_Argv(4));
4032 else if (!strcmp(Cmd_Argv(1), "anglesx"))
4034 if (Cmd_Argc() != 3)
4036 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4039 angles[0] = atof(Cmd_Argv(2));
4041 else if (!strcmp(Cmd_Argv(1), "anglesy"))
4043 if (Cmd_Argc() != 3)
4045 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4048 angles[1] = atof(Cmd_Argv(2));
4050 else if (!strcmp(Cmd_Argv(1), "anglesz"))
4052 if (Cmd_Argc() != 3)
4054 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4057 angles[2] = atof(Cmd_Argv(2));
4059 else if (!strcmp(Cmd_Argv(1), "color"))
4061 if (Cmd_Argc() != 5)
4063 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
4066 color[0] = atof(Cmd_Argv(2));
4067 color[1] = atof(Cmd_Argv(3));
4068 color[2] = atof(Cmd_Argv(4));
4070 else if (!strcmp(Cmd_Argv(1), "radius"))
4072 if (Cmd_Argc() != 3)
4074 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4077 radius = atof(Cmd_Argv(2));
4079 else if (!strcmp(Cmd_Argv(1), "colorscale"))
4081 if (Cmd_Argc() == 3)
4083 double scale = atof(Cmd_Argv(2));
4090 if (Cmd_Argc() != 5)
4092 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
4095 color[0] *= atof(Cmd_Argv(2));
4096 color[1] *= atof(Cmd_Argv(3));
4097 color[2] *= atof(Cmd_Argv(4));
4100 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
4102 if (Cmd_Argc() != 3)
4104 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4107 radius *= atof(Cmd_Argv(2));
4109 else if (!strcmp(Cmd_Argv(1), "style"))
4111 if (Cmd_Argc() != 3)
4113 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4116 style = atoi(Cmd_Argv(2));
4118 else if (!strcmp(Cmd_Argv(1), "cubemap"))
4122 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4125 if (Cmd_Argc() == 3)
4126 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
4130 else if (!strcmp(Cmd_Argv(1), "shadows"))
4132 if (Cmd_Argc() != 3)
4134 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4137 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4139 else if (!strcmp(Cmd_Argv(1), "corona"))
4141 if (Cmd_Argc() != 3)
4143 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4146 corona = atof(Cmd_Argv(2));
4148 else if (!strcmp(Cmd_Argv(1), "coronasize"))
4150 if (Cmd_Argc() != 3)
4152 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4155 coronasizescale = atof(Cmd_Argv(2));
4157 else if (!strcmp(Cmd_Argv(1), "ambient"))
4159 if (Cmd_Argc() != 3)
4161 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4164 ambientscale = atof(Cmd_Argv(2));
4166 else if (!strcmp(Cmd_Argv(1), "diffuse"))
4168 if (Cmd_Argc() != 3)
4170 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4173 diffusescale = atof(Cmd_Argv(2));
4175 else if (!strcmp(Cmd_Argv(1), "specular"))
4177 if (Cmd_Argc() != 3)
4179 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4182 specularscale = atof(Cmd_Argv(2));
4184 else if (!strcmp(Cmd_Argv(1), "normalmode"))
4186 if (Cmd_Argc() != 3)
4188 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4191 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4193 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
4195 if (Cmd_Argc() != 3)
4197 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4200 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4204 Con_Print("usage: r_editlights_edit [property] [value]\n");
4205 Con_Print("Selected light's properties:\n");
4206 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
4207 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
4208 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
4209 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
4210 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
4211 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
4212 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
4213 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
4214 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
4215 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
4216 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
4217 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
4218 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
4219 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
4222 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
4223 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4226 void R_Shadow_EditLights_EditAll_f(void)
4230 if (!r_editlights.integer)
4232 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
4236 for (light = r_shadow_worldlightchain;light;light = light->next)
4238 R_Shadow_SelectLight(light);
4239 R_Shadow_EditLights_Edit_f();
4243 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
4245 int lightnumber, lightcount;
4249 if (!r_editlights.integer)
4255 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
4256 if (light == r_shadow_selectedlight)
4257 lightnumber = lightcount;
4258 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;
4259 if (r_shadow_selectedlight == NULL)
4261 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
4262 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;
4263 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;
4264 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;
4265 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;
4266 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;
4267 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;
4268 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;
4269 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;
4270 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;
4271 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;
4272 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;
4273 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;
4274 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;
4275 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;
4278 void R_Shadow_EditLights_ToggleShadow_f(void)
4280 if (!r_editlights.integer)
4282 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4285 if (!r_shadow_selectedlight)
4287 Con_Print("No selected light.\n");
4290 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);
4293 void R_Shadow_EditLights_ToggleCorona_f(void)
4295 if (!r_editlights.integer)
4297 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4300 if (!r_shadow_selectedlight)
4302 Con_Print("No selected light.\n");
4305 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);
4308 void R_Shadow_EditLights_Remove_f(void)
4310 if (!r_editlights.integer)
4312 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
4315 if (!r_shadow_selectedlight)
4317 Con_Print("No selected light.\n");
4320 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
4321 r_shadow_selectedlight = NULL;
4324 void R_Shadow_EditLights_Help_f(void)
4327 "Documentation on r_editlights system:\n"
4329 "r_editlights : enable/disable editing mode\n"
4330 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
4331 "r_editlights_cursorpushback : push back cursor this far from surface\n"
4332 "r_editlights_cursorpushoff : push cursor off surface this far\n"
4333 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
4334 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
4336 "r_editlights_help : this help\n"
4337 "r_editlights_clear : remove all lights\n"
4338 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
4339 "r_editlights_save : save to .rtlights file\n"
4340 "r_editlights_spawn : create a light with default settings\n"
4341 "r_editlights_edit command : edit selected light - more documentation below\n"
4342 "r_editlights_remove : remove selected light\n"
4343 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
4344 "r_editlights_importlightentitiesfrommap : reload light entities\n"
4345 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
4347 "origin x y z : set light location\n"
4348 "originx x: set x component of light location\n"
4349 "originy y: set y component of light location\n"
4350 "originz z: set z component of light location\n"
4351 "move x y z : adjust light location\n"
4352 "movex x: adjust x component of light location\n"
4353 "movey y: adjust y component of light location\n"
4354 "movez z: adjust z component of light location\n"
4355 "angles x y z : set light angles\n"
4356 "anglesx x: set x component of light angles\n"
4357 "anglesy y: set y component of light angles\n"
4358 "anglesz z: set z component of light angles\n"
4359 "color r g b : set color of light (can be brighter than 1 1 1)\n"
4360 "radius radius : set radius (size) of light\n"
4361 "colorscale grey : multiply color of light (1 does nothing)\n"
4362 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
4363 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
4364 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
4365 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
4366 "cubemap basename : set filter cubemap of light (not yet supported)\n"
4367 "shadows 1/0 : turn on/off shadows\n"
4368 "corona n : set corona intensity\n"
4369 "coronasize n : set corona size (0-1)\n"
4370 "ambient n : set ambient intensity (0-1)\n"
4371 "diffuse n : set diffuse intensity (0-1)\n"
4372 "specular n : set specular intensity (0-1)\n"
4373 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
4374 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
4375 "<nothing> : print light properties to console\n"
4379 void R_Shadow_EditLights_CopyInfo_f(void)
4381 if (!r_editlights.integer)
4383 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
4386 if (!r_shadow_selectedlight)
4388 Con_Print("No selected light.\n");
4391 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
4392 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
4393 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
4394 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
4395 if (r_shadow_selectedlight->cubemapname)
4396 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
4398 r_shadow_bufferlight.cubemapname[0] = 0;
4399 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
4400 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
4401 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
4402 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
4403 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
4404 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
4405 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
4408 void R_Shadow_EditLights_PasteInfo_f(void)
4410 if (!r_editlights.integer)
4412 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
4415 if (!r_shadow_selectedlight)
4417 Con_Print("No selected light.\n");
4420 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);
4423 void R_Shadow_EditLights_Init(void)
4425 Cvar_RegisterVariable(&r_editlights);
4426 Cvar_RegisterVariable(&r_editlights_cursordistance);
4427 Cvar_RegisterVariable(&r_editlights_cursorpushback);
4428 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
4429 Cvar_RegisterVariable(&r_editlights_cursorgrid);
4430 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
4431 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
4432 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
4433 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)");
4434 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
4435 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
4436 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
4437 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)");
4438 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
4439 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
4440 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
4441 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
4442 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
4443 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
4444 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)");