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 // current light's cull box (copied out of an rtlight or calculated by GetLightInfo)
189 vec3_t r_shadow_rtlight_cullmins;
190 vec3_t r_shadow_rtlight_cullmaxs;
192 rtexturepool_t *r_shadow_texturepool;
193 rtexture_t *r_shadow_attenuation2dtexture;
194 rtexture_t *r_shadow_attenuation3dtexture;
196 // lights are reloaded when this changes
197 char r_shadow_mapname[MAX_QPATH];
199 // used only for light filters (cubemaps)
200 rtexturepool_t *r_shadow_filters_texturepool;
202 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"};
203 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"};
204 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
205 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)"};
206 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"};
207 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
208 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
209 cvar_t r_shadow_lightattenuationpower = {0, "r_shadow_lightattenuationpower", "0.5", "changes attenuation texture generation (does not affect r_glsl lighting)"};
210 cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1", "changes attenuation texture generation (does not affect r_glsl lighting)"};
211 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
212 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"};
213 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000", "how far to cast shadows"};
214 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)"};
215 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
216 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
217 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
218 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
219 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)"};
220 cvar_t r_shadow_realtime_world_dlightshadows = {CVAR_SAVE, "r_shadow_realtime_world_dlightshadows", "1", "enables shadows from dynamic lights when using full world lighting"};
221 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"};
222 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
223 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
224 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"};
225 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation"};
226 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation"};
227 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)"};
228 cvar_t r_shadow_shadow_polygonfactor = {0, "r_shadow_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
229 cvar_t r_shadow_shadow_polygonoffset = {0, "r_shadow_shadow_polygonoffset", "1", "how much to push shadow volumes into the distance when rendering, to reduce chances of zfighting artifacts (should not be less than 0)"};
230 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)"};
231 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatetencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
232 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
233 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
234 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
235 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
236 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
237 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
238 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
240 float r_shadow_attenpower, r_shadow_attenscale;
242 rtlight_t *r_shadow_compilingrtlight;
243 dlight_t *r_shadow_worldlightchain;
244 dlight_t *r_shadow_selectedlight;
245 dlight_t r_shadow_bufferlight;
246 vec3_t r_editlights_cursorlocation;
248 extern int con_vislines;
250 typedef struct cubemapinfo_s
257 #define MAX_CUBEMAPS 256
258 static int numcubemaps;
259 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
261 void R_Shadow_UncompileWorldLights(void);
262 void R_Shadow_ClearWorldLights(void);
263 void R_Shadow_SaveWorldLights(void);
264 void R_Shadow_LoadWorldLights(void);
265 void R_Shadow_LoadLightsFile(void);
266 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
267 void R_Shadow_EditLights_Reload_f(void);
268 void R_Shadow_ValidateCvars(void);
269 static void R_Shadow_MakeTextures(void);
270 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light);
272 void r_shadow_start(void)
274 // allocate vertex processing arrays
276 r_shadow_attenuation2dtexture = NULL;
277 r_shadow_attenuation3dtexture = NULL;
278 r_shadow_texturepool = NULL;
279 r_shadow_filters_texturepool = NULL;
280 R_Shadow_ValidateCvars();
281 R_Shadow_MakeTextures();
282 maxshadowtriangles = 0;
283 shadowelements = NULL;
284 maxshadowvertices = 0;
285 shadowvertex3f = NULL;
293 shadowmarklist = NULL;
295 r_shadow_buffer_numleafpvsbytes = 0;
296 r_shadow_buffer_leafpvs = NULL;
297 r_shadow_buffer_leaflist = NULL;
298 r_shadow_buffer_numsurfacepvsbytes = 0;
299 r_shadow_buffer_surfacepvs = NULL;
300 r_shadow_buffer_surfacelist = NULL;
303 void r_shadow_shutdown(void)
305 R_Shadow_UncompileWorldLights();
307 r_shadow_attenuation2dtexture = NULL;
308 r_shadow_attenuation3dtexture = NULL;
309 R_FreeTexturePool(&r_shadow_texturepool);
310 R_FreeTexturePool(&r_shadow_filters_texturepool);
311 maxshadowtriangles = 0;
313 Mem_Free(shadowelements);
314 shadowelements = NULL;
316 Mem_Free(shadowvertex3f);
317 shadowvertex3f = NULL;
320 Mem_Free(vertexupdate);
323 Mem_Free(vertexremap);
329 Mem_Free(shadowmark);
332 Mem_Free(shadowmarklist);
333 shadowmarklist = NULL;
335 r_shadow_buffer_numleafpvsbytes = 0;
336 if (r_shadow_buffer_leafpvs)
337 Mem_Free(r_shadow_buffer_leafpvs);
338 r_shadow_buffer_leafpvs = NULL;
339 if (r_shadow_buffer_leaflist)
340 Mem_Free(r_shadow_buffer_leaflist);
341 r_shadow_buffer_leaflist = NULL;
342 r_shadow_buffer_numsurfacepvsbytes = 0;
343 if (r_shadow_buffer_surfacepvs)
344 Mem_Free(r_shadow_buffer_surfacepvs);
345 r_shadow_buffer_surfacepvs = NULL;
346 if (r_shadow_buffer_surfacelist)
347 Mem_Free(r_shadow_buffer_surfacelist);
348 r_shadow_buffer_surfacelist = NULL;
351 void r_shadow_newmap(void)
355 void R_Shadow_Help_f(void)
358 "Documentation on r_shadow system:\n"
360 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
361 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
362 "r_shadow_debuglight : render only this light number (-1 = all)\n"
363 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
364 "r_shadow_gloss2intensity : brightness of forced gloss\n"
365 "r_shadow_glossintensity : brightness of textured gloss\n"
366 "r_shadow_lightattenuationpower : used to generate attenuation texture\n"
367 "r_shadow_lightattenuationscale : used to generate attenuation texture\n"
368 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
369 "r_shadow_portallight : use portal visibility for static light precomputation\n"
370 "r_shadow_projectdistance : shadow volume projection distance\n"
371 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
372 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
373 "r_shadow_realtime_world : use high quality world lighting mode\n"
374 "r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n"
375 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
376 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
377 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
378 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
379 "r_shadow_scissor : use scissor optimization\n"
380 "r_shadow_shadow_polygonfactor : nudge shadow volumes closer/further\n"
381 "r_shadow_shadow_polygonoffset : nudge shadow volumes closer/further\n"
382 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
383 "r_showlighting : useful for performance testing; bright = slow!\n"
384 "r_showshadowvolumes : useful for performance testing; bright = slow!\n"
386 "r_shadow_help : this help\n"
390 void R_Shadow_Init(void)
392 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
393 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
394 Cvar_RegisterVariable(&r_shadow_debuglight);
395 Cvar_RegisterVariable(&r_shadow_gloss);
396 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
397 Cvar_RegisterVariable(&r_shadow_glossintensity);
398 Cvar_RegisterVariable(&r_shadow_glossexponent);
399 Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
400 Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
401 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
402 Cvar_RegisterVariable(&r_shadow_portallight);
403 Cvar_RegisterVariable(&r_shadow_projectdistance);
404 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
405 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
406 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
407 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
408 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
409 Cvar_RegisterVariable(&r_shadow_realtime_world);
410 Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows);
411 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
412 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
413 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
414 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
415 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
416 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
417 Cvar_RegisterVariable(&r_shadow_scissor);
418 Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor);
419 Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset);
420 Cvar_RegisterVariable(&r_shadow_texture3d);
421 Cvar_RegisterVariable(&gl_ext_separatestencil);
422 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
423 if (gamemode == GAME_TENEBRAE)
425 Cvar_SetValue("r_shadow_gloss", 2);
426 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
428 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f, "prints documentation on console commands and variables used by realtime lighting and shadowing system");
429 R_Shadow_EditLights_Init();
430 r_shadow_worldlightchain = NULL;
431 maxshadowtriangles = 0;
432 shadowelements = NULL;
433 maxshadowvertices = 0;
434 shadowvertex3f = NULL;
442 shadowmarklist = NULL;
444 r_shadow_buffer_numleafpvsbytes = 0;
445 r_shadow_buffer_leafpvs = NULL;
446 r_shadow_buffer_leaflist = NULL;
447 r_shadow_buffer_numsurfacepvsbytes = 0;
448 r_shadow_buffer_surfacepvs = NULL;
449 r_shadow_buffer_surfacelist = NULL;
450 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
453 matrix4x4_t matrix_attenuationxyz =
456 {0.5, 0.0, 0.0, 0.5},
457 {0.0, 0.5, 0.0, 0.5},
458 {0.0, 0.0, 0.5, 0.5},
463 matrix4x4_t matrix_attenuationz =
466 {0.0, 0.0, 0.5, 0.5},
467 {0.0, 0.0, 0.0, 0.5},
468 {0.0, 0.0, 0.0, 0.5},
473 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles)
475 // make sure shadowelements is big enough for this volume
476 if (maxshadowtriangles < numtriangles)
478 maxshadowtriangles = numtriangles;
480 Mem_Free(shadowelements);
481 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[24]));
483 // make sure shadowvertex3f is big enough for this volume
484 if (maxshadowvertices < numvertices)
486 maxshadowvertices = numvertices;
488 Mem_Free(shadowvertex3f);
489 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[6]));
493 static void R_Shadow_EnlargeLeafSurfaceBuffer(int numleafs, int numsurfaces)
495 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
496 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
497 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
499 if (r_shadow_buffer_leafpvs)
500 Mem_Free(r_shadow_buffer_leafpvs);
501 if (r_shadow_buffer_leaflist)
502 Mem_Free(r_shadow_buffer_leaflist);
503 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
504 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
505 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
507 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
509 if (r_shadow_buffer_surfacepvs)
510 Mem_Free(r_shadow_buffer_surfacepvs);
511 if (r_shadow_buffer_surfacelist)
512 Mem_Free(r_shadow_buffer_surfacelist);
513 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
514 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
515 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
519 void R_Shadow_PrepareShadowMark(int numtris)
521 // make sure shadowmark is big enough for this volume
522 if (maxshadowmark < numtris)
524 maxshadowmark = numtris;
526 Mem_Free(shadowmark);
528 Mem_Free(shadowmarklist);
529 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
530 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
534 // if shadowmarkcount wrapped we clear the array and adjust accordingly
535 if (shadowmarkcount == 0)
538 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
543 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)
546 int outtriangles = 0, outvertices = 0;
549 float ratio, direction[3], projectvector[3];
551 if (projectdirection)
552 VectorScale(projectdirection, projectdistance, projectvector);
554 VectorClear(projectvector);
556 if (maxvertexupdate < innumvertices)
558 maxvertexupdate = innumvertices;
560 Mem_Free(vertexupdate);
562 Mem_Free(vertexremap);
563 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
564 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
568 if (vertexupdatenum == 0)
571 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
572 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
575 for (i = 0;i < numshadowmarktris;i++)
576 shadowmark[shadowmarktris[i]] = shadowmarkcount;
578 // create the vertices
579 if (projectdirection)
581 for (i = 0;i < numshadowmarktris;i++)
583 element = inelement3i + shadowmarktris[i] * 3;
584 for (j = 0;j < 3;j++)
586 if (vertexupdate[element[j]] != vertexupdatenum)
588 vertexupdate[element[j]] = vertexupdatenum;
589 vertexremap[element[j]] = outvertices;
590 vertex = invertex3f + element[j] * 3;
591 // project one copy of the vertex according to projectvector
592 VectorCopy(vertex, outvertex3f);
593 VectorAdd(vertex, projectvector, (outvertex3f + 3));
602 for (i = 0;i < numshadowmarktris;i++)
604 element = inelement3i + shadowmarktris[i] * 3;
605 for (j = 0;j < 3;j++)
607 if (vertexupdate[element[j]] != vertexupdatenum)
609 vertexupdate[element[j]] = vertexupdatenum;
610 vertexremap[element[j]] = outvertices;
611 vertex = invertex3f + element[j] * 3;
612 // project one copy of the vertex to the sphere radius of the light
613 // (FIXME: would projecting it to the light box be better?)
614 VectorSubtract(vertex, projectorigin, direction);
615 ratio = projectdistance / VectorLength(direction);
616 VectorCopy(vertex, outvertex3f);
617 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
625 if (r_shadow_frontsidecasting.integer)
627 for (i = 0;i < numshadowmarktris;i++)
629 int remappedelement[3];
631 const int *neighbortriangle;
633 markindex = shadowmarktris[i] * 3;
634 element = inelement3i + markindex;
635 neighbortriangle = inneighbor3i + markindex;
636 // output the front and back triangles
637 outelement3i[0] = vertexremap[element[0]];
638 outelement3i[1] = vertexremap[element[1]];
639 outelement3i[2] = vertexremap[element[2]];
640 outelement3i[3] = vertexremap[element[2]] + 1;
641 outelement3i[4] = vertexremap[element[1]] + 1;
642 outelement3i[5] = vertexremap[element[0]] + 1;
646 // output the sides (facing outward from this triangle)
647 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
649 remappedelement[0] = vertexremap[element[0]];
650 remappedelement[1] = vertexremap[element[1]];
651 outelement3i[0] = remappedelement[1];
652 outelement3i[1] = remappedelement[0];
653 outelement3i[2] = remappedelement[0] + 1;
654 outelement3i[3] = remappedelement[1];
655 outelement3i[4] = remappedelement[0] + 1;
656 outelement3i[5] = remappedelement[1] + 1;
661 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
663 remappedelement[1] = vertexremap[element[1]];
664 remappedelement[2] = vertexremap[element[2]];
665 outelement3i[0] = remappedelement[2];
666 outelement3i[1] = remappedelement[1];
667 outelement3i[2] = remappedelement[1] + 1;
668 outelement3i[3] = remappedelement[2];
669 outelement3i[4] = remappedelement[1] + 1;
670 outelement3i[5] = remappedelement[2] + 1;
675 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
677 remappedelement[0] = vertexremap[element[0]];
678 remappedelement[2] = vertexremap[element[2]];
679 outelement3i[0] = remappedelement[0];
680 outelement3i[1] = remappedelement[2];
681 outelement3i[2] = remappedelement[2] + 1;
682 outelement3i[3] = remappedelement[0];
683 outelement3i[4] = remappedelement[2] + 1;
684 outelement3i[5] = remappedelement[0] + 1;
693 for (i = 0;i < numshadowmarktris;i++)
695 int remappedelement[3];
697 const int *neighbortriangle;
699 markindex = shadowmarktris[i] * 3;
700 element = inelement3i + markindex;
701 neighbortriangle = inneighbor3i + markindex;
702 // output the front and back triangles
703 outelement3i[0] = vertexremap[element[2]];
704 outelement3i[1] = vertexremap[element[1]];
705 outelement3i[2] = vertexremap[element[0]];
706 outelement3i[3] = vertexremap[element[0]] + 1;
707 outelement3i[4] = vertexremap[element[1]] + 1;
708 outelement3i[5] = vertexremap[element[2]] + 1;
712 // output the sides (facing outward from this triangle)
713 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
715 remappedelement[0] = vertexremap[element[0]];
716 remappedelement[1] = vertexremap[element[1]];
717 outelement3i[0] = remappedelement[0];
718 outelement3i[1] = remappedelement[1];
719 outelement3i[2] = remappedelement[1] + 1;
720 outelement3i[3] = remappedelement[0];
721 outelement3i[4] = remappedelement[1] + 1;
722 outelement3i[5] = remappedelement[0] + 1;
727 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
729 remappedelement[1] = vertexremap[element[1]];
730 remappedelement[2] = vertexremap[element[2]];
731 outelement3i[0] = remappedelement[1];
732 outelement3i[1] = remappedelement[2];
733 outelement3i[2] = remappedelement[2] + 1;
734 outelement3i[3] = remappedelement[1];
735 outelement3i[4] = remappedelement[2] + 1;
736 outelement3i[5] = remappedelement[1] + 1;
741 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
743 remappedelement[0] = vertexremap[element[0]];
744 remappedelement[2] = vertexremap[element[2]];
745 outelement3i[0] = remappedelement[2];
746 outelement3i[1] = remappedelement[0];
747 outelement3i[2] = remappedelement[0] + 1;
748 outelement3i[3] = remappedelement[2];
749 outelement3i[4] = remappedelement[0] + 1;
750 outelement3i[5] = remappedelement[2] + 1;
758 *outnumvertices = outvertices;
762 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)
765 if (projectdistance < 0.1)
767 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
770 if (!numverts || !nummarktris)
772 // make sure shadowelements is big enough for this volume
773 if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
774 R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
775 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
776 r_refdef.stats.lights_dynamicshadowtriangles += tris;
777 R_Shadow_RenderVolume(outverts, tris, shadowvertex3f, shadowelements);
780 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)
786 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
788 tend = firsttriangle + numtris;
789 if (surfacemins[0] >= lightmins[0] && surfacemaxs[0] <= lightmaxs[0]
790 && surfacemins[1] >= lightmins[1] && surfacemaxs[1] <= lightmaxs[1]
791 && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2])
793 // surface box entirely inside light box, no box cull
794 if (projectdirection)
796 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
798 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
799 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
800 shadowmarklist[numshadowmark++] = t;
805 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
806 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
807 shadowmarklist[numshadowmark++] = t;
812 // surface box not entirely inside light box, cull each triangle
813 if (projectdirection)
815 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
817 v[0] = invertex3f + e[0] * 3;
818 v[1] = invertex3f + e[1] * 3;
819 v[2] = invertex3f + e[2] * 3;
820 TriangleNormal(v[0], v[1], v[2], normal);
821 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
822 && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
823 && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
824 && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
825 && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
826 && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
827 && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
828 shadowmarklist[numshadowmark++] = t;
833 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
835 v[0] = invertex3f + e[0] * 3;
836 v[1] = invertex3f + e[1] * 3;
837 v[2] = invertex3f + e[2] * 3;
838 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
839 && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
840 && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
841 && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
842 && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
843 && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
844 && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
845 shadowmarklist[numshadowmark++] = t;
851 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
853 if (r_shadow_compilingrtlight)
855 // if we're compiling an rtlight, capture the mesh
856 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
859 r_refdef.stats.lights_shadowtriangles += numtriangles;
861 R_Mesh_VertexPointer(vertex3f);
862 GL_LockArrays(0, numvertices);
863 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
865 // decrement stencil if backface is behind depthbuffer
866 GL_CullFace(GL_BACK); // quake is backwards, this culls front faces
867 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
868 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
869 // increment stencil if frontface is behind depthbuffer
870 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
871 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
873 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
878 static void R_Shadow_MakeTextures(void)
881 float v[3], intensity;
883 R_FreeTexturePool(&r_shadow_texturepool);
884 r_shadow_texturepool = R_AllocTexturePool();
885 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
886 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
887 #define ATTEN2DSIZE 64
888 #define ATTEN3DSIZE 32
889 data = (unsigned char *)Mem_Alloc(tempmempool, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4));
890 for (y = 0;y < ATTEN2DSIZE;y++)
892 for (x = 0;x < ATTEN2DSIZE;x++)
894 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
895 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
897 intensity = 1.0f - sqrt(DotProduct(v, v));
899 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
900 d = (int)bound(0, intensity, 255);
901 data[(y*ATTEN2DSIZE+x)*4+0] = d;
902 data[(y*ATTEN2DSIZE+x)*4+1] = d;
903 data[(y*ATTEN2DSIZE+x)*4+2] = d;
904 data[(y*ATTEN2DSIZE+x)*4+3] = d;
907 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
908 if (r_shadow_texture3d.integer && gl_texture3d)
910 for (z = 0;z < ATTEN3DSIZE;z++)
912 for (y = 0;y < ATTEN3DSIZE;y++)
914 for (x = 0;x < ATTEN3DSIZE;x++)
916 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
917 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
918 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
919 intensity = 1.0f - sqrt(DotProduct(v, v));
921 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
922 d = (int)bound(0, intensity, 255);
923 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
924 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
925 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
926 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
930 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
935 void R_Shadow_ValidateCvars(void)
937 if (r_shadow_texture3d.integer && !gl_texture3d)
938 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
939 if (gl_ext_separatestencil.integer && !gl_support_separatestencil)
940 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
941 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
942 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
945 // light currently being rendered
946 rtlight_t *r_shadow_rtlight;
948 // this is the location of the light in entity space
949 vec3_t r_shadow_entitylightorigin;
950 // this transforms entity coordinates to light filter cubemap coordinates
951 // (also often used for other purposes)
952 matrix4x4_t r_shadow_entitytolight;
953 // based on entitytolight this transforms -1 to +1 to 0 to 1 for purposes
954 // of attenuation texturing in full 3D (Z result often ignored)
955 matrix4x4_t r_shadow_entitytoattenuationxyz;
956 // this transforms only the Z to S, and T is always 0.5
957 matrix4x4_t r_shadow_entitytoattenuationz;
959 void R_Shadow_RenderMode_Begin(void)
961 R_Shadow_ValidateCvars();
963 if (!r_shadow_attenuation2dtexture
964 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
965 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
966 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
967 R_Shadow_MakeTextures();
970 R_Mesh_ColorPointer(NULL);
971 R_Mesh_ResetTextureState();
972 GL_BlendFunc(GL_ONE, GL_ZERO);
975 GL_Color(0, 0, 0, 1);
976 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
978 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
980 if (gl_ext_separatestencil.integer)
981 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
982 else if (gl_ext_stenciltwoside.integer)
983 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
985 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
987 if (r_glsl.integer && gl_support_fragment_shader)
988 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
989 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
990 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
992 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
995 void R_Shadow_RenderMode_ActiveLight(rtlight_t *rtlight)
997 r_shadow_rtlight = rtlight;
1000 void R_Shadow_RenderMode_Reset(void)
1003 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1005 qglUseProgramObjectARB(0);CHECKGLERROR
1007 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
1009 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1011 R_Mesh_ColorPointer(NULL);
1012 R_Mesh_ResetTextureState();
1014 GL_DepthMask(false);
1015 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1016 qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1017 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1018 qglStencilMask(~0);CHECKGLERROR
1019 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1020 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1021 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
1022 GL_Color(1, 1, 1, 1);
1023 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
1024 GL_BlendFunc(GL_ONE, GL_ZERO);
1027 void R_Shadow_RenderMode_StencilShadowVolumes(void)
1030 R_Shadow_RenderMode_Reset();
1031 GL_ColorMask(0, 0, 0, 0);
1032 qglPolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1033 qglDepthFunc(GL_LESS);CHECKGLERROR
1034 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1035 r_shadow_rendermode = r_shadow_shadowingrendermode;
1036 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SEPARATESTENCIL)
1038 GL_CullFace(GL_NONE);
1039 qglStencilOpSeparate(GL_BACK, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR // quake is backwards, this is front faces
1040 qglStencilOpSeparate(GL_FRONT, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR // quake is backwards, this is back faces
1042 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
1044 GL_CullFace(GL_NONE);
1045 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1046 qglActiveStencilFaceEXT(GL_BACK);CHECKGLERROR // quake is backwards, this is front faces
1047 qglStencilMask(~0);CHECKGLERROR
1048 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1049 qglActiveStencilFaceEXT(GL_FRONT);CHECKGLERROR // quake is backwards, this is back faces
1050 qglStencilMask(~0);CHECKGLERROR
1051 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1053 GL_Clear(GL_STENCIL_BUFFER_BIT);
1054 r_refdef.stats.lights_clears++;
1057 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent)
1060 R_Shadow_RenderMode_Reset();
1061 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1064 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1068 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1069 // only draw light where this geometry was already rendered AND the
1070 // stencil is 128 (values other than this mean shadow)
1071 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1073 r_shadow_rendermode = r_shadow_lightingrendermode;
1074 // do global setup needed for the chosen lighting mode
1075 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1077 R_Mesh_TexBind(0, R_GetTexture(r_texture_blanknormalmap)); // normal
1078 R_Mesh_TexBind(1, R_GetTexture(r_texture_white)); // diffuse
1079 R_Mesh_TexBind(2, R_GetTexture(r_texture_white)); // gloss
1080 R_Mesh_TexBindCubeMap(3, R_GetTexture(r_shadow_rtlight->currentcubemap)); // light filter
1081 R_Mesh_TexBind(4, R_GetTexture(r_texture_fogattenuation)); // fog
1082 R_Mesh_TexBind(5, R_GetTexture(r_texture_white)); // pants
1083 R_Mesh_TexBind(6, R_GetTexture(r_texture_white)); // shirt
1084 R_Mesh_TexBind(7, R_GetTexture(r_texture_white)); // lightmap
1085 R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap)); // deluxemap
1086 R_Mesh_TexBind(9, R_GetTexture(r_texture_black)); // glow
1087 //R_Mesh_TexMatrix(3, r_shadow_entitytolight); // light filter matrix
1088 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1089 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 0);
1094 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
1097 R_Shadow_RenderMode_Reset();
1098 GL_BlendFunc(GL_ONE, GL_ONE);
1099 GL_DepthTest(r_showshadowvolumes.integer < 2);
1100 GL_Color(0.0, 0.0125 * r_view.colorscale, 0.1 * r_view.colorscale, 1);
1101 qglPolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1102 GL_CullFace(GL_NONE);
1103 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
1106 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
1109 R_Shadow_RenderMode_Reset();
1110 GL_BlendFunc(GL_ONE, GL_ONE);
1111 GL_DepthTest(r_showlighting.integer < 2);
1112 GL_Color(0.1 * r_view.colorscale, 0.0125 * r_view.colorscale, 0, 1);
1115 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1119 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1120 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1122 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
1125 void R_Shadow_RenderMode_End(void)
1128 R_Shadow_RenderMode_Reset();
1129 R_Shadow_RenderMode_ActiveLight(NULL);
1131 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
1132 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1135 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1137 int i, ix1, iy1, ix2, iy2;
1138 float x1, y1, x2, y2;
1141 mplane_t planes[11];
1142 float vertex3f[256*3];
1144 // if view is inside the light box, just say yes it's visible
1145 if (BoxesOverlap(r_view.origin, r_view.origin, mins, maxs))
1147 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
1151 // create a temporary brush describing the area the light can affect in worldspace
1152 VectorNegate(r_view.frustum[0].normal, planes[ 0].normal);planes[ 0].dist = -r_view.frustum[0].dist;
1153 VectorNegate(r_view.frustum[1].normal, planes[ 1].normal);planes[ 1].dist = -r_view.frustum[1].dist;
1154 VectorNegate(r_view.frustum[2].normal, planes[ 2].normal);planes[ 2].dist = -r_view.frustum[2].dist;
1155 VectorNegate(r_view.frustum[3].normal, planes[ 3].normal);planes[ 3].dist = -r_view.frustum[3].dist;
1156 VectorNegate(r_view.frustum[4].normal, planes[ 4].normal);planes[ 4].dist = -r_view.frustum[4].dist;
1157 VectorSet (planes[ 5].normal, 1, 0, 0); planes[ 5].dist = maxs[0];
1158 VectorSet (planes[ 6].normal, -1, 0, 0); planes[ 6].dist = -mins[0];
1159 VectorSet (planes[ 7].normal, 0, 1, 0); planes[ 7].dist = maxs[1];
1160 VectorSet (planes[ 8].normal, 0, -1, 0); planes[ 8].dist = -mins[1];
1161 VectorSet (planes[ 9].normal, 0, 0, 1); planes[ 9].dist = maxs[2];
1162 VectorSet (planes[10].normal, 0, 0, -1); planes[10].dist = -mins[2];
1164 // turn the brush into a mesh
1165 memset(&mesh, 0, sizeof(rmesh_t));
1166 mesh.maxvertices = 256;
1167 mesh.vertex3f = vertex3f;
1168 mesh.epsilon2 = (1.0f / (32.0f * 32.0f));
1169 R_Mesh_AddBrushMeshFromPlanes(&mesh, 11, planes);
1171 // if that mesh is empty, the light is not visible at all
1172 if (!mesh.numvertices)
1175 if (!r_shadow_scissor.integer)
1178 // if that mesh is not empty, check what area of the screen it covers
1179 x1 = y1 = x2 = y2 = 0;
1181 //Con_Printf("%i vertices to transform...\n", mesh.numvertices);
1182 for (i = 0;i < mesh.numvertices;i++)
1184 VectorCopy(mesh.vertex3f + i * 3, v);
1185 GL_TransformToScreen(v, v2);
1186 //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]);
1189 if (x1 > v2[0]) x1 = v2[0];
1190 if (x2 < v2[0]) x2 = v2[0];
1191 if (y1 > v2[1]) y1 = v2[1];
1192 if (y2 < v2[1]) y2 = v2[1];
1201 // now convert the scissor rectangle to integer screen coordinates
1202 ix1 = (int)(x1 - 1.0f);
1203 iy1 = (int)(y1 - 1.0f);
1204 ix2 = (int)(x2 + 1.0f);
1205 iy2 = (int)(y2 + 1.0f);
1206 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1208 // clamp it to the screen
1209 if (ix1 < r_view.x) ix1 = r_view.x;
1210 if (iy1 < r_view.y) iy1 = r_view.y;
1211 if (ix2 > r_view.x + r_view.width) ix2 = r_view.x + r_view.width;
1212 if (iy2 > r_view.y + r_view.height) iy2 = r_view.y + r_view.height;
1214 // if it is inside out, it's not visible
1215 if (ix2 <= ix1 || iy2 <= iy1)
1218 // the light area is visible, set up the scissor rectangle
1219 GL_Scissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1220 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);CHECKGLERROR
1221 //qglEnable(GL_SCISSOR_TEST);CHECKGLERROR
1222 r_refdef.stats.lights_scissored++;
1226 static void R_Shadow_RenderSurfacesLighting_Light_Vertex_Shading(const msurface_t *surface, const float *diffusecolor, const float *ambientcolor)
1228 int numverts = surface->num_vertices;
1229 float *vertex3f = rsurface_vertex3f + 3 * surface->num_firstvertex;
1230 float *normal3f = rsurface_normal3f + 3 * surface->num_firstvertex;
1231 float *color4f = rsurface_array_color4f + 4 * surface->num_firstvertex;
1232 float dist, dot, distintensity, shadeintensity, v[3], n[3];
1233 if (r_textureunits.integer >= 3)
1235 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1237 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1238 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1239 if ((dot = DotProduct(n, v)) < 0)
1241 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1242 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]);
1243 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]);
1244 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]);
1245 if (r_refdef.fogenabled)
1247 float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
1248 VectorScale(color4f, f, color4f);
1252 VectorClear(color4f);
1256 else if (r_textureunits.integer >= 2)
1258 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1260 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1261 if ((dist = fabs(v[2])) < 1)
1263 distintensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1264 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1265 if ((dot = DotProduct(n, v)) < 0)
1267 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1268 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1269 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1270 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1274 color4f[0] = ambientcolor[0] * distintensity;
1275 color4f[1] = ambientcolor[1] * distintensity;
1276 color4f[2] = ambientcolor[2] * distintensity;
1278 if (r_refdef.fogenabled)
1280 float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
1281 VectorScale(color4f, f, color4f);
1285 VectorClear(color4f);
1291 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1293 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1294 if ((dist = DotProduct(v, v)) < 1)
1297 distintensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1298 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1299 if ((dot = DotProduct(n, v)) < 0)
1301 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1302 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1303 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1304 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1308 color4f[0] = ambientcolor[0] * distintensity;
1309 color4f[1] = ambientcolor[1] * distintensity;
1310 color4f[2] = ambientcolor[2] * distintensity;
1312 if (r_refdef.fogenabled)
1314 float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
1315 VectorScale(color4f, f, color4f);
1319 VectorClear(color4f);
1325 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1327 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int numsurfaces, msurface_t **surfacelist)
1329 int surfacelistindex;
1330 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1332 const msurface_t *surface = surfacelist[surfacelistindex];
1334 float *out3f = rsurface_array_texcoord3f + 3 * surface->num_firstvertex;
1335 const float *vertex3f = rsurface_vertex3f + 3 * surface->num_firstvertex;
1336 const float *svector3f = rsurface_svector3f + 3 * surface->num_firstvertex;
1337 const float *tvector3f = rsurface_tvector3f + 3 * surface->num_firstvertex;
1338 const float *normal3f = rsurface_normal3f + 3 * surface->num_firstvertex;
1340 for (i = 0;i < surface->num_vertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1342 VectorSubtract(r_shadow_entitylightorigin, vertex3f, lightdir);
1343 // the cubemap normalizes this for us
1344 out3f[0] = DotProduct(svector3f, lightdir);
1345 out3f[1] = DotProduct(tvector3f, lightdir);
1346 out3f[2] = DotProduct(normal3f, lightdir);
1351 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int numsurfaces, msurface_t **surfacelist)
1353 int surfacelistindex;
1354 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1356 const msurface_t *surface = surfacelist[surfacelistindex];
1358 float *out3f = rsurface_array_texcoord3f + 3 * surface->num_firstvertex;
1359 const float *vertex3f = rsurface_vertex3f + 3 * surface->num_firstvertex;
1360 const float *svector3f = rsurface_svector3f + 3 * surface->num_firstvertex;
1361 const float *tvector3f = rsurface_tvector3f + 3 * surface->num_firstvertex;
1362 const float *normal3f = rsurface_normal3f + 3 * surface->num_firstvertex;
1363 float lightdir[3], eyedir[3], halfdir[3];
1364 for (i = 0;i < surface->num_vertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1366 VectorSubtract(r_shadow_entitylightorigin, vertex3f, lightdir);
1367 VectorNormalize(lightdir);
1368 VectorSubtract(rsurface_modelorg, vertex3f, eyedir);
1369 VectorNormalize(eyedir);
1370 VectorAdd(lightdir, eyedir, halfdir);
1371 // the cubemap normalizes this for us
1372 out3f[0] = DotProduct(svector3f, halfdir);
1373 out3f[1] = DotProduct(tvector3f, halfdir);
1374 out3f[2] = DotProduct(normal3f, halfdir);
1379 static void R_Shadow_RenderSurfacesLighting_VisibleLighting(int numsurfaces, msurface_t **surfacelist, 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 specularscale, qboolean dopants, qboolean doshirt)
1381 // used to display how many times a surface is lit for level design purposes
1382 GL_Color(0.1 * r_view.colorscale, 0.025 * r_view.colorscale, 0, 1);
1383 R_Mesh_ColorPointer(NULL);
1384 R_Mesh_ResetTextureState();
1385 RSurf_PrepareVerticesForBatch(false, false, numsurfaces, surfacelist);
1386 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1387 GL_LockArrays(0, 0);
1390 static void R_Shadow_RenderSurfacesLighting_Light_GLSL(int numsurfaces, msurface_t **surfacelist, 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 specularscale, qboolean dopants, qboolean doshirt)
1392 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
1393 RSurf_PrepareVerticesForBatch(true, true, numsurfaces, surfacelist);
1394 R_SetupSurfaceShader(lightcolorbase, false);
1395 R_Mesh_TexCoordPointer(0, 2, rsurface_model->surfmesh.data_texcoordtexture2f);
1396 R_Mesh_TexCoordPointer(1, 3, rsurface_svector3f);
1397 R_Mesh_TexCoordPointer(2, 3, rsurface_tvector3f);
1398 R_Mesh_TexCoordPointer(3, 3, rsurface_normal3f);
1399 if (rsurface_texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1401 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1403 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1404 GL_LockArrays(0, 0);
1405 if (rsurface_texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1407 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1411 static void R_Shadow_RenderSurfacesLighting_Light_Dot3_Finalize(int numsurfaces, msurface_t **surfacelist, float r, float g, float b)
1413 // shared final code for all the dot3 layers
1415 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 0);
1416 for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
1418 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
1419 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1420 GL_LockArrays(0, 0);
1424 static void R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, rtexture_t *basetexture, float colorscale)
1427 // colorscale accounts for how much we multiply the brightness
1430 // mult is how many times the final pass of the lighting will be
1431 // performed to get more brightness than otherwise possible.
1433 // Limit mult to 64 for sanity sake.
1435 if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1437 // 3 3D combine path (Geforce3, Radeon 8500)
1438 memset(&m, 0, sizeof(m));
1439 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1440 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1441 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1442 m.tex[1] = R_GetTexture(basetexture);
1443 m.pointer_texcoord[1] = rsurface_model->surfmesh.data_texcoordtexture2f;
1444 m.texmatrix[1] = rsurface_texture->currenttexmatrix;
1445 m.texcubemap[2] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1446 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1447 m.texmatrix[2] = r_shadow_entitytolight;
1448 GL_BlendFunc(GL_ONE, GL_ONE);
1450 else if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1452 // 2 3D combine path (Geforce3, original Radeon)
1453 memset(&m, 0, sizeof(m));
1454 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1455 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1456 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1457 m.tex[1] = R_GetTexture(basetexture);
1458 m.pointer_texcoord[1] = rsurface_model->surfmesh.data_texcoordtexture2f;
1459 m.texmatrix[1] = rsurface_texture->currenttexmatrix;
1460 GL_BlendFunc(GL_ONE, GL_ONE);
1462 else if (r_textureunits.integer >= 4 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1464 // 4 2D combine path (Geforce3, Radeon 8500)
1465 memset(&m, 0, sizeof(m));
1466 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1467 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1468 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1469 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1470 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1471 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1472 m.tex[2] = R_GetTexture(basetexture);
1473 m.pointer_texcoord[2] = rsurface_model->surfmesh.data_texcoordtexture2f;
1474 m.texmatrix[2] = rsurface_texture->currenttexmatrix;
1475 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1477 m.texcubemap[3] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1478 m.pointer_texcoord3f[3] = rsurface_vertex3f;
1479 m.texmatrix[3] = r_shadow_entitytolight;
1481 GL_BlendFunc(GL_ONE, GL_ONE);
1483 else if (r_textureunits.integer >= 3 && r_shadow_rtlight->currentcubemap == r_texture_whitecube)
1485 // 3 2D combine path (Geforce3, original Radeon)
1486 memset(&m, 0, sizeof(m));
1487 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1488 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1489 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1490 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1491 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1492 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1493 m.tex[2] = R_GetTexture(basetexture);
1494 m.pointer_texcoord[2] = rsurface_model->surfmesh.data_texcoordtexture2f;
1495 m.texmatrix[2] = rsurface_texture->currenttexmatrix;
1496 GL_BlendFunc(GL_ONE, GL_ONE);
1500 // 2/2/2 2D combine path (any dot3 card)
1501 memset(&m, 0, sizeof(m));
1502 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1503 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1504 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1505 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1506 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1507 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1508 R_Mesh_TextureState(&m);
1509 GL_ColorMask(0,0,0,1);
1510 GL_BlendFunc(GL_ONE, GL_ZERO);
1511 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1512 GL_LockArrays(0, 0);
1515 memset(&m, 0, sizeof(m));
1516 m.tex[0] = R_GetTexture(basetexture);
1517 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1518 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1519 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1521 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1522 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1523 m.texmatrix[1] = r_shadow_entitytolight;
1525 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1527 // this final code is shared
1528 R_Mesh_TextureState(&m);
1529 R_Shadow_RenderSurfacesLighting_Light_Dot3_Finalize(numsurfaces, surfacelist, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1532 static void R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, rtexture_t *basetexture, rtexture_t *normalmaptexture, float colorscale)
1535 // colorscale accounts for how much we multiply the brightness
1538 // mult is how many times the final pass of the lighting will be
1539 // performed to get more brightness than otherwise possible.
1541 // Limit mult to 64 for sanity sake.
1543 // generate normalization cubemap texcoords
1544 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(numsurfaces, surfacelist);
1545 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1547 // 3/2 3D combine path (Geforce3, Radeon 8500)
1548 memset(&m, 0, sizeof(m));
1549 m.tex[0] = R_GetTexture(normalmaptexture);
1550 m.texcombinergb[0] = GL_REPLACE;
1551 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1552 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1553 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1554 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1555 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1556 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1557 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1558 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
1559 R_Mesh_TextureState(&m);
1560 GL_ColorMask(0,0,0,1);
1561 GL_BlendFunc(GL_ONE, GL_ZERO);
1562 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1563 GL_LockArrays(0, 0);
1566 memset(&m, 0, sizeof(m));
1567 m.tex[0] = R_GetTexture(basetexture);
1568 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1569 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1570 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1572 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1573 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1574 m.texmatrix[1] = r_shadow_entitytolight;
1576 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1578 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1580 // 1/2/2 3D combine path (original Radeon)
1581 memset(&m, 0, sizeof(m));
1582 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1583 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1584 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1585 R_Mesh_TextureState(&m);
1586 GL_ColorMask(0,0,0,1);
1587 GL_BlendFunc(GL_ONE, GL_ZERO);
1588 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1589 GL_LockArrays(0, 0);
1592 memset(&m, 0, sizeof(m));
1593 m.tex[0] = R_GetTexture(normalmaptexture);
1594 m.texcombinergb[0] = GL_REPLACE;
1595 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1596 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1597 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1598 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1599 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1600 R_Mesh_TextureState(&m);
1601 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1602 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1603 GL_LockArrays(0, 0);
1606 memset(&m, 0, sizeof(m));
1607 m.tex[0] = R_GetTexture(basetexture);
1608 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1609 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1610 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1612 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1613 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1614 m.texmatrix[1] = r_shadow_entitytolight;
1616 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1618 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap == r_texture_whitecube)
1620 // 2/2 3D combine path (original Radeon)
1621 memset(&m, 0, sizeof(m));
1622 m.tex[0] = R_GetTexture(normalmaptexture);
1623 m.texcombinergb[0] = GL_REPLACE;
1624 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1625 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1626 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1627 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1628 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1629 R_Mesh_TextureState(&m);
1630 GL_ColorMask(0,0,0,1);
1631 GL_BlendFunc(GL_ONE, GL_ZERO);
1632 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1633 GL_LockArrays(0, 0);
1636 memset(&m, 0, sizeof(m));
1637 m.tex[0] = R_GetTexture(basetexture);
1638 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1639 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1640 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1641 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1642 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
1643 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1645 else if (r_textureunits.integer >= 4)
1647 // 4/2 2D combine path (Geforce3, Radeon 8500)
1648 memset(&m, 0, sizeof(m));
1649 m.tex[0] = R_GetTexture(normalmaptexture);
1650 m.texcombinergb[0] = GL_REPLACE;
1651 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1652 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1653 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1654 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1655 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1656 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1657 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1658 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
1659 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1660 m.pointer_texcoord3f[3] = rsurface_vertex3f;
1661 m.texmatrix[3] = r_shadow_entitytoattenuationz;
1662 R_Mesh_TextureState(&m);
1663 GL_ColorMask(0,0,0,1);
1664 GL_BlendFunc(GL_ONE, GL_ZERO);
1665 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1666 GL_LockArrays(0, 0);
1669 memset(&m, 0, sizeof(m));
1670 m.tex[0] = R_GetTexture(basetexture);
1671 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1672 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1673 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1675 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1676 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1677 m.texmatrix[1] = r_shadow_entitytolight;
1679 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1683 // 2/2/2 2D combine path (any dot3 card)
1684 memset(&m, 0, sizeof(m));
1685 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1686 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1687 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1688 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1689 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1690 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1691 R_Mesh_TextureState(&m);
1692 GL_ColorMask(0,0,0,1);
1693 GL_BlendFunc(GL_ONE, GL_ZERO);
1694 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1695 GL_LockArrays(0, 0);
1698 memset(&m, 0, sizeof(m));
1699 m.tex[0] = R_GetTexture(normalmaptexture);
1700 m.texcombinergb[0] = GL_REPLACE;
1701 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1702 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1703 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1704 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1705 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1706 R_Mesh_TextureState(&m);
1707 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1708 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1709 GL_LockArrays(0, 0);
1712 memset(&m, 0, sizeof(m));
1713 m.tex[0] = R_GetTexture(basetexture);
1714 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1715 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1716 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1718 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1719 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1720 m.texmatrix[1] = r_shadow_entitytolight;
1722 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1724 // this final code is shared
1725 R_Mesh_TextureState(&m);
1726 R_Shadow_RenderSurfacesLighting_Light_Dot3_Finalize(numsurfaces, surfacelist, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1729 static void R_Shadow_RenderSurfacesLighting_Light_Dot3_SpecularPass(int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, rtexture_t *glosstexture, rtexture_t *normalmaptexture, float colorscale)
1731 float glossexponent;
1733 // FIXME: detect blendsquare!
1734 //if (!gl_support_blendsquare)
1737 // generate normalization cubemap texcoords
1738 R_Shadow_GenTexCoords_Specular_NormalCubeMap(numsurfaces, surfacelist);
1739 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1741 // 2/0/0/1/2 3D combine blendsquare path
1742 memset(&m, 0, sizeof(m));
1743 m.tex[0] = R_GetTexture(normalmaptexture);
1744 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1745 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1746 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1747 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1748 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1749 R_Mesh_TextureState(&m);
1750 GL_ColorMask(0,0,0,1);
1751 // this squares the result
1752 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1753 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1754 GL_LockArrays(0, 0);
1756 // second and third pass
1757 R_Mesh_ResetTextureState();
1758 // square alpha in framebuffer a few times to make it shiny
1759 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1760 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
1761 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1762 GL_LockArrays(0, 0);
1765 memset(&m, 0, sizeof(m));
1766 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1767 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1768 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1769 R_Mesh_TextureState(&m);
1770 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1771 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1772 GL_LockArrays(0, 0);
1775 memset(&m, 0, sizeof(m));
1776 m.tex[0] = R_GetTexture(glosstexture);
1777 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1778 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1779 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1781 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1782 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1783 m.texmatrix[1] = r_shadow_entitytolight;
1785 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1787 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
1789 // 2/0/0/2 3D combine blendsquare path
1790 memset(&m, 0, sizeof(m));
1791 m.tex[0] = R_GetTexture(normalmaptexture);
1792 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1793 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1794 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1795 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1796 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1797 R_Mesh_TextureState(&m);
1798 GL_ColorMask(0,0,0,1);
1799 // this squares the result
1800 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1801 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1802 GL_LockArrays(0, 0);
1804 // second and third pass
1805 R_Mesh_ResetTextureState();
1806 // square alpha in framebuffer a few times to make it shiny
1807 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1808 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
1809 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1810 GL_LockArrays(0, 0);
1813 memset(&m, 0, sizeof(m));
1814 m.tex[0] = R_GetTexture(glosstexture);
1815 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1816 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1817 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1818 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1819 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
1820 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1824 // 2/0/0/2/2 2D combine blendsquare path
1825 memset(&m, 0, sizeof(m));
1826 m.tex[0] = R_GetTexture(normalmaptexture);
1827 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1828 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1829 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1830 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1831 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1832 R_Mesh_TextureState(&m);
1833 GL_ColorMask(0,0,0,1);
1834 // this squares the result
1835 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1836 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1837 GL_LockArrays(0, 0);
1839 // second and third pass
1840 R_Mesh_ResetTextureState();
1841 // square alpha in framebuffer a few times to make it shiny
1842 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1843 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
1844 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1845 GL_LockArrays(0, 0);
1848 memset(&m, 0, sizeof(m));
1849 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1850 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1851 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1852 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1853 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1854 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1855 R_Mesh_TextureState(&m);
1856 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1857 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1858 GL_LockArrays(0, 0);
1861 memset(&m, 0, sizeof(m));
1862 m.tex[0] = R_GetTexture(glosstexture);
1863 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1864 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1865 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1867 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1868 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1869 m.texmatrix[1] = r_shadow_entitytolight;
1871 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1873 // this final code is shared
1874 R_Mesh_TextureState(&m);
1875 R_Shadow_RenderSurfacesLighting_Light_Dot3_Finalize(numsurfaces, surfacelist, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1878 static void R_Shadow_RenderSurfacesLighting_Light_Dot3(int numsurfaces, msurface_t **surfacelist, 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 specularscale, qboolean dopants, qboolean doshirt)
1880 // ARB path (any Geforce, any Radeon)
1881 qboolean doambient = r_shadow_rtlight->ambientscale > 0;
1882 qboolean dodiffuse = r_shadow_rtlight->diffusescale > 0;
1883 qboolean dospecular = specularscale > 0;
1884 if (!doambient && !dodiffuse && !dospecular)
1886 RSurf_PrepareVerticesForBatch(true, true, numsurfaces, surfacelist);
1887 R_Mesh_ColorPointer(NULL);
1889 R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(numsurfaces, surfacelist, lightcolorbase, basetexture, r_shadow_rtlight->ambientscale * r_view.colorscale);
1891 R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(numsurfaces, surfacelist, lightcolorbase, basetexture, normalmaptexture, r_shadow_rtlight->diffusescale * r_view.colorscale);
1895 R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(numsurfaces, surfacelist, lightcolorpants, pantstexture, r_shadow_rtlight->ambientscale * r_view.colorscale);
1897 R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(numsurfaces, surfacelist, lightcolorpants, pantstexture, normalmaptexture, r_shadow_rtlight->diffusescale * r_view.colorscale);
1902 R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(numsurfaces, surfacelist, lightcolorshirt, shirttexture, r_shadow_rtlight->ambientscale * r_view.colorscale);
1904 R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(numsurfaces, surfacelist, lightcolorshirt, shirttexture, normalmaptexture, r_shadow_rtlight->diffusescale * r_view.colorscale);
1907 R_Shadow_RenderSurfacesLighting_Light_Dot3_SpecularPass(numsurfaces, surfacelist, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_view.colorscale);
1910 void R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(const model_t *model, int numsurfaces, msurface_t **surfacelist, vec3_t diffusecolor2, vec3_t ambientcolor2)
1912 int surfacelistindex;
1914 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1916 const msurface_t *surface = surfacelist[surfacelistindex];
1917 R_Shadow_RenderSurfacesLighting_Light_Vertex_Shading(surface, diffusecolor2, ambientcolor2);
1919 for (renders = 0;renders < 64;renders++)
1925 int newnumtriangles;
1927 int newelements[3072];
1931 newnumtriangles = 0;
1933 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1935 const msurface_t *surface = surfacelist[surfacelistindex];
1936 const int *elements = rsurface_model->surfmesh.data_element3i + surface->num_firsttriangle * 3;
1938 // due to low fillrate on the cards this vertex lighting path is
1939 // designed for, we manually cull all triangles that do not
1940 // contain a lit vertex
1941 // this builds batches of triangles from multiple surfaces and
1942 // renders them at once
1943 for (i = 0, e = elements;i < surface->num_triangles;i++, e += 3)
1945 if (VectorLength2(rsurface_array_color4f + e[0] * 4) + VectorLength2(rsurface_array_color4f + e[1] * 4) + VectorLength2(rsurface_array_color4f + e[2] * 4) >= 0.01)
1947 if (newnumtriangles)
1949 firstvertex = min(firstvertex, e[0]);
1950 lastvertex = max(lastvertex, e[0]);
1957 firstvertex = min(firstvertex, e[1]);
1958 lastvertex = max(lastvertex, e[1]);
1959 firstvertex = min(firstvertex, e[2]);
1960 lastvertex = max(lastvertex, e[2]);
1966 if (newnumtriangles >= 1024)
1968 GL_LockArrays(firstvertex, lastvertex - firstvertex + 1);
1969 R_Mesh_Draw(firstvertex, lastvertex - firstvertex + 1, newnumtriangles, newelements);
1970 newnumtriangles = 0;
1977 if (newnumtriangles >= 1)
1979 GL_LockArrays(firstvertex, lastvertex - firstvertex + 1);
1980 R_Mesh_Draw(firstvertex, lastvertex - firstvertex + 1, newnumtriangles, newelements);
1983 GL_LockArrays(0, 0);
1984 // if we couldn't find any lit triangles, exit early
1987 // now reduce the intensity for the next overbright pass
1988 // we have to clamp to 0 here incase the drivers have improper
1989 // handling of negative colors
1990 // (some old drivers even have improper handling of >1 color)
1992 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1996 const msurface_t *surface = surfacelist[surfacelistindex];
1997 for (i = 0, c = rsurface_array_color4f + 4 * surface->num_firstvertex;i < surface->num_vertices;i++, c += 4)
1999 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2001 c[0] = max(0, c[0] - 1);
2002 c[1] = max(0, c[1] - 1);
2003 c[2] = max(0, c[2] - 1);
2016 static void R_Shadow_RenderSurfacesLighting_Light_Vertex(int numsurfaces, msurface_t **surfacelist, 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 specularscale, qboolean dopants, qboolean doshirt)
2018 // OpenGL 1.1 path (anything)
2019 model_t *model = rsurface_entity->model;
2020 float ambientcolorbase[3], diffusecolorbase[3];
2021 float ambientcolorpants[3], diffusecolorpants[3];
2022 float ambientcolorshirt[3], diffusecolorshirt[3];
2024 VectorScale(lightcolorbase, r_shadow_rtlight->ambientscale * 2 * r_view.colorscale, ambientcolorbase);
2025 VectorScale(lightcolorbase, r_shadow_rtlight->diffusescale * 2 * r_view.colorscale, diffusecolorbase);
2026 VectorScale(lightcolorpants, r_shadow_rtlight->ambientscale * 2 * r_view.colorscale, ambientcolorpants);
2027 VectorScale(lightcolorpants, r_shadow_rtlight->diffusescale * 2 * r_view.colorscale, diffusecolorpants);
2028 VectorScale(lightcolorshirt, r_shadow_rtlight->ambientscale * 2 * r_view.colorscale, ambientcolorshirt);
2029 VectorScale(lightcolorshirt, r_shadow_rtlight->diffusescale * 2 * r_view.colorscale, diffusecolorshirt);
2030 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2031 R_Mesh_ColorPointer(rsurface_array_color4f);
2032 memset(&m, 0, sizeof(m));
2033 m.tex[0] = R_GetTexture(basetexture);
2034 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
2035 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
2036 if (r_textureunits.integer >= 2)
2039 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2040 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2041 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2042 if (r_textureunits.integer >= 3)
2044 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
2045 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2046 m.texmatrix[2] = r_shadow_entitytoattenuationz;
2047 m.pointer_texcoord3f[2] = rsurface_vertex3f;
2050 R_Mesh_TextureState(&m);
2051 RSurf_PrepareVerticesForBatch(true, false, numsurfaces, surfacelist);
2052 R_Mesh_TexBind(0, R_GetTexture(basetexture));
2053 R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(model, numsurfaces, surfacelist, diffusecolorbase, ambientcolorbase);
2056 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
2057 R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(model, numsurfaces, surfacelist, diffusecolorpants, ambientcolorpants);
2061 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
2062 R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(model, numsurfaces, surfacelist, diffusecolorshirt, ambientcolorshirt);
2066 void R_Shadow_RenderSurfacesLighting(int numsurfaces, msurface_t **surfacelist)
2068 // FIXME: support MATERIALFLAG_NODEPTHTEST
2069 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
2070 // calculate colors to render this texture with
2071 lightcolorbase[0] = r_shadow_rtlight->currentcolor[0] * rsurface_entity->colormod[0] * rsurface_texture->currentalpha;
2072 lightcolorbase[1] = r_shadow_rtlight->currentcolor[1] * rsurface_entity->colormod[1] * rsurface_texture->currentalpha;
2073 lightcolorbase[2] = r_shadow_rtlight->currentcolor[2] * rsurface_entity->colormod[2] * rsurface_texture->currentalpha;
2074 if ((r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorbase) + (r_shadow_rtlight->specularscale * rsurface_texture->specularscale) * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
2076 GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
2077 GL_CullFace(((rsurface_texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) || (rsurface_entity->flags & RENDER_NOCULLFACE)) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
2078 if (rsurface_texture->colormapping)
2080 qboolean dopants = rsurface_texture->currentskinframe->pants != NULL && VectorLength2(rsurface_entity->colormap_pantscolor) >= (1.0f / 1048576.0f);
2081 qboolean doshirt = rsurface_texture->currentskinframe->shirt != NULL && VectorLength2(rsurface_entity->colormap_shirtcolor) >= (1.0f / 1048576.0f);
2084 lightcolorpants[0] = lightcolorbase[0] * rsurface_entity->colormap_pantscolor[0];
2085 lightcolorpants[1] = lightcolorbase[1] * rsurface_entity->colormap_pantscolor[1];
2086 lightcolorpants[2] = lightcolorbase[2] * rsurface_entity->colormap_pantscolor[2];
2089 VectorClear(lightcolorpants);
2092 lightcolorshirt[0] = lightcolorbase[0] * rsurface_entity->colormap_shirtcolor[0];
2093 lightcolorshirt[1] = lightcolorbase[1] * rsurface_entity->colormap_shirtcolor[1];
2094 lightcolorshirt[2] = lightcolorbase[2] * rsurface_entity->colormap_shirtcolor[2];
2097 VectorClear(lightcolorshirt);
2098 switch (r_shadow_rendermode)
2100 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2101 GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2102 R_Shadow_RenderSurfacesLighting_VisibleLighting(numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->currentskinframe->pants, rsurface_texture->currentskinframe->shirt, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, dopants, doshirt);
2104 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2105 R_Shadow_RenderSurfacesLighting_Light_GLSL(numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->currentskinframe->pants, rsurface_texture->currentskinframe->shirt, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, dopants, doshirt);
2107 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2108 R_Shadow_RenderSurfacesLighting_Light_Dot3(numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->currentskinframe->pants, rsurface_texture->currentskinframe->shirt, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, dopants, doshirt);
2110 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2111 R_Shadow_RenderSurfacesLighting_Light_Vertex(numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->currentskinframe->pants, rsurface_texture->currentskinframe->shirt, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, dopants, doshirt);
2114 Con_Printf("R_Shadow_RenderSurfacesLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2120 switch (r_shadow_rendermode)
2122 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2123 GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2124 R_Shadow_RenderSurfacesLighting_VisibleLighting(numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, false, false);
2126 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2127 R_Shadow_RenderSurfacesLighting_Light_GLSL(numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, false, false);
2129 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2130 R_Shadow_RenderSurfacesLighting_Light_Dot3(numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, false, false);
2132 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2133 R_Shadow_RenderSurfacesLighting_Light_Vertex(numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, false, false);
2136 Con_Printf("R_Shadow_RenderSurfacesLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2142 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)
2144 // if this light has been compiled before, free the associated data
2145 R_RTLight_Uncompile(rtlight);
2147 // clear it completely to avoid any lingering data
2148 memset(rtlight, 0, sizeof(*rtlight));
2150 // copy the properties
2151 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, matrix);
2152 Matrix4x4_OriginFromMatrix(matrix, rtlight->shadoworigin);
2153 rtlight->radius = Matrix4x4_ScaleFromMatrix(matrix);
2154 VectorCopy(color, rtlight->color);
2155 rtlight->cubemapname[0] = 0;
2156 if (cubemapname && cubemapname[0])
2157 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2158 rtlight->shadow = shadow;
2159 rtlight->corona = corona;
2160 rtlight->style = style;
2161 rtlight->isstatic = isstatic;
2162 rtlight->coronasizescale = coronasizescale;
2163 rtlight->ambientscale = ambientscale;
2164 rtlight->diffusescale = diffusescale;
2165 rtlight->specularscale = specularscale;
2166 rtlight->flags = flags;
2168 // compute derived data
2169 //rtlight->cullradius = rtlight->radius;
2170 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2171 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2172 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2173 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2174 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2175 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2176 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2179 // compiles rtlight geometry
2180 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2181 void R_RTLight_Compile(rtlight_t *rtlight)
2183 int shadowmeshes, shadowtris, numleafs, numleafpvsbytes, numsurfaces;
2184 entity_render_t *ent = r_refdef.worldentity;
2185 model_t *model = r_refdef.worldmodel;
2186 unsigned char *data;
2188 // compile the light
2189 rtlight->compiled = true;
2190 rtlight->static_numleafs = 0;
2191 rtlight->static_numleafpvsbytes = 0;
2192 rtlight->static_leaflist = NULL;
2193 rtlight->static_leafpvs = NULL;
2194 rtlight->static_numsurfaces = 0;
2195 rtlight->static_surfacelist = NULL;
2196 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2197 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2198 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2199 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2200 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2201 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2203 if (model && model->GetLightInfo)
2205 // this variable must be set for the CompileShadowVolume code
2206 r_shadow_compilingrtlight = rtlight;
2207 R_Shadow_EnlargeLeafSurfaceBuffer(model->brush.num_leafs, model->num_surfaces);
2208 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);
2209 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2210 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numleafs + numleafpvsbytes + sizeof(int) * numsurfaces);
2211 rtlight->static_numleafs = numleafs;
2212 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2213 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2214 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2215 rtlight->static_numsurfaces = numsurfaces;
2216 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2218 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2219 if (numleafpvsbytes)
2220 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2222 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2223 if (model->CompileShadowVolume && rtlight->shadow)
2224 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2225 // now we're done compiling the rtlight
2226 r_shadow_compilingrtlight = NULL;
2230 // use smallest available cullradius - box radius or light radius
2231 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2232 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2236 if (rtlight->static_meshchain_shadow)
2239 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2242 shadowtris += mesh->numtriangles;
2246 if (developer.integer >= 10)
2247 Con_Printf("static light built: %f %f %f : %f %f %f box, %i 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], shadowtris, shadowmeshes);
2250 void R_RTLight_Uncompile(rtlight_t *rtlight)
2252 if (rtlight->compiled)
2254 if (rtlight->static_meshchain_shadow)
2255 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2256 rtlight->static_meshchain_shadow = NULL;
2257 // these allocations are grouped
2258 if (rtlight->static_leaflist)
2259 Mem_Free(rtlight->static_leaflist);
2260 rtlight->static_numleafs = 0;
2261 rtlight->static_numleafpvsbytes = 0;
2262 rtlight->static_leaflist = NULL;
2263 rtlight->static_leafpvs = NULL;
2264 rtlight->static_numsurfaces = 0;
2265 rtlight->static_surfacelist = NULL;
2266 rtlight->compiled = false;
2270 void R_Shadow_UncompileWorldLights(void)
2273 for (light = r_shadow_worldlightchain;light;light = light->next)
2274 R_RTLight_Uncompile(&light->rtlight);
2277 void R_Shadow_DrawEntityShadow(entity_render_t *ent, int numsurfaces, int *surfacelist)
2279 model_t *model = ent->model;
2280 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
2281 vec_t relativeshadowradius;
2282 if (ent == r_refdef.worldentity)
2284 if (r_shadow_rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2287 R_Mesh_Matrix(&ent->matrix);
2289 for (mesh = r_shadow_rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2291 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
2292 R_Mesh_VertexPointer(mesh->vertex3f);
2293 GL_LockArrays(0, mesh->numverts);
2294 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
2296 // decrement stencil if backface is behind depthbuffer
2297 GL_CullFace(GL_BACK); // quake is backwards, this culls front faces
2298 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2299 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2300 // increment stencil if frontface is behind depthbuffer
2301 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
2302 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2304 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2305 GL_LockArrays(0, 0);
2309 else if (numsurfaces)
2311 R_Mesh_Matrix(&ent->matrix);
2312 model->DrawShadowVolume(ent, r_shadow_rtlight->shadoworigin, NULL, r_shadow_rtlight->radius, numsurfaces, surfacelist, r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs);
2317 Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, relativeshadoworigin);
2318 relativeshadowradius = r_shadow_rtlight->radius / ent->scale;
2319 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
2320 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
2321 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
2322 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
2323 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
2324 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
2325 R_Mesh_Matrix(&ent->matrix);
2326 model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, model->nummodelsurfaces, model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2330 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
2332 // set up properties for rendering light onto this entity
2333 RSurf_ActiveEntity(ent, true, true);
2334 Matrix4x4_Concat(&r_shadow_entitytolight, &r_shadow_rtlight->matrix_worldtolight, &ent->matrix);
2335 Matrix4x4_Concat(&r_shadow_entitytoattenuationxyz, &matrix_attenuationxyz, &r_shadow_entitytolight);
2336 Matrix4x4_Concat(&r_shadow_entitytoattenuationz, &matrix_attenuationz, &r_shadow_entitytolight);
2337 Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, r_shadow_entitylightorigin);
2338 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2339 R_Mesh_TexMatrix(3, &r_shadow_entitytolight);
2342 void R_Shadow_DrawEntityLight(entity_render_t *ent, int numsurfaces, int *surfacelist)
2344 model_t *model = ent->model;
2345 if (!model->DrawLight)
2347 R_Shadow_SetupEntityLight(ent);
2348 if (ent == r_refdef.worldentity)
2349 model->DrawLight(ent, numsurfaces, surfacelist);
2351 model->DrawLight(ent, model->nummodelsurfaces, model->surfacelist);
2354 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
2358 int numleafs, numsurfaces;
2359 int *leaflist, *surfacelist;
2360 unsigned char *leafpvs;
2361 int numlightentities;
2362 int numshadowentities;
2363 entity_render_t *lightentities[MAX_EDICTS];
2364 entity_render_t *shadowentities[MAX_EDICTS];
2366 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
2367 // skip lights that are basically invisible (color 0 0 0)
2368 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
2371 // loading is done before visibility checks because loading should happen
2372 // all at once at the start of a level, not when it stalls gameplay.
2373 // (especially important to benchmarks)
2375 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2376 R_RTLight_Compile(rtlight);
2378 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
2380 // look up the light style value at this time
2381 f = (rtlight->style >= 0 ? r_refdef.lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2382 VectorScale(rtlight->color, f, rtlight->currentcolor);
2384 if (rtlight->selected)
2386 f = 2 + sin(realtime * M_PI * 4.0);
2387 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
2391 // if lightstyle is currently off, don't draw the light
2392 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
2395 // if the light box is offscreen, skip it
2396 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2399 VectorCopy(rtlight->cullmins, r_shadow_rtlight_cullmins);
2400 VectorCopy(rtlight->cullmaxs, r_shadow_rtlight_cullmaxs);
2402 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2404 // compiled light, world available and can receive realtime lighting
2405 // retrieve leaf information
2406 numleafs = rtlight->static_numleafs;
2407 leaflist = rtlight->static_leaflist;
2408 leafpvs = rtlight->static_leafpvs;
2409 numsurfaces = rtlight->static_numsurfaces;
2410 surfacelist = rtlight->static_surfacelist;
2412 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2414 // dynamic light, world available and can receive realtime lighting
2415 // calculate lit surfaces and leafs
2416 R_Shadow_EnlargeLeafSurfaceBuffer(r_refdef.worldmodel->brush.num_leafs, r_refdef.worldmodel->num_surfaces);
2417 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);
2418 leaflist = r_shadow_buffer_leaflist;
2419 leafpvs = r_shadow_buffer_leafpvs;
2420 surfacelist = r_shadow_buffer_surfacelist;
2421 // if the reduced leaf bounds are offscreen, skip it
2422 if (R_CullBox(r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs))
2434 // check if light is illuminating any visible leafs
2437 for (i = 0;i < numleafs;i++)
2438 if (r_viewcache.world_leafvisible[leaflist[i]])
2443 // set up a scissor rectangle for this light
2444 if (R_Shadow_ScissorForBBox(r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs))
2447 // make a list of lit entities and shadow casting entities
2448 numlightentities = 0;
2449 numshadowentities = 0;
2450 // don't count the world unless some surfaces are actually lit
2453 lightentities[numlightentities++] = r_refdef.worldentity;
2454 shadowentities[numshadowentities++] = r_refdef.worldentity;
2456 // add dynamic entities that are lit by the light
2457 if (r_drawentities.integer)
2459 for (i = 0;i < r_refdef.numentities;i++)
2462 entity_render_t *ent = r_refdef.entities[i];
2463 if (BoxesOverlap(ent->mins, ent->maxs, r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs)
2464 && (model = ent->model)
2465 && !(ent->flags & RENDER_TRANSPARENT)
2466 && (r_refdef.worldmodel == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs)))
2468 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2470 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
2471 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
2472 shadowentities[numshadowentities++] = ent;
2473 if (r_viewcache.entityvisible[i] && (ent->flags & RENDER_LIGHT) && model->DrawLight)
2474 lightentities[numlightentities++] = ent;
2479 // return if there's nothing at all to light
2480 if (!numlightentities)
2483 // don't let sound skip if going slow
2484 if (r_refdef.extraupdate)
2487 // make this the active rtlight for rendering purposes
2488 R_Shadow_RenderMode_ActiveLight(rtlight);
2489 // count this light in the r_speeds
2490 r_refdef.stats.lights++;
2493 if (numshadowentities && rtlight->shadow && (rtlight->isstatic ? r_refdef.rtworldshadows : r_refdef.rtdlightshadows))
2495 // draw stencil shadow volumes to mask off pixels that are in shadow
2496 // so that they won't receive lighting
2500 R_Shadow_RenderMode_StencilShadowVolumes();
2501 for (i = 0;i < numshadowentities;i++)
2502 R_Shadow_DrawEntityShadow(shadowentities[i], numsurfaces, surfacelist);
2505 // optionally draw visible shape of the shadow volumes
2506 // for performance analysis by level designers
2507 if (r_showshadowvolumes.integer)
2509 R_Shadow_RenderMode_VisibleShadowVolumes();
2510 for (i = 0;i < numshadowentities;i++)
2511 R_Shadow_DrawEntityShadow(shadowentities[i], numsurfaces, surfacelist);
2515 if (numlightentities)
2517 // draw lighting in the unmasked areas
2518 R_Shadow_RenderMode_Lighting(usestencil, false);
2519 for (i = 0;i < numlightentities;i++)
2520 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
2522 // optionally draw the illuminated areas
2523 // for performance analysis by level designers
2524 if (r_showlighting.integer)
2526 R_Shadow_RenderMode_VisibleLighting(usestencil && !r_showdisabledepthtest.integer, false);
2527 for (i = 0;i < numlightentities;i++)
2528 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
2533 void R_ShadowVolumeLighting(qboolean visible)
2538 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2539 R_Shadow_EditLights_Reload_f();
2541 R_Shadow_RenderMode_Begin();
2543 flag = r_refdef.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2544 if (r_shadow_debuglight.integer >= 0)
2546 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2547 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
2548 R_DrawRTLight(&light->rtlight, visible);
2551 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2552 if (light->flags & flag)
2553 R_DrawRTLight(&light->rtlight, visible);
2554 if (r_refdef.rtdlight)
2555 for (lnum = 0;lnum < r_refdef.numlights;lnum++)
2556 R_DrawRTLight(&r_refdef.lights[lnum], visible);
2558 R_Shadow_RenderMode_End();
2561 extern void R_SetupView(const matrix4x4_t *matrix);
2562 extern cvar_t r_shadows_throwdistance;
2563 void R_DrawModelShadows(void)
2566 float relativethrowdistance;
2567 entity_render_t *ent;
2568 vec3_t relativelightorigin;
2569 vec3_t relativelightdirection;
2570 vec3_t relativeshadowmins, relativeshadowmaxs;
2573 if (!r_drawentities.integer || !gl_stencil)
2577 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
2579 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2581 if (gl_ext_separatestencil.integer)
2582 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
2583 else if (gl_ext_stenciltwoside.integer)
2584 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
2586 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
2588 R_Shadow_RenderMode_StencilShadowVolumes();
2590 for (i = 0;i < r_refdef.numentities;i++)
2592 ent = r_refdef.entities[i];
2593 // cast shadows from anything that is not a submodel of the map
2594 if (ent->model && ent->model->DrawShadowVolume != NULL && !ent->model->brush.submodel && (ent->flags & RENDER_SHADOW))
2596 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
2597 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
2598 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
2599 VectorNegate(ent->modellight_lightdir, relativelightdirection);
2600 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
2601 R_Mesh_Matrix(&ent->matrix);
2602 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2606 // not really the right mode, but this will disable any silly stencil features
2607 R_Shadow_RenderMode_VisibleLighting(true, true);
2609 // vertex coordinates for a quad that covers the screen exactly
2610 vertex3f[0] = 0;vertex3f[1] = 0;vertex3f[2] = 0;
2611 vertex3f[3] = 1;vertex3f[4] = 0;vertex3f[5] = 0;
2612 vertex3f[6] = 1;vertex3f[7] = 1;vertex3f[8] = 0;
2613 vertex3f[9] = 0;vertex3f[10] = 1;vertex3f[11] = 0;
2615 // set up ortho view for rendering this pass
2616 GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
2617 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
2618 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
2619 GL_ScissorTest(true);
2620 R_Mesh_Matrix(&identitymatrix);
2621 R_Mesh_ResetTextureState();
2622 R_Mesh_VertexPointer(vertex3f);
2623 R_Mesh_ColorPointer(NULL);
2625 // set up a 50% darkening blend on shadowed areas
2626 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2627 GL_DepthTest(false);
2628 GL_DepthMask(false);
2629 qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
2630 GL_Color(0, 0, 0, 0.5);
2631 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
2632 qglDepthFunc(GL_ALWAYS);CHECKGLERROR
2633 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2634 qglStencilMask(~0);CHECKGLERROR
2635 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
2636 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
2638 // apply the blend to the shadowed areas
2639 R_Mesh_Draw(0, 4, 2, polygonelements);
2641 // restoring the perspective view is done by R_RenderScene
2642 //R_SetupView(&r_view.matrix);
2644 // restore other state to normal
2645 R_Shadow_RenderMode_End();
2649 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2650 typedef struct suffixinfo_s
2653 qboolean flipx, flipy, flipdiagonal;
2656 static suffixinfo_t suffix[3][6] =
2659 {"px", false, false, false},
2660 {"nx", false, false, false},
2661 {"py", false, false, false},
2662 {"ny", false, false, false},
2663 {"pz", false, false, false},
2664 {"nz", false, false, false}
2667 {"posx", false, false, false},
2668 {"negx", false, false, false},
2669 {"posy", false, false, false},
2670 {"negy", false, false, false},
2671 {"posz", false, false, false},
2672 {"negz", false, false, false}
2675 {"rt", true, false, true},
2676 {"lf", false, true, true},
2677 {"ft", true, true, false},
2678 {"bk", false, false, false},
2679 {"up", true, false, true},
2680 {"dn", true, false, true}
2684 static int componentorder[4] = {0, 1, 2, 3};
2686 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2688 int i, j, cubemapsize;
2689 unsigned char *cubemappixels, *image_rgba;
2690 rtexture_t *cubemaptexture;
2692 // must start 0 so the first loadimagepixels has no requested width/height
2694 cubemappixels = NULL;
2695 cubemaptexture = NULL;
2696 // keep trying different suffix groups (posx, px, rt) until one loads
2697 for (j = 0;j < 3 && !cubemappixels;j++)
2699 // load the 6 images in the suffix group
2700 for (i = 0;i < 6;i++)
2702 // generate an image name based on the base and and suffix
2703 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2705 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2707 // an image loaded, make sure width and height are equal
2708 if (image_width == image_height)
2710 // if this is the first image to load successfully, allocate the cubemap memory
2711 if (!cubemappixels && image_width >= 1)
2713 cubemapsize = image_width;
2714 // note this clears to black, so unavailable sides are black
2715 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2717 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2719 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);
2722 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2724 Mem_Free(image_rgba);
2728 // if a cubemap loaded, upload it
2731 if (!r_shadow_filters_texturepool)
2732 r_shadow_filters_texturepool = R_AllocTexturePool();
2733 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
2734 Mem_Free(cubemappixels);
2738 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
2739 for (j = 0;j < 3;j++)
2740 for (i = 0;i < 6;i++)
2741 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2742 Con_Print(" and was unable to find any of them.\n");
2744 return cubemaptexture;
2747 rtexture_t *R_Shadow_Cubemap(const char *basename)
2750 for (i = 0;i < numcubemaps;i++)
2751 if (!strcasecmp(cubemaps[i].basename, basename))
2752 return cubemaps[i].texture;
2753 if (i >= MAX_CUBEMAPS)
2754 return r_texture_whitecube;
2756 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
2757 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
2758 if (!cubemaps[i].texture)
2759 cubemaps[i].texture = r_texture_whitecube;
2760 return cubemaps[i].texture;
2763 void R_Shadow_FreeCubemaps(void)
2766 R_FreeTexturePool(&r_shadow_filters_texturepool);
2769 dlight_t *R_Shadow_NewWorldLight(void)
2772 light = (dlight_t *)Mem_Alloc(r_main_mempool, sizeof(dlight_t));
2773 light->next = r_shadow_worldlightchain;
2774 r_shadow_worldlightchain = light;
2778 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)
2781 // validate parameters
2782 if (style < 0 || style >= MAX_LIGHTSTYLES)
2784 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
2790 // copy to light properties
2791 VectorCopy(origin, light->origin);
2792 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
2793 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
2794 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
2795 light->color[0] = max(color[0], 0);
2796 light->color[1] = max(color[1], 0);
2797 light->color[2] = max(color[2], 0);
2798 light->radius = max(radius, 0);
2799 light->style = style;
2800 light->shadow = shadowenable;
2801 light->corona = corona;
2802 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
2803 light->coronasizescale = coronasizescale;
2804 light->ambientscale = ambientscale;
2805 light->diffusescale = diffusescale;
2806 light->specularscale = specularscale;
2807 light->flags = flags;
2809 // update renderable light data
2810 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
2811 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);
2814 void R_Shadow_FreeWorldLight(dlight_t *light)
2816 dlight_t **lightpointer;
2817 R_RTLight_Uncompile(&light->rtlight);
2818 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
2819 if (*lightpointer != light)
2820 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain");
2821 *lightpointer = light->next;
2825 void R_Shadow_ClearWorldLights(void)
2827 while (r_shadow_worldlightchain)
2828 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
2829 r_shadow_selectedlight = NULL;
2830 R_Shadow_FreeCubemaps();
2833 void R_Shadow_SelectLight(dlight_t *light)
2835 if (r_shadow_selectedlight)
2836 r_shadow_selectedlight->selected = false;
2837 r_shadow_selectedlight = light;
2838 if (r_shadow_selectedlight)
2839 r_shadow_selectedlight->selected = true;
2842 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2844 // this is never batched (there can be only one)
2845 float scale = r_editlights_cursorgrid.value * 0.5f;
2846 R_DrawSprite(GL_SRC_ALPHA, GL_ONE, r_crosshairs[1]->tex, NULL, false, r_editlights_cursorlocation, r_view.right, r_view.up, scale, -scale, -scale, scale, 1, 1, 1, 0.5f);
2849 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2851 // this is never batched (due to the ent parameter changing every time)
2852 // so numsurfaces == 1 and surfacelist[0] == lightnumber
2854 const dlight_t *light = (dlight_t *)ent;
2856 if (light->selected)
2857 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
2860 R_DrawSprite(GL_SRC_ALPHA, GL_ONE, r_crosshairs[surfacelist[0]]->tex, NULL, false, light->origin, r_view.right, r_view.up, 8, -8, -8, 8, intensity, intensity, intensity, 0.5);
2863 void R_Shadow_DrawLightSprites(void)
2868 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
2869 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 1+(i % 5), &light->rtlight);
2870 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
2873 void R_Shadow_SelectLightInView(void)
2875 float bestrating, rating, temp[3];
2876 dlight_t *best, *light;
2879 for (light = r_shadow_worldlightchain;light;light = light->next)
2881 VectorSubtract(light->origin, r_view.origin, temp);
2882 rating = (DotProduct(temp, r_view.forward) / sqrt(DotProduct(temp, temp)));
2885 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
2886 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)
2888 bestrating = rating;
2893 R_Shadow_SelectLight(best);
2896 void R_Shadow_LoadWorldLights(void)
2898 int n, a, style, shadow, flags;
2899 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
2900 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
2901 if (r_refdef.worldmodel == NULL)
2903 Con_Print("No map loaded.\n");
2906 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
2907 strlcat (name, ".rtlights", sizeof (name));
2908 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
2918 for (;COM_Parse(t, true) && strcmp(
2919 if (COM_Parse(t, true))
2921 if (com_token[0] == '!')
2924 origin[0] = atof(com_token+1);
2927 origin[0] = atof(com_token);
2932 while (*s && *s != '\n' && *s != '\r')
2938 // check for modifier flags
2945 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);
2948 flags = LIGHTFLAG_REALTIMEMODE;
2956 coronasizescale = 0.25f;
2958 VectorClear(angles);
2961 if (a < 9 || !strcmp(cubemapname, "\"\""))
2963 // remove quotes on cubemapname
2964 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
2967 namelen = strlen(cubemapname) - 2;
2968 memmove(cubemapname, cubemapname + 1, namelen);
2969 cubemapname[namelen] = '\0';
2973 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);
2976 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
2984 Con_Printf("invalid rtlights file \"%s\"\n", name);
2985 Mem_Free(lightsstring);
2989 void R_Shadow_SaveWorldLights(void)
2992 size_t bufchars, bufmaxchars;
2994 char name[MAX_QPATH];
2995 char line[MAX_INPUTLINE];
2996 if (!r_shadow_worldlightchain)
2998 if (r_refdef.worldmodel == NULL)
3000 Con_Print("No map loaded.\n");
3003 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3004 strlcat (name, ".rtlights", sizeof (name));
3005 bufchars = bufmaxchars = 0;
3007 for (light = r_shadow_worldlightchain;light;light = light->next)
3009 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3010 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);
3011 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3012 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]);
3014 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);
3015 if (bufchars + strlen(line) > bufmaxchars)
3017 bufmaxchars = bufchars + strlen(line) + 2048;
3019 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
3023 memcpy(buf, oldbuf, bufchars);
3029 memcpy(buf + bufchars, line, strlen(line));
3030 bufchars += strlen(line);
3034 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
3039 void R_Shadow_LoadLightsFile(void)
3042 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3043 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3044 if (r_refdef.worldmodel == NULL)
3046 Con_Print("No map loaded.\n");
3049 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3050 strlcat (name, ".lights", sizeof (name));
3051 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3059 while (*s && *s != '\n' && *s != '\r')
3065 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);
3069 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);
3072 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3073 radius = bound(15, radius, 4096);
3074 VectorScale(color, (2.0f / (8388608.0f)), color);
3075 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3083 Con_Printf("invalid lights file \"%s\"\n", name);
3084 Mem_Free(lightsstring);
3088 // tyrlite/hmap2 light types in the delay field
3089 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3091 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3093 int entnum, style, islight, skin, pflags, effects, type, n;
3096 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3097 char key[256], value[MAX_INPUTLINE];
3099 if (r_refdef.worldmodel == NULL)
3101 Con_Print("No map loaded.\n");
3104 // try to load a .ent file first
3105 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3106 strlcat (key, ".ent", sizeof (key));
3107 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
3108 // and if that is not found, fall back to the bsp file entity string
3110 data = r_refdef.worldmodel->brush.entities;
3113 for (entnum = 0;COM_ParseTokenConsole(&data) && com_token[0] == '{';entnum++)
3115 type = LIGHTTYPE_MINUSX;
3116 origin[0] = origin[1] = origin[2] = 0;
3117 originhack[0] = originhack[1] = originhack[2] = 0;
3118 angles[0] = angles[1] = angles[2] = 0;
3119 color[0] = color[1] = color[2] = 1;
3120 light[0] = light[1] = light[2] = 1;light[3] = 300;
3121 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3131 if (!COM_ParseTokenConsole(&data))
3133 if (com_token[0] == '}')
3134 break; // end of entity
3135 if (com_token[0] == '_')
3136 strlcpy(key, com_token + 1, sizeof(key));
3138 strlcpy(key, com_token, sizeof(key));
3139 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3140 key[strlen(key)-1] = 0;
3141 if (!COM_ParseTokenConsole(&data))
3143 strlcpy(value, com_token, sizeof(value));
3145 // now that we have the key pair worked out...
3146 if (!strcmp("light", key))
3148 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3152 light[0] = vec[0] * (1.0f / 256.0f);
3153 light[1] = vec[0] * (1.0f / 256.0f);
3154 light[2] = vec[0] * (1.0f / 256.0f);
3160 light[0] = vec[0] * (1.0f / 255.0f);
3161 light[1] = vec[1] * (1.0f / 255.0f);
3162 light[2] = vec[2] * (1.0f / 255.0f);
3166 else if (!strcmp("delay", key))
3168 else if (!strcmp("origin", key))
3169 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3170 else if (!strcmp("angle", key))
3171 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3172 else if (!strcmp("angles", key))
3173 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3174 else if (!strcmp("color", key))
3175 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3176 else if (!strcmp("wait", key))
3177 fadescale = atof(value);
3178 else if (!strcmp("classname", key))
3180 if (!strncmp(value, "light", 5))
3183 if (!strcmp(value, "light_fluoro"))
3188 overridecolor[0] = 1;
3189 overridecolor[1] = 1;
3190 overridecolor[2] = 1;
3192 if (!strcmp(value, "light_fluorospark"))
3197 overridecolor[0] = 1;
3198 overridecolor[1] = 1;
3199 overridecolor[2] = 1;
3201 if (!strcmp(value, "light_globe"))
3206 overridecolor[0] = 1;
3207 overridecolor[1] = 0.8;
3208 overridecolor[2] = 0.4;
3210 if (!strcmp(value, "light_flame_large_yellow"))
3215 overridecolor[0] = 1;
3216 overridecolor[1] = 0.5;
3217 overridecolor[2] = 0.1;
3219 if (!strcmp(value, "light_flame_small_yellow"))
3224 overridecolor[0] = 1;
3225 overridecolor[1] = 0.5;
3226 overridecolor[2] = 0.1;
3228 if (!strcmp(value, "light_torch_small_white"))
3233 overridecolor[0] = 1;
3234 overridecolor[1] = 0.5;
3235 overridecolor[2] = 0.1;
3237 if (!strcmp(value, "light_torch_small_walltorch"))
3242 overridecolor[0] = 1;
3243 overridecolor[1] = 0.5;
3244 overridecolor[2] = 0.1;
3248 else if (!strcmp("style", key))
3249 style = atoi(value);
3250 else if (!strcmp("skin", key))
3251 skin = (int)atof(value);
3252 else if (!strcmp("pflags", key))
3253 pflags = (int)atof(value);
3254 else if (!strcmp("effects", key))
3255 effects = (int)atof(value);
3256 else if (r_refdef.worldmodel->type == mod_brushq3)
3258 if (!strcmp("scale", key))
3259 lightscale = atof(value);
3260 if (!strcmp("fade", key))
3261 fadescale = atof(value);
3266 if (lightscale <= 0)
3270 if (color[0] == color[1] && color[0] == color[2])
3272 color[0] *= overridecolor[0];
3273 color[1] *= overridecolor[1];
3274 color[2] *= overridecolor[2];
3276 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3277 color[0] = color[0] * light[0];
3278 color[1] = color[1] * light[1];
3279 color[2] = color[2] * light[2];
3282 case LIGHTTYPE_MINUSX:
3284 case LIGHTTYPE_RECIPX:
3286 VectorScale(color, (1.0f / 16.0f), color);
3288 case LIGHTTYPE_RECIPXX:
3290 VectorScale(color, (1.0f / 16.0f), color);
3293 case LIGHTTYPE_NONE:
3297 case LIGHTTYPE_MINUSXX:
3300 VectorAdd(origin, originhack, origin);
3302 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);
3305 Mem_Free(entfiledata);
3309 void R_Shadow_SetCursorLocationForView(void)
3312 vec3_t dest, endpos;
3314 VectorMA(r_view.origin, r_editlights_cursordistance.value, r_view.forward, dest);
3315 trace = CL_Move(r_view.origin, vec3_origin, vec3_origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
3316 if (trace.fraction < 1)
3318 dist = trace.fraction * r_editlights_cursordistance.value;
3319 push = r_editlights_cursorpushback.value;
3323 VectorMA(trace.endpos, push, r_view.forward, endpos);
3324 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
3328 VectorClear( endpos );
3330 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3331 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3332 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3335 void R_Shadow_UpdateWorldLightSelection(void)
3337 if (r_editlights.integer)
3339 R_Shadow_SetCursorLocationForView();
3340 R_Shadow_SelectLightInView();
3341 R_Shadow_DrawLightSprites();
3344 R_Shadow_SelectLight(NULL);
3347 void R_Shadow_EditLights_Clear_f(void)
3349 R_Shadow_ClearWorldLights();
3352 void R_Shadow_EditLights_Reload_f(void)
3354 if (!r_refdef.worldmodel)
3356 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3357 R_Shadow_ClearWorldLights();
3358 R_Shadow_LoadWorldLights();
3359 if (r_shadow_worldlightchain == NULL)
3361 R_Shadow_LoadLightsFile();
3362 if (r_shadow_worldlightchain == NULL)
3363 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3367 void R_Shadow_EditLights_Save_f(void)
3369 if (!r_refdef.worldmodel)
3371 R_Shadow_SaveWorldLights();
3374 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3376 R_Shadow_ClearWorldLights();
3377 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3380 void R_Shadow_EditLights_ImportLightsFile_f(void)
3382 R_Shadow_ClearWorldLights();
3383 R_Shadow_LoadLightsFile();
3386 void R_Shadow_EditLights_Spawn_f(void)
3389 if (!r_editlights.integer)
3391 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3394 if (Cmd_Argc() != 1)
3396 Con_Print("r_editlights_spawn does not take parameters\n");
3399 color[0] = color[1] = color[2] = 1;
3400 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3403 void R_Shadow_EditLights_Edit_f(void)
3405 vec3_t origin, angles, color;
3406 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3407 int style, shadows, flags, normalmode, realtimemode;
3408 char cubemapname[MAX_INPUTLINE];
3409 if (!r_editlights.integer)
3411 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3414 if (!r_shadow_selectedlight)
3416 Con_Print("No selected light.\n");
3419 VectorCopy(r_shadow_selectedlight->origin, origin);
3420 VectorCopy(r_shadow_selectedlight->angles, angles);
3421 VectorCopy(r_shadow_selectedlight->color, color);
3422 radius = r_shadow_selectedlight->radius;
3423 style = r_shadow_selectedlight->style;
3424 if (r_shadow_selectedlight->cubemapname)
3425 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
3428 shadows = r_shadow_selectedlight->shadow;
3429 corona = r_shadow_selectedlight->corona;
3430 coronasizescale = r_shadow_selectedlight->coronasizescale;
3431 ambientscale = r_shadow_selectedlight->ambientscale;
3432 diffusescale = r_shadow_selectedlight->diffusescale;
3433 specularscale = r_shadow_selectedlight->specularscale;
3434 flags = r_shadow_selectedlight->flags;
3435 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3436 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3437 if (!strcmp(Cmd_Argv(1), "origin"))
3439 if (Cmd_Argc() != 5)
3441 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3444 origin[0] = atof(Cmd_Argv(2));
3445 origin[1] = atof(Cmd_Argv(3));
3446 origin[2] = atof(Cmd_Argv(4));
3448 else if (!strcmp(Cmd_Argv(1), "originx"))
3450 if (Cmd_Argc() != 3)
3452 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3455 origin[0] = atof(Cmd_Argv(2));
3457 else if (!strcmp(Cmd_Argv(1), "originy"))
3459 if (Cmd_Argc() != 3)
3461 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3464 origin[1] = atof(Cmd_Argv(2));
3466 else if (!strcmp(Cmd_Argv(1), "originz"))
3468 if (Cmd_Argc() != 3)
3470 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3473 origin[2] = atof(Cmd_Argv(2));
3475 else if (!strcmp(Cmd_Argv(1), "move"))
3477 if (Cmd_Argc() != 5)
3479 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3482 origin[0] += atof(Cmd_Argv(2));
3483 origin[1] += atof(Cmd_Argv(3));
3484 origin[2] += atof(Cmd_Argv(4));
3486 else if (!strcmp(Cmd_Argv(1), "movex"))
3488 if (Cmd_Argc() != 3)
3490 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3493 origin[0] += atof(Cmd_Argv(2));
3495 else if (!strcmp(Cmd_Argv(1), "movey"))
3497 if (Cmd_Argc() != 3)
3499 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3502 origin[1] += atof(Cmd_Argv(2));
3504 else if (!strcmp(Cmd_Argv(1), "movez"))
3506 if (Cmd_Argc() != 3)
3508 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3511 origin[2] += atof(Cmd_Argv(2));
3513 else if (!strcmp(Cmd_Argv(1), "angles"))
3515 if (Cmd_Argc() != 5)
3517 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3520 angles[0] = atof(Cmd_Argv(2));
3521 angles[1] = atof(Cmd_Argv(3));
3522 angles[2] = atof(Cmd_Argv(4));
3524 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3526 if (Cmd_Argc() != 3)
3528 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3531 angles[0] = atof(Cmd_Argv(2));
3533 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3535 if (Cmd_Argc() != 3)
3537 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3540 angles[1] = atof(Cmd_Argv(2));
3542 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3544 if (Cmd_Argc() != 3)
3546 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3549 angles[2] = atof(Cmd_Argv(2));
3551 else if (!strcmp(Cmd_Argv(1), "color"))
3553 if (Cmd_Argc() != 5)
3555 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3558 color[0] = atof(Cmd_Argv(2));
3559 color[1] = atof(Cmd_Argv(3));
3560 color[2] = atof(Cmd_Argv(4));
3562 else if (!strcmp(Cmd_Argv(1), "radius"))
3564 if (Cmd_Argc() != 3)
3566 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3569 radius = atof(Cmd_Argv(2));
3571 else if (!strcmp(Cmd_Argv(1), "colorscale"))
3573 if (Cmd_Argc() == 3)
3575 double scale = atof(Cmd_Argv(2));
3582 if (Cmd_Argc() != 5)
3584 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
3587 color[0] *= atof(Cmd_Argv(2));
3588 color[1] *= atof(Cmd_Argv(3));
3589 color[2] *= atof(Cmd_Argv(4));
3592 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
3594 if (Cmd_Argc() != 3)
3596 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3599 radius *= atof(Cmd_Argv(2));
3601 else if (!strcmp(Cmd_Argv(1), "style"))
3603 if (Cmd_Argc() != 3)
3605 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3608 style = atoi(Cmd_Argv(2));
3610 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3614 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3617 if (Cmd_Argc() == 3)
3618 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
3622 else if (!strcmp(Cmd_Argv(1), "shadows"))
3624 if (Cmd_Argc() != 3)
3626 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3629 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3631 else if (!strcmp(Cmd_Argv(1), "corona"))
3633 if (Cmd_Argc() != 3)
3635 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3638 corona = atof(Cmd_Argv(2));
3640 else if (!strcmp(Cmd_Argv(1), "coronasize"))
3642 if (Cmd_Argc() != 3)
3644 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3647 coronasizescale = atof(Cmd_Argv(2));
3649 else if (!strcmp(Cmd_Argv(1), "ambient"))
3651 if (Cmd_Argc() != 3)
3653 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3656 ambientscale = atof(Cmd_Argv(2));
3658 else if (!strcmp(Cmd_Argv(1), "diffuse"))
3660 if (Cmd_Argc() != 3)
3662 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3665 diffusescale = atof(Cmd_Argv(2));
3667 else if (!strcmp(Cmd_Argv(1), "specular"))
3669 if (Cmd_Argc() != 3)
3671 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3674 specularscale = atof(Cmd_Argv(2));
3676 else if (!strcmp(Cmd_Argv(1), "normalmode"))
3678 if (Cmd_Argc() != 3)
3680 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3683 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3685 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
3687 if (Cmd_Argc() != 3)
3689 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3692 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3696 Con_Print("usage: r_editlights_edit [property] [value]\n");
3697 Con_Print("Selected light's properties:\n");
3698 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3699 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3700 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3701 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3702 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3703 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3704 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3705 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
3706 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
3707 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
3708 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
3709 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
3710 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
3711 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
3714 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
3715 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3718 void R_Shadow_EditLights_EditAll_f(void)
3722 if (!r_editlights.integer)
3724 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
3728 for (light = r_shadow_worldlightchain;light;light = light->next)
3730 R_Shadow_SelectLight(light);
3731 R_Shadow_EditLights_Edit_f();
3735 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3737 int lightnumber, lightcount;
3741 if (!r_editlights.integer)
3747 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
3748 if (light == r_shadow_selectedlight)
3749 lightnumber = lightcount;
3750 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);y += 8;
3751 if (r_shadow_selectedlight == NULL)
3753 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3754 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);y += 8;
3755 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);y += 8;
3756 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);y += 8;
3757 sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3758 sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3759 sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3760 sprintf(temp, "Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3761 sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3762 sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3763 sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3764 sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3765 sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3766 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);y += 8;
3767 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);y += 8;
3770 void R_Shadow_EditLights_ToggleShadow_f(void)
3772 if (!r_editlights.integer)
3774 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3777 if (!r_shadow_selectedlight)
3779 Con_Print("No selected light.\n");
3782 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);
3785 void R_Shadow_EditLights_ToggleCorona_f(void)
3787 if (!r_editlights.integer)
3789 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3792 if (!r_shadow_selectedlight)
3794 Con_Print("No selected light.\n");
3797 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);
3800 void R_Shadow_EditLights_Remove_f(void)
3802 if (!r_editlights.integer)
3804 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
3807 if (!r_shadow_selectedlight)
3809 Con_Print("No selected light.\n");
3812 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3813 r_shadow_selectedlight = NULL;
3816 void R_Shadow_EditLights_Help_f(void)
3819 "Documentation on r_editlights system:\n"
3821 "r_editlights : enable/disable editing mode\n"
3822 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
3823 "r_editlights_cursorpushback : push back cursor this far from surface\n"
3824 "r_editlights_cursorpushoff : push cursor off surface this far\n"
3825 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
3826 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
3828 "r_editlights_help : this help\n"
3829 "r_editlights_clear : remove all lights\n"
3830 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
3831 "r_editlights_save : save to .rtlights file\n"
3832 "r_editlights_spawn : create a light with default settings\n"
3833 "r_editlights_edit command : edit selected light - more documentation below\n"
3834 "r_editlights_remove : remove selected light\n"
3835 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
3836 "r_editlights_importlightentitiesfrommap : reload light entities\n"
3837 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
3839 "origin x y z : set light location\n"
3840 "originx x: set x component of light location\n"
3841 "originy y: set y component of light location\n"
3842 "originz z: set z component of light location\n"
3843 "move x y z : adjust light location\n"
3844 "movex x: adjust x component of light location\n"
3845 "movey y: adjust y component of light location\n"
3846 "movez z: adjust z component of light location\n"
3847 "angles x y z : set light angles\n"
3848 "anglesx x: set x component of light angles\n"
3849 "anglesy y: set y component of light angles\n"
3850 "anglesz z: set z component of light angles\n"
3851 "color r g b : set color of light (can be brighter than 1 1 1)\n"
3852 "radius radius : set radius (size) of light\n"
3853 "colorscale grey : multiply color of light (1 does nothing)\n"
3854 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
3855 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
3856 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
3857 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
3858 "cubemap basename : set filter cubemap of light (not yet supported)\n"
3859 "shadows 1/0 : turn on/off shadows\n"
3860 "corona n : set corona intensity\n"
3861 "coronasize n : set corona size (0-1)\n"
3862 "ambient n : set ambient intensity (0-1)\n"
3863 "diffuse n : set diffuse intensity (0-1)\n"
3864 "specular n : set specular intensity (0-1)\n"
3865 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
3866 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
3867 "<nothing> : print light properties to console\n"
3871 void R_Shadow_EditLights_CopyInfo_f(void)
3873 if (!r_editlights.integer)
3875 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
3878 if (!r_shadow_selectedlight)
3880 Con_Print("No selected light.\n");
3883 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
3884 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
3885 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
3886 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
3887 if (r_shadow_selectedlight->cubemapname)
3888 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
3890 r_shadow_bufferlight.cubemapname[0] = 0;
3891 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
3892 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
3893 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
3894 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
3895 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
3896 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
3897 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
3900 void R_Shadow_EditLights_PasteInfo_f(void)
3902 if (!r_editlights.integer)
3904 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
3907 if (!r_shadow_selectedlight)
3909 Con_Print("No selected light.\n");
3912 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);
3915 void R_Shadow_EditLights_Init(void)
3917 Cvar_RegisterVariable(&r_editlights);
3918 Cvar_RegisterVariable(&r_editlights_cursordistance);
3919 Cvar_RegisterVariable(&r_editlights_cursorpushback);
3920 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
3921 Cvar_RegisterVariable(&r_editlights_cursorgrid);
3922 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
3923 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
3924 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
3925 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)");
3926 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
3927 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
3928 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
3929 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)");
3930 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
3931 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
3932 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
3933 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
3934 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
3935 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
3936 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)");