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", "2", "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_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)"};
219 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"};
220 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"};
221 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
222 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
223 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"};
224 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation"};
225 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)"};
226 cvar_t r_shadow_shadow_polygonfactor = {0, "r_shadow_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
227 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)"};
228 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)"};
229 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatetencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
230 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
231 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
232 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
233 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
234 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
235 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
236 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
238 float r_shadow_attenpower, r_shadow_attenscale;
240 rtlight_t *r_shadow_compilingrtlight;
241 dlight_t *r_shadow_worldlightchain;
242 dlight_t *r_shadow_selectedlight;
243 dlight_t r_shadow_bufferlight;
244 vec3_t r_editlights_cursorlocation;
246 extern int con_vislines;
248 typedef struct cubemapinfo_s
255 #define MAX_CUBEMAPS 256
256 static int numcubemaps;
257 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
259 void R_Shadow_UncompileWorldLights(void);
260 void R_Shadow_ClearWorldLights(void);
261 void R_Shadow_SaveWorldLights(void);
262 void R_Shadow_LoadWorldLights(void);
263 void R_Shadow_LoadLightsFile(void);
264 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
265 void R_Shadow_EditLights_Reload_f(void);
266 void R_Shadow_ValidateCvars(void);
267 static void R_Shadow_MakeTextures(void);
268 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light);
270 void r_shadow_start(void)
272 // allocate vertex processing arrays
274 r_shadow_attenuation2dtexture = NULL;
275 r_shadow_attenuation3dtexture = NULL;
276 r_shadow_texturepool = NULL;
277 r_shadow_filters_texturepool = NULL;
278 R_Shadow_ValidateCvars();
279 R_Shadow_MakeTextures();
280 maxshadowtriangles = 0;
281 shadowelements = NULL;
282 maxshadowvertices = 0;
283 shadowvertex3f = NULL;
291 shadowmarklist = NULL;
293 r_shadow_buffer_numleafpvsbytes = 0;
294 r_shadow_buffer_leafpvs = NULL;
295 r_shadow_buffer_leaflist = NULL;
296 r_shadow_buffer_numsurfacepvsbytes = 0;
297 r_shadow_buffer_surfacepvs = NULL;
298 r_shadow_buffer_surfacelist = NULL;
301 void r_shadow_shutdown(void)
303 R_Shadow_UncompileWorldLights();
305 r_shadow_attenuation2dtexture = NULL;
306 r_shadow_attenuation3dtexture = NULL;
307 R_FreeTexturePool(&r_shadow_texturepool);
308 R_FreeTexturePool(&r_shadow_filters_texturepool);
309 maxshadowtriangles = 0;
311 Mem_Free(shadowelements);
312 shadowelements = NULL;
314 Mem_Free(shadowvertex3f);
315 shadowvertex3f = NULL;
318 Mem_Free(vertexupdate);
321 Mem_Free(vertexremap);
327 Mem_Free(shadowmark);
330 Mem_Free(shadowmarklist);
331 shadowmarklist = NULL;
333 r_shadow_buffer_numleafpvsbytes = 0;
334 if (r_shadow_buffer_leafpvs)
335 Mem_Free(r_shadow_buffer_leafpvs);
336 r_shadow_buffer_leafpvs = NULL;
337 if (r_shadow_buffer_leaflist)
338 Mem_Free(r_shadow_buffer_leaflist);
339 r_shadow_buffer_leaflist = NULL;
340 r_shadow_buffer_numsurfacepvsbytes = 0;
341 if (r_shadow_buffer_surfacepvs)
342 Mem_Free(r_shadow_buffer_surfacepvs);
343 r_shadow_buffer_surfacepvs = NULL;
344 if (r_shadow_buffer_surfacelist)
345 Mem_Free(r_shadow_buffer_surfacelist);
346 r_shadow_buffer_surfacelist = NULL;
349 void r_shadow_newmap(void)
353 void R_Shadow_Help_f(void)
356 "Documentation on r_shadow system:\n"
358 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
359 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
360 "r_shadow_debuglight : render only this light number (-1 = all)\n"
361 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
362 "r_shadow_gloss2intensity : brightness of forced gloss\n"
363 "r_shadow_glossintensity : brightness of textured gloss\n"
364 "r_shadow_lightattenuationpower : used to generate attenuation texture\n"
365 "r_shadow_lightattenuationscale : used to generate attenuation texture\n"
366 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
367 "r_shadow_portallight : use portal visibility for static light precomputation\n"
368 "r_shadow_projectdistance : shadow volume projection distance\n"
369 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
370 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
371 "r_shadow_realtime_world : use high quality world lighting mode\n"
372 "r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n"
373 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
374 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
375 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
376 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
377 "r_shadow_scissor : use scissor optimization\n"
378 "r_shadow_shadow_polygonfactor : nudge shadow volumes closer/further\n"
379 "r_shadow_shadow_polygonoffset : nudge shadow volumes closer/further\n"
380 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
381 "r_showlighting : useful for performance testing; bright = slow!\n"
382 "r_showshadowvolumes : useful for performance testing; bright = slow!\n"
384 "r_shadow_help : this help\n"
388 void R_Shadow_Init(void)
390 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
391 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
392 Cvar_RegisterVariable(&r_shadow_debuglight);
393 Cvar_RegisterVariable(&r_shadow_gloss);
394 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
395 Cvar_RegisterVariable(&r_shadow_glossintensity);
396 Cvar_RegisterVariable(&r_shadow_glossexponent);
397 Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
398 Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
399 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
400 Cvar_RegisterVariable(&r_shadow_portallight);
401 Cvar_RegisterVariable(&r_shadow_projectdistance);
402 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
403 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
404 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
405 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
406 Cvar_RegisterVariable(&r_shadow_realtime_world);
407 Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows);
408 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
409 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
410 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
411 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
412 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
413 Cvar_RegisterVariable(&r_shadow_scissor);
414 Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor);
415 Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset);
416 Cvar_RegisterVariable(&r_shadow_texture3d);
417 Cvar_RegisterVariable(&gl_ext_separatestencil);
418 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
419 if (gamemode == GAME_TENEBRAE)
421 Cvar_SetValue("r_shadow_gloss", 2);
422 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
424 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f, "prints documentation on console commands and variables used by realtime lighting and shadowing system");
425 R_Shadow_EditLights_Init();
426 r_shadow_worldlightchain = NULL;
427 maxshadowtriangles = 0;
428 shadowelements = NULL;
429 maxshadowvertices = 0;
430 shadowvertex3f = NULL;
438 shadowmarklist = NULL;
440 r_shadow_buffer_numleafpvsbytes = 0;
441 r_shadow_buffer_leafpvs = NULL;
442 r_shadow_buffer_leaflist = NULL;
443 r_shadow_buffer_numsurfacepvsbytes = 0;
444 r_shadow_buffer_surfacepvs = NULL;
445 r_shadow_buffer_surfacelist = NULL;
446 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
449 matrix4x4_t matrix_attenuationxyz =
452 {0.5, 0.0, 0.0, 0.5},
453 {0.0, 0.5, 0.0, 0.5},
454 {0.0, 0.0, 0.5, 0.5},
459 matrix4x4_t matrix_attenuationz =
462 {0.0, 0.0, 0.5, 0.5},
463 {0.0, 0.0, 0.0, 0.5},
464 {0.0, 0.0, 0.0, 0.5},
469 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles)
471 // make sure shadowelements is big enough for this volume
472 if (maxshadowtriangles < numtriangles)
474 maxshadowtriangles = numtriangles;
476 Mem_Free(shadowelements);
477 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[24]));
479 // make sure shadowvertex3f is big enough for this volume
480 if (maxshadowvertices < numvertices)
482 maxshadowvertices = numvertices;
484 Mem_Free(shadowvertex3f);
485 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[6]));
489 static void R_Shadow_EnlargeLeafSurfaceBuffer(int numleafs, int numsurfaces)
491 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
492 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
493 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
495 if (r_shadow_buffer_leafpvs)
496 Mem_Free(r_shadow_buffer_leafpvs);
497 if (r_shadow_buffer_leaflist)
498 Mem_Free(r_shadow_buffer_leaflist);
499 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
500 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
501 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
503 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
505 if (r_shadow_buffer_surfacepvs)
506 Mem_Free(r_shadow_buffer_surfacepvs);
507 if (r_shadow_buffer_surfacelist)
508 Mem_Free(r_shadow_buffer_surfacelist);
509 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
510 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
511 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
515 void R_Shadow_PrepareShadowMark(int numtris)
517 // make sure shadowmark is big enough for this volume
518 if (maxshadowmark < numtris)
520 maxshadowmark = numtris;
522 Mem_Free(shadowmark);
524 Mem_Free(shadowmarklist);
525 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
526 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
530 // if shadowmarkcount wrapped we clear the array and adjust accordingly
531 if (shadowmarkcount == 0)
534 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
539 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)
542 int outtriangles = 0, outvertices = 0;
545 float ratio, direction[3], projectvector[3];
547 if (projectdirection)
548 VectorScale(projectdirection, projectdistance, projectvector);
550 VectorClear(projectvector);
552 if (maxvertexupdate < innumvertices)
554 maxvertexupdate = innumvertices;
556 Mem_Free(vertexupdate);
558 Mem_Free(vertexremap);
559 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
560 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
564 if (vertexupdatenum == 0)
567 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
568 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
571 for (i = 0;i < numshadowmarktris;i++)
572 shadowmark[shadowmarktris[i]] = shadowmarkcount;
574 // create the vertices
575 if (projectdirection)
577 for (i = 0;i < numshadowmarktris;i++)
579 element = inelement3i + shadowmarktris[i] * 3;
580 for (j = 0;j < 3;j++)
582 if (vertexupdate[element[j]] != vertexupdatenum)
584 vertexupdate[element[j]] = vertexupdatenum;
585 vertexremap[element[j]] = outvertices;
586 vertex = invertex3f + element[j] * 3;
587 // project one copy of the vertex according to projectvector
588 VectorCopy(vertex, outvertex3f);
589 VectorAdd(vertex, projectvector, (outvertex3f + 3));
598 for (i = 0;i < numshadowmarktris;i++)
600 element = inelement3i + shadowmarktris[i] * 3;
601 for (j = 0;j < 3;j++)
603 if (vertexupdate[element[j]] != vertexupdatenum)
605 vertexupdate[element[j]] = vertexupdatenum;
606 vertexremap[element[j]] = outvertices;
607 vertex = invertex3f + element[j] * 3;
608 // project one copy of the vertex to the sphere radius of the light
609 // (FIXME: would projecting it to the light box be better?)
610 VectorSubtract(vertex, projectorigin, direction);
611 ratio = projectdistance / VectorLength(direction);
612 VectorCopy(vertex, outvertex3f);
613 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
621 if (r_shadow_frontsidecasting.integer)
623 for (i = 0;i < numshadowmarktris;i++)
625 int remappedelement[3];
627 const int *neighbortriangle;
629 markindex = shadowmarktris[i] * 3;
630 element = inelement3i + markindex;
631 neighbortriangle = inneighbor3i + markindex;
632 // output the front and back triangles
633 outelement3i[0] = vertexremap[element[0]];
634 outelement3i[1] = vertexremap[element[1]];
635 outelement3i[2] = vertexremap[element[2]];
636 outelement3i[3] = vertexremap[element[2]] + 1;
637 outelement3i[4] = vertexremap[element[1]] + 1;
638 outelement3i[5] = vertexremap[element[0]] + 1;
642 // output the sides (facing outward from this triangle)
643 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
645 remappedelement[0] = vertexremap[element[0]];
646 remappedelement[1] = vertexremap[element[1]];
647 outelement3i[0] = remappedelement[1];
648 outelement3i[1] = remappedelement[0];
649 outelement3i[2] = remappedelement[0] + 1;
650 outelement3i[3] = remappedelement[1];
651 outelement3i[4] = remappedelement[0] + 1;
652 outelement3i[5] = remappedelement[1] + 1;
657 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
659 remappedelement[1] = vertexremap[element[1]];
660 remappedelement[2] = vertexremap[element[2]];
661 outelement3i[0] = remappedelement[2];
662 outelement3i[1] = remappedelement[1];
663 outelement3i[2] = remappedelement[1] + 1;
664 outelement3i[3] = remappedelement[2];
665 outelement3i[4] = remappedelement[1] + 1;
666 outelement3i[5] = remappedelement[2] + 1;
671 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
673 remappedelement[0] = vertexremap[element[0]];
674 remappedelement[2] = vertexremap[element[2]];
675 outelement3i[0] = remappedelement[0];
676 outelement3i[1] = remappedelement[2];
677 outelement3i[2] = remappedelement[2] + 1;
678 outelement3i[3] = remappedelement[0];
679 outelement3i[4] = remappedelement[2] + 1;
680 outelement3i[5] = remappedelement[0] + 1;
689 for (i = 0;i < numshadowmarktris;i++)
691 int remappedelement[3];
693 const int *neighbortriangle;
695 markindex = shadowmarktris[i] * 3;
696 element = inelement3i + markindex;
697 neighbortriangle = inneighbor3i + markindex;
698 // output the front and back triangles
699 outelement3i[0] = vertexremap[element[2]];
700 outelement3i[1] = vertexremap[element[1]];
701 outelement3i[2] = vertexremap[element[0]];
702 outelement3i[3] = vertexremap[element[0]] + 1;
703 outelement3i[4] = vertexremap[element[1]] + 1;
704 outelement3i[5] = vertexremap[element[2]] + 1;
708 // output the sides (facing outward from this triangle)
709 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
711 remappedelement[0] = vertexremap[element[0]];
712 remappedelement[1] = vertexremap[element[1]];
713 outelement3i[0] = remappedelement[0];
714 outelement3i[1] = remappedelement[1];
715 outelement3i[2] = remappedelement[1] + 1;
716 outelement3i[3] = remappedelement[0];
717 outelement3i[4] = remappedelement[1] + 1;
718 outelement3i[5] = remappedelement[0] + 1;
723 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
725 remappedelement[1] = vertexremap[element[1]];
726 remappedelement[2] = vertexremap[element[2]];
727 outelement3i[0] = remappedelement[1];
728 outelement3i[1] = remappedelement[2];
729 outelement3i[2] = remappedelement[2] + 1;
730 outelement3i[3] = remappedelement[1];
731 outelement3i[4] = remappedelement[2] + 1;
732 outelement3i[5] = remappedelement[1] + 1;
737 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
739 remappedelement[0] = vertexremap[element[0]];
740 remappedelement[2] = vertexremap[element[2]];
741 outelement3i[0] = remappedelement[2];
742 outelement3i[1] = remappedelement[0];
743 outelement3i[2] = remappedelement[0] + 1;
744 outelement3i[3] = remappedelement[2];
745 outelement3i[4] = remappedelement[0] + 1;
746 outelement3i[5] = remappedelement[2] + 1;
754 *outnumvertices = outvertices;
758 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)
761 if (projectdistance < 0.1)
763 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
766 if (!numverts || !nummarktris)
768 // make sure shadowelements is big enough for this volume
769 if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
770 R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
771 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
772 r_refdef.stats.lights_dynamicshadowtriangles += tris;
773 R_Shadow_RenderVolume(outverts, tris, shadowvertex3f, shadowelements);
776 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)
782 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
784 tend = firsttriangle + numtris;
785 if (surfacemins[0] >= lightmins[0] && surfacemaxs[0] <= lightmaxs[0]
786 && surfacemins[1] >= lightmins[1] && surfacemaxs[1] <= lightmaxs[1]
787 && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2])
789 // surface box entirely inside light box, no box cull
790 if (projectdirection)
792 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
794 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
795 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
796 shadowmarklist[numshadowmark++] = t;
801 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
802 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
803 shadowmarklist[numshadowmark++] = t;
808 // surface box not entirely inside light box, cull each triangle
809 if (projectdirection)
811 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
813 v[0] = invertex3f + e[0] * 3;
814 v[1] = invertex3f + e[1] * 3;
815 v[2] = invertex3f + e[2] * 3;
816 TriangleNormal(v[0], v[1], v[2], normal);
817 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
818 && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
819 && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
820 && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
821 && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
822 && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
823 && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
824 shadowmarklist[numshadowmark++] = t;
829 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
831 v[0] = invertex3f + e[0] * 3;
832 v[1] = invertex3f + e[1] * 3;
833 v[2] = invertex3f + e[2] * 3;
834 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
835 && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
836 && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
837 && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
838 && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
839 && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
840 && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
841 shadowmarklist[numshadowmark++] = t;
847 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
849 if (r_shadow_compilingrtlight)
851 // if we're compiling an rtlight, capture the mesh
852 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
855 r_refdef.stats.lights_shadowtriangles += numtriangles;
857 R_Mesh_VertexPointer(vertex3f);
858 GL_LockArrays(0, numvertices);
859 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
861 // decrement stencil if backface is behind depthbuffer
862 GL_CullFace(GL_BACK); // quake is backwards, this culls front faces
863 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
864 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
865 // increment stencil if frontface is behind depthbuffer
866 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
867 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
869 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
874 static void R_Shadow_MakeTextures(void)
877 float v[3], intensity;
879 R_FreeTexturePool(&r_shadow_texturepool);
880 r_shadow_texturepool = R_AllocTexturePool();
881 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
882 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
883 #define ATTEN2DSIZE 64
884 #define ATTEN3DSIZE 32
885 data = (unsigned char *)Mem_Alloc(tempmempool, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4));
886 for (y = 0;y < ATTEN2DSIZE;y++)
888 for (x = 0;x < ATTEN2DSIZE;x++)
890 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
891 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
893 intensity = 1.0f - sqrt(DotProduct(v, v));
895 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
896 d = (int)bound(0, intensity, 255);
897 data[(y*ATTEN2DSIZE+x)*4+0] = d;
898 data[(y*ATTEN2DSIZE+x)*4+1] = d;
899 data[(y*ATTEN2DSIZE+x)*4+2] = d;
900 data[(y*ATTEN2DSIZE+x)*4+3] = d;
903 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
904 if (r_shadow_texture3d.integer && gl_texture3d)
906 for (z = 0;z < ATTEN3DSIZE;z++)
908 for (y = 0;y < ATTEN3DSIZE;y++)
910 for (x = 0;x < ATTEN3DSIZE;x++)
912 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
913 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
914 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
915 intensity = 1.0f - sqrt(DotProduct(v, v));
917 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
918 d = (int)bound(0, intensity, 255);
919 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
920 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
921 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
922 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
926 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
931 void R_Shadow_ValidateCvars(void)
933 if (r_shadow_texture3d.integer && !gl_texture3d)
934 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
935 if (gl_ext_separatestencil.integer && !gl_support_separatestencil)
936 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
937 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
938 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
941 // light currently being rendered
942 rtlight_t *r_shadow_rtlight;
944 // this is the location of the light in entity space
945 vec3_t r_shadow_entitylightorigin;
946 // this transforms entity coordinates to light filter cubemap coordinates
947 // (also often used for other purposes)
948 matrix4x4_t r_shadow_entitytolight;
949 // based on entitytolight this transforms -1 to +1 to 0 to 1 for purposes
950 // of attenuation texturing in full 3D (Z result often ignored)
951 matrix4x4_t r_shadow_entitytoattenuationxyz;
952 // this transforms only the Z to S, and T is always 0.5
953 matrix4x4_t r_shadow_entitytoattenuationz;
955 void R_Shadow_RenderMode_Begin(void)
957 R_Shadow_ValidateCvars();
959 if (!r_shadow_attenuation2dtexture
960 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
961 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
962 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
963 R_Shadow_MakeTextures();
966 R_Mesh_ColorPointer(NULL);
967 R_Mesh_ResetTextureState();
968 GL_BlendFunc(GL_ONE, GL_ZERO);
971 GL_Color(0, 0, 0, 1);
972 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
974 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
976 if (gl_ext_separatestencil.integer)
977 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
978 else if (gl_ext_stenciltwoside.integer)
979 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
981 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
983 if (r_glsl.integer && gl_support_fragment_shader)
984 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
985 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
986 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
988 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
991 void R_Shadow_RenderMode_ActiveLight(rtlight_t *rtlight)
993 r_shadow_rtlight = rtlight;
996 void R_Shadow_RenderMode_Reset(void)
999 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1001 qglUseProgramObjectARB(0);CHECKGLERROR
1003 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
1005 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1007 R_Mesh_ColorPointer(NULL);
1008 R_Mesh_ResetTextureState();
1010 GL_DepthMask(false);
1011 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1012 qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1013 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1014 qglStencilMask(~0);CHECKGLERROR
1015 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1016 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1017 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
1018 GL_Color(1, 1, 1, 1);
1019 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
1020 GL_BlendFunc(GL_ONE, GL_ZERO);
1023 void R_Shadow_RenderMode_StencilShadowVolumes(void)
1026 R_Shadow_RenderMode_Reset();
1027 GL_ColorMask(0, 0, 0, 0);
1028 qglPolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1029 qglDepthFunc(GL_LESS);CHECKGLERROR
1030 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1031 r_shadow_rendermode = r_shadow_shadowingrendermode;
1032 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SEPARATESTENCIL)
1034 GL_CullFace(GL_NONE);
1035 qglStencilOpSeparate(GL_BACK, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR // quake is backwards, this is front faces
1036 qglStencilOpSeparate(GL_FRONT, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR // quake is backwards, this is back faces
1038 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
1040 GL_CullFace(GL_NONE);
1041 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1042 qglActiveStencilFaceEXT(GL_BACK);CHECKGLERROR // quake is backwards, this is front faces
1043 qglStencilMask(~0);CHECKGLERROR
1044 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1045 qglActiveStencilFaceEXT(GL_FRONT);CHECKGLERROR // quake is backwards, this is back faces
1046 qglStencilMask(~0);CHECKGLERROR
1047 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1049 GL_Clear(GL_STENCIL_BUFFER_BIT);
1050 r_refdef.stats.lights_clears++;
1053 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent)
1056 R_Shadow_RenderMode_Reset();
1057 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1060 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1064 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1065 // only draw light where this geometry was already rendered AND the
1066 // stencil is 128 (values other than this mean shadow)
1067 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1069 r_shadow_rendermode = r_shadow_lightingrendermode;
1070 // do global setup needed for the chosen lighting mode
1071 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1073 R_Mesh_TexBind(0, R_GetTexture(r_texture_blanknormalmap)); // normal
1074 R_Mesh_TexBind(1, R_GetTexture(r_texture_white)); // diffuse
1075 R_Mesh_TexBind(2, R_GetTexture(r_texture_white)); // gloss
1076 R_Mesh_TexBindCubeMap(3, R_GetTexture(r_shadow_rtlight->currentcubemap)); // light filter
1077 R_Mesh_TexBind(4, R_GetTexture(r_texture_fogattenuation)); // fog
1078 R_Mesh_TexBind(5, R_GetTexture(r_texture_white)); // pants
1079 R_Mesh_TexBind(6, R_GetTexture(r_texture_white)); // shirt
1080 R_Mesh_TexBind(7, R_GetTexture(r_texture_white)); // lightmap
1081 R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap)); // deluxemap
1082 R_Mesh_TexBind(9, R_GetTexture(r_texture_black)); // glow
1083 //R_Mesh_TexMatrix(3, r_shadow_entitytolight); // light filter matrix
1084 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1085 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 0);
1090 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
1093 R_Shadow_RenderMode_Reset();
1094 GL_BlendFunc(GL_ONE, GL_ONE);
1095 GL_DepthTest(r_showshadowvolumes.integer < 2);
1096 GL_Color(0.0, 0.0125 * r_view.colorscale, 0.1 * r_view.colorscale, 1);
1097 qglPolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1098 GL_CullFace(GL_NONE);
1099 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
1102 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
1105 R_Shadow_RenderMode_Reset();
1106 GL_BlendFunc(GL_ONE, GL_ONE);
1107 GL_DepthTest(r_showlighting.integer < 2);
1108 GL_Color(0.1 * r_view.colorscale, 0.0125 * r_view.colorscale, 0, 1);
1111 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1115 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1116 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1118 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
1121 void R_Shadow_RenderMode_End(void)
1124 R_Shadow_RenderMode_Reset();
1125 R_Shadow_RenderMode_ActiveLight(NULL);
1127 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
1128 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1131 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1133 int i, ix1, iy1, ix2, iy2;
1134 float x1, y1, x2, y2;
1137 mplane_t planes[11];
1138 float vertex3f[256*3];
1140 // if view is inside the light box, just say yes it's visible
1141 if (BoxesOverlap(r_view.origin, r_view.origin, mins, maxs))
1143 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
1147 // create a temporary brush describing the area the light can affect in worldspace
1148 VectorNegate(r_view.frustum[0].normal, planes[ 0].normal);planes[ 0].dist = -r_view.frustum[0].dist;
1149 VectorNegate(r_view.frustum[1].normal, planes[ 1].normal);planes[ 1].dist = -r_view.frustum[1].dist;
1150 VectorNegate(r_view.frustum[2].normal, planes[ 2].normal);planes[ 2].dist = -r_view.frustum[2].dist;
1151 VectorNegate(r_view.frustum[3].normal, planes[ 3].normal);planes[ 3].dist = -r_view.frustum[3].dist;
1152 VectorNegate(r_view.frustum[4].normal, planes[ 4].normal);planes[ 4].dist = -r_view.frustum[4].dist;
1153 VectorSet (planes[ 5].normal, 1, 0, 0); planes[ 5].dist = maxs[0];
1154 VectorSet (planes[ 6].normal, -1, 0, 0); planes[ 6].dist = -mins[0];
1155 VectorSet (planes[ 7].normal, 0, 1, 0); planes[ 7].dist = maxs[1];
1156 VectorSet (planes[ 8].normal, 0, -1, 0); planes[ 8].dist = -mins[1];
1157 VectorSet (planes[ 9].normal, 0, 0, 1); planes[ 9].dist = maxs[2];
1158 VectorSet (planes[10].normal, 0, 0, -1); planes[10].dist = -mins[2];
1160 // turn the brush into a mesh
1161 memset(&mesh, 0, sizeof(rmesh_t));
1162 mesh.maxvertices = 256;
1163 mesh.vertex3f = vertex3f;
1164 mesh.epsilon2 = (1.0f / (32.0f * 32.0f));
1165 R_Mesh_AddBrushMeshFromPlanes(&mesh, 11, planes);
1167 // if that mesh is empty, the light is not visible at all
1168 if (!mesh.numvertices)
1171 if (!r_shadow_scissor.integer)
1174 // if that mesh is not empty, check what area of the screen it covers
1175 x1 = y1 = x2 = y2 = 0;
1177 //Con_Printf("%i vertices to transform...\n", mesh.numvertices);
1178 for (i = 0;i < mesh.numvertices;i++)
1180 VectorCopy(mesh.vertex3f + i * 3, v);
1181 GL_TransformToScreen(v, v2);
1182 //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]);
1185 if (x1 > v2[0]) x1 = v2[0];
1186 if (x2 < v2[0]) x2 = v2[0];
1187 if (y1 > v2[1]) y1 = v2[1];
1188 if (y2 < v2[1]) y2 = v2[1];
1197 // now convert the scissor rectangle to integer screen coordinates
1198 ix1 = (int)(x1 - 1.0f);
1199 iy1 = (int)(y1 - 1.0f);
1200 ix2 = (int)(x2 + 1.0f);
1201 iy2 = (int)(y2 + 1.0f);
1202 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1204 // clamp it to the screen
1205 if (ix1 < r_view.x) ix1 = r_view.x;
1206 if (iy1 < r_view.y) iy1 = r_view.y;
1207 if (ix2 > r_view.x + r_view.width) ix2 = r_view.x + r_view.width;
1208 if (iy2 > r_view.y + r_view.height) iy2 = r_view.y + r_view.height;
1210 // if it is inside out, it's not visible
1211 if (ix2 <= ix1 || iy2 <= iy1)
1214 // the light area is visible, set up the scissor rectangle
1215 GL_Scissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1216 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);CHECKGLERROR
1217 //qglEnable(GL_SCISSOR_TEST);CHECKGLERROR
1218 r_refdef.stats.lights_scissored++;
1222 static void R_Shadow_RenderSurfacesLighting_Light_Vertex_Shading(const msurface_t *surface, const float *diffusecolor, const float *ambientcolor)
1224 int numverts = surface->num_vertices;
1225 float *vertex3f = rsurface_vertex3f + 3 * surface->num_firstvertex;
1226 float *normal3f = rsurface_normal3f + 3 * surface->num_firstvertex;
1227 float *color4f = rsurface_array_color4f + 4 * surface->num_firstvertex;
1228 float dist, dot, distintensity, shadeintensity, v[3], n[3];
1229 if (r_textureunits.integer >= 3)
1231 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1233 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1234 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1235 if ((dot = DotProduct(n, v)) < 0)
1237 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1238 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]);
1239 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]);
1240 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]);
1241 if (r_refdef.fogenabled)
1243 float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
1244 VectorScale(color4f, f, color4f);
1248 VectorClear(color4f);
1252 else if (r_textureunits.integer >= 2)
1254 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1256 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1257 if ((dist = fabs(v[2])) < 1)
1259 distintensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1260 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1261 if ((dot = DotProduct(n, v)) < 0)
1263 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1264 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1265 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1266 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1270 color4f[0] = ambientcolor[0] * distintensity;
1271 color4f[1] = ambientcolor[1] * distintensity;
1272 color4f[2] = ambientcolor[2] * distintensity;
1274 if (r_refdef.fogenabled)
1276 float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
1277 VectorScale(color4f, f, color4f);
1281 VectorClear(color4f);
1287 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1289 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1290 if ((dist = DotProduct(v, v)) < 1)
1293 distintensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1294 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1295 if ((dot = DotProduct(n, v)) < 0)
1297 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1298 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1299 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1300 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1304 color4f[0] = ambientcolor[0] * distintensity;
1305 color4f[1] = ambientcolor[1] * distintensity;
1306 color4f[2] = ambientcolor[2] * distintensity;
1308 if (r_refdef.fogenabled)
1310 float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
1311 VectorScale(color4f, f, color4f);
1315 VectorClear(color4f);
1321 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1323 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int numsurfaces, msurface_t **surfacelist)
1325 int surfacelistindex;
1326 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1328 const msurface_t *surface = surfacelist[surfacelistindex];
1330 float *out3f = rsurface_array_texcoord3f + 3 * surface->num_firstvertex;
1331 const float *vertex3f = rsurface_vertex3f + 3 * surface->num_firstvertex;
1332 const float *svector3f = rsurface_svector3f + 3 * surface->num_firstvertex;
1333 const float *tvector3f = rsurface_tvector3f + 3 * surface->num_firstvertex;
1334 const float *normal3f = rsurface_normal3f + 3 * surface->num_firstvertex;
1336 for (i = 0;i < surface->num_vertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1338 VectorSubtract(r_shadow_entitylightorigin, vertex3f, lightdir);
1339 // the cubemap normalizes this for us
1340 out3f[0] = DotProduct(svector3f, lightdir);
1341 out3f[1] = DotProduct(tvector3f, lightdir);
1342 out3f[2] = DotProduct(normal3f, lightdir);
1347 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int numsurfaces, msurface_t **surfacelist)
1349 int surfacelistindex;
1350 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1352 const msurface_t *surface = surfacelist[surfacelistindex];
1354 float *out3f = rsurface_array_texcoord3f + 3 * surface->num_firstvertex;
1355 const float *vertex3f = rsurface_vertex3f + 3 * surface->num_firstvertex;
1356 const float *svector3f = rsurface_svector3f + 3 * surface->num_firstvertex;
1357 const float *tvector3f = rsurface_tvector3f + 3 * surface->num_firstvertex;
1358 const float *normal3f = rsurface_normal3f + 3 * surface->num_firstvertex;
1359 float lightdir[3], eyedir[3], halfdir[3];
1360 for (i = 0;i < surface->num_vertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1362 VectorSubtract(r_shadow_entitylightorigin, vertex3f, lightdir);
1363 VectorNormalize(lightdir);
1364 VectorSubtract(rsurface_modelorg, vertex3f, eyedir);
1365 VectorNormalize(eyedir);
1366 VectorAdd(lightdir, eyedir, halfdir);
1367 // the cubemap normalizes this for us
1368 out3f[0] = DotProduct(svector3f, halfdir);
1369 out3f[1] = DotProduct(tvector3f, halfdir);
1370 out3f[2] = DotProduct(normal3f, halfdir);
1375 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)
1377 // used to display how many times a surface is lit for level design purposes
1378 GL_Color(0.1 * r_view.colorscale, 0.025 * r_view.colorscale, 0, 1);
1379 R_Mesh_ColorPointer(NULL);
1380 R_Mesh_ResetTextureState();
1381 RSurf_PrepareVerticesForBatch(false, false, numsurfaces, surfacelist);
1382 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1383 GL_LockArrays(0, 0);
1386 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)
1388 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
1389 RSurf_PrepareVerticesForBatch(true, true, numsurfaces, surfacelist);
1390 R_SetupSurfaceShader(lightcolorbase, false);
1391 R_Mesh_TexCoordPointer(0, 2, rsurface_model->surfmesh.data_texcoordtexture2f);
1392 R_Mesh_TexCoordPointer(1, 3, rsurface_svector3f);
1393 R_Mesh_TexCoordPointer(2, 3, rsurface_tvector3f);
1394 R_Mesh_TexCoordPointer(3, 3, rsurface_normal3f);
1395 if (rsurface_texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1397 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1399 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1400 GL_LockArrays(0, 0);
1401 if (rsurface_texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1403 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1407 static void R_Shadow_RenderSurfacesLighting_Light_Dot3_Finalize(int numsurfaces, msurface_t **surfacelist, float r, float g, float b)
1409 // shared final code for all the dot3 layers
1411 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 0);
1412 for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
1414 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
1415 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1416 GL_LockArrays(0, 0);
1420 static void R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, rtexture_t *basetexture, float colorscale)
1423 // colorscale accounts for how much we multiply the brightness
1426 // mult is how many times the final pass of the lighting will be
1427 // performed to get more brightness than otherwise possible.
1429 // Limit mult to 64 for sanity sake.
1431 if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1433 // 3 3D combine path (Geforce3, Radeon 8500)
1434 memset(&m, 0, sizeof(m));
1435 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1436 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1437 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1438 m.tex[1] = R_GetTexture(basetexture);
1439 m.pointer_texcoord[1] = rsurface_model->surfmesh.data_texcoordtexture2f;
1440 m.texmatrix[1] = rsurface_texture->currenttexmatrix;
1441 m.texcubemap[2] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1442 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1443 m.texmatrix[2] = r_shadow_entitytolight;
1444 GL_BlendFunc(GL_ONE, GL_ONE);
1446 else if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1448 // 2 3D combine path (Geforce3, original Radeon)
1449 memset(&m, 0, sizeof(m));
1450 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1451 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1452 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1453 m.tex[1] = R_GetTexture(basetexture);
1454 m.pointer_texcoord[1] = rsurface_model->surfmesh.data_texcoordtexture2f;
1455 m.texmatrix[1] = rsurface_texture->currenttexmatrix;
1456 GL_BlendFunc(GL_ONE, GL_ONE);
1458 else if (r_textureunits.integer >= 4 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1460 // 4 2D combine path (Geforce3, Radeon 8500)
1461 memset(&m, 0, sizeof(m));
1462 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1463 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1464 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1465 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1466 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1467 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1468 m.tex[2] = R_GetTexture(basetexture);
1469 m.pointer_texcoord[2] = rsurface_model->surfmesh.data_texcoordtexture2f;
1470 m.texmatrix[2] = rsurface_texture->currenttexmatrix;
1471 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1473 m.texcubemap[3] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1474 m.pointer_texcoord3f[3] = rsurface_vertex3f;
1475 m.texmatrix[3] = r_shadow_entitytolight;
1477 GL_BlendFunc(GL_ONE, GL_ONE);
1479 else if (r_textureunits.integer >= 3 && r_shadow_rtlight->currentcubemap == r_texture_whitecube)
1481 // 3 2D combine path (Geforce3, original Radeon)
1482 memset(&m, 0, sizeof(m));
1483 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1484 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1485 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1486 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1487 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1488 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1489 m.tex[2] = R_GetTexture(basetexture);
1490 m.pointer_texcoord[2] = rsurface_model->surfmesh.data_texcoordtexture2f;
1491 m.texmatrix[2] = rsurface_texture->currenttexmatrix;
1492 GL_BlendFunc(GL_ONE, GL_ONE);
1496 // 2/2/2 2D combine path (any dot3 card)
1497 memset(&m, 0, sizeof(m));
1498 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1499 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1500 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1501 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1502 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1503 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1504 R_Mesh_TextureState(&m);
1505 GL_ColorMask(0,0,0,1);
1506 GL_BlendFunc(GL_ONE, GL_ZERO);
1507 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1508 GL_LockArrays(0, 0);
1511 memset(&m, 0, sizeof(m));
1512 m.tex[0] = R_GetTexture(basetexture);
1513 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1514 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1515 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1517 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1518 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1519 m.texmatrix[1] = r_shadow_entitytolight;
1521 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1523 // this final code is shared
1524 R_Mesh_TextureState(&m);
1525 R_Shadow_RenderSurfacesLighting_Light_Dot3_Finalize(numsurfaces, surfacelist, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1528 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)
1531 // colorscale accounts for how much we multiply the brightness
1534 // mult is how many times the final pass of the lighting will be
1535 // performed to get more brightness than otherwise possible.
1537 // Limit mult to 64 for sanity sake.
1539 // generate normalization cubemap texcoords
1540 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(numsurfaces, surfacelist);
1541 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1543 // 3/2 3D combine path (Geforce3, Radeon 8500)
1544 memset(&m, 0, sizeof(m));
1545 m.tex[0] = R_GetTexture(normalmaptexture);
1546 m.texcombinergb[0] = GL_REPLACE;
1547 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1548 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1549 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1550 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1551 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1552 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1553 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1554 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
1555 R_Mesh_TextureState(&m);
1556 GL_ColorMask(0,0,0,1);
1557 GL_BlendFunc(GL_ONE, GL_ZERO);
1558 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1559 GL_LockArrays(0, 0);
1562 memset(&m, 0, sizeof(m));
1563 m.tex[0] = R_GetTexture(basetexture);
1564 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1565 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1566 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1568 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1569 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1570 m.texmatrix[1] = r_shadow_entitytolight;
1572 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1574 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1576 // 1/2/2 3D combine path (original Radeon)
1577 memset(&m, 0, sizeof(m));
1578 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1579 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1580 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1581 R_Mesh_TextureState(&m);
1582 GL_ColorMask(0,0,0,1);
1583 GL_BlendFunc(GL_ONE, GL_ZERO);
1584 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1585 GL_LockArrays(0, 0);
1588 memset(&m, 0, sizeof(m));
1589 m.tex[0] = R_GetTexture(normalmaptexture);
1590 m.texcombinergb[0] = GL_REPLACE;
1591 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1592 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1593 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1594 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1595 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1596 R_Mesh_TextureState(&m);
1597 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1598 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1599 GL_LockArrays(0, 0);
1602 memset(&m, 0, sizeof(m));
1603 m.tex[0] = R_GetTexture(basetexture);
1604 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1605 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1606 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1608 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1609 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1610 m.texmatrix[1] = r_shadow_entitytolight;
1612 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1614 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap == r_texture_whitecube)
1616 // 2/2 3D combine path (original Radeon)
1617 memset(&m, 0, sizeof(m));
1618 m.tex[0] = R_GetTexture(normalmaptexture);
1619 m.texcombinergb[0] = GL_REPLACE;
1620 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1621 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1622 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1623 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1624 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1625 R_Mesh_TextureState(&m);
1626 GL_ColorMask(0,0,0,1);
1627 GL_BlendFunc(GL_ONE, GL_ZERO);
1628 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1629 GL_LockArrays(0, 0);
1632 memset(&m, 0, sizeof(m));
1633 m.tex[0] = R_GetTexture(basetexture);
1634 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1635 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1636 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1637 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1638 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
1639 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1641 else if (r_textureunits.integer >= 4)
1643 // 4/2 2D combine path (Geforce3, Radeon 8500)
1644 memset(&m, 0, sizeof(m));
1645 m.tex[0] = R_GetTexture(normalmaptexture);
1646 m.texcombinergb[0] = GL_REPLACE;
1647 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1648 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1649 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1650 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1651 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1652 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1653 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1654 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
1655 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1656 m.pointer_texcoord3f[3] = rsurface_vertex3f;
1657 m.texmatrix[3] = r_shadow_entitytoattenuationz;
1658 R_Mesh_TextureState(&m);
1659 GL_ColorMask(0,0,0,1);
1660 GL_BlendFunc(GL_ONE, GL_ZERO);
1661 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1662 GL_LockArrays(0, 0);
1665 memset(&m, 0, sizeof(m));
1666 m.tex[0] = R_GetTexture(basetexture);
1667 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1668 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1669 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1671 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1672 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1673 m.texmatrix[1] = r_shadow_entitytolight;
1675 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1679 // 2/2/2 2D combine path (any dot3 card)
1680 memset(&m, 0, sizeof(m));
1681 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1682 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1683 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1684 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1685 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1686 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1687 R_Mesh_TextureState(&m);
1688 GL_ColorMask(0,0,0,1);
1689 GL_BlendFunc(GL_ONE, GL_ZERO);
1690 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1691 GL_LockArrays(0, 0);
1694 memset(&m, 0, sizeof(m));
1695 m.tex[0] = R_GetTexture(normalmaptexture);
1696 m.texcombinergb[0] = GL_REPLACE;
1697 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1698 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1699 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1700 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1701 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1702 R_Mesh_TextureState(&m);
1703 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1704 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1705 GL_LockArrays(0, 0);
1708 memset(&m, 0, sizeof(m));
1709 m.tex[0] = R_GetTexture(basetexture);
1710 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1711 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1712 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1714 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1715 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1716 m.texmatrix[1] = r_shadow_entitytolight;
1718 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1720 // this final code is shared
1721 R_Mesh_TextureState(&m);
1722 R_Shadow_RenderSurfacesLighting_Light_Dot3_Finalize(numsurfaces, surfacelist, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1725 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)
1727 float glossexponent;
1729 // FIXME: detect blendsquare!
1730 //if (!gl_support_blendsquare)
1733 // generate normalization cubemap texcoords
1734 R_Shadow_GenTexCoords_Specular_NormalCubeMap(numsurfaces, surfacelist);
1735 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1737 // 2/0/0/1/2 3D combine blendsquare path
1738 memset(&m, 0, sizeof(m));
1739 m.tex[0] = R_GetTexture(normalmaptexture);
1740 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1741 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1742 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1743 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1744 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1745 R_Mesh_TextureState(&m);
1746 GL_ColorMask(0,0,0,1);
1747 // this squares the result
1748 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1749 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1750 GL_LockArrays(0, 0);
1752 // second and third pass
1753 R_Mesh_ResetTextureState();
1754 // square alpha in framebuffer a few times to make it shiny
1755 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1756 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
1757 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1758 GL_LockArrays(0, 0);
1761 memset(&m, 0, sizeof(m));
1762 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1763 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1764 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1765 R_Mesh_TextureState(&m);
1766 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1767 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1768 GL_LockArrays(0, 0);
1771 memset(&m, 0, sizeof(m));
1772 m.tex[0] = R_GetTexture(glosstexture);
1773 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1774 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1775 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1777 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1778 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1779 m.texmatrix[1] = r_shadow_entitytolight;
1781 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1783 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
1785 // 2/0/0/2 3D combine blendsquare path
1786 memset(&m, 0, sizeof(m));
1787 m.tex[0] = R_GetTexture(normalmaptexture);
1788 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1789 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1790 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1791 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1792 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1793 R_Mesh_TextureState(&m);
1794 GL_ColorMask(0,0,0,1);
1795 // this squares the result
1796 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1797 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1798 GL_LockArrays(0, 0);
1800 // second and third pass
1801 R_Mesh_ResetTextureState();
1802 // square alpha in framebuffer a few times to make it shiny
1803 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1804 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
1805 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1806 GL_LockArrays(0, 0);
1809 memset(&m, 0, sizeof(m));
1810 m.tex[0] = R_GetTexture(glosstexture);
1811 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1812 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1813 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1814 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1815 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
1816 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1820 // 2/0/0/2/2 2D combine blendsquare path
1821 memset(&m, 0, sizeof(m));
1822 m.tex[0] = R_GetTexture(normalmaptexture);
1823 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1824 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1825 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1826 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1827 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1828 R_Mesh_TextureState(&m);
1829 GL_ColorMask(0,0,0,1);
1830 // this squares the result
1831 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1832 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1833 GL_LockArrays(0, 0);
1835 // second and third pass
1836 R_Mesh_ResetTextureState();
1837 // square alpha in framebuffer a few times to make it shiny
1838 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1839 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
1840 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1841 GL_LockArrays(0, 0);
1844 memset(&m, 0, sizeof(m));
1845 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1846 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1847 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1848 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1849 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1850 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1851 R_Mesh_TextureState(&m);
1852 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1853 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1854 GL_LockArrays(0, 0);
1857 memset(&m, 0, sizeof(m));
1858 m.tex[0] = R_GetTexture(glosstexture);
1859 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1860 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1861 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1863 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1864 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1865 m.texmatrix[1] = r_shadow_entitytolight;
1867 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1869 // this final code is shared
1870 R_Mesh_TextureState(&m);
1871 R_Shadow_RenderSurfacesLighting_Light_Dot3_Finalize(numsurfaces, surfacelist, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1874 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)
1876 // ARB path (any Geforce, any Radeon)
1877 qboolean doambient = r_shadow_rtlight->ambientscale > 0;
1878 qboolean dodiffuse = r_shadow_rtlight->diffusescale > 0;
1879 qboolean dospecular = specularscale > 0;
1880 if (!doambient && !dodiffuse && !dospecular)
1882 RSurf_PrepareVerticesForBatch(true, true, numsurfaces, surfacelist);
1883 R_Mesh_ColorPointer(NULL);
1885 R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(numsurfaces, surfacelist, lightcolorbase, basetexture, r_shadow_rtlight->ambientscale * r_view.colorscale);
1887 R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(numsurfaces, surfacelist, lightcolorbase, basetexture, normalmaptexture, r_shadow_rtlight->diffusescale * r_view.colorscale);
1891 R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(numsurfaces, surfacelist, lightcolorpants, pantstexture, r_shadow_rtlight->ambientscale * r_view.colorscale);
1893 R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(numsurfaces, surfacelist, lightcolorpants, pantstexture, normalmaptexture, r_shadow_rtlight->diffusescale * r_view.colorscale);
1898 R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(numsurfaces, surfacelist, lightcolorshirt, shirttexture, r_shadow_rtlight->ambientscale * r_view.colorscale);
1900 R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(numsurfaces, surfacelist, lightcolorshirt, shirttexture, normalmaptexture, r_shadow_rtlight->diffusescale * r_view.colorscale);
1903 R_Shadow_RenderSurfacesLighting_Light_Dot3_SpecularPass(numsurfaces, surfacelist, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_view.colorscale);
1906 void R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(const model_t *model, int numsurfaces, msurface_t **surfacelist, vec3_t diffusecolor2, vec3_t ambientcolor2)
1908 int surfacelistindex;
1910 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1912 const msurface_t *surface = surfacelist[surfacelistindex];
1913 R_Shadow_RenderSurfacesLighting_Light_Vertex_Shading(surface, diffusecolor2, ambientcolor2);
1915 for (renders = 0;renders < 64;renders++)
1921 int newnumtriangles;
1923 int newelements[3072];
1927 newnumtriangles = 0;
1929 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1931 const msurface_t *surface = surfacelist[surfacelistindex];
1932 const int *elements = rsurface_model->surfmesh.data_element3i + surface->num_firsttriangle * 3;
1934 // due to low fillrate on the cards this vertex lighting path is
1935 // designed for, we manually cull all triangles that do not
1936 // contain a lit vertex
1937 // this builds batches of triangles from multiple surfaces and
1938 // renders them at once
1939 for (i = 0, e = elements;i < surface->num_triangles;i++, e += 3)
1941 if (VectorLength2(rsurface_array_color4f + e[0] * 4) + VectorLength2(rsurface_array_color4f + e[1] * 4) + VectorLength2(rsurface_array_color4f + e[2] * 4) >= 0.01)
1943 if (newnumtriangles)
1945 firstvertex = min(firstvertex, e[0]);
1946 lastvertex = max(lastvertex, e[0]);
1953 firstvertex = min(firstvertex, e[1]);
1954 lastvertex = max(lastvertex, e[1]);
1955 firstvertex = min(firstvertex, e[2]);
1956 lastvertex = max(lastvertex, e[2]);
1962 if (newnumtriangles >= 1024)
1964 GL_LockArrays(firstvertex, lastvertex - firstvertex + 1);
1965 R_Mesh_Draw(firstvertex, lastvertex - firstvertex + 1, newnumtriangles, newelements);
1966 newnumtriangles = 0;
1973 if (newnumtriangles >= 1)
1975 GL_LockArrays(firstvertex, lastvertex - firstvertex + 1);
1976 R_Mesh_Draw(firstvertex, lastvertex - firstvertex + 1, newnumtriangles, newelements);
1979 GL_LockArrays(0, 0);
1980 // if we couldn't find any lit triangles, exit early
1983 // now reduce the intensity for the next overbright pass
1984 // we have to clamp to 0 here incase the drivers have improper
1985 // handling of negative colors
1986 // (some old drivers even have improper handling of >1 color)
1988 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1992 const msurface_t *surface = surfacelist[surfacelistindex];
1993 for (i = 0, c = rsurface_array_color4f + 4 * surface->num_firstvertex;i < surface->num_vertices;i++, c += 4)
1995 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
1997 c[0] = max(0, c[0] - 1);
1998 c[1] = max(0, c[1] - 1);
1999 c[2] = max(0, c[2] - 1);
2012 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)
2014 // OpenGL 1.1 path (anything)
2015 model_t *model = rsurface_entity->model;
2016 float ambientcolorbase[3], diffusecolorbase[3];
2017 float ambientcolorpants[3], diffusecolorpants[3];
2018 float ambientcolorshirt[3], diffusecolorshirt[3];
2020 VectorScale(lightcolorbase, r_shadow_rtlight->ambientscale * 2 * r_view.colorscale, ambientcolorbase);
2021 VectorScale(lightcolorbase, r_shadow_rtlight->diffusescale * 2 * r_view.colorscale, diffusecolorbase);
2022 VectorScale(lightcolorpants, r_shadow_rtlight->ambientscale * 2 * r_view.colorscale, ambientcolorpants);
2023 VectorScale(lightcolorpants, r_shadow_rtlight->diffusescale * 2 * r_view.colorscale, diffusecolorpants);
2024 VectorScale(lightcolorshirt, r_shadow_rtlight->ambientscale * 2 * r_view.colorscale, ambientcolorshirt);
2025 VectorScale(lightcolorshirt, r_shadow_rtlight->diffusescale * 2 * r_view.colorscale, diffusecolorshirt);
2026 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2027 R_Mesh_ColorPointer(rsurface_array_color4f);
2028 memset(&m, 0, sizeof(m));
2029 m.tex[0] = R_GetTexture(basetexture);
2030 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
2031 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
2032 if (r_textureunits.integer >= 2)
2035 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2036 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2037 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2038 if (r_textureunits.integer >= 3)
2040 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
2041 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2042 m.texmatrix[2] = r_shadow_entitytoattenuationz;
2043 m.pointer_texcoord3f[2] = rsurface_vertex3f;
2046 R_Mesh_TextureState(&m);
2047 RSurf_PrepareVerticesForBatch(true, false, numsurfaces, surfacelist);
2048 R_Mesh_TexBind(0, R_GetTexture(basetexture));
2049 R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(model, numsurfaces, surfacelist, diffusecolorbase, ambientcolorbase);
2052 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
2053 R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(model, numsurfaces, surfacelist, diffusecolorpants, ambientcolorpants);
2057 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
2058 R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(model, numsurfaces, surfacelist, diffusecolorshirt, ambientcolorshirt);
2062 void R_Shadow_RenderSurfacesLighting(int numsurfaces, msurface_t **surfacelist)
2064 // FIXME: support MATERIALFLAG_NODEPTHTEST
2065 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
2066 // calculate colors to render this texture with
2067 lightcolorbase[0] = r_shadow_rtlight->currentcolor[0] * rsurface_entity->colormod[0] * rsurface_texture->currentalpha;
2068 lightcolorbase[1] = r_shadow_rtlight->currentcolor[1] * rsurface_entity->colormod[1] * rsurface_texture->currentalpha;
2069 lightcolorbase[2] = r_shadow_rtlight->currentcolor[2] * rsurface_entity->colormod[2] * rsurface_texture->currentalpha;
2070 if ((r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorbase) + (r_shadow_rtlight->specularscale * rsurface_texture->specularscale) * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
2072 GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
2073 GL_CullFace(((rsurface_texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) || (rsurface_entity->flags & RENDER_NOCULLFACE)) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
2074 if (rsurface_texture->colormapping)
2076 qboolean dopants = rsurface_texture->currentskinframe->pants != NULL && VectorLength2(rsurface_entity->colormap_pantscolor) >= (1.0f / 1048576.0f);
2077 qboolean doshirt = rsurface_texture->currentskinframe->shirt != NULL && VectorLength2(rsurface_entity->colormap_shirtcolor) >= (1.0f / 1048576.0f);
2080 lightcolorpants[0] = lightcolorbase[0] * rsurface_entity->colormap_pantscolor[0];
2081 lightcolorpants[1] = lightcolorbase[1] * rsurface_entity->colormap_pantscolor[1];
2082 lightcolorpants[2] = lightcolorbase[2] * rsurface_entity->colormap_pantscolor[2];
2085 VectorClear(lightcolorpants);
2088 lightcolorshirt[0] = lightcolorbase[0] * rsurface_entity->colormap_shirtcolor[0];
2089 lightcolorshirt[1] = lightcolorbase[1] * rsurface_entity->colormap_shirtcolor[1];
2090 lightcolorshirt[2] = lightcolorbase[2] * rsurface_entity->colormap_shirtcolor[2];
2093 VectorClear(lightcolorshirt);
2094 switch (r_shadow_rendermode)
2096 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2097 GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2098 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);
2100 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2101 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);
2103 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2104 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);
2106 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2107 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);
2110 Con_Printf("R_Shadow_RenderSurfacesLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2116 switch (r_shadow_rendermode)
2118 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2119 GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2120 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);
2122 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2123 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);
2125 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2126 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);
2128 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2129 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);
2132 Con_Printf("R_Shadow_RenderSurfacesLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2138 void R_RTLight_Update(dlight_t *light, int isstatic)
2141 rtlight_t *rtlight = &light->rtlight;
2142 R_RTLight_Uncompile(rtlight);
2143 memset(rtlight, 0, sizeof(*rtlight));
2145 VectorCopy(light->origin, rtlight->shadoworigin);
2146 VectorCopy(light->color, rtlight->color);
2147 rtlight->radius = light->radius;
2148 //rtlight->cullradius = rtlight->radius;
2149 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2150 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2151 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2152 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2153 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2154 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2155 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2156 rtlight->cubemapname[0] = 0;
2157 if (light->cubemapname[0])
2158 strlcpy(rtlight->cubemapname, light->cubemapname, sizeof(rtlight->cubemapname));
2159 else if (light->cubemapnum > 0)
2160 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
2161 rtlight->shadow = light->shadow;
2162 rtlight->corona = light->corona;
2163 rtlight->style = light->style;
2164 rtlight->isstatic = isstatic;
2165 rtlight->coronasizescale = light->coronasizescale;
2166 rtlight->ambientscale = light->ambientscale;
2167 rtlight->diffusescale = light->diffusescale;
2168 rtlight->specularscale = light->specularscale;
2169 rtlight->flags = light->flags;
2170 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
2171 // this has to scale both rotate and translate because this is an already
2172 // inverted matrix (it transforms from world to light space, not the other
2174 scale = 1.0 / rtlight->radius;
2175 Matrix4x4_Scale(&rtlight->matrix_worldtolight, scale, scale);
2178 // compiles rtlight geometry
2179 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2180 void R_RTLight_Compile(rtlight_t *rtlight)
2182 int shadowmeshes, shadowtris, numleafs, numleafpvsbytes, numsurfaces;
2183 entity_render_t *ent = r_refdef.worldentity;
2184 model_t *model = r_refdef.worldmodel;
2185 unsigned char *data;
2187 // compile the light
2188 rtlight->compiled = true;
2189 rtlight->static_numleafs = 0;
2190 rtlight->static_numleafpvsbytes = 0;
2191 rtlight->static_leaflist = NULL;
2192 rtlight->static_leafpvs = NULL;
2193 rtlight->static_numsurfaces = 0;
2194 rtlight->static_surfacelist = NULL;
2195 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2196 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2197 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2198 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2199 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2200 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2202 if (model && model->GetLightInfo)
2204 // this variable must be set for the CompileShadowVolume code
2205 r_shadow_compilingrtlight = rtlight;
2206 R_Shadow_EnlargeLeafSurfaceBuffer(model->brush.num_leafs, model->num_surfaces);
2207 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);
2208 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2209 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numleafs + numleafpvsbytes + sizeof(int) * numsurfaces);
2210 rtlight->static_numleafs = numleafs;
2211 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2212 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2213 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2214 rtlight->static_numsurfaces = numsurfaces;
2215 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2217 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2218 if (numleafpvsbytes)
2219 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2221 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2222 if (model->CompileShadowVolume && rtlight->shadow)
2223 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2224 // now we're done compiling the rtlight
2225 r_shadow_compilingrtlight = NULL;
2229 // use smallest available cullradius - box radius or light radius
2230 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2231 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2235 if (rtlight->static_meshchain_shadow)
2238 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2241 shadowtris += mesh->numtriangles;
2245 if (developer.integer >= 10)
2246 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);
2249 void R_RTLight_Uncompile(rtlight_t *rtlight)
2251 if (rtlight->compiled)
2253 if (rtlight->static_meshchain_shadow)
2254 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2255 rtlight->static_meshchain_shadow = NULL;
2256 // these allocations are grouped
2257 if (rtlight->static_leaflist)
2258 Mem_Free(rtlight->static_leaflist);
2259 rtlight->static_numleafs = 0;
2260 rtlight->static_numleafpvsbytes = 0;
2261 rtlight->static_leaflist = NULL;
2262 rtlight->static_leafpvs = NULL;
2263 rtlight->static_numsurfaces = 0;
2264 rtlight->static_surfacelist = NULL;
2265 rtlight->compiled = false;
2269 void R_Shadow_UncompileWorldLights(void)
2272 for (light = r_shadow_worldlightchain;light;light = light->next)
2273 R_RTLight_Uncompile(&light->rtlight);
2276 void R_Shadow_DrawEntityShadow(entity_render_t *ent, int numsurfaces, int *surfacelist)
2278 model_t *model = ent->model;
2279 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
2280 vec_t relativeshadowradius;
2281 if (ent == r_refdef.worldentity)
2283 if (r_shadow_rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2286 R_Mesh_Matrix(&ent->matrix);
2288 for (mesh = r_shadow_rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2290 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
2291 R_Mesh_VertexPointer(mesh->vertex3f);
2292 GL_LockArrays(0, mesh->numverts);
2293 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
2295 // decrement stencil if backface is behind depthbuffer
2296 GL_CullFace(GL_BACK); // quake is backwards, this culls front faces
2297 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2298 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2299 // increment stencil if frontface is behind depthbuffer
2300 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
2301 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2303 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2304 GL_LockArrays(0, 0);
2308 else if (numsurfaces)
2310 R_Mesh_Matrix(&ent->matrix);
2311 model->DrawShadowVolume(ent, r_shadow_rtlight->shadoworigin, NULL, r_shadow_rtlight->radius, numsurfaces, surfacelist, r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs);
2316 Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, relativeshadoworigin);
2317 relativeshadowradius = r_shadow_rtlight->radius / ent->scale;
2318 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
2319 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
2320 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
2321 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
2322 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
2323 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
2324 R_Mesh_Matrix(&ent->matrix);
2325 model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, model->nummodelsurfaces, model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2329 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
2331 // set up properties for rendering light onto this entity
2332 RSurf_ActiveEntity(ent, true, true);
2333 Matrix4x4_Concat(&r_shadow_entitytolight, &r_shadow_rtlight->matrix_worldtolight, &ent->matrix);
2334 Matrix4x4_Concat(&r_shadow_entitytoattenuationxyz, &matrix_attenuationxyz, &r_shadow_entitytolight);
2335 Matrix4x4_Concat(&r_shadow_entitytoattenuationz, &matrix_attenuationz, &r_shadow_entitytolight);
2336 Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, r_shadow_entitylightorigin);
2337 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2338 R_Mesh_TexMatrix(3, &r_shadow_entitytolight);
2341 void R_Shadow_DrawEntityLight(entity_render_t *ent, int numsurfaces, int *surfacelist)
2343 model_t *model = ent->model;
2344 if (!model->DrawLight)
2346 R_Shadow_SetupEntityLight(ent);
2347 if (ent == r_refdef.worldentity)
2348 model->DrawLight(ent, numsurfaces, surfacelist);
2350 model->DrawLight(ent, model->nummodelsurfaces, model->surfacelist);
2353 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
2357 int numleafs, numsurfaces;
2358 int *leaflist, *surfacelist;
2359 unsigned char *leafpvs;
2360 int numlightentities;
2361 int numshadowentities;
2362 entity_render_t *lightentities[MAX_EDICTS];
2363 entity_render_t *shadowentities[MAX_EDICTS];
2365 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
2366 // skip lights that are basically invisible (color 0 0 0)
2367 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
2370 // loading is done before visibility checks because loading should happen
2371 // all at once at the start of a level, not when it stalls gameplay.
2372 // (especially important to benchmarks)
2374 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2375 R_RTLight_Compile(rtlight);
2377 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
2379 // look up the light style value at this time
2380 f = (rtlight->style >= 0 ? r_refdef.lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2381 VectorScale(rtlight->color, f, rtlight->currentcolor);
2383 if (rtlight->selected)
2385 f = 2 + sin(realtime * M_PI * 4.0);
2386 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
2390 // if lightstyle is currently off, don't draw the light
2391 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
2394 // if the light box is offscreen, skip it
2395 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2398 VectorCopy(rtlight->cullmins, r_shadow_rtlight_cullmins);
2399 VectorCopy(rtlight->cullmaxs, r_shadow_rtlight_cullmaxs);
2401 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2403 // compiled light, world available and can receive realtime lighting
2404 // retrieve leaf information
2405 numleafs = rtlight->static_numleafs;
2406 leaflist = rtlight->static_leaflist;
2407 leafpvs = rtlight->static_leafpvs;
2408 numsurfaces = rtlight->static_numsurfaces;
2409 surfacelist = rtlight->static_surfacelist;
2411 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2413 // dynamic light, world available and can receive realtime lighting
2414 // calculate lit surfaces and leafs
2415 R_Shadow_EnlargeLeafSurfaceBuffer(r_refdef.worldmodel->brush.num_leafs, r_refdef.worldmodel->num_surfaces);
2416 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);
2417 leaflist = r_shadow_buffer_leaflist;
2418 leafpvs = r_shadow_buffer_leafpvs;
2419 surfacelist = r_shadow_buffer_surfacelist;
2420 // if the reduced leaf bounds are offscreen, skip it
2421 if (R_CullBox(r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs))
2433 // check if light is illuminating any visible leafs
2436 for (i = 0;i < numleafs;i++)
2437 if (r_viewcache.world_leafvisible[leaflist[i]])
2442 // set up a scissor rectangle for this light
2443 if (R_Shadow_ScissorForBBox(r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs))
2446 // make a list of lit entities and shadow casting entities
2447 numlightentities = 0;
2448 numshadowentities = 0;
2449 // don't count the world unless some surfaces are actually lit
2452 lightentities[numlightentities++] = r_refdef.worldentity;
2453 shadowentities[numshadowentities++] = r_refdef.worldentity;
2455 // add dynamic entities that are lit by the light
2456 if (r_drawentities.integer)
2458 for (i = 0;i < r_refdef.numentities;i++)
2461 entity_render_t *ent = r_refdef.entities[i];
2462 if (BoxesOverlap(ent->mins, ent->maxs, r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs)
2463 && (model = ent->model)
2464 && !(ent->flags & RENDER_TRANSPARENT)
2465 && (r_refdef.worldmodel == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs)))
2467 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2469 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
2470 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
2471 shadowentities[numshadowentities++] = ent;
2472 if (r_viewcache.entityvisible[i] && (ent->flags & RENDER_LIGHT) && model->DrawLight)
2473 lightentities[numlightentities++] = ent;
2478 // return if there's nothing at all to light
2479 if (!numlightentities)
2482 // don't let sound skip if going slow
2483 if (r_refdef.extraupdate)
2486 // make this the active rtlight for rendering purposes
2487 R_Shadow_RenderMode_ActiveLight(rtlight);
2488 // count this light in the r_speeds
2489 r_refdef.stats.lights++;
2492 if (numshadowentities && rtlight->shadow && (rtlight->isstatic ? r_refdef.rtworldshadows : r_refdef.rtdlightshadows))
2494 // draw stencil shadow volumes to mask off pixels that are in shadow
2495 // so that they won't receive lighting
2499 R_Shadow_RenderMode_StencilShadowVolumes();
2500 for (i = 0;i < numshadowentities;i++)
2501 R_Shadow_DrawEntityShadow(shadowentities[i], numsurfaces, surfacelist);
2504 // optionally draw visible shape of the shadow volumes
2505 // for performance analysis by level designers
2506 if (r_showshadowvolumes.integer)
2508 R_Shadow_RenderMode_VisibleShadowVolumes();
2509 for (i = 0;i < numshadowentities;i++)
2510 R_Shadow_DrawEntityShadow(shadowentities[i], numsurfaces, surfacelist);
2514 if (numlightentities)
2516 // draw lighting in the unmasked areas
2517 R_Shadow_RenderMode_Lighting(usestencil, false);
2518 for (i = 0;i < numlightentities;i++)
2519 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
2521 // optionally draw the illuminated areas
2522 // for performance analysis by level designers
2523 if (r_showlighting.integer)
2525 R_Shadow_RenderMode_VisibleLighting(usestencil && !r_showdisabledepthtest.integer, false);
2526 for (i = 0;i < numlightentities;i++)
2527 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
2532 void R_ShadowVolumeLighting(qboolean visible)
2537 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2538 R_Shadow_EditLights_Reload_f();
2540 R_Shadow_RenderMode_Begin();
2542 flag = r_refdef.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2543 if (r_shadow_debuglight.integer >= 0)
2545 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2546 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
2547 R_DrawRTLight(&light->rtlight, visible);
2550 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2551 if (light->flags & flag)
2552 R_DrawRTLight(&light->rtlight, visible);
2553 if (r_refdef.rtdlight)
2554 for (lnum = 0;lnum < r_refdef.numlights;lnum++)
2555 R_DrawRTLight(&r_refdef.lights[lnum]->rtlight, visible);
2557 R_Shadow_RenderMode_End();
2560 extern void R_SetupView(const matrix4x4_t *matrix);
2561 extern cvar_t r_shadows_throwdistance;
2562 void R_DrawModelShadows(void)
2565 float relativethrowdistance;
2566 entity_render_t *ent;
2567 vec3_t relativelightorigin;
2568 vec3_t relativelightdirection;
2569 vec3_t relativeshadowmins, relativeshadowmaxs;
2572 if (!r_drawentities.integer || !gl_stencil)
2576 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
2578 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2580 if (gl_ext_separatestencil.integer)
2581 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
2582 else if (gl_ext_stenciltwoside.integer)
2583 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
2585 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
2587 R_Shadow_RenderMode_StencilShadowVolumes();
2589 for (i = 0;i < r_refdef.numentities;i++)
2591 ent = r_refdef.entities[i];
2592 // cast shadows from anything that is not a submodel of the map
2593 if (ent->model && ent->model->DrawShadowVolume != NULL && !ent->model->brush.submodel && (ent->flags & RENDER_SHADOW))
2595 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
2596 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
2597 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
2598 VectorNegate(ent->modellight_lightdir, relativelightdirection);
2599 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
2600 R_Mesh_Matrix(&ent->matrix);
2601 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2605 // not really the right mode, but this will disable any silly stencil features
2606 R_Shadow_RenderMode_VisibleLighting(true, true);
2608 // vertex coordinates for a quad that covers the screen exactly
2609 vertex3f[0] = 0;vertex3f[1] = 0;vertex3f[2] = 0;
2610 vertex3f[3] = 1;vertex3f[4] = 0;vertex3f[5] = 0;
2611 vertex3f[6] = 1;vertex3f[7] = 1;vertex3f[8] = 0;
2612 vertex3f[9] = 0;vertex3f[10] = 1;vertex3f[11] = 0;
2614 // set up ortho view for rendering this pass
2615 GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
2616 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
2617 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
2618 GL_ScissorTest(true);
2619 R_Mesh_Matrix(&identitymatrix);
2620 R_Mesh_ResetTextureState();
2621 R_Mesh_VertexPointer(vertex3f);
2622 R_Mesh_ColorPointer(NULL);
2624 // set up a 50% darkening blend on shadowed areas
2625 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2626 GL_DepthTest(false);
2627 GL_DepthMask(false);
2628 qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
2629 GL_Color(0, 0, 0, 0.5);
2630 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
2631 qglDepthFunc(GL_ALWAYS);CHECKGLERROR
2632 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2633 qglStencilMask(~0);CHECKGLERROR
2634 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
2635 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
2637 // apply the blend to the shadowed areas
2638 R_Mesh_Draw(0, 4, 2, polygonelements);
2640 // restoring the perspective view is done by R_RenderScene
2641 //R_SetupView(&r_view.matrix);
2643 // restore other state to normal
2644 R_Shadow_RenderMode_End();
2648 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2649 typedef struct suffixinfo_s
2652 qboolean flipx, flipy, flipdiagonal;
2655 static suffixinfo_t suffix[3][6] =
2658 {"px", false, false, false},
2659 {"nx", false, false, false},
2660 {"py", false, false, false},
2661 {"ny", false, false, false},
2662 {"pz", false, false, false},
2663 {"nz", false, false, false}
2666 {"posx", false, false, false},
2667 {"negx", false, false, false},
2668 {"posy", false, false, false},
2669 {"negy", false, false, false},
2670 {"posz", false, false, false},
2671 {"negz", false, false, false}
2674 {"rt", true, false, true},
2675 {"lf", false, true, true},
2676 {"ft", true, true, false},
2677 {"bk", false, false, false},
2678 {"up", true, false, true},
2679 {"dn", true, false, true}
2683 static int componentorder[4] = {0, 1, 2, 3};
2685 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2687 int i, j, cubemapsize;
2688 unsigned char *cubemappixels, *image_rgba;
2689 rtexture_t *cubemaptexture;
2691 // must start 0 so the first loadimagepixels has no requested width/height
2693 cubemappixels = NULL;
2694 cubemaptexture = NULL;
2695 // keep trying different suffix groups (posx, px, rt) until one loads
2696 for (j = 0;j < 3 && !cubemappixels;j++)
2698 // load the 6 images in the suffix group
2699 for (i = 0;i < 6;i++)
2701 // generate an image name based on the base and and suffix
2702 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2704 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2706 // an image loaded, make sure width and height are equal
2707 if (image_width == image_height)
2709 // if this is the first image to load successfully, allocate the cubemap memory
2710 if (!cubemappixels && image_width >= 1)
2712 cubemapsize = image_width;
2713 // note this clears to black, so unavailable sides are black
2714 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2716 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2718 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);
2721 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2723 Mem_Free(image_rgba);
2727 // if a cubemap loaded, upload it
2730 if (!r_shadow_filters_texturepool)
2731 r_shadow_filters_texturepool = R_AllocTexturePool();
2732 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
2733 Mem_Free(cubemappixels);
2737 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
2738 for (j = 0;j < 3;j++)
2739 for (i = 0;i < 6;i++)
2740 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2741 Con_Print(" and was unable to find any of them.\n");
2743 return cubemaptexture;
2746 rtexture_t *R_Shadow_Cubemap(const char *basename)
2749 for (i = 0;i < numcubemaps;i++)
2750 if (!strcasecmp(cubemaps[i].basename, basename))
2751 return cubemaps[i].texture;
2752 if (i >= MAX_CUBEMAPS)
2753 return r_texture_whitecube;
2755 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
2756 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
2757 if (!cubemaps[i].texture)
2758 cubemaps[i].texture = r_texture_whitecube;
2759 return cubemaps[i].texture;
2762 void R_Shadow_FreeCubemaps(void)
2765 R_FreeTexturePool(&r_shadow_filters_texturepool);
2768 dlight_t *R_Shadow_NewWorldLight(void)
2771 light = (dlight_t *)Mem_Alloc(r_main_mempool, sizeof(dlight_t));
2772 light->next = r_shadow_worldlightchain;
2773 r_shadow_worldlightchain = light;
2777 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)
2779 VectorCopy(origin, light->origin);
2780 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
2781 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
2782 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
2783 light->color[0] = max(color[0], 0);
2784 light->color[1] = max(color[1], 0);
2785 light->color[2] = max(color[2], 0);
2786 light->radius = max(radius, 0);
2787 light->style = style;
2788 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
2790 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
2793 light->shadow = shadowenable;
2794 light->corona = corona;
2797 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
2798 light->coronasizescale = coronasizescale;
2799 light->ambientscale = ambientscale;
2800 light->diffusescale = diffusescale;
2801 light->specularscale = specularscale;
2802 light->flags = flags;
2803 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
2805 R_RTLight_Update(light, true);
2808 void R_Shadow_FreeWorldLight(dlight_t *light)
2810 dlight_t **lightpointer;
2811 R_RTLight_Uncompile(&light->rtlight);
2812 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
2813 if (*lightpointer != light)
2814 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain");
2815 *lightpointer = light->next;
2819 void R_Shadow_ClearWorldLights(void)
2821 while (r_shadow_worldlightchain)
2822 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
2823 r_shadow_selectedlight = NULL;
2824 R_Shadow_FreeCubemaps();
2827 void R_Shadow_SelectLight(dlight_t *light)
2829 if (r_shadow_selectedlight)
2830 r_shadow_selectedlight->selected = false;
2831 r_shadow_selectedlight = light;
2832 if (r_shadow_selectedlight)
2833 r_shadow_selectedlight->selected = true;
2836 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2838 // this is never batched (there can be only one)
2839 float scale = r_editlights_cursorgrid.value * 0.5f;
2840 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);
2843 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2845 // this is never batched (due to the ent parameter changing every time)
2846 // so numsurfaces == 1 and surfacelist[0] == lightnumber
2848 const dlight_t *light = (dlight_t *)ent;
2850 if (light->selected)
2851 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
2854 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);
2857 void R_Shadow_DrawLightSprites(void)
2862 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
2863 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 1+(i % 5), &light->rtlight);
2864 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
2867 void R_Shadow_SelectLightInView(void)
2869 float bestrating, rating, temp[3];
2870 dlight_t *best, *light;
2873 for (light = r_shadow_worldlightchain;light;light = light->next)
2875 VectorSubtract(light->origin, r_view.origin, temp);
2876 rating = (DotProduct(temp, r_view.forward) / sqrt(DotProduct(temp, temp)));
2879 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
2880 if (bestrating < rating && CL_TraceBox(light->origin, vec3_origin, vec3_origin, r_view.origin, true, NULL, SUPERCONTENTS_SOLID, false).fraction == 1.0f)
2882 bestrating = rating;
2887 R_Shadow_SelectLight(best);
2890 void R_Shadow_LoadWorldLights(void)
2892 int n, a, style, shadow, flags;
2893 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
2894 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
2895 if (r_refdef.worldmodel == NULL)
2897 Con_Print("No map loaded.\n");
2900 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
2901 strlcat (name, ".rtlights", sizeof (name));
2902 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
2912 for (;COM_Parse(t, true) && strcmp(
2913 if (COM_Parse(t, true))
2915 if (com_token[0] == '!')
2918 origin[0] = atof(com_token+1);
2921 origin[0] = atof(com_token);
2926 while (*s && *s != '\n' && *s != '\r')
2932 // check for modifier flags
2939 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);
2942 flags = LIGHTFLAG_REALTIMEMODE;
2950 coronasizescale = 0.25f;
2952 VectorClear(angles);
2955 if (a < 9 || !strcmp(cubemapname, "\"\""))
2957 // remove quotes on cubemapname
2958 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
2961 namelen = strlen(cubemapname) - 2;
2962 memmove(cubemapname, cubemapname + 1, namelen);
2963 cubemapname[namelen] = '\0';
2967 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);
2970 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
2978 Con_Printf("invalid rtlights file \"%s\"\n", name);
2979 Mem_Free(lightsstring);
2983 void R_Shadow_SaveWorldLights(void)
2986 size_t bufchars, bufmaxchars;
2988 char name[MAX_QPATH];
2989 char line[MAX_INPUTLINE];
2990 if (!r_shadow_worldlightchain)
2992 if (r_refdef.worldmodel == NULL)
2994 Con_Print("No map loaded.\n");
2997 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
2998 strlcat (name, ".rtlights", sizeof (name));
2999 bufchars = bufmaxchars = 0;
3001 for (light = r_shadow_worldlightchain;light;light = light->next)
3003 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3004 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);
3005 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3006 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]);
3008 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);
3009 if (bufchars + strlen(line) > bufmaxchars)
3011 bufmaxchars = bufchars + strlen(line) + 2048;
3013 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
3017 memcpy(buf, oldbuf, bufchars);
3023 memcpy(buf + bufchars, line, strlen(line));
3024 bufchars += strlen(line);
3028 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
3033 void R_Shadow_LoadLightsFile(void)
3036 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3037 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3038 if (r_refdef.worldmodel == NULL)
3040 Con_Print("No map loaded.\n");
3043 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3044 strlcat (name, ".lights", sizeof (name));
3045 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3053 while (*s && *s != '\n' && *s != '\r')
3059 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);
3063 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);
3066 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3067 radius = bound(15, radius, 4096);
3068 VectorScale(color, (2.0f / (8388608.0f)), color);
3069 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3077 Con_Printf("invalid lights file \"%s\"\n", name);
3078 Mem_Free(lightsstring);
3082 // tyrlite/hmap2 light types in the delay field
3083 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3085 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3087 int entnum, style, islight, skin, pflags, effects, type, n;
3090 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3091 char key[256], value[MAX_INPUTLINE];
3093 if (r_refdef.worldmodel == NULL)
3095 Con_Print("No map loaded.\n");
3098 // try to load a .ent file first
3099 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3100 strlcat (key, ".ent", sizeof (key));
3101 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
3102 // and if that is not found, fall back to the bsp file entity string
3104 data = r_refdef.worldmodel->brush.entities;
3107 for (entnum = 0;COM_ParseTokenConsole(&data) && com_token[0] == '{';entnum++)
3109 type = LIGHTTYPE_MINUSX;
3110 origin[0] = origin[1] = origin[2] = 0;
3111 originhack[0] = originhack[1] = originhack[2] = 0;
3112 angles[0] = angles[1] = angles[2] = 0;
3113 color[0] = color[1] = color[2] = 1;
3114 light[0] = light[1] = light[2] = 1;light[3] = 300;
3115 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3125 if (!COM_ParseTokenConsole(&data))
3127 if (com_token[0] == '}')
3128 break; // end of entity
3129 if (com_token[0] == '_')
3130 strlcpy(key, com_token + 1, sizeof(key));
3132 strlcpy(key, com_token, sizeof(key));
3133 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3134 key[strlen(key)-1] = 0;
3135 if (!COM_ParseTokenConsole(&data))
3137 strlcpy(value, com_token, sizeof(value));
3139 // now that we have the key pair worked out...
3140 if (!strcmp("light", key))
3142 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3146 light[0] = vec[0] * (1.0f / 256.0f);
3147 light[1] = vec[0] * (1.0f / 256.0f);
3148 light[2] = vec[0] * (1.0f / 256.0f);
3154 light[0] = vec[0] * (1.0f / 255.0f);
3155 light[1] = vec[1] * (1.0f / 255.0f);
3156 light[2] = vec[2] * (1.0f / 255.0f);
3160 else if (!strcmp("delay", key))
3162 else if (!strcmp("origin", key))
3163 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3164 else if (!strcmp("angle", key))
3165 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3166 else if (!strcmp("angles", key))
3167 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3168 else if (!strcmp("color", key))
3169 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3170 else if (!strcmp("wait", key))
3171 fadescale = atof(value);
3172 else if (!strcmp("classname", key))
3174 if (!strncmp(value, "light", 5))
3177 if (!strcmp(value, "light_fluoro"))
3182 overridecolor[0] = 1;
3183 overridecolor[1] = 1;
3184 overridecolor[2] = 1;
3186 if (!strcmp(value, "light_fluorospark"))
3191 overridecolor[0] = 1;
3192 overridecolor[1] = 1;
3193 overridecolor[2] = 1;
3195 if (!strcmp(value, "light_globe"))
3200 overridecolor[0] = 1;
3201 overridecolor[1] = 0.8;
3202 overridecolor[2] = 0.4;
3204 if (!strcmp(value, "light_flame_large_yellow"))
3209 overridecolor[0] = 1;
3210 overridecolor[1] = 0.5;
3211 overridecolor[2] = 0.1;
3213 if (!strcmp(value, "light_flame_small_yellow"))
3218 overridecolor[0] = 1;
3219 overridecolor[1] = 0.5;
3220 overridecolor[2] = 0.1;
3222 if (!strcmp(value, "light_torch_small_white"))
3227 overridecolor[0] = 1;
3228 overridecolor[1] = 0.5;
3229 overridecolor[2] = 0.1;
3231 if (!strcmp(value, "light_torch_small_walltorch"))
3236 overridecolor[0] = 1;
3237 overridecolor[1] = 0.5;
3238 overridecolor[2] = 0.1;
3242 else if (!strcmp("style", key))
3243 style = atoi(value);
3244 else if (!strcmp("skin", key))
3245 skin = (int)atof(value);
3246 else if (!strcmp("pflags", key))
3247 pflags = (int)atof(value);
3248 else if (!strcmp("effects", key))
3249 effects = (int)atof(value);
3250 else if (r_refdef.worldmodel->type == mod_brushq3)
3252 if (!strcmp("scale", key))
3253 lightscale = atof(value);
3254 if (!strcmp("fade", key))
3255 fadescale = atof(value);
3260 if (lightscale <= 0)
3264 if (color[0] == color[1] && color[0] == color[2])
3266 color[0] *= overridecolor[0];
3267 color[1] *= overridecolor[1];
3268 color[2] *= overridecolor[2];
3270 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3271 color[0] = color[0] * light[0];
3272 color[1] = color[1] * light[1];
3273 color[2] = color[2] * light[2];
3276 case LIGHTTYPE_MINUSX:
3278 case LIGHTTYPE_RECIPX:
3280 VectorScale(color, (1.0f / 16.0f), color);
3282 case LIGHTTYPE_RECIPXX:
3284 VectorScale(color, (1.0f / 16.0f), color);
3287 case LIGHTTYPE_NONE:
3291 case LIGHTTYPE_MINUSXX:
3294 VectorAdd(origin, originhack, origin);
3296 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);
3299 Mem_Free(entfiledata);
3303 void R_Shadow_SetCursorLocationForView(void)
3306 vec3_t dest, endpos;
3308 VectorMA(r_view.origin, r_editlights_cursordistance.value, r_view.forward, dest);
3309 trace = CL_TraceBox(r_view.origin, vec3_origin, vec3_origin, dest, true, NULL, SUPERCONTENTS_SOLID, false);
3310 if (trace.fraction < 1)
3312 dist = trace.fraction * r_editlights_cursordistance.value;
3313 push = r_editlights_cursorpushback.value;
3317 VectorMA(trace.endpos, push, r_view.forward, endpos);
3318 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
3322 VectorClear( endpos );
3324 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3325 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3326 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3329 void R_Shadow_UpdateWorldLightSelection(void)
3331 if (r_editlights.integer)
3333 R_Shadow_SetCursorLocationForView();
3334 R_Shadow_SelectLightInView();
3335 R_Shadow_DrawLightSprites();
3338 R_Shadow_SelectLight(NULL);
3341 void R_Shadow_EditLights_Clear_f(void)
3343 R_Shadow_ClearWorldLights();
3346 void R_Shadow_EditLights_Reload_f(void)
3348 if (!r_refdef.worldmodel)
3350 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3351 R_Shadow_ClearWorldLights();
3352 R_Shadow_LoadWorldLights();
3353 if (r_shadow_worldlightchain == NULL)
3355 R_Shadow_LoadLightsFile();
3356 if (r_shadow_worldlightchain == NULL)
3357 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3361 void R_Shadow_EditLights_Save_f(void)
3363 if (!r_refdef.worldmodel)
3365 R_Shadow_SaveWorldLights();
3368 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3370 R_Shadow_ClearWorldLights();
3371 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3374 void R_Shadow_EditLights_ImportLightsFile_f(void)
3376 R_Shadow_ClearWorldLights();
3377 R_Shadow_LoadLightsFile();
3380 void R_Shadow_EditLights_Spawn_f(void)
3383 if (!r_editlights.integer)
3385 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3388 if (Cmd_Argc() != 1)
3390 Con_Print("r_editlights_spawn does not take parameters\n");
3393 color[0] = color[1] = color[2] = 1;
3394 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3397 void R_Shadow_EditLights_Edit_f(void)
3399 vec3_t origin, angles, color;
3400 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3401 int style, shadows, flags, normalmode, realtimemode;
3402 char cubemapname[MAX_INPUTLINE];
3403 if (!r_editlights.integer)
3405 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3408 if (!r_shadow_selectedlight)
3410 Con_Print("No selected light.\n");
3413 VectorCopy(r_shadow_selectedlight->origin, origin);
3414 VectorCopy(r_shadow_selectedlight->angles, angles);
3415 VectorCopy(r_shadow_selectedlight->color, color);
3416 radius = r_shadow_selectedlight->radius;
3417 style = r_shadow_selectedlight->style;
3418 if (r_shadow_selectedlight->cubemapname)
3419 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
3422 shadows = r_shadow_selectedlight->shadow;
3423 corona = r_shadow_selectedlight->corona;
3424 coronasizescale = r_shadow_selectedlight->coronasizescale;
3425 ambientscale = r_shadow_selectedlight->ambientscale;
3426 diffusescale = r_shadow_selectedlight->diffusescale;
3427 specularscale = r_shadow_selectedlight->specularscale;
3428 flags = r_shadow_selectedlight->flags;
3429 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3430 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3431 if (!strcmp(Cmd_Argv(1), "origin"))
3433 if (Cmd_Argc() != 5)
3435 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3438 origin[0] = atof(Cmd_Argv(2));
3439 origin[1] = atof(Cmd_Argv(3));
3440 origin[2] = atof(Cmd_Argv(4));
3442 else if (!strcmp(Cmd_Argv(1), "originx"))
3444 if (Cmd_Argc() != 3)
3446 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3449 origin[0] = atof(Cmd_Argv(2));
3451 else if (!strcmp(Cmd_Argv(1), "originy"))
3453 if (Cmd_Argc() != 3)
3455 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3458 origin[1] = atof(Cmd_Argv(2));
3460 else if (!strcmp(Cmd_Argv(1), "originz"))
3462 if (Cmd_Argc() != 3)
3464 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3467 origin[2] = atof(Cmd_Argv(2));
3469 else if (!strcmp(Cmd_Argv(1), "move"))
3471 if (Cmd_Argc() != 5)
3473 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3476 origin[0] += atof(Cmd_Argv(2));
3477 origin[1] += atof(Cmd_Argv(3));
3478 origin[2] += atof(Cmd_Argv(4));
3480 else if (!strcmp(Cmd_Argv(1), "movex"))
3482 if (Cmd_Argc() != 3)
3484 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3487 origin[0] += atof(Cmd_Argv(2));
3489 else if (!strcmp(Cmd_Argv(1), "movey"))
3491 if (Cmd_Argc() != 3)
3493 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3496 origin[1] += atof(Cmd_Argv(2));
3498 else if (!strcmp(Cmd_Argv(1), "movez"))
3500 if (Cmd_Argc() != 3)
3502 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3505 origin[2] += atof(Cmd_Argv(2));
3507 else if (!strcmp(Cmd_Argv(1), "angles"))
3509 if (Cmd_Argc() != 5)
3511 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3514 angles[0] = atof(Cmd_Argv(2));
3515 angles[1] = atof(Cmd_Argv(3));
3516 angles[2] = atof(Cmd_Argv(4));
3518 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3520 if (Cmd_Argc() != 3)
3522 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3525 angles[0] = atof(Cmd_Argv(2));
3527 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3529 if (Cmd_Argc() != 3)
3531 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3534 angles[1] = atof(Cmd_Argv(2));
3536 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3538 if (Cmd_Argc() != 3)
3540 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3543 angles[2] = atof(Cmd_Argv(2));
3545 else if (!strcmp(Cmd_Argv(1), "color"))
3547 if (Cmd_Argc() != 5)
3549 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3552 color[0] = atof(Cmd_Argv(2));
3553 color[1] = atof(Cmd_Argv(3));
3554 color[2] = atof(Cmd_Argv(4));
3556 else if (!strcmp(Cmd_Argv(1), "radius"))
3558 if (Cmd_Argc() != 3)
3560 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3563 radius = atof(Cmd_Argv(2));
3565 else if (!strcmp(Cmd_Argv(1), "colorscale"))
3567 if (Cmd_Argc() == 3)
3569 double scale = atof(Cmd_Argv(2));
3576 if (Cmd_Argc() != 5)
3578 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
3581 color[0] *= atof(Cmd_Argv(2));
3582 color[1] *= atof(Cmd_Argv(3));
3583 color[2] *= atof(Cmd_Argv(4));
3586 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
3588 if (Cmd_Argc() != 3)
3590 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3593 radius *= atof(Cmd_Argv(2));
3595 else if (!strcmp(Cmd_Argv(1), "style"))
3597 if (Cmd_Argc() != 3)
3599 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3602 style = atoi(Cmd_Argv(2));
3604 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3608 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3611 if (Cmd_Argc() == 3)
3612 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
3616 else if (!strcmp(Cmd_Argv(1), "shadows"))
3618 if (Cmd_Argc() != 3)
3620 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3623 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3625 else if (!strcmp(Cmd_Argv(1), "corona"))
3627 if (Cmd_Argc() != 3)
3629 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3632 corona = atof(Cmd_Argv(2));
3634 else if (!strcmp(Cmd_Argv(1), "coronasize"))
3636 if (Cmd_Argc() != 3)
3638 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3641 coronasizescale = atof(Cmd_Argv(2));
3643 else if (!strcmp(Cmd_Argv(1), "ambient"))
3645 if (Cmd_Argc() != 3)
3647 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3650 ambientscale = atof(Cmd_Argv(2));
3652 else if (!strcmp(Cmd_Argv(1), "diffuse"))
3654 if (Cmd_Argc() != 3)
3656 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3659 diffusescale = atof(Cmd_Argv(2));
3661 else if (!strcmp(Cmd_Argv(1), "specular"))
3663 if (Cmd_Argc() != 3)
3665 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3668 specularscale = atof(Cmd_Argv(2));
3670 else if (!strcmp(Cmd_Argv(1), "normalmode"))
3672 if (Cmd_Argc() != 3)
3674 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3677 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3679 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
3681 if (Cmd_Argc() != 3)
3683 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3686 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3690 Con_Print("usage: r_editlights_edit [property] [value]\n");
3691 Con_Print("Selected light's properties:\n");
3692 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3693 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3694 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3695 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3696 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3697 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3698 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3699 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
3700 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
3701 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
3702 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
3703 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
3704 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
3705 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
3708 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
3709 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3712 void R_Shadow_EditLights_EditAll_f(void)
3716 if (!r_editlights.integer)
3718 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
3722 for (light = r_shadow_worldlightchain;light;light = light->next)
3724 R_Shadow_SelectLight(light);
3725 R_Shadow_EditLights_Edit_f();
3729 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3731 int lightnumber, lightcount;
3735 if (!r_editlights.integer)
3741 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
3742 if (light == r_shadow_selectedlight)
3743 lightnumber = lightcount;
3744 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;
3745 if (r_shadow_selectedlight == NULL)
3747 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3748 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;
3749 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;
3750 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;
3751 sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3752 sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3753 sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3754 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;
3755 sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3756 sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3757 sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3758 sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3759 sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3760 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;
3761 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;
3764 void R_Shadow_EditLights_ToggleShadow_f(void)
3766 if (!r_editlights.integer)
3768 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3771 if (!r_shadow_selectedlight)
3773 Con_Print("No selected light.\n");
3776 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);
3779 void R_Shadow_EditLights_ToggleCorona_f(void)
3781 if (!r_editlights.integer)
3783 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3786 if (!r_shadow_selectedlight)
3788 Con_Print("No selected light.\n");
3791 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);
3794 void R_Shadow_EditLights_Remove_f(void)
3796 if (!r_editlights.integer)
3798 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
3801 if (!r_shadow_selectedlight)
3803 Con_Print("No selected light.\n");
3806 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3807 r_shadow_selectedlight = NULL;
3810 void R_Shadow_EditLights_Help_f(void)
3813 "Documentation on r_editlights system:\n"
3815 "r_editlights : enable/disable editing mode\n"
3816 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
3817 "r_editlights_cursorpushback : push back cursor this far from surface\n"
3818 "r_editlights_cursorpushoff : push cursor off surface this far\n"
3819 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
3820 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
3822 "r_editlights_help : this help\n"
3823 "r_editlights_clear : remove all lights\n"
3824 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
3825 "r_editlights_save : save to .rtlights file\n"
3826 "r_editlights_spawn : create a light with default settings\n"
3827 "r_editlights_edit command : edit selected light - more documentation below\n"
3828 "r_editlights_remove : remove selected light\n"
3829 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
3830 "r_editlights_importlightentitiesfrommap : reload light entities\n"
3831 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
3833 "origin x y z : set light location\n"
3834 "originx x: set x component of light location\n"
3835 "originy y: set y component of light location\n"
3836 "originz z: set z component of light location\n"
3837 "move x y z : adjust light location\n"
3838 "movex x: adjust x component of light location\n"
3839 "movey y: adjust y component of light location\n"
3840 "movez z: adjust z component of light location\n"
3841 "angles x y z : set light angles\n"
3842 "anglesx x: set x component of light angles\n"
3843 "anglesy y: set y component of light angles\n"
3844 "anglesz z: set z component of light angles\n"
3845 "color r g b : set color of light (can be brighter than 1 1 1)\n"
3846 "radius radius : set radius (size) of light\n"
3847 "colorscale grey : multiply color of light (1 does nothing)\n"
3848 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
3849 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
3850 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
3851 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
3852 "cubemap basename : set filter cubemap of light (not yet supported)\n"
3853 "shadows 1/0 : turn on/off shadows\n"
3854 "corona n : set corona intensity\n"
3855 "coronasize n : set corona size (0-1)\n"
3856 "ambient n : set ambient intensity (0-1)\n"
3857 "diffuse n : set diffuse intensity (0-1)\n"
3858 "specular n : set specular intensity (0-1)\n"
3859 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
3860 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
3861 "<nothing> : print light properties to console\n"
3865 void R_Shadow_EditLights_CopyInfo_f(void)
3867 if (!r_editlights.integer)
3869 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
3872 if (!r_shadow_selectedlight)
3874 Con_Print("No selected light.\n");
3877 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
3878 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
3879 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
3880 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
3881 if (r_shadow_selectedlight->cubemapname)
3882 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
3884 r_shadow_bufferlight.cubemapname[0] = 0;
3885 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
3886 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
3887 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
3888 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
3889 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
3890 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
3891 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
3894 void R_Shadow_EditLights_PasteInfo_f(void)
3896 if (!r_editlights.integer)
3898 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
3901 if (!r_shadow_selectedlight)
3903 Con_Print("No selected light.\n");
3906 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);
3909 void R_Shadow_EditLights_Init(void)
3911 Cvar_RegisterVariable(&r_editlights);
3912 Cvar_RegisterVariable(&r_editlights_cursordistance);
3913 Cvar_RegisterVariable(&r_editlights_cursorpushback);
3914 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
3915 Cvar_RegisterVariable(&r_editlights_cursorgrid);
3916 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
3917 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
3918 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
3919 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)");
3920 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
3921 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
3922 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
3923 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)");
3924 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
3925 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
3926 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
3927 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
3928 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
3929 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
3930 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)");