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_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"};
232 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
233 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
234 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"};
235 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation"};
236 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation"};
237 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)"};
238 cvar_t r_shadow_culltriangles = {0, "r_shadow_culltriangles", "1", "performs more expensive tests to remove unnecessary triangles of lit surfaces"};
239 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
240 cvar_t r_shadow_polygonoffset = {0, "r_shadow_polygonoffset", "1", "how much to push shadow volumes into the distance when rendering, to reduce chances of zfighting artifacts (should not be less than 0)"};
241 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)"};
242 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
243 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
244 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
245 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
246 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
247 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
248 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
249 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
251 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
252 #define ATTENTABLESIZE 256
253 // 1D gradient, 2D circle and 3D sphere attenuation textures
254 #define ATTEN1DSIZE 32
255 #define ATTEN2DSIZE 64
256 #define ATTEN3DSIZE 32
258 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
259 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
260 static float r_shadow_attentable[ATTENTABLESIZE+1];
262 rtlight_t *r_shadow_compilingrtlight;
263 dlight_t *r_shadow_worldlightchain;
264 dlight_t *r_shadow_selectedlight;
265 dlight_t r_shadow_bufferlight;
266 vec3_t r_editlights_cursorlocation;
268 extern int con_vislines;
270 typedef struct cubemapinfo_s
277 #define MAX_CUBEMAPS 256
278 static int numcubemaps;
279 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
281 void R_Shadow_UncompileWorldLights(void);
282 void R_Shadow_ClearWorldLights(void);
283 void R_Shadow_SaveWorldLights(void);
284 void R_Shadow_LoadWorldLights(void);
285 void R_Shadow_LoadLightsFile(void);
286 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
287 void R_Shadow_EditLights_Reload_f(void);
288 void R_Shadow_ValidateCvars(void);
289 static void R_Shadow_MakeTextures(void);
291 void r_shadow_start(void)
293 // allocate vertex processing arrays
295 r_shadow_attenuationgradienttexture = NULL;
296 r_shadow_attenuation2dtexture = NULL;
297 r_shadow_attenuation3dtexture = NULL;
298 r_shadow_texturepool = NULL;
299 r_shadow_filters_texturepool = NULL;
300 R_Shadow_ValidateCvars();
301 R_Shadow_MakeTextures();
302 maxshadowtriangles = 0;
303 shadowelements = NULL;
304 maxshadowvertices = 0;
305 shadowvertex3f = NULL;
313 shadowmarklist = NULL;
315 r_shadow_buffer_numleafpvsbytes = 0;
316 r_shadow_buffer_leafpvs = NULL;
317 r_shadow_buffer_leaflist = NULL;
318 r_shadow_buffer_numsurfacepvsbytes = 0;
319 r_shadow_buffer_surfacepvs = NULL;
320 r_shadow_buffer_surfacelist = NULL;
321 r_shadow_buffer_numshadowtrispvsbytes = 0;
322 r_shadow_buffer_shadowtrispvs = NULL;
323 r_shadow_buffer_numlighttrispvsbytes = 0;
324 r_shadow_buffer_lighttrispvs = NULL;
327 void r_shadow_shutdown(void)
329 R_Shadow_UncompileWorldLights();
331 r_shadow_attenuationgradienttexture = NULL;
332 r_shadow_attenuation2dtexture = NULL;
333 r_shadow_attenuation3dtexture = NULL;
334 R_FreeTexturePool(&r_shadow_texturepool);
335 R_FreeTexturePool(&r_shadow_filters_texturepool);
336 maxshadowtriangles = 0;
338 Mem_Free(shadowelements);
339 shadowelements = NULL;
341 Mem_Free(shadowvertex3f);
342 shadowvertex3f = NULL;
345 Mem_Free(vertexupdate);
348 Mem_Free(vertexremap);
354 Mem_Free(shadowmark);
357 Mem_Free(shadowmarklist);
358 shadowmarklist = NULL;
360 r_shadow_buffer_numleafpvsbytes = 0;
361 if (r_shadow_buffer_leafpvs)
362 Mem_Free(r_shadow_buffer_leafpvs);
363 r_shadow_buffer_leafpvs = NULL;
364 if (r_shadow_buffer_leaflist)
365 Mem_Free(r_shadow_buffer_leaflist);
366 r_shadow_buffer_leaflist = NULL;
367 r_shadow_buffer_numsurfacepvsbytes = 0;
368 if (r_shadow_buffer_surfacepvs)
369 Mem_Free(r_shadow_buffer_surfacepvs);
370 r_shadow_buffer_surfacepvs = NULL;
371 if (r_shadow_buffer_surfacelist)
372 Mem_Free(r_shadow_buffer_surfacelist);
373 r_shadow_buffer_surfacelist = NULL;
374 r_shadow_buffer_numshadowtrispvsbytes = 0;
375 if (r_shadow_buffer_shadowtrispvs)
376 Mem_Free(r_shadow_buffer_shadowtrispvs);
377 r_shadow_buffer_numlighttrispvsbytes = 0;
378 if (r_shadow_buffer_lighttrispvs)
379 Mem_Free(r_shadow_buffer_lighttrispvs);
382 void r_shadow_newmap(void)
386 void R_Shadow_Help_f(void)
389 "Documentation on r_shadow system:\n"
391 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
392 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
393 "r_shadow_debuglight : render only this light number (-1 = all)\n"
394 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
395 "r_shadow_gloss2intensity : brightness of forced gloss\n"
396 "r_shadow_glossintensity : brightness of textured gloss\n"
397 "r_shadow_lightattenuationlinearscale : used to generate attenuation texture\n"
398 "r_shadow_lightattenuationdividebias : used to generate attenuation texture\n"
399 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
400 "r_shadow_lightradiusscale : scale rendering radius of all lights\n"
401 "r_shadow_portallight : use portal visibility for static light precomputation\n"
402 "r_shadow_projectdistance : shadow volume projection distance\n"
403 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
404 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
405 "r_shadow_realtime_world : use high quality world lighting mode\n"
406 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
407 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
408 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
409 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
410 "r_shadow_scissor : use scissor optimization\n"
411 "r_shadow_polygonfactor : nudge shadow volumes closer/further\n"
412 "r_shadow_polygonoffset : nudge shadow volumes closer/further\n"
413 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
414 "r_showlighting : useful for performance testing; bright = slow!\n"
415 "r_showshadowvolumes : useful for performance testing; bright = slow!\n"
417 "r_shadow_help : this help\n"
421 void R_Shadow_Init(void)
423 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
424 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
425 Cvar_RegisterVariable(&r_shadow_usenormalmap);
426 Cvar_RegisterVariable(&r_shadow_debuglight);
427 Cvar_RegisterVariable(&r_shadow_gloss);
428 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
429 Cvar_RegisterVariable(&r_shadow_glossintensity);
430 Cvar_RegisterVariable(&r_shadow_glossexponent);
431 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
432 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
433 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
434 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
435 Cvar_RegisterVariable(&r_shadow_portallight);
436 Cvar_RegisterVariable(&r_shadow_projectdistance);
437 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
438 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
439 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
440 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
441 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
442 Cvar_RegisterVariable(&r_shadow_realtime_world);
443 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
444 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
445 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
446 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
447 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
448 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
449 Cvar_RegisterVariable(&r_shadow_scissor);
450 Cvar_RegisterVariable(&r_shadow_culltriangles);
451 Cvar_RegisterVariable(&r_shadow_polygonfactor);
452 Cvar_RegisterVariable(&r_shadow_polygonoffset);
453 Cvar_RegisterVariable(&r_shadow_texture3d);
454 Cvar_RegisterVariable(&gl_ext_separatestencil);
455 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
456 if (gamemode == GAME_TENEBRAE)
458 Cvar_SetValue("r_shadow_gloss", 2);
459 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
461 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f, "prints documentation on console commands and variables used by realtime lighting and shadowing system");
462 R_Shadow_EditLights_Init();
463 r_shadow_worldlightchain = NULL;
464 maxshadowtriangles = 0;
465 shadowelements = NULL;
466 maxshadowvertices = 0;
467 shadowvertex3f = NULL;
475 shadowmarklist = NULL;
477 r_shadow_buffer_numleafpvsbytes = 0;
478 r_shadow_buffer_leafpvs = NULL;
479 r_shadow_buffer_leaflist = NULL;
480 r_shadow_buffer_numsurfacepvsbytes = 0;
481 r_shadow_buffer_surfacepvs = NULL;
482 r_shadow_buffer_surfacelist = NULL;
483 r_shadow_buffer_shadowtrispvs = NULL;
484 r_shadow_buffer_lighttrispvs = NULL;
485 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
488 matrix4x4_t matrix_attenuationxyz =
491 {0.5, 0.0, 0.0, 0.5},
492 {0.0, 0.5, 0.0, 0.5},
493 {0.0, 0.0, 0.5, 0.5},
498 matrix4x4_t matrix_attenuationz =
501 {0.0, 0.0, 0.5, 0.5},
502 {0.0, 0.0, 0.0, 0.5},
503 {0.0, 0.0, 0.0, 0.5},
508 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles)
510 // make sure shadowelements is big enough for this volume
511 if (maxshadowtriangles < numtriangles)
513 maxshadowtriangles = numtriangles;
515 Mem_Free(shadowelements);
516 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[24]));
518 // make sure shadowvertex3f is big enough for this volume
519 if (maxshadowvertices < numvertices)
521 maxshadowvertices = numvertices;
523 Mem_Free(shadowvertex3f);
524 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[6]));
528 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
530 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
531 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
532 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
533 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
534 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
536 if (r_shadow_buffer_leafpvs)
537 Mem_Free(r_shadow_buffer_leafpvs);
538 if (r_shadow_buffer_leaflist)
539 Mem_Free(r_shadow_buffer_leaflist);
540 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
541 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
542 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
544 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
546 if (r_shadow_buffer_surfacepvs)
547 Mem_Free(r_shadow_buffer_surfacepvs);
548 if (r_shadow_buffer_surfacelist)
549 Mem_Free(r_shadow_buffer_surfacelist);
550 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
551 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
552 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
554 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
556 if (r_shadow_buffer_shadowtrispvs)
557 Mem_Free(r_shadow_buffer_shadowtrispvs);
558 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
559 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
561 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
563 if (r_shadow_buffer_lighttrispvs)
564 Mem_Free(r_shadow_buffer_lighttrispvs);
565 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
566 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
570 void R_Shadow_PrepareShadowMark(int numtris)
572 // make sure shadowmark is big enough for this volume
573 if (maxshadowmark < numtris)
575 maxshadowmark = numtris;
577 Mem_Free(shadowmark);
579 Mem_Free(shadowmarklist);
580 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
581 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
585 // if shadowmarkcount wrapped we clear the array and adjust accordingly
586 if (shadowmarkcount == 0)
589 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
594 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)
597 int outtriangles = 0, outvertices = 0;
600 float ratio, direction[3], projectvector[3];
602 if (projectdirection)
603 VectorScale(projectdirection, projectdistance, projectvector);
605 VectorClear(projectvector);
607 if (maxvertexupdate < innumvertices)
609 maxvertexupdate = innumvertices;
611 Mem_Free(vertexupdate);
613 Mem_Free(vertexremap);
614 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
615 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
619 if (vertexupdatenum == 0)
622 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
623 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
626 for (i = 0;i < numshadowmarktris;i++)
627 shadowmark[shadowmarktris[i]] = shadowmarkcount;
629 // create the vertices
630 if (projectdirection)
632 for (i = 0;i < numshadowmarktris;i++)
634 element = inelement3i + shadowmarktris[i] * 3;
635 for (j = 0;j < 3;j++)
637 if (vertexupdate[element[j]] != vertexupdatenum)
639 vertexupdate[element[j]] = vertexupdatenum;
640 vertexremap[element[j]] = outvertices;
641 vertex = invertex3f + element[j] * 3;
642 // project one copy of the vertex according to projectvector
643 VectorCopy(vertex, outvertex3f);
644 VectorAdd(vertex, projectvector, (outvertex3f + 3));
653 for (i = 0;i < numshadowmarktris;i++)
655 element = inelement3i + shadowmarktris[i] * 3;
656 for (j = 0;j < 3;j++)
658 if (vertexupdate[element[j]] != vertexupdatenum)
660 vertexupdate[element[j]] = vertexupdatenum;
661 vertexremap[element[j]] = outvertices;
662 vertex = invertex3f + element[j] * 3;
663 // project one copy of the vertex to the sphere radius of the light
664 // (FIXME: would projecting it to the light box be better?)
665 VectorSubtract(vertex, projectorigin, direction);
666 ratio = projectdistance / VectorLength(direction);
667 VectorCopy(vertex, outvertex3f);
668 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
676 if (r_shadow_frontsidecasting.integer)
678 for (i = 0;i < numshadowmarktris;i++)
680 int remappedelement[3];
682 const int *neighbortriangle;
684 markindex = shadowmarktris[i] * 3;
685 element = inelement3i + markindex;
686 neighbortriangle = inneighbor3i + markindex;
687 // output the front and back triangles
688 outelement3i[0] = vertexremap[element[0]];
689 outelement3i[1] = vertexremap[element[1]];
690 outelement3i[2] = vertexremap[element[2]];
691 outelement3i[3] = vertexremap[element[2]] + 1;
692 outelement3i[4] = vertexremap[element[1]] + 1;
693 outelement3i[5] = vertexremap[element[0]] + 1;
697 // output the sides (facing outward from this triangle)
698 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
700 remappedelement[0] = vertexremap[element[0]];
701 remappedelement[1] = vertexremap[element[1]];
702 outelement3i[0] = remappedelement[1];
703 outelement3i[1] = remappedelement[0];
704 outelement3i[2] = remappedelement[0] + 1;
705 outelement3i[3] = remappedelement[1];
706 outelement3i[4] = remappedelement[0] + 1;
707 outelement3i[5] = remappedelement[1] + 1;
712 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
714 remappedelement[1] = vertexremap[element[1]];
715 remappedelement[2] = vertexremap[element[2]];
716 outelement3i[0] = remappedelement[2];
717 outelement3i[1] = remappedelement[1];
718 outelement3i[2] = remappedelement[1] + 1;
719 outelement3i[3] = remappedelement[2];
720 outelement3i[4] = remappedelement[1] + 1;
721 outelement3i[5] = remappedelement[2] + 1;
726 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
728 remappedelement[0] = vertexremap[element[0]];
729 remappedelement[2] = vertexremap[element[2]];
730 outelement3i[0] = remappedelement[0];
731 outelement3i[1] = remappedelement[2];
732 outelement3i[2] = remappedelement[2] + 1;
733 outelement3i[3] = remappedelement[0];
734 outelement3i[4] = remappedelement[2] + 1;
735 outelement3i[5] = remappedelement[0] + 1;
744 for (i = 0;i < numshadowmarktris;i++)
746 int remappedelement[3];
748 const int *neighbortriangle;
750 markindex = shadowmarktris[i] * 3;
751 element = inelement3i + markindex;
752 neighbortriangle = inneighbor3i + markindex;
753 // output the front and back triangles
754 outelement3i[0] = vertexremap[element[2]];
755 outelement3i[1] = vertexremap[element[1]];
756 outelement3i[2] = vertexremap[element[0]];
757 outelement3i[3] = vertexremap[element[0]] + 1;
758 outelement3i[4] = vertexremap[element[1]] + 1;
759 outelement3i[5] = vertexremap[element[2]] + 1;
763 // output the sides (facing outward from this triangle)
764 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
766 remappedelement[0] = vertexremap[element[0]];
767 remappedelement[1] = vertexremap[element[1]];
768 outelement3i[0] = remappedelement[0];
769 outelement3i[1] = remappedelement[1];
770 outelement3i[2] = remappedelement[1] + 1;
771 outelement3i[3] = remappedelement[0];
772 outelement3i[4] = remappedelement[1] + 1;
773 outelement3i[5] = remappedelement[0] + 1;
778 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
780 remappedelement[1] = vertexremap[element[1]];
781 remappedelement[2] = vertexremap[element[2]];
782 outelement3i[0] = remappedelement[1];
783 outelement3i[1] = remappedelement[2];
784 outelement3i[2] = remappedelement[2] + 1;
785 outelement3i[3] = remappedelement[1];
786 outelement3i[4] = remappedelement[2] + 1;
787 outelement3i[5] = remappedelement[1] + 1;
792 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
794 remappedelement[0] = vertexremap[element[0]];
795 remappedelement[2] = vertexremap[element[2]];
796 outelement3i[0] = remappedelement[2];
797 outelement3i[1] = remappedelement[0];
798 outelement3i[2] = remappedelement[0] + 1;
799 outelement3i[3] = remappedelement[2];
800 outelement3i[4] = remappedelement[0] + 1;
801 outelement3i[5] = remappedelement[2] + 1;
809 *outnumvertices = outvertices;
813 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)
816 if (projectdistance < 0.1)
818 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
821 if (!numverts || !nummarktris)
823 // make sure shadowelements is big enough for this volume
824 if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
825 R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
826 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
827 r_refdef.stats.lights_dynamicshadowtriangles += tris;
828 R_Shadow_RenderVolume(outverts, tris, shadowvertex3f, shadowelements);
831 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)
837 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
839 tend = firsttriangle + numtris;
840 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
842 // surface box entirely inside light box, no box cull
843 if (projectdirection)
845 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
847 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
848 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
849 shadowmarklist[numshadowmark++] = t;
854 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
855 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
856 shadowmarklist[numshadowmark++] = t;
861 // surface box not entirely inside light box, cull each triangle
862 if (projectdirection)
864 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
866 v[0] = invertex3f + e[0] * 3;
867 v[1] = invertex3f + e[1] * 3;
868 v[2] = invertex3f + e[2] * 3;
869 TriangleNormal(v[0], v[1], v[2], normal);
870 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
871 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
872 shadowmarklist[numshadowmark++] = t;
877 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
879 v[0] = invertex3f + e[0] * 3;
880 v[1] = invertex3f + e[1] * 3;
881 v[2] = invertex3f + e[2] * 3;
882 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
883 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
884 shadowmarklist[numshadowmark++] = t;
890 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
892 if (r_shadow_compilingrtlight)
894 // if we're compiling an rtlight, capture the mesh
895 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
898 r_refdef.stats.lights_shadowtriangles += numtriangles;
900 R_Mesh_VertexPointer(vertex3f, 0, 0);
901 GL_LockArrays(0, numvertices);
902 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
904 // decrement stencil if backface is behind depthbuffer
905 GL_CullFace(GL_BACK); // quake is backwards, this culls front faces
906 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
907 R_Mesh_Draw(0, numvertices, numtriangles, element3i, 0, 0);
908 // increment stencil if frontface is behind depthbuffer
909 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
910 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
912 R_Mesh_Draw(0, numvertices, numtriangles, element3i, 0, 0);
917 static unsigned char R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
919 float dist = sqrt(x*x+y*y+z*z);
920 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
921 return (unsigned char)bound(0, intensity * 256.0f, 255);
924 static void R_Shadow_MakeTextures(void)
927 float intensity, dist;
929 unsigned int palette[256];
930 R_FreeTexturePool(&r_shadow_texturepool);
931 r_shadow_texturepool = R_AllocTexturePool();
932 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
933 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
934 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
935 for (x = 0;x < 256;x++)
936 palette[x] = x * 0x01010101;
937 data = (unsigned char *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE));
938 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
939 for (x = 0;x <= ATTENTABLESIZE;x++)
941 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
942 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
943 r_shadow_attentable[x] = bound(0, intensity, 1);
945 // 1D gradient texture
946 for (x = 0;x < ATTEN1DSIZE;x++)
947 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
948 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, data, TEXTYPE_PALETTE, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, palette);
950 for (y = 0;y < ATTEN2DSIZE;y++)
951 for (x = 0;x < ATTEN2DSIZE;x++)
952 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);
953 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_PALETTE, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, palette);
955 if (r_shadow_texture3d.integer && gl_texture3d)
957 for (z = 0;z < ATTEN3DSIZE;z++)
958 for (y = 0;y < ATTEN3DSIZE;y++)
959 for (x = 0;x < ATTEN3DSIZE;x++)
960 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));
961 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_PALETTE, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, palette);
964 r_shadow_attenuation3dtexture = NULL;
968 void R_Shadow_ValidateCvars(void)
970 if (r_shadow_texture3d.integer && !gl_texture3d)
971 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
972 if (gl_ext_separatestencil.integer && !gl_support_separatestencil)
973 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
974 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
975 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
978 // light currently being rendered
979 rtlight_t *r_shadow_rtlight;
981 // this is the location of the light in entity space
982 vec3_t r_shadow_entitylightorigin;
983 // this transforms entity coordinates to light filter cubemap coordinates
984 // (also often used for other purposes)
985 matrix4x4_t r_shadow_entitytolight;
986 // based on entitytolight this transforms -1 to +1 to 0 to 1 for purposes
987 // of attenuation texturing in full 3D (Z result often ignored)
988 matrix4x4_t r_shadow_entitytoattenuationxyz;
989 // this transforms only the Z to S, and T is always 0.5
990 matrix4x4_t r_shadow_entitytoattenuationz;
992 void R_Shadow_RenderMode_Begin(void)
994 R_Shadow_ValidateCvars();
996 if (!r_shadow_attenuation2dtexture
997 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
998 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
999 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1000 R_Shadow_MakeTextures();
1003 R_Mesh_ColorPointer(NULL, 0, 0);
1004 R_Mesh_ResetTextureState();
1005 GL_BlendFunc(GL_ONE, GL_ZERO);
1006 GL_DepthRange(0, 1);
1008 GL_DepthMask(false);
1009 GL_Color(0, 0, 0, 1);
1010 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
1012 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1014 if (gl_ext_separatestencil.integer)
1015 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
1016 else if (gl_ext_stenciltwoside.integer)
1017 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
1019 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
1021 if (r_glsl.integer && gl_support_fragment_shader)
1022 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1023 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
1024 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
1026 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1029 void R_Shadow_RenderMode_ActiveLight(rtlight_t *rtlight)
1031 r_shadow_rtlight = rtlight;
1034 void R_Shadow_RenderMode_Reset(void)
1037 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1039 qglUseProgramObjectARB(0);CHECKGLERROR
1041 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
1043 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1045 R_Mesh_ColorPointer(NULL, 0, 0);
1046 R_Mesh_ResetTextureState();
1047 GL_DepthRange(0, 1);
1049 GL_DepthMask(false);
1050 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1051 qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1052 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1053 qglStencilMask(~0);CHECKGLERROR
1054 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1055 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1056 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
1057 GL_Color(1, 1, 1, 1);
1058 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
1059 GL_BlendFunc(GL_ONE, GL_ZERO);
1062 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean clearstencil)
1065 R_Shadow_RenderMode_Reset();
1066 GL_ColorMask(0, 0, 0, 0);
1067 qglPolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1068 qglDepthFunc(GL_LESS);CHECKGLERROR
1069 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1070 r_shadow_rendermode = r_shadow_shadowingrendermode;
1071 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SEPARATESTENCIL)
1073 GL_CullFace(GL_NONE);
1074 qglStencilOpSeparate(GL_BACK, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR // quake is backwards, this is front faces
1075 qglStencilOpSeparate(GL_FRONT, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR // quake is backwards, this is back faces
1077 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
1079 GL_CullFace(GL_NONE);
1080 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1081 qglActiveStencilFaceEXT(GL_BACK);CHECKGLERROR // quake is backwards, this is front faces
1082 qglStencilMask(~0);CHECKGLERROR
1083 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1084 qglActiveStencilFaceEXT(GL_FRONT);CHECKGLERROR // quake is backwards, this is back faces
1085 qglStencilMask(~0);CHECKGLERROR
1086 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1089 GL_Clear(GL_STENCIL_BUFFER_BIT);
1090 r_refdef.stats.lights_clears++;
1093 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent)
1096 R_Shadow_RenderMode_Reset();
1097 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1100 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1104 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1105 // only draw light where this geometry was already rendered AND the
1106 // stencil is 128 (values other than this mean shadow)
1107 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1109 r_shadow_rendermode = r_shadow_lightingrendermode;
1110 // do global setup needed for the chosen lighting mode
1111 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1113 R_Mesh_TexBind(0, R_GetTexture(r_texture_blanknormalmap)); // normal
1114 R_Mesh_TexBind(1, R_GetTexture(r_texture_white)); // diffuse
1115 R_Mesh_TexBind(2, R_GetTexture(r_texture_white)); // gloss
1116 R_Mesh_TexBindCubeMap(3, R_GetTexture(r_shadow_rtlight->currentcubemap)); // light filter
1117 R_Mesh_TexBind(4, R_GetTexture(r_texture_fogattenuation)); // fog
1118 R_Mesh_TexBind(5, R_GetTexture(r_texture_white)); // pants
1119 R_Mesh_TexBind(6, R_GetTexture(r_texture_white)); // shirt
1120 R_Mesh_TexBind(7, R_GetTexture(r_texture_white)); // lightmap
1121 R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap)); // deluxemap
1122 R_Mesh_TexBind(9, R_GetTexture(r_texture_black)); // glow
1123 //R_Mesh_TexMatrix(3, r_shadow_entitytolight); // light filter matrix
1124 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1125 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 0);
1130 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
1133 R_Shadow_RenderMode_Reset();
1134 GL_BlendFunc(GL_ONE, GL_ONE);
1135 GL_DepthRange(0, 1);
1136 GL_DepthTest(r_showshadowvolumes.integer < 2);
1137 GL_Color(0.0, 0.0125 * r_view.colorscale, 0.1 * r_view.colorscale, 1);
1138 qglPolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1139 GL_CullFace(GL_NONE);
1140 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
1143 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
1146 R_Shadow_RenderMode_Reset();
1147 GL_BlendFunc(GL_ONE, GL_ONE);
1148 GL_DepthRange(0, 1);
1149 GL_DepthTest(r_showlighting.integer < 2);
1150 GL_Color(0.1 * r_view.colorscale, 0.0125 * r_view.colorscale, 0, 1);
1153 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1157 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1158 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1160 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
1163 void R_Shadow_RenderMode_End(void)
1166 R_Shadow_RenderMode_Reset();
1167 R_Shadow_RenderMode_ActiveLight(NULL);
1169 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
1170 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1173 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1175 int i, ix1, iy1, ix2, iy2;
1176 float x1, y1, x2, y2;
1179 mplane_t planes[11];
1180 float vertex3f[256*3];
1182 // if view is inside the light box, just say yes it's visible
1183 if (BoxesOverlap(r_view.origin, r_view.origin, mins, maxs))
1185 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
1189 // create a temporary brush describing the area the light can affect in worldspace
1190 VectorNegate(r_view.frustum[0].normal, planes[ 0].normal);planes[ 0].dist = -r_view.frustum[0].dist;
1191 VectorNegate(r_view.frustum[1].normal, planes[ 1].normal);planes[ 1].dist = -r_view.frustum[1].dist;
1192 VectorNegate(r_view.frustum[2].normal, planes[ 2].normal);planes[ 2].dist = -r_view.frustum[2].dist;
1193 VectorNegate(r_view.frustum[3].normal, planes[ 3].normal);planes[ 3].dist = -r_view.frustum[3].dist;
1194 VectorNegate(r_view.frustum[4].normal, planes[ 4].normal);planes[ 4].dist = -r_view.frustum[4].dist;
1195 VectorSet (planes[ 5].normal, 1, 0, 0); planes[ 5].dist = maxs[0];
1196 VectorSet (planes[ 6].normal, -1, 0, 0); planes[ 6].dist = -mins[0];
1197 VectorSet (planes[ 7].normal, 0, 1, 0); planes[ 7].dist = maxs[1];
1198 VectorSet (planes[ 8].normal, 0, -1, 0); planes[ 8].dist = -mins[1];
1199 VectorSet (planes[ 9].normal, 0, 0, 1); planes[ 9].dist = maxs[2];
1200 VectorSet (planes[10].normal, 0, 0, -1); planes[10].dist = -mins[2];
1202 // turn the brush into a mesh
1203 memset(&mesh, 0, sizeof(rmesh_t));
1204 mesh.maxvertices = 256;
1205 mesh.vertex3f = vertex3f;
1206 mesh.epsilon2 = (1.0f / (32.0f * 32.0f));
1207 R_Mesh_AddBrushMeshFromPlanes(&mesh, 11, planes);
1209 // if that mesh is empty, the light is not visible at all
1210 if (!mesh.numvertices)
1213 if (!r_shadow_scissor.integer)
1216 // if that mesh is not empty, check what area of the screen it covers
1217 x1 = y1 = x2 = y2 = 0;
1219 //Con_Printf("%i vertices to transform...\n", mesh.numvertices);
1220 for (i = 0;i < mesh.numvertices;i++)
1222 VectorCopy(mesh.vertex3f + i * 3, v);
1223 GL_TransformToScreen(v, v2);
1224 //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]);
1227 if (x1 > v2[0]) x1 = v2[0];
1228 if (x2 < v2[0]) x2 = v2[0];
1229 if (y1 > v2[1]) y1 = v2[1];
1230 if (y2 < v2[1]) y2 = v2[1];
1239 // now convert the scissor rectangle to integer screen coordinates
1240 ix1 = (int)(x1 - 1.0f);
1241 iy1 = (int)(y1 - 1.0f);
1242 ix2 = (int)(x2 + 1.0f);
1243 iy2 = (int)(y2 + 1.0f);
1244 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1246 // clamp it to the screen
1247 if (ix1 < r_view.x) ix1 = r_view.x;
1248 if (iy1 < r_view.y) iy1 = r_view.y;
1249 if (ix2 > r_view.x + r_view.width) ix2 = r_view.x + r_view.width;
1250 if (iy2 > r_view.y + r_view.height) iy2 = r_view.y + r_view.height;
1252 // if it is inside out, it's not visible
1253 if (ix2 <= ix1 || iy2 <= iy1)
1256 // the light area is visible, set up the scissor rectangle
1257 GL_Scissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1258 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);CHECKGLERROR
1259 //qglEnable(GL_SCISSOR_TEST);CHECKGLERROR
1260 r_refdef.stats.lights_scissored++;
1264 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
1266 float *vertex3f = rsurface_vertex3f + 3 * firstvertex;
1267 float *normal3f = rsurface_normal3f + 3 * firstvertex;
1268 float *color4f = rsurface_array_color4f + 4 * firstvertex;
1269 float dist, dot, distintensity, shadeintensity, v[3], n[3];
1270 if (r_textureunits.integer >= 3)
1272 if (VectorLength2(diffusecolor) > 0)
1274 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1276 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1277 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1278 if ((dot = DotProduct(n, v)) < 0)
1280 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1281 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
1284 VectorCopy(ambientcolor, color4f);
1285 if (r_refdef.fogenabled)
1288 f = FogPoint_Model(vertex3f);
1289 VectorScale(color4f, f, color4f);
1296 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1298 VectorCopy(ambientcolor, color4f);
1299 if (r_refdef.fogenabled)
1302 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1303 f = FogPoint_Model(vertex3f);
1304 VectorScale(color4f, f, color4f);
1310 else if (r_textureunits.integer >= 2)
1312 if (VectorLength2(diffusecolor) > 0)
1314 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1316 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1317 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1319 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1320 if ((dot = DotProduct(n, v)) < 0)
1322 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1323 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1324 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1325 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1329 color4f[0] = ambientcolor[0] * distintensity;
1330 color4f[1] = ambientcolor[1] * distintensity;
1331 color4f[2] = ambientcolor[2] * distintensity;
1333 if (r_refdef.fogenabled)
1336 f = FogPoint_Model(vertex3f);
1337 VectorScale(color4f, f, color4f);
1341 VectorClear(color4f);
1347 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1349 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1350 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1352 color4f[0] = ambientcolor[0] * distintensity;
1353 color4f[1] = ambientcolor[1] * distintensity;
1354 color4f[2] = ambientcolor[2] * distintensity;
1355 if (r_refdef.fogenabled)
1358 f = FogPoint_Model(vertex3f);
1359 VectorScale(color4f, f, color4f);
1363 VectorClear(color4f);
1370 if (VectorLength2(diffusecolor) > 0)
1372 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1374 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1375 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1377 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
1378 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1379 if ((dot = DotProduct(n, v)) < 0)
1381 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1382 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1383 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1384 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1388 color4f[0] = ambientcolor[0] * distintensity;
1389 color4f[1] = ambientcolor[1] * distintensity;
1390 color4f[2] = ambientcolor[2] * distintensity;
1392 if (r_refdef.fogenabled)
1395 f = FogPoint_Model(vertex3f);
1396 VectorScale(color4f, f, color4f);
1400 VectorClear(color4f);
1406 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1408 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1409 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1411 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
1412 color4f[0] = ambientcolor[0] * distintensity;
1413 color4f[1] = ambientcolor[1] * distintensity;
1414 color4f[2] = ambientcolor[2] * distintensity;
1415 if (r_refdef.fogenabled)
1418 f = FogPoint_Model(vertex3f);
1419 VectorScale(color4f, f, color4f);
1423 VectorClear(color4f);
1430 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1432 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
1435 float *out3f = rsurface_array_texcoord3f + 3 * firstvertex;
1436 const float *vertex3f = rsurface_vertex3f + 3 * firstvertex;
1437 const float *svector3f = rsurface_svector3f + 3 * firstvertex;
1438 const float *tvector3f = rsurface_tvector3f + 3 * firstvertex;
1439 const float *normal3f = rsurface_normal3f + 3 * firstvertex;
1441 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1443 VectorSubtract(r_shadow_entitylightorigin, vertex3f, lightdir);
1444 // the cubemap normalizes this for us
1445 out3f[0] = DotProduct(svector3f, lightdir);
1446 out3f[1] = DotProduct(tvector3f, lightdir);
1447 out3f[2] = DotProduct(normal3f, lightdir);
1451 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
1454 float *out3f = rsurface_array_texcoord3f + 3 * firstvertex;
1455 const float *vertex3f = rsurface_vertex3f + 3 * firstvertex;
1456 const float *svector3f = rsurface_svector3f + 3 * firstvertex;
1457 const float *tvector3f = rsurface_tvector3f + 3 * firstvertex;
1458 const float *normal3f = rsurface_normal3f + 3 * firstvertex;
1459 float lightdir[3], eyedir[3], halfdir[3];
1460 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1462 VectorSubtract(r_shadow_entitylightorigin, vertex3f, lightdir);
1463 VectorNormalize(lightdir);
1464 VectorSubtract(rsurface_modelorg, vertex3f, eyedir);
1465 VectorNormalize(eyedir);
1466 VectorAdd(lightdir, eyedir, halfdir);
1467 // the cubemap normalizes this for us
1468 out3f[0] = DotProduct(svector3f, halfdir);
1469 out3f[1] = DotProduct(tvector3f, halfdir);
1470 out3f[2] = DotProduct(normal3f, halfdir);
1474 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)
1476 // used to display how many times a surface is lit for level design purposes
1477 GL_Color(0.1 * r_view.colorscale, 0.025 * r_view.colorscale, 0, 1);
1478 R_Mesh_ColorPointer(NULL, 0, 0);
1479 R_Mesh_ResetTextureState();
1480 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1483 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)
1485 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
1486 R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale);
1487 R_Mesh_TexCoordPointer(0, 2, rsurface_model->surfmesh.data_texcoordtexture2f, rsurface_model->surfmesh.vbo, rsurface_model->surfmesh.vbooffset_texcoordtexture2f);
1488 R_Mesh_TexCoordPointer(1, 3, rsurface_svector3f, rsurface_svector3f_bufferobject, rsurface_svector3f_bufferoffset);
1489 R_Mesh_TexCoordPointer(2, 3, rsurface_tvector3f, rsurface_tvector3f_bufferobject, rsurface_tvector3f_bufferoffset);
1490 R_Mesh_TexCoordPointer(3, 3, rsurface_normal3f, rsurface_normal3f_bufferobject, rsurface_normal3f_bufferoffset);
1491 if (rsurface_texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1493 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1495 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1496 if (rsurface_texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1498 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1502 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)
1504 // shared final code for all the dot3 layers
1506 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 0);
1507 for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
1509 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
1510 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1514 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)
1517 // colorscale accounts for how much we multiply the brightness
1520 // mult is how many times the final pass of the lighting will be
1521 // performed to get more brightness than otherwise possible.
1523 // Limit mult to 64 for sanity sake.
1525 if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1527 // 3 3D combine path (Geforce3, Radeon 8500)
1528 memset(&m, 0, sizeof(m));
1529 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1530 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1531 m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
1532 m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
1533 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1534 m.tex[1] = R_GetTexture(basetexture);
1535 m.pointer_texcoord[1] = rsurface_model->surfmesh.data_texcoordtexture2f;
1536 m.pointer_texcoord_bufferobject[1] = rsurface_model->surfmesh.vbo;
1537 m.pointer_texcoord_bufferoffset[1] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1538 m.texmatrix[1] = rsurface_texture->currenttexmatrix;
1539 m.texcubemap[2] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1540 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1541 m.pointer_texcoord_bufferobject[2] = rsurface_vertex3f_bufferobject;
1542 m.pointer_texcoord_bufferoffset[2] = rsurface_vertex3f_bufferoffset;
1543 m.texmatrix[2] = r_shadow_entitytolight;
1544 GL_BlendFunc(GL_ONE, GL_ONE);
1546 else if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1548 // 2 3D combine path (Geforce3, original Radeon)
1549 memset(&m, 0, sizeof(m));
1550 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1551 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1552 m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
1553 m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
1554 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1555 m.tex[1] = R_GetTexture(basetexture);
1556 m.pointer_texcoord[1] = rsurface_model->surfmesh.data_texcoordtexture2f;
1557 m.pointer_texcoord_bufferobject[1] = rsurface_model->surfmesh.vbo;
1558 m.pointer_texcoord_bufferoffset[1] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1559 m.texmatrix[1] = rsurface_texture->currenttexmatrix;
1560 GL_BlendFunc(GL_ONE, GL_ONE);
1562 else if (r_textureunits.integer >= 4 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1564 // 4 2D combine path (Geforce3, Radeon 8500)
1565 memset(&m, 0, sizeof(m));
1566 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1567 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1568 m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
1569 m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
1570 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1571 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1572 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1573 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1574 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1575 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1576 m.tex[2] = R_GetTexture(basetexture);
1577 m.pointer_texcoord[2] = rsurface_model->surfmesh.data_texcoordtexture2f;
1578 m.pointer_texcoord_bufferobject[2] = rsurface_model->surfmesh.vbo;
1579 m.pointer_texcoord_bufferoffset[2] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1580 m.texmatrix[2] = rsurface_texture->currenttexmatrix;
1581 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1583 m.texcubemap[3] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1584 m.pointer_texcoord3f[3] = rsurface_vertex3f;
1585 m.pointer_texcoord_bufferobject[3] = rsurface_vertex3f_bufferobject;
1586 m.pointer_texcoord_bufferoffset[3] = rsurface_vertex3f_bufferoffset;
1587 m.texmatrix[3] = r_shadow_entitytolight;
1589 GL_BlendFunc(GL_ONE, GL_ONE);
1591 else if (r_textureunits.integer >= 3 && r_shadow_rtlight->currentcubemap == r_texture_whitecube)
1593 // 3 2D combine path (Geforce3, original Radeon)
1594 memset(&m, 0, sizeof(m));
1595 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1596 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1597 m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
1598 m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
1599 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1600 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1601 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1602 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1603 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1604 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1605 m.tex[2] = R_GetTexture(basetexture);
1606 m.pointer_texcoord[2] = rsurface_model->surfmesh.data_texcoordtexture2f;
1607 m.pointer_texcoord_bufferobject[2] = rsurface_model->surfmesh.vbo;
1608 m.pointer_texcoord_bufferoffset[2] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1609 m.texmatrix[2] = rsurface_texture->currenttexmatrix;
1610 GL_BlendFunc(GL_ONE, GL_ONE);
1614 // 2/2/2 2D combine path (any dot3 card)
1615 memset(&m, 0, sizeof(m));
1616 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1617 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1618 m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
1619 m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
1620 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1621 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1622 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1623 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1624 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1625 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1626 R_Mesh_TextureState(&m);
1627 GL_ColorMask(0,0,0,1);
1628 GL_BlendFunc(GL_ONE, GL_ZERO);
1629 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1632 memset(&m, 0, sizeof(m));
1633 m.tex[0] = R_GetTexture(basetexture);
1634 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1635 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1636 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1637 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1638 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1640 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1641 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1642 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1643 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1644 m.texmatrix[1] = r_shadow_entitytolight;
1646 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1648 // this final code is shared
1649 R_Mesh_TextureState(&m);
1650 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1653 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)
1656 // colorscale accounts for how much we multiply the brightness
1659 // mult is how many times the final pass of the lighting will be
1660 // performed to get more brightness than otherwise possible.
1662 // Limit mult to 64 for sanity sake.
1664 // generate normalization cubemap texcoords
1665 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
1666 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1668 // 3/2 3D combine path (Geforce3, Radeon 8500)
1669 memset(&m, 0, sizeof(m));
1670 m.tex[0] = R_GetTexture(normalmaptexture);
1671 m.texcombinergb[0] = GL_REPLACE;
1672 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1673 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1674 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1675 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1676 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1677 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1678 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1679 m.pointer_texcoord_bufferobject[1] = 0;
1680 m.pointer_texcoord_bufferoffset[1] = 0;
1681 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1682 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1683 m.pointer_texcoord_bufferobject[2] = rsurface_vertex3f_bufferobject;
1684 m.pointer_texcoord_bufferoffset[2] = rsurface_vertex3f_bufferoffset;
1685 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
1686 R_Mesh_TextureState(&m);
1687 GL_ColorMask(0,0,0,1);
1688 GL_BlendFunc(GL_ONE, GL_ZERO);
1689 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1692 memset(&m, 0, sizeof(m));
1693 m.tex[0] = R_GetTexture(basetexture);
1694 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1695 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1696 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1697 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1698 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1700 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1701 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1702 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1703 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1704 m.texmatrix[1] = r_shadow_entitytolight;
1706 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1708 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1710 // 1/2/2 3D combine path (original Radeon)
1711 memset(&m, 0, sizeof(m));
1712 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1713 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1714 m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
1715 m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
1716 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1717 R_Mesh_TextureState(&m);
1718 GL_ColorMask(0,0,0,1);
1719 GL_BlendFunc(GL_ONE, GL_ZERO);
1720 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1723 memset(&m, 0, sizeof(m));
1724 m.tex[0] = R_GetTexture(normalmaptexture);
1725 m.texcombinergb[0] = GL_REPLACE;
1726 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1727 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1728 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1729 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1730 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1731 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1732 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1733 m.pointer_texcoord_bufferobject[1] = 0;
1734 m.pointer_texcoord_bufferoffset[1] = 0;
1735 R_Mesh_TextureState(&m);
1736 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1737 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1740 memset(&m, 0, sizeof(m));
1741 m.tex[0] = R_GetTexture(basetexture);
1742 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1743 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1744 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1745 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1746 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1748 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1749 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1750 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1751 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1752 m.texmatrix[1] = r_shadow_entitytolight;
1754 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1756 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap == r_texture_whitecube)
1758 // 2/2 3D combine path (original Radeon)
1759 memset(&m, 0, sizeof(m));
1760 m.tex[0] = R_GetTexture(normalmaptexture);
1761 m.texcombinergb[0] = GL_REPLACE;
1762 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1763 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1764 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1765 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1766 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1767 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1768 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1769 m.pointer_texcoord_bufferobject[1] = 0;
1770 m.pointer_texcoord_bufferoffset[1] = 0;
1771 R_Mesh_TextureState(&m);
1772 GL_ColorMask(0,0,0,1);
1773 GL_BlendFunc(GL_ONE, GL_ZERO);
1774 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1777 memset(&m, 0, sizeof(m));
1778 m.tex[0] = R_GetTexture(basetexture);
1779 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1780 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1781 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1782 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1783 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1784 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1785 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1786 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1787 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
1788 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1790 else if (r_textureunits.integer >= 4)
1792 // 4/2 2D combine path (Geforce3, Radeon 8500)
1793 memset(&m, 0, sizeof(m));
1794 m.tex[0] = R_GetTexture(normalmaptexture);
1795 m.texcombinergb[0] = GL_REPLACE;
1796 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1797 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1798 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1799 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1800 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1801 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1802 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1803 m.pointer_texcoord_bufferobject[1] = 0;
1804 m.pointer_texcoord_bufferoffset[1] = 0;
1805 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1806 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1807 m.pointer_texcoord_bufferobject[2] = rsurface_vertex3f_bufferobject;
1808 m.pointer_texcoord_bufferoffset[2] = rsurface_vertex3f_bufferoffset;
1809 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
1810 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1811 m.pointer_texcoord3f[3] = rsurface_vertex3f;
1812 m.pointer_texcoord_bufferobject[3] = rsurface_vertex3f_bufferobject;
1813 m.pointer_texcoord_bufferoffset[3] = rsurface_vertex3f_bufferoffset;
1814 m.texmatrix[3] = r_shadow_entitytoattenuationz;
1815 R_Mesh_TextureState(&m);
1816 GL_ColorMask(0,0,0,1);
1817 GL_BlendFunc(GL_ONE, GL_ZERO);
1818 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1821 memset(&m, 0, sizeof(m));
1822 m.tex[0] = R_GetTexture(basetexture);
1823 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1824 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1825 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1826 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1827 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1829 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1830 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1831 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1832 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1833 m.texmatrix[1] = r_shadow_entitytolight;
1835 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1839 // 2/2/2 2D combine path (any dot3 card)
1840 memset(&m, 0, sizeof(m));
1841 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1842 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1843 m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
1844 m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
1845 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1846 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1847 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1848 m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
1849 m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
1850 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1851 R_Mesh_TextureState(&m);
1852 GL_ColorMask(0,0,0,1);
1853 GL_BlendFunc(GL_ONE, GL_ZERO);
1854 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1857 memset(&m, 0, sizeof(m));
1858 m.tex[0] = R_GetTexture(normalmaptexture);
1859 m.texcombinergb[0] = GL_REPLACE;
1860 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1861 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1862 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1863 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1864 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1865 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1866 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1867 m.pointer_texcoord_bufferobject[1] = 0;
1868 m.pointer_texcoord_bufferoffset[1] = 0;
1869 R_Mesh_TextureState(&m);
1870 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1871 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1874 memset(&m, 0, sizeof(m));
1875 m.tex[0] = R_GetTexture(basetexture);
1876 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1877 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1878 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1879 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1880 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1882 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1883 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1884 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1885 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1886 m.texmatrix[1] = r_shadow_entitytolight;
1888 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1890 // this final code is shared
1891 R_Mesh_TextureState(&m);
1892 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1895 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)
1897 float glossexponent;
1899 // FIXME: detect blendsquare!
1900 //if (!gl_support_blendsquare)
1903 // generate normalization cubemap texcoords
1904 R_Shadow_GenTexCoords_Specular_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
1905 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1907 // 2/0/0/1/2 3D combine blendsquare path
1908 memset(&m, 0, sizeof(m));
1909 m.tex[0] = R_GetTexture(normalmaptexture);
1910 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1911 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1912 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1913 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1914 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1915 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1916 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1917 m.pointer_texcoord_bufferobject[1] = 0;
1918 m.pointer_texcoord_bufferoffset[1] = 0;
1919 R_Mesh_TextureState(&m);
1920 GL_ColorMask(0,0,0,1);
1921 // this squares the result
1922 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1923 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1925 // second and third pass
1926 R_Mesh_ResetTextureState();
1927 // square alpha in framebuffer a few times to make it shiny
1928 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1929 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
1930 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1933 memset(&m, 0, sizeof(m));
1934 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1935 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1936 m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
1937 m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
1938 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1939 R_Mesh_TextureState(&m);
1940 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1941 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1944 memset(&m, 0, sizeof(m));
1945 m.tex[0] = R_GetTexture(glosstexture);
1946 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1947 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1948 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1949 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1950 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1952 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1953 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1954 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1955 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1956 m.texmatrix[1] = r_shadow_entitytolight;
1958 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1960 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
1962 // 2/0/0/2 3D combine blendsquare path
1963 memset(&m, 0, sizeof(m));
1964 m.tex[0] = R_GetTexture(normalmaptexture);
1965 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1966 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1967 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1968 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1969 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1970 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1971 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1972 m.pointer_texcoord_bufferobject[1] = 0;
1973 m.pointer_texcoord_bufferoffset[1] = 0;
1974 R_Mesh_TextureState(&m);
1975 GL_ColorMask(0,0,0,1);
1976 // this squares the result
1977 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1978 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1980 // second and third pass
1981 R_Mesh_ResetTextureState();
1982 // square alpha in framebuffer a few times to make it shiny
1983 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1984 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
1985 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
1988 memset(&m, 0, sizeof(m));
1989 m.tex[0] = R_GetTexture(glosstexture);
1990 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1991 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
1992 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
1993 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1994 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1995 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1996 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
1997 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
1998 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
1999 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2003 // 2/0/0/2/2 2D combine blendsquare path
2004 memset(&m, 0, sizeof(m));
2005 m.tex[0] = R_GetTexture(normalmaptexture);
2006 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
2007 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
2008 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
2009 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
2010 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2011 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2012 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
2013 m.pointer_texcoord_bufferobject[1] = 0;
2014 m.pointer_texcoord_bufferoffset[1] = 0;
2015 R_Mesh_TextureState(&m);
2016 GL_ColorMask(0,0,0,1);
2017 // this squares the result
2018 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2019 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2021 // second and third pass
2022 R_Mesh_ResetTextureState();
2023 // square alpha in framebuffer a few times to make it shiny
2024 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2025 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2026 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2029 memset(&m, 0, sizeof(m));
2030 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2031 m.pointer_texcoord3f[0] = rsurface_vertex3f;
2032 m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject;
2033 m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset;
2034 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
2035 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2036 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2037 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
2038 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
2039 m.texmatrix[1] = r_shadow_entitytoattenuationz;
2040 R_Mesh_TextureState(&m);
2041 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2042 R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2045 memset(&m, 0, sizeof(m));
2046 m.tex[0] = R_GetTexture(glosstexture);
2047 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
2048 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
2049 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
2050 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
2051 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
2053 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
2054 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2055 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
2056 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
2057 m.texmatrix[1] = r_shadow_entitytolight;
2059 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2061 // this final code is shared
2062 R_Mesh_TextureState(&m);
2063 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
2066 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)
2068 // ARB path (any Geforce, any Radeon)
2069 qboolean doambient = ambientscale > 0;
2070 qboolean dodiffuse = diffusescale > 0;
2071 qboolean dospecular = specularscale > 0;
2072 if (!doambient && !dodiffuse && !dospecular)
2074 R_Mesh_ColorPointer(NULL, 0, 0);
2076 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, basetexture, ambientscale * r_view.colorscale);
2078 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, basetexture, normalmaptexture, diffusescale * r_view.colorscale);
2082 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorpants, pantstexture, ambientscale * r_view.colorscale);
2084 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorpants, pantstexture, normalmaptexture, diffusescale * r_view.colorscale);
2089 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorshirt, shirttexture, ambientscale * r_view.colorscale);
2091 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorshirt, shirttexture, normalmaptexture, diffusescale * r_view.colorscale);
2094 R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_view.colorscale);
2097 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)
2104 int newnumtriangles;
2108 int newelements[4096*3];
2109 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
2110 for (renders = 0;renders < 64;renders++)
2115 newnumtriangles = 0;
2117 // due to low fillrate on the cards this vertex lighting path is
2118 // designed for, we manually cull all triangles that do not
2119 // contain a lit vertex
2120 // this builds batches of triangles from multiple surfaces and
2121 // renders them at once
2122 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2124 if (VectorLength2(rsurface_array_color4f + e[0] * 4) + VectorLength2(rsurface_array_color4f + e[1] * 4) + VectorLength2(rsurface_array_color4f + e[2] * 4) >= 0.01)
2126 if (newnumtriangles)
2128 newfirstvertex = min(newfirstvertex, e[0]);
2129 newlastvertex = max(newlastvertex, e[0]);
2133 newfirstvertex = e[0];
2134 newlastvertex = e[0];
2136 newfirstvertex = min(newfirstvertex, e[1]);
2137 newlastvertex = max(newlastvertex, e[1]);
2138 newfirstvertex = min(newfirstvertex, e[2]);
2139 newlastvertex = max(newlastvertex, e[2]);
2145 if (newnumtriangles >= (int)(sizeof(newelements)/sizeof(float[3])))
2147 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, newnumtriangles, newelements, 0, 0);
2148 newnumtriangles = 0;
2154 if (newnumtriangles >= 1)
2156 // if all triangles are included, use the original array to take advantage of the bufferobject if possible
2157 if (newnumtriangles == numtriangles)
2158 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset);
2160 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, newnumtriangles, newelements, 0, 0);
2163 // if we couldn't find any lit triangles, exit early
2166 // now reduce the intensity for the next overbright pass
2167 // we have to clamp to 0 here incase the drivers have improper
2168 // handling of negative colors
2169 // (some old drivers even have improper handling of >1 color)
2171 for (i = 0, c = rsurface_array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2173 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2175 c[0] = max(0, c[0] - 1);
2176 c[1] = max(0, c[1] - 1);
2177 c[2] = max(0, c[2] - 1);
2189 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)
2191 // OpenGL 1.1 path (anything)
2192 const model_t *model = rsurface_model;
2193 float ambientcolorbase[3], diffusecolorbase[3];
2194 float ambientcolorpants[3], diffusecolorpants[3];
2195 float ambientcolorshirt[3], diffusecolorshirt[3];
2197 VectorScale(lightcolorbase, ambientscale * 2 * r_view.colorscale, ambientcolorbase);
2198 VectorScale(lightcolorbase, diffusescale * 2 * r_view.colorscale, diffusecolorbase);
2199 VectorScale(lightcolorpants, ambientscale * 2 * r_view.colorscale, ambientcolorpants);
2200 VectorScale(lightcolorpants, diffusescale * 2 * r_view.colorscale, diffusecolorpants);
2201 VectorScale(lightcolorshirt, ambientscale * 2 * r_view.colorscale, ambientcolorshirt);
2202 VectorScale(lightcolorshirt, diffusescale * 2 * r_view.colorscale, diffusecolorshirt);
2203 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2204 R_Mesh_ColorPointer(rsurface_array_color4f, 0, 0);
2205 memset(&m, 0, sizeof(m));
2206 m.tex[0] = R_GetTexture(basetexture);
2207 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
2208 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
2209 m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo;
2210 m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f;
2211 if (r_textureunits.integer >= 2)
2214 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2215 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2216 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2217 m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject;
2218 m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset;
2219 if (r_textureunits.integer >= 3)
2221 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
2222 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2223 m.texmatrix[2] = r_shadow_entitytoattenuationz;
2224 m.pointer_texcoord3f[2] = rsurface_vertex3f;
2225 m.pointer_texcoord_bufferobject[2] = rsurface_vertex3f_bufferobject;
2226 m.pointer_texcoord_bufferoffset[2] = rsurface_vertex3f_bufferoffset;
2229 R_Mesh_TextureState(&m);
2230 //R_Mesh_TexBind(0, R_GetTexture(basetexture));
2231 R_Shadow_RenderLighting_Light_Vertex_Pass(model, firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, diffusecolorbase, ambientcolorbase);
2234 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
2235 R_Shadow_RenderLighting_Light_Vertex_Pass(model, firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, diffusecolorpants, ambientcolorpants);
2239 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
2240 R_Shadow_RenderLighting_Light_Vertex_Pass(model, firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, diffusecolorshirt, ambientcolorshirt);
2244 void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset)
2246 float ambientscale, diffusescale, specularscale;
2247 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
2248 // calculate colors to render this texture with
2249 lightcolorbase[0] = r_shadow_rtlight->currentcolor[0] * rsurface_texture->currentlayers[0].color[0] * rsurface_texture->currentlayers[0].color[3];
2250 lightcolorbase[1] = r_shadow_rtlight->currentcolor[1] * rsurface_texture->currentlayers[0].color[1] * rsurface_texture->currentlayers[0].color[3];
2251 lightcolorbase[2] = r_shadow_rtlight->currentcolor[2] * rsurface_texture->currentlayers[0].color[2] * rsurface_texture->currentlayers[0].color[3];
2252 ambientscale = r_shadow_rtlight->ambientscale;
2253 diffusescale = r_shadow_rtlight->diffusescale;
2254 specularscale = r_shadow_rtlight->specularscale * rsurface_texture->specularscale;
2255 if (!r_shadow_usenormalmap.integer)
2257 ambientscale += 1.0f * diffusescale;
2261 if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
2263 GL_DepthRange(0, (rsurface_texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
2264 GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
2265 GL_CullFace((rsurface_texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
2266 if (rsurface_texture->colormapping)
2268 qboolean dopants = rsurface_texture->currentskinframe->pants != NULL && VectorLength2(rsurface_colormap_pantscolor) >= (1.0f / 1048576.0f);
2269 qboolean doshirt = rsurface_texture->currentskinframe->shirt != NULL && VectorLength2(rsurface_colormap_shirtcolor) >= (1.0f / 1048576.0f);
2272 lightcolorpants[0] = lightcolorbase[0] * rsurface_colormap_pantscolor[0];
2273 lightcolorpants[1] = lightcolorbase[1] * rsurface_colormap_pantscolor[1];
2274 lightcolorpants[2] = lightcolorbase[2] * rsurface_colormap_pantscolor[2];
2277 VectorClear(lightcolorpants);
2280 lightcolorshirt[0] = lightcolorbase[0] * rsurface_colormap_shirtcolor[0];
2281 lightcolorshirt[1] = lightcolorbase[1] * rsurface_colormap_shirtcolor[1];
2282 lightcolorshirt[2] = lightcolorbase[2] * rsurface_colormap_shirtcolor[2];
2285 VectorClear(lightcolorshirt);
2286 switch (r_shadow_rendermode)
2288 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2289 GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2290 R_Shadow_RenderLighting_VisibleLighting(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, 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);
2292 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2293 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);
2295 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2296 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);
2298 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2299 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);
2302 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2308 switch (r_shadow_rendermode)
2310 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2311 GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2312 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);
2314 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2315 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);
2317 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2318 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);
2320 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2321 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);
2324 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2330 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)
2332 matrix4x4_t tempmatrix = *matrix;
2333 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2335 // if this light has been compiled before, free the associated data
2336 R_RTLight_Uncompile(rtlight);
2338 // clear it completely to avoid any lingering data
2339 memset(rtlight, 0, sizeof(*rtlight));
2341 // copy the properties
2342 rtlight->matrix_lighttoworld = tempmatrix;
2343 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2344 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2345 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2346 VectorCopy(color, rtlight->color);
2347 rtlight->cubemapname[0] = 0;
2348 if (cubemapname && cubemapname[0])
2349 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2350 rtlight->shadow = shadow;
2351 rtlight->corona = corona;
2352 rtlight->style = style;
2353 rtlight->isstatic = isstatic;
2354 rtlight->coronasizescale = coronasizescale;
2355 rtlight->ambientscale = ambientscale;
2356 rtlight->diffusescale = diffusescale;
2357 rtlight->specularscale = specularscale;
2358 rtlight->flags = flags;
2360 // compute derived data
2361 //rtlight->cullradius = rtlight->radius;
2362 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2363 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2364 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2365 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2366 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2367 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2368 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2371 // compiles rtlight geometry
2372 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2373 void R_RTLight_Compile(rtlight_t *rtlight)
2376 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2377 int lighttris, shadowtris, shadowmeshes, shadowmeshtris;
2378 entity_render_t *ent = r_refdef.worldentity;
2379 model_t *model = r_refdef.worldmodel;
2380 unsigned char *data;
2382 // compile the light
2383 rtlight->compiled = true;
2384 rtlight->static_numleafs = 0;
2385 rtlight->static_numleafpvsbytes = 0;
2386 rtlight->static_leaflist = NULL;
2387 rtlight->static_leafpvs = NULL;
2388 rtlight->static_numsurfaces = 0;
2389 rtlight->static_surfacelist = NULL;
2390 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2391 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2392 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2393 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2394 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2395 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2397 if (model && model->GetLightInfo)
2399 // this variable must be set for the CompileShadowVolume code
2400 r_shadow_compilingrtlight = rtlight;
2401 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);
2402 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);
2403 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2404 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
2405 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
2406 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
2407 rtlight->static_numsurfaces = numsurfaces;
2408 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2409 rtlight->static_numleafs = numleafs;
2410 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2411 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2412 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2413 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
2414 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
2415 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
2416 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
2417 if (rtlight->static_numsurfaces)
2418 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2419 if (rtlight->static_numleafs)
2420 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2421 if (rtlight->static_numleafpvsbytes)
2422 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2423 if (rtlight->static_numshadowtrispvsbytes)
2424 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
2425 if (rtlight->static_numlighttrispvsbytes)
2426 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
2427 if (model->CompileShadowVolume && rtlight->shadow)
2428 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2429 // now we're done compiling the rtlight
2430 r_shadow_compilingrtlight = NULL;
2434 // use smallest available cullradius - box radius or light radius
2435 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2436 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2440 if (rtlight->static_meshchain_shadow)
2443 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2446 shadowmeshtris += mesh->numtriangles;
2451 if (rtlight->static_numlighttrispvsbytes)
2452 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
2453 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
2457 if (rtlight->static_numlighttrispvsbytes)
2458 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
2459 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
2462 if (developer.integer >= 10)
2463 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);
2466 void R_RTLight_Uncompile(rtlight_t *rtlight)
2468 if (rtlight->compiled)
2470 if (rtlight->static_meshchain_shadow)
2471 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2472 rtlight->static_meshchain_shadow = NULL;
2473 // these allocations are grouped
2474 if (rtlight->static_surfacelist)
2475 Mem_Free(rtlight->static_surfacelist);
2476 rtlight->static_numleafs = 0;
2477 rtlight->static_numleafpvsbytes = 0;
2478 rtlight->static_leaflist = NULL;
2479 rtlight->static_leafpvs = NULL;
2480 rtlight->static_numsurfaces = 0;
2481 rtlight->static_surfacelist = NULL;
2482 rtlight->static_numshadowtrispvsbytes = 0;
2483 rtlight->static_shadowtrispvs = NULL;
2484 rtlight->static_numlighttrispvsbytes = 0;
2485 rtlight->static_lighttrispvs = NULL;
2486 rtlight->compiled = false;
2490 void R_Shadow_UncompileWorldLights(void)
2493 for (light = r_shadow_worldlightchain;light;light = light->next)
2494 R_RTLight_Uncompile(&light->rtlight);
2497 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
2501 // reset the count of frustum planes
2502 // see r_shadow_rtlight_frustumplanes definition for how much this array
2504 r_shadow_rtlight_numfrustumplanes = 0;
2507 // generate a deformed frustum that includes the light origin, this is
2508 // used to cull shadow casting surfaces that can not possibly cast a
2509 // shadow onto the visible light-receiving surfaces, which can be a
2512 // if the light origin is onscreen the result will be 4 planes exactly
2513 // if the light origin is offscreen on only one axis the result will
2514 // be exactly 5 planes (split-side case)
2515 // if the light origin is offscreen on two axes the result will be
2516 // exactly 4 planes (stretched corner case)
2517 for (i = 0;i < 4;i++)
2519 // quickly reject standard frustum planes that put the light
2520 // origin outside the frustum
2521 if (PlaneDiff(rtlight->shadoworigin, &r_view.frustum[i]) < -0.03125)
2524 r_shadow_rtlight_frustumplanes[r_shadow_rtlight_numfrustumplanes++] = r_view.frustum[i];
2526 // if all the standard frustum planes were accepted, the light is onscreen
2527 // otherwise we need to generate some more planes below...
2528 if (r_shadow_rtlight_numfrustumplanes < 4)
2530 // at least one of the stock frustum planes failed, so we need to
2531 // create one or two custom planes to enclose the light origin
2532 for (i = 0;i < 4;i++)
2534 // create a plane using the view origin and light origin, and a
2535 // single point from the frustum corner set
2536 TriangleNormal(r_view.origin, r_view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
2537 VectorNormalize(plane.normal);
2538 plane.dist = DotProduct(r_view.origin, plane.normal);
2539 // see if this plane is backwards and flip it if so
2540 for (j = 0;j < 4;j++)
2541 if (j != i && DotProduct(r_view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
2545 VectorNegate(plane.normal, plane.normal);
2547 // flipped plane, test again to see if it is now valid
2548 for (j = 0;j < 4;j++)
2549 if (j != i && DotProduct(r_view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
2551 // if the plane is still not valid, then it is dividing the
2552 // frustum and has to be rejected
2556 // we have created a valid plane, compute extra info
2557 PlaneClassify(&plane);
2559 r_shadow_rtlight_frustumplanes[r_shadow_rtlight_numfrustumplanes++] = plane;
2561 // if we've found 5 frustum planes then we have constructed a
2562 // proper split-side case and do not need to keep searching for
2563 // planes to enclose the light origin
2564 if (r_shadow_rtlight_numfrustumplanes == 5)
2572 for (i = 0;i < r_shadow_rtlight_numfrustumplanes;i++)
2574 plane = r_shadow_rtlight_frustumplanes[i];
2575 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));
2580 // now add the light-space box planes if the light box is rotated, as any
2581 // caster outside the oriented light box is irrelevant (even if it passed
2582 // the worldspace light box, which is axial)
2583 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
2585 for (i = 0;i < 6;i++)
2589 v[i >> 1] = (i & 1) ? -1 : 1;
2590 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
2591 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
2592 plane.dist = VectorNormalizeLength(plane.normal);
2593 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
2594 r_shadow_rtlight_frustumplanes[r_shadow_rtlight_numfrustumplanes++] = plane;
2600 // add the world-space reduced box planes
2601 for (i = 0;i < 6;i++)
2603 VectorClear(plane.normal);
2604 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
2605 plane.dist = (i & 1) ? -r_shadow_rtlight_cullmaxs[i >> 1] : r_shadow_rtlight_cullmins[i >> 1];
2606 r_shadow_rtlight_frustumplanes[r_shadow_rtlight_numfrustumplanes++] = plane;
2615 // reduce all plane distances to tightly fit the rtlight cull box, which
2617 VectorSet(points[0], r_shadow_rtlight_cullmins[0], r_shadow_rtlight_cullmins[1], r_shadow_rtlight_cullmins[2]);
2618 VectorSet(points[1], r_shadow_rtlight_cullmaxs[0], r_shadow_rtlight_cullmins[1], r_shadow_rtlight_cullmins[2]);
2619 VectorSet(points[2], r_shadow_rtlight_cullmins[0], r_shadow_rtlight_cullmaxs[1], r_shadow_rtlight_cullmins[2]);
2620 VectorSet(points[3], r_shadow_rtlight_cullmaxs[0], r_shadow_rtlight_cullmaxs[1], r_shadow_rtlight_cullmins[2]);
2621 VectorSet(points[4], r_shadow_rtlight_cullmins[0], r_shadow_rtlight_cullmins[1], r_shadow_rtlight_cullmaxs[2]);
2622 VectorSet(points[5], r_shadow_rtlight_cullmaxs[0], r_shadow_rtlight_cullmins[1], r_shadow_rtlight_cullmaxs[2]);
2623 VectorSet(points[6], r_shadow_rtlight_cullmins[0], r_shadow_rtlight_cullmaxs[1], r_shadow_rtlight_cullmaxs[2]);
2624 VectorSet(points[7], r_shadow_rtlight_cullmaxs[0], r_shadow_rtlight_cullmaxs[1], r_shadow_rtlight_cullmaxs[2]);
2625 oldnum = r_shadow_rtlight_numfrustumplanes;
2626 r_shadow_rtlight_numfrustumplanes = 0;
2627 for (j = 0;j < oldnum;j++)
2629 // find the nearest point on the box to this plane
2630 bestdist = DotProduct(r_shadow_rtlight_frustumplanes[j].normal, points[0]);
2631 for (i = 1;i < 8;i++)
2633 dist = DotProduct(r_shadow_rtlight_frustumplanes[j].normal, points[i]);
2634 if (bestdist > dist)
2637 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);
2638 // if the nearest point is near or behind the plane, we want this
2639 // plane, otherwise the plane is useless as it won't cull anything
2640 if (r_shadow_rtlight_frustumplanes[j].dist < bestdist + 0.03125)
2642 PlaneClassify(&r_shadow_rtlight_frustumplanes[j]);
2643 r_shadow_rtlight_frustumplanes[r_shadow_rtlight_numfrustumplanes++] = r_shadow_rtlight_frustumplanes[j];
2650 void R_Shadow_DrawWorldShadow(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
2652 RSurf_ActiveWorldEntity();
2653 if (r_shadow_rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2657 for (mesh = r_shadow_rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2659 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
2660 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
2661 GL_LockArrays(0, mesh->numverts);
2662 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
2664 // decrement stencil if backface is behind depthbuffer
2665 GL_CullFace(GL_BACK); // quake is backwards, this culls front faces
2666 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2667 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->ebo, 0);
2668 // increment stencil if frontface is behind depthbuffer
2669 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
2670 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2672 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->ebo, 0);
2673 GL_LockArrays(0, 0);
2677 else if (numsurfaces && r_refdef.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
2680 int surfacelistindex;
2681 msurface_t *surface;
2682 R_Shadow_PrepareShadowMark(r_refdef.worldmodel->brush.shadowmesh->numtriangles);
2683 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
2685 surface = r_refdef.worldmodel->data_surfaces + surfacelist[surfacelistindex];
2686 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
2687 if (CHECKPVSBIT(trispvs, t))
2688 shadowmarklist[numshadowmark++] = t;
2690 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);
2692 else if (numsurfaces)
2693 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);
2696 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
2698 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
2699 vec_t relativeshadowradius;
2700 RSurf_ActiveModelEntity(ent, false, false);
2701 Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, relativeshadoworigin);
2702 relativeshadowradius = r_shadow_rtlight->radius / ent->scale;
2703 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
2704 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
2705 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
2706 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
2707 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
2708 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
2709 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2712 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
2714 // set up properties for rendering light onto this entity
2715 RSurf_ActiveModelEntity(ent, true, true);
2716 Matrix4x4_Concat(&r_shadow_entitytolight, &r_shadow_rtlight->matrix_worldtolight, &ent->matrix);
2717 Matrix4x4_Concat(&r_shadow_entitytoattenuationxyz, &matrix_attenuationxyz, &r_shadow_entitytolight);
2718 Matrix4x4_Concat(&r_shadow_entitytoattenuationz, &matrix_attenuationz, &r_shadow_entitytolight);
2719 Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, r_shadow_entitylightorigin);
2720 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2721 R_Mesh_TexMatrix(3, &r_shadow_entitytolight);
2724 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
2726 if (!r_refdef.worldmodel->DrawLight)
2729 // set up properties for rendering light onto this entity
2730 RSurf_ActiveWorldEntity();
2731 r_shadow_entitytolight = r_shadow_rtlight->matrix_worldtolight;
2732 Matrix4x4_Concat(&r_shadow_entitytoattenuationxyz, &matrix_attenuationxyz, &r_shadow_entitytolight);
2733 Matrix4x4_Concat(&r_shadow_entitytoattenuationz, &matrix_attenuationz, &r_shadow_entitytolight);
2734 VectorCopy(r_shadow_rtlight->shadoworigin, r_shadow_entitylightorigin);
2735 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2736 R_Mesh_TexMatrix(3, &r_shadow_entitytolight);
2738 r_refdef.worldmodel->DrawLight(r_refdef.worldentity, numsurfaces, surfacelist, trispvs);
2741 void R_Shadow_DrawEntityLight(entity_render_t *ent, int numsurfaces, int *surfacelist)
2743 model_t *model = ent->model;
2744 if (!model->DrawLight)
2747 R_Shadow_SetupEntityLight(ent);
2749 model->DrawLight(ent, model->nummodelsurfaces, model->surfacelist, NULL);
2752 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
2756 int numleafs, numsurfaces;
2757 int *leaflist, *surfacelist;
2758 unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs;
2759 int numlightentities;
2760 int numlightentities_noselfshadow;
2761 int numshadowentities;
2762 int numshadowentities_noselfshadow;
2763 entity_render_t *lightentities[MAX_EDICTS];
2764 entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
2765 entity_render_t *shadowentities[MAX_EDICTS];
2766 entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
2768 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
2769 // skip lights that are basically invisible (color 0 0 0)
2770 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
2773 // loading is done before visibility checks because loading should happen
2774 // all at once at the start of a level, not when it stalls gameplay.
2775 // (especially important to benchmarks)
2777 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2778 R_RTLight_Compile(rtlight);
2780 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
2782 // look up the light style value at this time
2783 f = (rtlight->style >= 0 ? r_refdef.lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2784 VectorScale(rtlight->color, f, rtlight->currentcolor);
2786 if (rtlight->selected)
2788 f = 2 + sin(realtime * M_PI * 4.0);
2789 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
2793 // if lightstyle is currently off, don't draw the light
2794 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
2797 // if the light box is offscreen, skip it
2798 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2801 VectorCopy(rtlight->cullmins, r_shadow_rtlight_cullmins);
2802 VectorCopy(rtlight->cullmaxs, r_shadow_rtlight_cullmaxs);
2804 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2806 // compiled light, world available and can receive realtime lighting
2807 // retrieve leaf information
2808 numleafs = rtlight->static_numleafs;
2809 leaflist = rtlight->static_leaflist;
2810 leafpvs = rtlight->static_leafpvs;
2811 numsurfaces = rtlight->static_numsurfaces;
2812 surfacelist = rtlight->static_surfacelist;
2813 shadowtrispvs = rtlight->static_shadowtrispvs;
2814 lighttrispvs = rtlight->static_lighttrispvs;
2816 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2818 // dynamic light, world available and can receive realtime lighting
2819 // calculate lit surfaces and leafs
2820 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);
2821 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);
2822 leaflist = r_shadow_buffer_leaflist;
2823 leafpvs = r_shadow_buffer_leafpvs;
2824 surfacelist = r_shadow_buffer_surfacelist;
2825 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
2826 lighttrispvs = r_shadow_buffer_lighttrispvs;
2827 // if the reduced leaf bounds are offscreen, skip it
2828 if (R_CullBox(r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs))
2839 shadowtrispvs = NULL;
2840 lighttrispvs = NULL;
2842 // check if light is illuminating any visible leafs
2845 for (i = 0;i < numleafs;i++)
2846 if (r_viewcache.world_leafvisible[leaflist[i]])
2851 // set up a scissor rectangle for this light
2852 if (R_Shadow_ScissorForBBox(r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs))
2855 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
2857 // make a list of lit entities and shadow casting entities
2858 numlightentities = 0;
2859 numlightentities_noselfshadow = 0;
2860 numshadowentities = 0;
2861 numshadowentities_noselfshadow = 0;
2862 // add dynamic entities that are lit by the light
2863 if (r_drawentities.integer)
2865 for (i = 0;i < r_refdef.numentities;i++)
2868 entity_render_t *ent = r_refdef.entities[i];
2870 if (!BoxesOverlap(ent->mins, ent->maxs, r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs))
2872 // skip the object entirely if it is not within the valid
2873 // shadow-casting region (which includes the lit region)
2874 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, r_shadow_rtlight_numfrustumplanes, r_shadow_rtlight_frustumplanes))
2876 if (!(model = ent->model))
2878 if (r_viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
2880 // this entity wants to receive light, is visible, and is
2881 // inside the light box
2882 // TODO: check if the surfaces in the model can receive light
2883 // so now check if it's in a leaf seen by the light
2884 if (r_refdef.worldmodel && r_refdef.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs))
2886 if (ent->flags & RENDER_NOSELFSHADOW)
2887 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
2889 lightentities[numlightentities++] = ent;
2890 // since it is lit, it probably also casts a shadow...
2891 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2892 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
2893 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
2895 // note: exterior models without the RENDER_NOSELFSHADOW
2896 // flag still create a RENDER_NOSELFSHADOW shadow but
2897 // are lit normally, this means that they are
2898 // self-shadowing but do not shadow other
2899 // RENDER_NOSELFSHADOW entities such as the gun
2900 // (very weird, but keeps the player shadow off the gun)
2901 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
2902 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
2904 shadowentities[numshadowentities++] = ent;
2907 else if (ent->flags & RENDER_SHADOW)
2909 // this entity is not receiving light, but may still need to
2911 // TODO: check if the surfaces in the model can cast shadow
2912 // now check if it is in a leaf seen by the light
2913 if (r_refdef.worldmodel && r_refdef.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs))
2915 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2916 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
2917 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
2919 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
2920 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
2922 shadowentities[numshadowentities++] = ent;
2928 // return if there's nothing at all to light
2929 if (!numlightentities && !numsurfaces)
2932 // don't let sound skip if going slow
2933 if (r_refdef.extraupdate)
2936 // make this the active rtlight for rendering purposes
2937 R_Shadow_RenderMode_ActiveLight(rtlight);
2938 // count this light in the r_speeds
2939 r_refdef.stats.lights++;
2941 if (r_showshadowvolumes.integer && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.rtworldshadows : r_refdef.rtdlightshadows))
2943 // optionally draw visible shape of the shadow volumes
2944 // for performance analysis by level designers
2945 R_Shadow_RenderMode_VisibleShadowVolumes();
2947 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
2948 for (i = 0;i < numshadowentities;i++)
2949 R_Shadow_DrawEntityShadow(shadowentities[i]);
2950 for (i = 0;i < numshadowentities_noselfshadow;i++)
2951 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
2954 if (gl_stencil && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.rtworldshadows : r_refdef.rtdlightshadows))
2956 // draw stencil shadow volumes to mask off pixels that are in shadow
2957 // so that they won't receive lighting
2958 R_Shadow_RenderMode_StencilShadowVolumes(true);
2960 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
2961 for (i = 0;i < numshadowentities;i++)
2962 R_Shadow_DrawEntityShadow(shadowentities[i]);
2963 if (numlightentities_noselfshadow)
2965 // draw lighting in the unmasked areas
2966 R_Shadow_RenderMode_Lighting(true, false);
2967 for (i = 0;i < numlightentities_noselfshadow;i++)
2968 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i], numsurfaces, surfacelist);
2970 // optionally draw the illuminated areas
2971 // for performance analysis by level designers
2972 if (r_showlighting.integer)
2974 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
2975 for (i = 0;i < numlightentities_noselfshadow;i++)
2976 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i], numsurfaces, surfacelist);
2979 R_Shadow_RenderMode_StencilShadowVolumes(false);
2981 for (i = 0;i < numshadowentities_noselfshadow;i++)
2982 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
2984 if (numsurfaces + numlightentities)
2986 // draw lighting in the unmasked areas
2987 R_Shadow_RenderMode_Lighting(true, false);
2989 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
2990 for (i = 0;i < numlightentities;i++)
2991 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
2993 // optionally draw the illuminated areas
2994 // for performance analysis by level designers
2995 if (r_showlighting.integer)
2997 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
2999 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3000 for (i = 0;i < numlightentities;i++)
3001 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
3007 if (numsurfaces + numlightentities)
3009 // draw lighting in the unmasked areas
3010 R_Shadow_RenderMode_Lighting(false, false);
3012 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3013 for (i = 0;i < numlightentities;i++)
3014 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
3015 for (i = 0;i < numlightentities_noselfshadow;i++)
3016 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i], numsurfaces, surfacelist);
3018 // optionally draw the illuminated areas
3019 // for performance analysis by level designers
3020 if (r_showlighting.integer)
3022 R_Shadow_RenderMode_VisibleLighting(false, false);
3024 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3025 for (i = 0;i < numlightentities;i++)
3026 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
3027 for (i = 0;i < numlightentities_noselfshadow;i++)
3028 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i], numsurfaces, surfacelist);
3034 void R_Shadow_DrawLightSprites(void);
3035 void R_ShadowVolumeLighting(qboolean visible)
3040 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
3041 R_Shadow_EditLights_Reload_f();
3043 if (r_editlights.integer)
3044 R_Shadow_DrawLightSprites();
3046 R_Shadow_RenderMode_Begin();
3048 flag = r_refdef.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3049 if (r_shadow_debuglight.integer >= 0)
3051 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
3052 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
3053 R_DrawRTLight(&light->rtlight, visible);
3056 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
3057 if (light->flags & flag)
3058 R_DrawRTLight(&light->rtlight, visible);
3059 if (r_refdef.rtdlight)
3060 for (lnum = 0;lnum < r_refdef.numlights;lnum++)
3061 R_DrawRTLight(&r_refdef.lights[lnum], visible);
3063 R_Shadow_RenderMode_End();
3066 extern void R_SetupView(const matrix4x4_t *matrix);
3067 extern cvar_t r_shadows_throwdistance;
3068 void R_DrawModelShadows(void)
3071 float relativethrowdistance;
3072 entity_render_t *ent;
3073 vec3_t relativelightorigin;
3074 vec3_t relativelightdirection;
3075 vec3_t relativeshadowmins, relativeshadowmaxs;
3078 if (!r_drawentities.integer || !gl_stencil)
3082 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
3084 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
3086 if (gl_ext_separatestencil.integer)
3087 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
3088 else if (gl_ext_stenciltwoside.integer)
3089 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
3091 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
3093 R_Shadow_RenderMode_StencilShadowVolumes(true);
3095 for (i = 0;i < r_refdef.numentities;i++)
3097 ent = r_refdef.entities[i];
3098 // cast shadows from anything that is not a submodel of the map
3099 if (ent->model && ent->model->DrawShadowVolume != NULL && !ent->model->brush.submodel && (ent->flags & RENDER_SHADOW))
3101 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
3102 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
3103 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
3104 VectorNegate(ent->modellight_lightdir, relativelightdirection);
3105 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
3106 RSurf_ActiveModelEntity(ent, false, false);
3107 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
3111 // not really the right mode, but this will disable any silly stencil features
3112 R_Shadow_RenderMode_VisibleLighting(true, true);
3114 // vertex coordinates for a quad that covers the screen exactly
3115 vertex3f[0] = 0;vertex3f[1] = 0;vertex3f[2] = 0;
3116 vertex3f[3] = 1;vertex3f[4] = 0;vertex3f[5] = 0;
3117 vertex3f[6] = 1;vertex3f[7] = 1;vertex3f[8] = 0;
3118 vertex3f[9] = 0;vertex3f[10] = 1;vertex3f[11] = 0;
3120 // set up ortho view for rendering this pass
3121 GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
3122 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
3123 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
3124 GL_ScissorTest(true);
3125 R_Mesh_Matrix(&identitymatrix);
3126 R_Mesh_ResetTextureState();
3127 R_Mesh_VertexPointer(vertex3f, 0, 0);
3128 R_Mesh_ColorPointer(NULL, 0, 0);
3130 // set up a 50% darkening blend on shadowed areas
3131 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3132 GL_DepthRange(0, 1);
3133 GL_DepthTest(false);
3134 GL_DepthMask(false);
3135 qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
3136 GL_Color(0, 0, 0, 0.5);
3137 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
3138 qglDepthFunc(GL_ALWAYS);CHECKGLERROR
3139 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
3140 qglStencilMask(~0);CHECKGLERROR
3141 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
3142 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
3144 // apply the blend to the shadowed areas
3145 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3147 // restoring the perspective view is done by R_RenderScene
3148 //R_SetupView(&r_view.matrix);
3150 // restore other state to normal
3151 R_Shadow_RenderMode_End();
3155 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
3156 typedef struct suffixinfo_s
3159 qboolean flipx, flipy, flipdiagonal;
3162 static suffixinfo_t suffix[3][6] =
3165 {"px", false, false, false},
3166 {"nx", false, false, false},
3167 {"py", false, false, false},
3168 {"ny", false, false, false},
3169 {"pz", false, false, false},
3170 {"nz", false, false, false}
3173 {"posx", false, false, false},
3174 {"negx", false, false, false},
3175 {"posy", false, false, false},
3176 {"negy", false, false, false},
3177 {"posz", false, false, false},
3178 {"negz", false, false, false}
3181 {"rt", true, false, true},
3182 {"lf", false, true, true},
3183 {"ft", true, true, false},
3184 {"bk", false, false, false},
3185 {"up", true, false, true},
3186 {"dn", true, false, true}
3190 static int componentorder[4] = {0, 1, 2, 3};
3192 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
3194 int i, j, cubemapsize;
3195 unsigned char *cubemappixels, *image_rgba;
3196 rtexture_t *cubemaptexture;
3198 // must start 0 so the first loadimagepixels has no requested width/height
3200 cubemappixels = NULL;
3201 cubemaptexture = NULL;
3202 // keep trying different suffix groups (posx, px, rt) until one loads
3203 for (j = 0;j < 3 && !cubemappixels;j++)
3205 // load the 6 images in the suffix group
3206 for (i = 0;i < 6;i++)
3208 // generate an image name based on the base and and suffix
3209 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
3211 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
3213 // an image loaded, make sure width and height are equal
3214 if (image_width == image_height)
3216 // if this is the first image to load successfully, allocate the cubemap memory
3217 if (!cubemappixels && image_width >= 1)
3219 cubemapsize = image_width;
3220 // note this clears to black, so unavailable sides are black
3221 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
3223 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
3225 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);
3228 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
3230 Mem_Free(image_rgba);
3234 // if a cubemap loaded, upload it
3237 if (!r_shadow_filters_texturepool)
3238 r_shadow_filters_texturepool = R_AllocTexturePool();
3239 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
3240 Mem_Free(cubemappixels);
3244 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
3245 for (j = 0;j < 3;j++)
3246 for (i = 0;i < 6;i++)
3247 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
3248 Con_Print(" and was unable to find any of them.\n");
3250 return cubemaptexture;
3253 rtexture_t *R_Shadow_Cubemap(const char *basename)
3256 for (i = 0;i < numcubemaps;i++)
3257 if (!strcasecmp(cubemaps[i].basename, basename))
3258 return cubemaps[i].texture;
3259 if (i >= MAX_CUBEMAPS)
3260 return r_texture_whitecube;
3262 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
3263 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
3264 if (!cubemaps[i].texture)
3265 cubemaps[i].texture = r_texture_whitecube;
3266 return cubemaps[i].texture;
3269 void R_Shadow_FreeCubemaps(void)
3272 R_FreeTexturePool(&r_shadow_filters_texturepool);
3275 dlight_t *R_Shadow_NewWorldLight(void)
3278 light = (dlight_t *)Mem_Alloc(r_main_mempool, sizeof(dlight_t));
3279 light->next = r_shadow_worldlightchain;
3280 r_shadow_worldlightchain = light;
3284 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)
3287 // validate parameters
3288 if (style < 0 || style >= MAX_LIGHTSTYLES)
3290 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
3296 // copy to light properties
3297 VectorCopy(origin, light->origin);
3298 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
3299 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
3300 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
3301 light->color[0] = max(color[0], 0);
3302 light->color[1] = max(color[1], 0);
3303 light->color[2] = max(color[2], 0);
3304 light->radius = max(radius, 0);
3305 light->style = style;
3306 light->shadow = shadowenable;
3307 light->corona = corona;
3308 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
3309 light->coronasizescale = coronasizescale;
3310 light->ambientscale = ambientscale;
3311 light->diffusescale = diffusescale;
3312 light->specularscale = specularscale;
3313 light->flags = flags;
3315 // update renderable light data
3316 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
3317 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);
3320 void R_Shadow_FreeWorldLight(dlight_t *light)
3322 dlight_t **lightpointer;
3323 R_RTLight_Uncompile(&light->rtlight);
3324 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
3325 if (*lightpointer != light)
3326 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain");
3327 *lightpointer = light->next;
3331 void R_Shadow_ClearWorldLights(void)
3333 while (r_shadow_worldlightchain)
3334 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
3335 r_shadow_selectedlight = NULL;
3336 R_Shadow_FreeCubemaps();
3339 void R_Shadow_SelectLight(dlight_t *light)
3341 if (r_shadow_selectedlight)
3342 r_shadow_selectedlight->selected = false;
3343 r_shadow_selectedlight = light;
3344 if (r_shadow_selectedlight)
3345 r_shadow_selectedlight->selected = true;
3348 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
3350 // this is never batched (there can be only one)
3351 float scale = r_editlights_cursorgrid.value * 0.5f;
3352 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);
3355 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
3357 // this is never batched (due to the ent parameter changing every time)
3358 // so numsurfaces == 1 and surfacelist[0] == lightnumber
3360 const dlight_t *light = (dlight_t *)ent;
3362 if (light->selected)
3363 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
3366 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);
3369 void R_Shadow_DrawLightSprites(void)
3374 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
3375 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 1+(i % 5), &light->rtlight);
3376 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
3379 void R_Shadow_SelectLightInView(void)
3381 float bestrating, rating, temp[3];
3382 dlight_t *best, *light;
3385 for (light = r_shadow_worldlightchain;light;light = light->next)
3387 VectorSubtract(light->origin, r_view.origin, temp);
3388 rating = (DotProduct(temp, r_view.forward) / sqrt(DotProduct(temp, temp)));
3391 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
3392 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)
3394 bestrating = rating;
3399 R_Shadow_SelectLight(best);
3402 void R_Shadow_LoadWorldLights(void)
3404 int n, a, style, shadow, flags;
3405 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
3406 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
3407 if (r_refdef.worldmodel == NULL)
3409 Con_Print("No map loaded.\n");
3412 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3413 strlcat (name, ".rtlights", sizeof (name));
3414 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3424 for (;COM_Parse(t, true) && strcmp(
3425 if (COM_Parse(t, true))
3427 if (com_token[0] == '!')
3430 origin[0] = atof(com_token+1);
3433 origin[0] = atof(com_token);
3438 while (*s && *s != '\n' && *s != '\r')
3444 // check for modifier flags
3451 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);
3454 flags = LIGHTFLAG_REALTIMEMODE;
3462 coronasizescale = 0.25f;
3464 VectorClear(angles);
3467 if (a < 9 || !strcmp(cubemapname, "\"\""))
3469 // remove quotes on cubemapname
3470 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
3473 namelen = strlen(cubemapname) - 2;
3474 memmove(cubemapname, cubemapname + 1, namelen);
3475 cubemapname[namelen] = '\0';
3479 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);
3482 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3490 Con_Printf("invalid rtlights file \"%s\"\n", name);
3491 Mem_Free(lightsstring);
3495 void R_Shadow_SaveWorldLights(void)
3498 size_t bufchars, bufmaxchars;
3500 char name[MAX_QPATH];
3501 char line[MAX_INPUTLINE];
3502 if (!r_shadow_worldlightchain)
3504 if (r_refdef.worldmodel == NULL)
3506 Con_Print("No map loaded.\n");
3509 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3510 strlcat (name, ".rtlights", sizeof (name));
3511 bufchars = bufmaxchars = 0;
3513 for (light = r_shadow_worldlightchain;light;light = light->next)
3515 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3516 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);
3517 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3518 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]);
3520 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);
3521 if (bufchars + strlen(line) > bufmaxchars)
3523 bufmaxchars = bufchars + strlen(line) + 2048;
3525 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
3529 memcpy(buf, oldbuf, bufchars);
3535 memcpy(buf + bufchars, line, strlen(line));
3536 bufchars += strlen(line);
3540 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
3545 void R_Shadow_LoadLightsFile(void)
3548 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3549 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3550 if (r_refdef.worldmodel == NULL)
3552 Con_Print("No map loaded.\n");
3555 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3556 strlcat (name, ".lights", sizeof (name));
3557 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3565 while (*s && *s != '\n' && *s != '\r')
3571 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);
3575 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);
3578 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3579 radius = bound(15, radius, 4096);
3580 VectorScale(color, (2.0f / (8388608.0f)), color);
3581 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3589 Con_Printf("invalid lights file \"%s\"\n", name);
3590 Mem_Free(lightsstring);
3594 // tyrlite/hmap2 light types in the delay field
3595 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3597 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3599 int entnum, style, islight, skin, pflags, effects, type, n;
3602 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3603 char key[256], value[MAX_INPUTLINE];
3605 if (r_refdef.worldmodel == NULL)
3607 Con_Print("No map loaded.\n");
3610 // try to load a .ent file first
3611 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3612 strlcat (key, ".ent", sizeof (key));
3613 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
3614 // and if that is not found, fall back to the bsp file entity string
3616 data = r_refdef.worldmodel->brush.entities;
3619 for (entnum = 0;COM_ParseToken_Simple(&data, false) && com_token[0] == '{';entnum++)
3621 type = LIGHTTYPE_MINUSX;
3622 origin[0] = origin[1] = origin[2] = 0;
3623 originhack[0] = originhack[1] = originhack[2] = 0;
3624 angles[0] = angles[1] = angles[2] = 0;
3625 color[0] = color[1] = color[2] = 1;
3626 light[0] = light[1] = light[2] = 1;light[3] = 300;
3627 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3637 if (!COM_ParseToken_Simple(&data, false))
3639 if (com_token[0] == '}')
3640 break; // end of entity
3641 if (com_token[0] == '_')
3642 strlcpy(key, com_token + 1, sizeof(key));
3644 strlcpy(key, com_token, sizeof(key));
3645 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3646 key[strlen(key)-1] = 0;
3647 if (!COM_ParseToken_Simple(&data, false))
3649 strlcpy(value, com_token, sizeof(value));
3651 // now that we have the key pair worked out...
3652 if (!strcmp("light", key))
3654 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3658 light[0] = vec[0] * (1.0f / 256.0f);
3659 light[1] = vec[0] * (1.0f / 256.0f);
3660 light[2] = vec[0] * (1.0f / 256.0f);
3666 light[0] = vec[0] * (1.0f / 255.0f);
3667 light[1] = vec[1] * (1.0f / 255.0f);
3668 light[2] = vec[2] * (1.0f / 255.0f);
3672 else if (!strcmp("delay", key))
3674 else if (!strcmp("origin", key))
3675 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3676 else if (!strcmp("angle", key))
3677 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3678 else if (!strcmp("angles", key))
3679 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3680 else if (!strcmp("color", key))
3681 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3682 else if (!strcmp("wait", key))
3683 fadescale = atof(value);
3684 else if (!strcmp("classname", key))
3686 if (!strncmp(value, "light", 5))
3689 if (!strcmp(value, "light_fluoro"))
3694 overridecolor[0] = 1;
3695 overridecolor[1] = 1;
3696 overridecolor[2] = 1;
3698 if (!strcmp(value, "light_fluorospark"))
3703 overridecolor[0] = 1;
3704 overridecolor[1] = 1;
3705 overridecolor[2] = 1;
3707 if (!strcmp(value, "light_globe"))
3712 overridecolor[0] = 1;
3713 overridecolor[1] = 0.8;
3714 overridecolor[2] = 0.4;
3716 if (!strcmp(value, "light_flame_large_yellow"))
3721 overridecolor[0] = 1;
3722 overridecolor[1] = 0.5;
3723 overridecolor[2] = 0.1;
3725 if (!strcmp(value, "light_flame_small_yellow"))
3730 overridecolor[0] = 1;
3731 overridecolor[1] = 0.5;
3732 overridecolor[2] = 0.1;
3734 if (!strcmp(value, "light_torch_small_white"))
3739 overridecolor[0] = 1;
3740 overridecolor[1] = 0.5;
3741 overridecolor[2] = 0.1;
3743 if (!strcmp(value, "light_torch_small_walltorch"))
3748 overridecolor[0] = 1;
3749 overridecolor[1] = 0.5;
3750 overridecolor[2] = 0.1;
3754 else if (!strcmp("style", key))
3755 style = atoi(value);
3756 else if (!strcmp("skin", key))
3757 skin = (int)atof(value);
3758 else if (!strcmp("pflags", key))
3759 pflags = (int)atof(value);
3760 else if (!strcmp("effects", key))
3761 effects = (int)atof(value);
3762 else if (r_refdef.worldmodel->type == mod_brushq3)
3764 if (!strcmp("scale", key))
3765 lightscale = atof(value);
3766 if (!strcmp("fade", key))
3767 fadescale = atof(value);
3772 if (lightscale <= 0)
3776 if (color[0] == color[1] && color[0] == color[2])
3778 color[0] *= overridecolor[0];
3779 color[1] *= overridecolor[1];
3780 color[2] *= overridecolor[2];
3782 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3783 color[0] = color[0] * light[0];
3784 color[1] = color[1] * light[1];
3785 color[2] = color[2] * light[2];
3788 case LIGHTTYPE_MINUSX:
3790 case LIGHTTYPE_RECIPX:
3792 VectorScale(color, (1.0f / 16.0f), color);
3794 case LIGHTTYPE_RECIPXX:
3796 VectorScale(color, (1.0f / 16.0f), color);
3799 case LIGHTTYPE_NONE:
3803 case LIGHTTYPE_MINUSXX:
3806 VectorAdd(origin, originhack, origin);
3808 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);
3811 Mem_Free(entfiledata);
3815 void R_Shadow_SetCursorLocationForView(void)
3818 vec3_t dest, endpos;
3820 VectorMA(r_view.origin, r_editlights_cursordistance.value, r_view.forward, dest);
3821 trace = CL_Move(r_view.origin, vec3_origin, vec3_origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
3822 if (trace.fraction < 1)
3824 dist = trace.fraction * r_editlights_cursordistance.value;
3825 push = r_editlights_cursorpushback.value;
3829 VectorMA(trace.endpos, push, r_view.forward, endpos);
3830 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
3834 VectorClear( endpos );
3836 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3837 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3838 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3841 void R_Shadow_UpdateWorldLightSelection(void)
3843 if (r_editlights.integer)
3845 R_Shadow_SetCursorLocationForView();
3846 R_Shadow_SelectLightInView();
3849 R_Shadow_SelectLight(NULL);
3852 void R_Shadow_EditLights_Clear_f(void)
3854 R_Shadow_ClearWorldLights();
3857 void R_Shadow_EditLights_Reload_f(void)
3859 if (!r_refdef.worldmodel)
3861 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3862 R_Shadow_ClearWorldLights();
3863 R_Shadow_LoadWorldLights();
3864 if (r_shadow_worldlightchain == NULL)
3866 R_Shadow_LoadLightsFile();
3867 if (r_shadow_worldlightchain == NULL)
3868 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3872 void R_Shadow_EditLights_Save_f(void)
3874 if (!r_refdef.worldmodel)
3876 R_Shadow_SaveWorldLights();
3879 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3881 R_Shadow_ClearWorldLights();
3882 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3885 void R_Shadow_EditLights_ImportLightsFile_f(void)
3887 R_Shadow_ClearWorldLights();
3888 R_Shadow_LoadLightsFile();
3891 void R_Shadow_EditLights_Spawn_f(void)
3894 if (!r_editlights.integer)
3896 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3899 if (Cmd_Argc() != 1)
3901 Con_Print("r_editlights_spawn does not take parameters\n");
3904 color[0] = color[1] = color[2] = 1;
3905 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3908 void R_Shadow_EditLights_Edit_f(void)
3910 vec3_t origin, angles, color;
3911 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3912 int style, shadows, flags, normalmode, realtimemode;
3913 char cubemapname[MAX_INPUTLINE];
3914 if (!r_editlights.integer)
3916 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3919 if (!r_shadow_selectedlight)
3921 Con_Print("No selected light.\n");
3924 VectorCopy(r_shadow_selectedlight->origin, origin);
3925 VectorCopy(r_shadow_selectedlight->angles, angles);
3926 VectorCopy(r_shadow_selectedlight->color, color);
3927 radius = r_shadow_selectedlight->radius;
3928 style = r_shadow_selectedlight->style;
3929 if (r_shadow_selectedlight->cubemapname)
3930 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
3933 shadows = r_shadow_selectedlight->shadow;
3934 corona = r_shadow_selectedlight->corona;
3935 coronasizescale = r_shadow_selectedlight->coronasizescale;
3936 ambientscale = r_shadow_selectedlight->ambientscale;
3937 diffusescale = r_shadow_selectedlight->diffusescale;
3938 specularscale = r_shadow_selectedlight->specularscale;
3939 flags = r_shadow_selectedlight->flags;
3940 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3941 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3942 if (!strcmp(Cmd_Argv(1), "origin"))
3944 if (Cmd_Argc() != 5)
3946 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3949 origin[0] = atof(Cmd_Argv(2));
3950 origin[1] = atof(Cmd_Argv(3));
3951 origin[2] = atof(Cmd_Argv(4));
3953 else if (!strcmp(Cmd_Argv(1), "originx"))
3955 if (Cmd_Argc() != 3)
3957 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3960 origin[0] = atof(Cmd_Argv(2));
3962 else if (!strcmp(Cmd_Argv(1), "originy"))
3964 if (Cmd_Argc() != 3)
3966 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3969 origin[1] = atof(Cmd_Argv(2));
3971 else if (!strcmp(Cmd_Argv(1), "originz"))
3973 if (Cmd_Argc() != 3)
3975 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3978 origin[2] = atof(Cmd_Argv(2));
3980 else if (!strcmp(Cmd_Argv(1), "move"))
3982 if (Cmd_Argc() != 5)
3984 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3987 origin[0] += atof(Cmd_Argv(2));
3988 origin[1] += atof(Cmd_Argv(3));
3989 origin[2] += atof(Cmd_Argv(4));
3991 else if (!strcmp(Cmd_Argv(1), "movex"))
3993 if (Cmd_Argc() != 3)
3995 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3998 origin[0] += atof(Cmd_Argv(2));
4000 else if (!strcmp(Cmd_Argv(1), "movey"))
4002 if (Cmd_Argc() != 3)
4004 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4007 origin[1] += atof(Cmd_Argv(2));
4009 else if (!strcmp(Cmd_Argv(1), "movez"))
4011 if (Cmd_Argc() != 3)
4013 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4016 origin[2] += atof(Cmd_Argv(2));
4018 else if (!strcmp(Cmd_Argv(1), "angles"))
4020 if (Cmd_Argc() != 5)
4022 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
4025 angles[0] = atof(Cmd_Argv(2));
4026 angles[1] = atof(Cmd_Argv(3));
4027 angles[2] = atof(Cmd_Argv(4));
4029 else if (!strcmp(Cmd_Argv(1), "anglesx"))
4031 if (Cmd_Argc() != 3)
4033 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4036 angles[0] = atof(Cmd_Argv(2));
4038 else if (!strcmp(Cmd_Argv(1), "anglesy"))
4040 if (Cmd_Argc() != 3)
4042 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4045 angles[1] = atof(Cmd_Argv(2));
4047 else if (!strcmp(Cmd_Argv(1), "anglesz"))
4049 if (Cmd_Argc() != 3)
4051 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4054 angles[2] = atof(Cmd_Argv(2));
4056 else if (!strcmp(Cmd_Argv(1), "color"))
4058 if (Cmd_Argc() != 5)
4060 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
4063 color[0] = atof(Cmd_Argv(2));
4064 color[1] = atof(Cmd_Argv(3));
4065 color[2] = atof(Cmd_Argv(4));
4067 else if (!strcmp(Cmd_Argv(1), "radius"))
4069 if (Cmd_Argc() != 3)
4071 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4074 radius = atof(Cmd_Argv(2));
4076 else if (!strcmp(Cmd_Argv(1), "colorscale"))
4078 if (Cmd_Argc() == 3)
4080 double scale = atof(Cmd_Argv(2));
4087 if (Cmd_Argc() != 5)
4089 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
4092 color[0] *= atof(Cmd_Argv(2));
4093 color[1] *= atof(Cmd_Argv(3));
4094 color[2] *= atof(Cmd_Argv(4));
4097 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
4099 if (Cmd_Argc() != 3)
4101 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4104 radius *= atof(Cmd_Argv(2));
4106 else if (!strcmp(Cmd_Argv(1), "style"))
4108 if (Cmd_Argc() != 3)
4110 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4113 style = atoi(Cmd_Argv(2));
4115 else if (!strcmp(Cmd_Argv(1), "cubemap"))
4119 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4122 if (Cmd_Argc() == 3)
4123 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
4127 else if (!strcmp(Cmd_Argv(1), "shadows"))
4129 if (Cmd_Argc() != 3)
4131 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4134 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4136 else if (!strcmp(Cmd_Argv(1), "corona"))
4138 if (Cmd_Argc() != 3)
4140 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4143 corona = atof(Cmd_Argv(2));
4145 else if (!strcmp(Cmd_Argv(1), "coronasize"))
4147 if (Cmd_Argc() != 3)
4149 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4152 coronasizescale = atof(Cmd_Argv(2));
4154 else if (!strcmp(Cmd_Argv(1), "ambient"))
4156 if (Cmd_Argc() != 3)
4158 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4161 ambientscale = atof(Cmd_Argv(2));
4163 else if (!strcmp(Cmd_Argv(1), "diffuse"))
4165 if (Cmd_Argc() != 3)
4167 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4170 diffusescale = atof(Cmd_Argv(2));
4172 else if (!strcmp(Cmd_Argv(1), "specular"))
4174 if (Cmd_Argc() != 3)
4176 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4179 specularscale = atof(Cmd_Argv(2));
4181 else if (!strcmp(Cmd_Argv(1), "normalmode"))
4183 if (Cmd_Argc() != 3)
4185 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4188 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4190 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
4192 if (Cmd_Argc() != 3)
4194 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4197 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
4201 Con_Print("usage: r_editlights_edit [property] [value]\n");
4202 Con_Print("Selected light's properties:\n");
4203 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
4204 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
4205 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
4206 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
4207 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
4208 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
4209 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
4210 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
4211 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
4212 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
4213 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
4214 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
4215 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
4216 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
4219 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
4220 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4223 void R_Shadow_EditLights_EditAll_f(void)
4227 if (!r_editlights.integer)
4229 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
4233 for (light = r_shadow_worldlightchain;light;light = light->next)
4235 R_Shadow_SelectLight(light);
4236 R_Shadow_EditLights_Edit_f();
4240 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
4242 int lightnumber, lightcount;
4246 if (!r_editlights.integer)
4252 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
4253 if (light == r_shadow_selectedlight)
4254 lightnumber = lightcount;
4255 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;
4256 if (r_shadow_selectedlight == NULL)
4258 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
4259 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;
4260 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;
4261 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;
4262 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;
4263 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;
4264 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;
4265 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;
4266 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;
4267 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;
4268 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;
4269 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;
4270 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;
4271 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;
4272 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;
4275 void R_Shadow_EditLights_ToggleShadow_f(void)
4277 if (!r_editlights.integer)
4279 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4282 if (!r_shadow_selectedlight)
4284 Con_Print("No selected light.\n");
4287 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);
4290 void R_Shadow_EditLights_ToggleCorona_f(void)
4292 if (!r_editlights.integer)
4294 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4297 if (!r_shadow_selectedlight)
4299 Con_Print("No selected light.\n");
4302 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);
4305 void R_Shadow_EditLights_Remove_f(void)
4307 if (!r_editlights.integer)
4309 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
4312 if (!r_shadow_selectedlight)
4314 Con_Print("No selected light.\n");
4317 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
4318 r_shadow_selectedlight = NULL;
4321 void R_Shadow_EditLights_Help_f(void)
4324 "Documentation on r_editlights system:\n"
4326 "r_editlights : enable/disable editing mode\n"
4327 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
4328 "r_editlights_cursorpushback : push back cursor this far from surface\n"
4329 "r_editlights_cursorpushoff : push cursor off surface this far\n"
4330 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
4331 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
4333 "r_editlights_help : this help\n"
4334 "r_editlights_clear : remove all lights\n"
4335 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
4336 "r_editlights_save : save to .rtlights file\n"
4337 "r_editlights_spawn : create a light with default settings\n"
4338 "r_editlights_edit command : edit selected light - more documentation below\n"
4339 "r_editlights_remove : remove selected light\n"
4340 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
4341 "r_editlights_importlightentitiesfrommap : reload light entities\n"
4342 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
4344 "origin x y z : set light location\n"
4345 "originx x: set x component of light location\n"
4346 "originy y: set y component of light location\n"
4347 "originz z: set z component of light location\n"
4348 "move x y z : adjust light location\n"
4349 "movex x: adjust x component of light location\n"
4350 "movey y: adjust y component of light location\n"
4351 "movez z: adjust z component of light location\n"
4352 "angles x y z : set light angles\n"
4353 "anglesx x: set x component of light angles\n"
4354 "anglesy y: set y component of light angles\n"
4355 "anglesz z: set z component of light angles\n"
4356 "color r g b : set color of light (can be brighter than 1 1 1)\n"
4357 "radius radius : set radius (size) of light\n"
4358 "colorscale grey : multiply color of light (1 does nothing)\n"
4359 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
4360 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
4361 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
4362 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
4363 "cubemap basename : set filter cubemap of light (not yet supported)\n"
4364 "shadows 1/0 : turn on/off shadows\n"
4365 "corona n : set corona intensity\n"
4366 "coronasize n : set corona size (0-1)\n"
4367 "ambient n : set ambient intensity (0-1)\n"
4368 "diffuse n : set diffuse intensity (0-1)\n"
4369 "specular n : set specular intensity (0-1)\n"
4370 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
4371 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
4372 "<nothing> : print light properties to console\n"
4376 void R_Shadow_EditLights_CopyInfo_f(void)
4378 if (!r_editlights.integer)
4380 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
4383 if (!r_shadow_selectedlight)
4385 Con_Print("No selected light.\n");
4388 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
4389 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
4390 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
4391 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
4392 if (r_shadow_selectedlight->cubemapname)
4393 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
4395 r_shadow_bufferlight.cubemapname[0] = 0;
4396 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
4397 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
4398 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
4399 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
4400 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
4401 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
4402 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
4405 void R_Shadow_EditLights_PasteInfo_f(void)
4407 if (!r_editlights.integer)
4409 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
4412 if (!r_shadow_selectedlight)
4414 Con_Print("No selected light.\n");
4417 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);
4420 void R_Shadow_EditLights_Init(void)
4422 Cvar_RegisterVariable(&r_editlights);
4423 Cvar_RegisterVariable(&r_editlights_cursordistance);
4424 Cvar_RegisterVariable(&r_editlights_cursorpushback);
4425 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
4426 Cvar_RegisterVariable(&r_editlights_cursorgrid);
4427 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
4428 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
4429 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
4430 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)");
4431 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
4432 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
4433 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
4434 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)");
4435 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
4436 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
4437 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
4438 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
4439 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
4440 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
4441 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)");