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(rtlight_t *rtlight, int isstatic, matrix4x4_t *matrix, vec3_t color, int style, const char *cubemapname, qboolean shadow, vec_t corona, vec_t coronasizescale, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int flags)
2140 // if this light has been compiled before, free the associated data
2141 R_RTLight_Uncompile(rtlight);
2143 // clear it completely to avoid any lingering data
2144 memset(rtlight, 0, sizeof(*rtlight));
2146 // copy the properties
2147 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, matrix);
2148 Matrix4x4_OriginFromMatrix(matrix, rtlight->shadoworigin);
2149 rtlight->radius = Matrix4x4_ScaleFromMatrix(matrix);
2150 VectorCopy(color, rtlight->color);
2151 rtlight->cubemapname[0] = 0;
2152 if (cubemapname && cubemapname[0])
2153 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2154 rtlight->shadow = shadow;
2155 rtlight->corona = corona;
2156 rtlight->style = style;
2157 rtlight->isstatic = isstatic;
2158 rtlight->coronasizescale = coronasizescale;
2159 rtlight->ambientscale = ambientscale;
2160 rtlight->diffusescale = diffusescale;
2161 rtlight->specularscale = specularscale;
2162 rtlight->flags = flags;
2164 // compute derived data
2165 //rtlight->cullradius = rtlight->radius;
2166 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2167 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2168 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2169 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2170 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2171 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2172 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2175 // compiles rtlight geometry
2176 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2177 void R_RTLight_Compile(rtlight_t *rtlight)
2179 int shadowmeshes, shadowtris, numleafs, numleafpvsbytes, numsurfaces;
2180 entity_render_t *ent = r_refdef.worldentity;
2181 model_t *model = r_refdef.worldmodel;
2182 unsigned char *data;
2184 // compile the light
2185 rtlight->compiled = true;
2186 rtlight->static_numleafs = 0;
2187 rtlight->static_numleafpvsbytes = 0;
2188 rtlight->static_leaflist = NULL;
2189 rtlight->static_leafpvs = NULL;
2190 rtlight->static_numsurfaces = 0;
2191 rtlight->static_surfacelist = NULL;
2192 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2193 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2194 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2195 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2196 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2197 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2199 if (model && model->GetLightInfo)
2201 // this variable must be set for the CompileShadowVolume code
2202 r_shadow_compilingrtlight = rtlight;
2203 R_Shadow_EnlargeLeafSurfaceBuffer(model->brush.num_leafs, model->num_surfaces);
2204 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);
2205 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2206 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numleafs + numleafpvsbytes + sizeof(int) * numsurfaces);
2207 rtlight->static_numleafs = numleafs;
2208 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2209 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2210 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2211 rtlight->static_numsurfaces = numsurfaces;
2212 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2214 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2215 if (numleafpvsbytes)
2216 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2218 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2219 if (model->CompileShadowVolume && rtlight->shadow)
2220 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2221 // now we're done compiling the rtlight
2222 r_shadow_compilingrtlight = NULL;
2226 // use smallest available cullradius - box radius or light radius
2227 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2228 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2232 if (rtlight->static_meshchain_shadow)
2235 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2238 shadowtris += mesh->numtriangles;
2242 if (developer.integer >= 10)
2243 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);
2246 void R_RTLight_Uncompile(rtlight_t *rtlight)
2248 if (rtlight->compiled)
2250 if (rtlight->static_meshchain_shadow)
2251 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2252 rtlight->static_meshchain_shadow = NULL;
2253 // these allocations are grouped
2254 if (rtlight->static_leaflist)
2255 Mem_Free(rtlight->static_leaflist);
2256 rtlight->static_numleafs = 0;
2257 rtlight->static_numleafpvsbytes = 0;
2258 rtlight->static_leaflist = NULL;
2259 rtlight->static_leafpvs = NULL;
2260 rtlight->static_numsurfaces = 0;
2261 rtlight->static_surfacelist = NULL;
2262 rtlight->compiled = false;
2266 void R_Shadow_UncompileWorldLights(void)
2269 for (light = r_shadow_worldlightchain;light;light = light->next)
2270 R_RTLight_Uncompile(&light->rtlight);
2273 void R_Shadow_DrawEntityShadow(entity_render_t *ent, int numsurfaces, int *surfacelist)
2275 model_t *model = ent->model;
2276 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
2277 vec_t relativeshadowradius;
2278 if (ent == r_refdef.worldentity)
2280 if (r_shadow_rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2283 R_Mesh_Matrix(&ent->matrix);
2285 for (mesh = r_shadow_rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2287 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
2288 R_Mesh_VertexPointer(mesh->vertex3f);
2289 GL_LockArrays(0, mesh->numverts);
2290 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
2292 // decrement stencil if backface is behind depthbuffer
2293 GL_CullFace(GL_BACK); // quake is backwards, this culls front faces
2294 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2295 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2296 // increment stencil if frontface is behind depthbuffer
2297 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
2298 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2300 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2301 GL_LockArrays(0, 0);
2305 else if (numsurfaces)
2307 R_Mesh_Matrix(&ent->matrix);
2308 model->DrawShadowVolume(ent, r_shadow_rtlight->shadoworigin, NULL, r_shadow_rtlight->radius, numsurfaces, surfacelist, r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs);
2313 Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, relativeshadoworigin);
2314 relativeshadowradius = r_shadow_rtlight->radius / ent->scale;
2315 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
2316 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
2317 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
2318 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
2319 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
2320 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
2321 R_Mesh_Matrix(&ent->matrix);
2322 model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, model->nummodelsurfaces, model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2326 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
2328 // set up properties for rendering light onto this entity
2329 RSurf_ActiveEntity(ent, true, true);
2330 Matrix4x4_Concat(&r_shadow_entitytolight, &r_shadow_rtlight->matrix_worldtolight, &ent->matrix);
2331 Matrix4x4_Concat(&r_shadow_entitytoattenuationxyz, &matrix_attenuationxyz, &r_shadow_entitytolight);
2332 Matrix4x4_Concat(&r_shadow_entitytoattenuationz, &matrix_attenuationz, &r_shadow_entitytolight);
2333 Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, r_shadow_entitylightorigin);
2334 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2335 R_Mesh_TexMatrix(3, &r_shadow_entitytolight);
2338 void R_Shadow_DrawEntityLight(entity_render_t *ent, int numsurfaces, int *surfacelist)
2340 model_t *model = ent->model;
2341 if (!model->DrawLight)
2343 R_Shadow_SetupEntityLight(ent);
2344 if (ent == r_refdef.worldentity)
2345 model->DrawLight(ent, numsurfaces, surfacelist);
2347 model->DrawLight(ent, model->nummodelsurfaces, model->surfacelist);
2350 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
2354 int numleafs, numsurfaces;
2355 int *leaflist, *surfacelist;
2356 unsigned char *leafpvs;
2357 int numlightentities;
2358 int numshadowentities;
2359 entity_render_t *lightentities[MAX_EDICTS];
2360 entity_render_t *shadowentities[MAX_EDICTS];
2362 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
2363 // skip lights that are basically invisible (color 0 0 0)
2364 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
2367 // loading is done before visibility checks because loading should happen
2368 // all at once at the start of a level, not when it stalls gameplay.
2369 // (especially important to benchmarks)
2371 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2372 R_RTLight_Compile(rtlight);
2374 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
2376 // look up the light style value at this time
2377 f = (rtlight->style >= 0 ? r_refdef.lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2378 VectorScale(rtlight->color, f, rtlight->currentcolor);
2380 if (rtlight->selected)
2382 f = 2 + sin(realtime * M_PI * 4.0);
2383 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
2387 // if lightstyle is currently off, don't draw the light
2388 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
2391 // if the light box is offscreen, skip it
2392 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2395 VectorCopy(rtlight->cullmins, r_shadow_rtlight_cullmins);
2396 VectorCopy(rtlight->cullmaxs, r_shadow_rtlight_cullmaxs);
2398 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2400 // compiled light, world available and can receive realtime lighting
2401 // retrieve leaf information
2402 numleafs = rtlight->static_numleafs;
2403 leaflist = rtlight->static_leaflist;
2404 leafpvs = rtlight->static_leafpvs;
2405 numsurfaces = rtlight->static_numsurfaces;
2406 surfacelist = rtlight->static_surfacelist;
2408 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2410 // dynamic light, world available and can receive realtime lighting
2411 // calculate lit surfaces and leafs
2412 R_Shadow_EnlargeLeafSurfaceBuffer(r_refdef.worldmodel->brush.num_leafs, r_refdef.worldmodel->num_surfaces);
2413 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);
2414 leaflist = r_shadow_buffer_leaflist;
2415 leafpvs = r_shadow_buffer_leafpvs;
2416 surfacelist = r_shadow_buffer_surfacelist;
2417 // if the reduced leaf bounds are offscreen, skip it
2418 if (R_CullBox(r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs))
2430 // check if light is illuminating any visible leafs
2433 for (i = 0;i < numleafs;i++)
2434 if (r_viewcache.world_leafvisible[leaflist[i]])
2439 // set up a scissor rectangle for this light
2440 if (R_Shadow_ScissorForBBox(r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs))
2443 // make a list of lit entities and shadow casting entities
2444 numlightentities = 0;
2445 numshadowentities = 0;
2446 // don't count the world unless some surfaces are actually lit
2449 lightentities[numlightentities++] = r_refdef.worldentity;
2450 shadowentities[numshadowentities++] = r_refdef.worldentity;
2452 // add dynamic entities that are lit by the light
2453 if (r_drawentities.integer)
2455 for (i = 0;i < r_refdef.numentities;i++)
2458 entity_render_t *ent = r_refdef.entities[i];
2459 if (BoxesOverlap(ent->mins, ent->maxs, r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs)
2460 && (model = ent->model)
2461 && !(ent->flags & RENDER_TRANSPARENT)
2462 && (r_refdef.worldmodel == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs)))
2464 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2466 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
2467 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
2468 shadowentities[numshadowentities++] = ent;
2469 if (r_viewcache.entityvisible[i] && (ent->flags & RENDER_LIGHT) && model->DrawLight)
2470 lightentities[numlightentities++] = ent;
2475 // return if there's nothing at all to light
2476 if (!numlightentities)
2479 // don't let sound skip if going slow
2480 if (r_refdef.extraupdate)
2483 // make this the active rtlight for rendering purposes
2484 R_Shadow_RenderMode_ActiveLight(rtlight);
2485 // count this light in the r_speeds
2486 r_refdef.stats.lights++;
2489 if (numshadowentities && rtlight->shadow && (rtlight->isstatic ? r_refdef.rtworldshadows : r_refdef.rtdlightshadows))
2491 // draw stencil shadow volumes to mask off pixels that are in shadow
2492 // so that they won't receive lighting
2496 R_Shadow_RenderMode_StencilShadowVolumes();
2497 for (i = 0;i < numshadowentities;i++)
2498 R_Shadow_DrawEntityShadow(shadowentities[i], numsurfaces, surfacelist);
2501 // optionally draw visible shape of the shadow volumes
2502 // for performance analysis by level designers
2503 if (r_showshadowvolumes.integer)
2505 R_Shadow_RenderMode_VisibleShadowVolumes();
2506 for (i = 0;i < numshadowentities;i++)
2507 R_Shadow_DrawEntityShadow(shadowentities[i], numsurfaces, surfacelist);
2511 if (numlightentities)
2513 // draw lighting in the unmasked areas
2514 R_Shadow_RenderMode_Lighting(usestencil, false);
2515 for (i = 0;i < numlightentities;i++)
2516 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
2518 // optionally draw the illuminated areas
2519 // for performance analysis by level designers
2520 if (r_showlighting.integer)
2522 R_Shadow_RenderMode_VisibleLighting(usestencil && !r_showdisabledepthtest.integer, false);
2523 for (i = 0;i < numlightentities;i++)
2524 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
2529 void R_ShadowVolumeLighting(qboolean visible)
2534 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2535 R_Shadow_EditLights_Reload_f();
2537 R_Shadow_RenderMode_Begin();
2539 flag = r_refdef.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2540 if (r_shadow_debuglight.integer >= 0)
2542 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2543 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
2544 R_DrawRTLight(&light->rtlight, visible);
2547 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2548 if (light->flags & flag)
2549 R_DrawRTLight(&light->rtlight, visible);
2550 if (r_refdef.rtdlight)
2551 for (lnum = 0;lnum < r_refdef.numlights;lnum++)
2552 R_DrawRTLight(&r_refdef.lights[lnum], visible);
2554 R_Shadow_RenderMode_End();
2557 extern void R_SetupView(const matrix4x4_t *matrix);
2558 extern cvar_t r_shadows_throwdistance;
2559 void R_DrawModelShadows(void)
2562 float relativethrowdistance;
2563 entity_render_t *ent;
2564 vec3_t relativelightorigin;
2565 vec3_t relativelightdirection;
2566 vec3_t relativeshadowmins, relativeshadowmaxs;
2569 if (!r_drawentities.integer || !gl_stencil)
2573 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
2575 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2577 if (gl_ext_separatestencil.integer)
2578 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
2579 else if (gl_ext_stenciltwoside.integer)
2580 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
2582 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
2584 R_Shadow_RenderMode_StencilShadowVolumes();
2586 for (i = 0;i < r_refdef.numentities;i++)
2588 ent = r_refdef.entities[i];
2589 // cast shadows from anything that is not a submodel of the map
2590 if (ent->model && ent->model->DrawShadowVolume != NULL && !ent->model->brush.submodel && (ent->flags & RENDER_SHADOW))
2592 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
2593 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
2594 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
2595 VectorNegate(ent->modellight_lightdir, relativelightdirection);
2596 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
2597 R_Mesh_Matrix(&ent->matrix);
2598 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2602 // not really the right mode, but this will disable any silly stencil features
2603 R_Shadow_RenderMode_VisibleLighting(true, true);
2605 // vertex coordinates for a quad that covers the screen exactly
2606 vertex3f[0] = 0;vertex3f[1] = 0;vertex3f[2] = 0;
2607 vertex3f[3] = 1;vertex3f[4] = 0;vertex3f[5] = 0;
2608 vertex3f[6] = 1;vertex3f[7] = 1;vertex3f[8] = 0;
2609 vertex3f[9] = 0;vertex3f[10] = 1;vertex3f[11] = 0;
2611 // set up ortho view for rendering this pass
2612 GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
2613 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
2614 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
2615 GL_ScissorTest(true);
2616 R_Mesh_Matrix(&identitymatrix);
2617 R_Mesh_ResetTextureState();
2618 R_Mesh_VertexPointer(vertex3f);
2619 R_Mesh_ColorPointer(NULL);
2621 // set up a 50% darkening blend on shadowed areas
2622 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2623 GL_DepthTest(false);
2624 GL_DepthMask(false);
2625 qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
2626 GL_Color(0, 0, 0, 0.5);
2627 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
2628 qglDepthFunc(GL_ALWAYS);CHECKGLERROR
2629 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2630 qglStencilMask(~0);CHECKGLERROR
2631 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
2632 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
2634 // apply the blend to the shadowed areas
2635 R_Mesh_Draw(0, 4, 2, polygonelements);
2637 // restoring the perspective view is done by R_RenderScene
2638 //R_SetupView(&r_view.matrix);
2640 // restore other state to normal
2641 R_Shadow_RenderMode_End();
2645 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2646 typedef struct suffixinfo_s
2649 qboolean flipx, flipy, flipdiagonal;
2652 static suffixinfo_t suffix[3][6] =
2655 {"px", false, false, false},
2656 {"nx", false, false, false},
2657 {"py", false, false, false},
2658 {"ny", false, false, false},
2659 {"pz", false, false, false},
2660 {"nz", false, false, false}
2663 {"posx", false, false, false},
2664 {"negx", false, false, false},
2665 {"posy", false, false, false},
2666 {"negy", false, false, false},
2667 {"posz", false, false, false},
2668 {"negz", false, false, false}
2671 {"rt", true, false, true},
2672 {"lf", false, true, true},
2673 {"ft", true, true, false},
2674 {"bk", false, false, false},
2675 {"up", true, false, true},
2676 {"dn", true, false, true}
2680 static int componentorder[4] = {0, 1, 2, 3};
2682 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2684 int i, j, cubemapsize;
2685 unsigned char *cubemappixels, *image_rgba;
2686 rtexture_t *cubemaptexture;
2688 // must start 0 so the first loadimagepixels has no requested width/height
2690 cubemappixels = NULL;
2691 cubemaptexture = NULL;
2692 // keep trying different suffix groups (posx, px, rt) until one loads
2693 for (j = 0;j < 3 && !cubemappixels;j++)
2695 // load the 6 images in the suffix group
2696 for (i = 0;i < 6;i++)
2698 // generate an image name based on the base and and suffix
2699 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2701 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2703 // an image loaded, make sure width and height are equal
2704 if (image_width == image_height)
2706 // if this is the first image to load successfully, allocate the cubemap memory
2707 if (!cubemappixels && image_width >= 1)
2709 cubemapsize = image_width;
2710 // note this clears to black, so unavailable sides are black
2711 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2713 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2715 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);
2718 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2720 Mem_Free(image_rgba);
2724 // if a cubemap loaded, upload it
2727 if (!r_shadow_filters_texturepool)
2728 r_shadow_filters_texturepool = R_AllocTexturePool();
2729 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
2730 Mem_Free(cubemappixels);
2734 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
2735 for (j = 0;j < 3;j++)
2736 for (i = 0;i < 6;i++)
2737 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2738 Con_Print(" and was unable to find any of them.\n");
2740 return cubemaptexture;
2743 rtexture_t *R_Shadow_Cubemap(const char *basename)
2746 for (i = 0;i < numcubemaps;i++)
2747 if (!strcasecmp(cubemaps[i].basename, basename))
2748 return cubemaps[i].texture;
2749 if (i >= MAX_CUBEMAPS)
2750 return r_texture_whitecube;
2752 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
2753 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
2754 if (!cubemaps[i].texture)
2755 cubemaps[i].texture = r_texture_whitecube;
2756 return cubemaps[i].texture;
2759 void R_Shadow_FreeCubemaps(void)
2762 R_FreeTexturePool(&r_shadow_filters_texturepool);
2765 dlight_t *R_Shadow_NewWorldLight(void)
2768 light = (dlight_t *)Mem_Alloc(r_main_mempool, sizeof(dlight_t));
2769 light->next = r_shadow_worldlightchain;
2770 r_shadow_worldlightchain = light;
2774 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)
2777 // validate parameters
2778 if (style < 0 || style >= MAX_LIGHTSTYLES)
2780 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
2786 // copy to light properties
2787 VectorCopy(origin, light->origin);
2788 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
2789 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
2790 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
2791 light->color[0] = max(color[0], 0);
2792 light->color[1] = max(color[1], 0);
2793 light->color[2] = max(color[2], 0);
2794 light->radius = max(radius, 0);
2795 light->style = style;
2796 light->shadow = shadowenable;
2797 light->corona = corona;
2798 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
2799 light->coronasizescale = coronasizescale;
2800 light->ambientscale = ambientscale;
2801 light->diffusescale = diffusescale;
2802 light->specularscale = specularscale;
2803 light->flags = flags;
2805 // update renderable light data
2806 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
2807 R_RTLight_Update(&light->rtlight, true, &matrix, light->color, light->style, light->cubemapname[0] ? light->cubemapname : NULL, light->shadow, light->corona, light->coronasizescale, light->ambientscale, light->diffusescale, light->specularscale, light->flags);
2810 void R_Shadow_FreeWorldLight(dlight_t *light)
2812 dlight_t **lightpointer;
2813 R_RTLight_Uncompile(&light->rtlight);
2814 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
2815 if (*lightpointer != light)
2816 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain");
2817 *lightpointer = light->next;
2821 void R_Shadow_ClearWorldLights(void)
2823 while (r_shadow_worldlightchain)
2824 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
2825 r_shadow_selectedlight = NULL;
2826 R_Shadow_FreeCubemaps();
2829 void R_Shadow_SelectLight(dlight_t *light)
2831 if (r_shadow_selectedlight)
2832 r_shadow_selectedlight->selected = false;
2833 r_shadow_selectedlight = light;
2834 if (r_shadow_selectedlight)
2835 r_shadow_selectedlight->selected = true;
2838 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2840 // this is never batched (there can be only one)
2841 float scale = r_editlights_cursorgrid.value * 0.5f;
2842 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);
2845 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2847 // this is never batched (due to the ent parameter changing every time)
2848 // so numsurfaces == 1 and surfacelist[0] == lightnumber
2850 const dlight_t *light = (dlight_t *)ent;
2852 if (light->selected)
2853 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
2856 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);
2859 void R_Shadow_DrawLightSprites(void)
2864 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
2865 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 1+(i % 5), &light->rtlight);
2866 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
2869 void R_Shadow_SelectLightInView(void)
2871 float bestrating, rating, temp[3];
2872 dlight_t *best, *light;
2875 for (light = r_shadow_worldlightchain;light;light = light->next)
2877 VectorSubtract(light->origin, r_view.origin, temp);
2878 rating = (DotProduct(temp, r_view.forward) / sqrt(DotProduct(temp, temp)));
2881 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
2882 if (bestrating < rating && CL_TraceBox(light->origin, vec3_origin, vec3_origin, r_view.origin, true, NULL, SUPERCONTENTS_SOLID, false).fraction == 1.0f)
2884 bestrating = rating;
2889 R_Shadow_SelectLight(best);
2892 void R_Shadow_LoadWorldLights(void)
2894 int n, a, style, shadow, flags;
2895 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
2896 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
2897 if (r_refdef.worldmodel == NULL)
2899 Con_Print("No map loaded.\n");
2902 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
2903 strlcat (name, ".rtlights", sizeof (name));
2904 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
2914 for (;COM_Parse(t, true) && strcmp(
2915 if (COM_Parse(t, true))
2917 if (com_token[0] == '!')
2920 origin[0] = atof(com_token+1);
2923 origin[0] = atof(com_token);
2928 while (*s && *s != '\n' && *s != '\r')
2934 // check for modifier flags
2941 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);
2944 flags = LIGHTFLAG_REALTIMEMODE;
2952 coronasizescale = 0.25f;
2954 VectorClear(angles);
2957 if (a < 9 || !strcmp(cubemapname, "\"\""))
2959 // remove quotes on cubemapname
2960 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
2963 namelen = strlen(cubemapname) - 2;
2964 memmove(cubemapname, cubemapname + 1, namelen);
2965 cubemapname[namelen] = '\0';
2969 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);
2972 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
2980 Con_Printf("invalid rtlights file \"%s\"\n", name);
2981 Mem_Free(lightsstring);
2985 void R_Shadow_SaveWorldLights(void)
2988 size_t bufchars, bufmaxchars;
2990 char name[MAX_QPATH];
2991 char line[MAX_INPUTLINE];
2992 if (!r_shadow_worldlightchain)
2994 if (r_refdef.worldmodel == NULL)
2996 Con_Print("No map loaded.\n");
2999 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3000 strlcat (name, ".rtlights", sizeof (name));
3001 bufchars = bufmaxchars = 0;
3003 for (light = r_shadow_worldlightchain;light;light = light->next)
3005 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3006 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);
3007 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3008 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]);
3010 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);
3011 if (bufchars + strlen(line) > bufmaxchars)
3013 bufmaxchars = bufchars + strlen(line) + 2048;
3015 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
3019 memcpy(buf, oldbuf, bufchars);
3025 memcpy(buf + bufchars, line, strlen(line));
3026 bufchars += strlen(line);
3030 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
3035 void R_Shadow_LoadLightsFile(void)
3038 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3039 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3040 if (r_refdef.worldmodel == NULL)
3042 Con_Print("No map loaded.\n");
3045 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3046 strlcat (name, ".lights", sizeof (name));
3047 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3055 while (*s && *s != '\n' && *s != '\r')
3061 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);
3065 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);
3068 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3069 radius = bound(15, radius, 4096);
3070 VectorScale(color, (2.0f / (8388608.0f)), color);
3071 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3079 Con_Printf("invalid lights file \"%s\"\n", name);
3080 Mem_Free(lightsstring);
3084 // tyrlite/hmap2 light types in the delay field
3085 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3087 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3089 int entnum, style, islight, skin, pflags, effects, type, n;
3092 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3093 char key[256], value[MAX_INPUTLINE];
3095 if (r_refdef.worldmodel == NULL)
3097 Con_Print("No map loaded.\n");
3100 // try to load a .ent file first
3101 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3102 strlcat (key, ".ent", sizeof (key));
3103 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
3104 // and if that is not found, fall back to the bsp file entity string
3106 data = r_refdef.worldmodel->brush.entities;
3109 for (entnum = 0;COM_ParseTokenConsole(&data) && com_token[0] == '{';entnum++)
3111 type = LIGHTTYPE_MINUSX;
3112 origin[0] = origin[1] = origin[2] = 0;
3113 originhack[0] = originhack[1] = originhack[2] = 0;
3114 angles[0] = angles[1] = angles[2] = 0;
3115 color[0] = color[1] = color[2] = 1;
3116 light[0] = light[1] = light[2] = 1;light[3] = 300;
3117 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3127 if (!COM_ParseTokenConsole(&data))
3129 if (com_token[0] == '}')
3130 break; // end of entity
3131 if (com_token[0] == '_')
3132 strlcpy(key, com_token + 1, sizeof(key));
3134 strlcpy(key, com_token, sizeof(key));
3135 while (key[strlen(key)-1] == ' ') // remove trailing spaces
3136 key[strlen(key)-1] = 0;
3137 if (!COM_ParseTokenConsole(&data))
3139 strlcpy(value, com_token, sizeof(value));
3141 // now that we have the key pair worked out...
3142 if (!strcmp("light", key))
3144 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3148 light[0] = vec[0] * (1.0f / 256.0f);
3149 light[1] = vec[0] * (1.0f / 256.0f);
3150 light[2] = vec[0] * (1.0f / 256.0f);
3156 light[0] = vec[0] * (1.0f / 255.0f);
3157 light[1] = vec[1] * (1.0f / 255.0f);
3158 light[2] = vec[2] * (1.0f / 255.0f);
3162 else if (!strcmp("delay", key))
3164 else if (!strcmp("origin", key))
3165 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3166 else if (!strcmp("angle", key))
3167 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3168 else if (!strcmp("angles", key))
3169 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3170 else if (!strcmp("color", key))
3171 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3172 else if (!strcmp("wait", key))
3173 fadescale = atof(value);
3174 else if (!strcmp("classname", key))
3176 if (!strncmp(value, "light", 5))
3179 if (!strcmp(value, "light_fluoro"))
3184 overridecolor[0] = 1;
3185 overridecolor[1] = 1;
3186 overridecolor[2] = 1;
3188 if (!strcmp(value, "light_fluorospark"))
3193 overridecolor[0] = 1;
3194 overridecolor[1] = 1;
3195 overridecolor[2] = 1;
3197 if (!strcmp(value, "light_globe"))
3202 overridecolor[0] = 1;
3203 overridecolor[1] = 0.8;
3204 overridecolor[2] = 0.4;
3206 if (!strcmp(value, "light_flame_large_yellow"))
3211 overridecolor[0] = 1;
3212 overridecolor[1] = 0.5;
3213 overridecolor[2] = 0.1;
3215 if (!strcmp(value, "light_flame_small_yellow"))
3220 overridecolor[0] = 1;
3221 overridecolor[1] = 0.5;
3222 overridecolor[2] = 0.1;
3224 if (!strcmp(value, "light_torch_small_white"))
3229 overridecolor[0] = 1;
3230 overridecolor[1] = 0.5;
3231 overridecolor[2] = 0.1;
3233 if (!strcmp(value, "light_torch_small_walltorch"))
3238 overridecolor[0] = 1;
3239 overridecolor[1] = 0.5;
3240 overridecolor[2] = 0.1;
3244 else if (!strcmp("style", key))
3245 style = atoi(value);
3246 else if (!strcmp("skin", key))
3247 skin = (int)atof(value);
3248 else if (!strcmp("pflags", key))
3249 pflags = (int)atof(value);
3250 else if (!strcmp("effects", key))
3251 effects = (int)atof(value);
3252 else if (r_refdef.worldmodel->type == mod_brushq3)
3254 if (!strcmp("scale", key))
3255 lightscale = atof(value);
3256 if (!strcmp("fade", key))
3257 fadescale = atof(value);
3262 if (lightscale <= 0)
3266 if (color[0] == color[1] && color[0] == color[2])
3268 color[0] *= overridecolor[0];
3269 color[1] *= overridecolor[1];
3270 color[2] *= overridecolor[2];
3272 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3273 color[0] = color[0] * light[0];
3274 color[1] = color[1] * light[1];
3275 color[2] = color[2] * light[2];
3278 case LIGHTTYPE_MINUSX:
3280 case LIGHTTYPE_RECIPX:
3282 VectorScale(color, (1.0f / 16.0f), color);
3284 case LIGHTTYPE_RECIPXX:
3286 VectorScale(color, (1.0f / 16.0f), color);
3289 case LIGHTTYPE_NONE:
3293 case LIGHTTYPE_MINUSXX:
3296 VectorAdd(origin, originhack, origin);
3298 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);
3301 Mem_Free(entfiledata);
3305 void R_Shadow_SetCursorLocationForView(void)
3308 vec3_t dest, endpos;
3310 VectorMA(r_view.origin, r_editlights_cursordistance.value, r_view.forward, dest);
3311 trace = CL_TraceBox(r_view.origin, vec3_origin, vec3_origin, dest, true, NULL, SUPERCONTENTS_SOLID, false);
3312 if (trace.fraction < 1)
3314 dist = trace.fraction * r_editlights_cursordistance.value;
3315 push = r_editlights_cursorpushback.value;
3319 VectorMA(trace.endpos, push, r_view.forward, endpos);
3320 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
3324 VectorClear( endpos );
3326 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3327 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3328 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3331 void R_Shadow_UpdateWorldLightSelection(void)
3333 if (r_editlights.integer)
3335 R_Shadow_SetCursorLocationForView();
3336 R_Shadow_SelectLightInView();
3337 R_Shadow_DrawLightSprites();
3340 R_Shadow_SelectLight(NULL);
3343 void R_Shadow_EditLights_Clear_f(void)
3345 R_Shadow_ClearWorldLights();
3348 void R_Shadow_EditLights_Reload_f(void)
3350 if (!r_refdef.worldmodel)
3352 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3353 R_Shadow_ClearWorldLights();
3354 R_Shadow_LoadWorldLights();
3355 if (r_shadow_worldlightchain == NULL)
3357 R_Shadow_LoadLightsFile();
3358 if (r_shadow_worldlightchain == NULL)
3359 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3363 void R_Shadow_EditLights_Save_f(void)
3365 if (!r_refdef.worldmodel)
3367 R_Shadow_SaveWorldLights();
3370 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3372 R_Shadow_ClearWorldLights();
3373 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3376 void R_Shadow_EditLights_ImportLightsFile_f(void)
3378 R_Shadow_ClearWorldLights();
3379 R_Shadow_LoadLightsFile();
3382 void R_Shadow_EditLights_Spawn_f(void)
3385 if (!r_editlights.integer)
3387 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3390 if (Cmd_Argc() != 1)
3392 Con_Print("r_editlights_spawn does not take parameters\n");
3395 color[0] = color[1] = color[2] = 1;
3396 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3399 void R_Shadow_EditLights_Edit_f(void)
3401 vec3_t origin, angles, color;
3402 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3403 int style, shadows, flags, normalmode, realtimemode;
3404 char cubemapname[MAX_INPUTLINE];
3405 if (!r_editlights.integer)
3407 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3410 if (!r_shadow_selectedlight)
3412 Con_Print("No selected light.\n");
3415 VectorCopy(r_shadow_selectedlight->origin, origin);
3416 VectorCopy(r_shadow_selectedlight->angles, angles);
3417 VectorCopy(r_shadow_selectedlight->color, color);
3418 radius = r_shadow_selectedlight->radius;
3419 style = r_shadow_selectedlight->style;
3420 if (r_shadow_selectedlight->cubemapname)
3421 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
3424 shadows = r_shadow_selectedlight->shadow;
3425 corona = r_shadow_selectedlight->corona;
3426 coronasizescale = r_shadow_selectedlight->coronasizescale;
3427 ambientscale = r_shadow_selectedlight->ambientscale;
3428 diffusescale = r_shadow_selectedlight->diffusescale;
3429 specularscale = r_shadow_selectedlight->specularscale;
3430 flags = r_shadow_selectedlight->flags;
3431 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3432 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3433 if (!strcmp(Cmd_Argv(1), "origin"))
3435 if (Cmd_Argc() != 5)
3437 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3440 origin[0] = atof(Cmd_Argv(2));
3441 origin[1] = atof(Cmd_Argv(3));
3442 origin[2] = atof(Cmd_Argv(4));
3444 else if (!strcmp(Cmd_Argv(1), "originx"))
3446 if (Cmd_Argc() != 3)
3448 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3451 origin[0] = atof(Cmd_Argv(2));
3453 else if (!strcmp(Cmd_Argv(1), "originy"))
3455 if (Cmd_Argc() != 3)
3457 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3460 origin[1] = atof(Cmd_Argv(2));
3462 else if (!strcmp(Cmd_Argv(1), "originz"))
3464 if (Cmd_Argc() != 3)
3466 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3469 origin[2] = atof(Cmd_Argv(2));
3471 else if (!strcmp(Cmd_Argv(1), "move"))
3473 if (Cmd_Argc() != 5)
3475 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3478 origin[0] += atof(Cmd_Argv(2));
3479 origin[1] += atof(Cmd_Argv(3));
3480 origin[2] += atof(Cmd_Argv(4));
3482 else if (!strcmp(Cmd_Argv(1), "movex"))
3484 if (Cmd_Argc() != 3)
3486 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3489 origin[0] += atof(Cmd_Argv(2));
3491 else if (!strcmp(Cmd_Argv(1), "movey"))
3493 if (Cmd_Argc() != 3)
3495 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3498 origin[1] += atof(Cmd_Argv(2));
3500 else if (!strcmp(Cmd_Argv(1), "movez"))
3502 if (Cmd_Argc() != 3)
3504 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3507 origin[2] += atof(Cmd_Argv(2));
3509 else if (!strcmp(Cmd_Argv(1), "angles"))
3511 if (Cmd_Argc() != 5)
3513 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3516 angles[0] = atof(Cmd_Argv(2));
3517 angles[1] = atof(Cmd_Argv(3));
3518 angles[2] = atof(Cmd_Argv(4));
3520 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3522 if (Cmd_Argc() != 3)
3524 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3527 angles[0] = atof(Cmd_Argv(2));
3529 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3531 if (Cmd_Argc() != 3)
3533 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3536 angles[1] = atof(Cmd_Argv(2));
3538 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3540 if (Cmd_Argc() != 3)
3542 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3545 angles[2] = atof(Cmd_Argv(2));
3547 else if (!strcmp(Cmd_Argv(1), "color"))
3549 if (Cmd_Argc() != 5)
3551 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3554 color[0] = atof(Cmd_Argv(2));
3555 color[1] = atof(Cmd_Argv(3));
3556 color[2] = atof(Cmd_Argv(4));
3558 else if (!strcmp(Cmd_Argv(1), "radius"))
3560 if (Cmd_Argc() != 3)
3562 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3565 radius = atof(Cmd_Argv(2));
3567 else if (!strcmp(Cmd_Argv(1), "colorscale"))
3569 if (Cmd_Argc() == 3)
3571 double scale = atof(Cmd_Argv(2));
3578 if (Cmd_Argc() != 5)
3580 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
3583 color[0] *= atof(Cmd_Argv(2));
3584 color[1] *= atof(Cmd_Argv(3));
3585 color[2] *= atof(Cmd_Argv(4));
3588 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
3590 if (Cmd_Argc() != 3)
3592 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3595 radius *= atof(Cmd_Argv(2));
3597 else if (!strcmp(Cmd_Argv(1), "style"))
3599 if (Cmd_Argc() != 3)
3601 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3604 style = atoi(Cmd_Argv(2));
3606 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3610 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3613 if (Cmd_Argc() == 3)
3614 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
3618 else if (!strcmp(Cmd_Argv(1), "shadows"))
3620 if (Cmd_Argc() != 3)
3622 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3625 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3627 else if (!strcmp(Cmd_Argv(1), "corona"))
3629 if (Cmd_Argc() != 3)
3631 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3634 corona = atof(Cmd_Argv(2));
3636 else if (!strcmp(Cmd_Argv(1), "coronasize"))
3638 if (Cmd_Argc() != 3)
3640 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3643 coronasizescale = atof(Cmd_Argv(2));
3645 else if (!strcmp(Cmd_Argv(1), "ambient"))
3647 if (Cmd_Argc() != 3)
3649 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3652 ambientscale = atof(Cmd_Argv(2));
3654 else if (!strcmp(Cmd_Argv(1), "diffuse"))
3656 if (Cmd_Argc() != 3)
3658 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3661 diffusescale = atof(Cmd_Argv(2));
3663 else if (!strcmp(Cmd_Argv(1), "specular"))
3665 if (Cmd_Argc() != 3)
3667 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3670 specularscale = atof(Cmd_Argv(2));
3672 else if (!strcmp(Cmd_Argv(1), "normalmode"))
3674 if (Cmd_Argc() != 3)
3676 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3679 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3681 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
3683 if (Cmd_Argc() != 3)
3685 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3688 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3692 Con_Print("usage: r_editlights_edit [property] [value]\n");
3693 Con_Print("Selected light's properties:\n");
3694 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3695 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3696 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3697 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3698 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3699 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3700 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3701 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
3702 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
3703 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
3704 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
3705 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
3706 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
3707 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
3710 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
3711 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3714 void R_Shadow_EditLights_EditAll_f(void)
3718 if (!r_editlights.integer)
3720 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
3724 for (light = r_shadow_worldlightchain;light;light = light->next)
3726 R_Shadow_SelectLight(light);
3727 R_Shadow_EditLights_Edit_f();
3731 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3733 int lightnumber, lightcount;
3737 if (!r_editlights.integer)
3743 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
3744 if (light == r_shadow_selectedlight)
3745 lightnumber = lightcount;
3746 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;
3747 if (r_shadow_selectedlight == NULL)
3749 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3750 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;
3751 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;
3752 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;
3753 sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3754 sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3755 sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3756 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;
3757 sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3758 sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3759 sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3760 sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3761 sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3762 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;
3763 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;
3766 void R_Shadow_EditLights_ToggleShadow_f(void)
3768 if (!r_editlights.integer)
3770 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3773 if (!r_shadow_selectedlight)
3775 Con_Print("No selected light.\n");
3778 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);
3781 void R_Shadow_EditLights_ToggleCorona_f(void)
3783 if (!r_editlights.integer)
3785 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3788 if (!r_shadow_selectedlight)
3790 Con_Print("No selected light.\n");
3793 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);
3796 void R_Shadow_EditLights_Remove_f(void)
3798 if (!r_editlights.integer)
3800 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
3803 if (!r_shadow_selectedlight)
3805 Con_Print("No selected light.\n");
3808 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3809 r_shadow_selectedlight = NULL;
3812 void R_Shadow_EditLights_Help_f(void)
3815 "Documentation on r_editlights system:\n"
3817 "r_editlights : enable/disable editing mode\n"
3818 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
3819 "r_editlights_cursorpushback : push back cursor this far from surface\n"
3820 "r_editlights_cursorpushoff : push cursor off surface this far\n"
3821 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
3822 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
3824 "r_editlights_help : this help\n"
3825 "r_editlights_clear : remove all lights\n"
3826 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
3827 "r_editlights_save : save to .rtlights file\n"
3828 "r_editlights_spawn : create a light with default settings\n"
3829 "r_editlights_edit command : edit selected light - more documentation below\n"
3830 "r_editlights_remove : remove selected light\n"
3831 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
3832 "r_editlights_importlightentitiesfrommap : reload light entities\n"
3833 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
3835 "origin x y z : set light location\n"
3836 "originx x: set x component of light location\n"
3837 "originy y: set y component of light location\n"
3838 "originz z: set z component of light location\n"
3839 "move x y z : adjust light location\n"
3840 "movex x: adjust x component of light location\n"
3841 "movey y: adjust y component of light location\n"
3842 "movez z: adjust z component of light location\n"
3843 "angles x y z : set light angles\n"
3844 "anglesx x: set x component of light angles\n"
3845 "anglesy y: set y component of light angles\n"
3846 "anglesz z: set z component of light angles\n"
3847 "color r g b : set color of light (can be brighter than 1 1 1)\n"
3848 "radius radius : set radius (size) of light\n"
3849 "colorscale grey : multiply color of light (1 does nothing)\n"
3850 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
3851 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
3852 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
3853 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
3854 "cubemap basename : set filter cubemap of light (not yet supported)\n"
3855 "shadows 1/0 : turn on/off shadows\n"
3856 "corona n : set corona intensity\n"
3857 "coronasize n : set corona size (0-1)\n"
3858 "ambient n : set ambient intensity (0-1)\n"
3859 "diffuse n : set diffuse intensity (0-1)\n"
3860 "specular n : set specular intensity (0-1)\n"
3861 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
3862 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
3863 "<nothing> : print light properties to console\n"
3867 void R_Shadow_EditLights_CopyInfo_f(void)
3869 if (!r_editlights.integer)
3871 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
3874 if (!r_shadow_selectedlight)
3876 Con_Print("No selected light.\n");
3879 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
3880 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
3881 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
3882 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
3883 if (r_shadow_selectedlight->cubemapname)
3884 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
3886 r_shadow_bufferlight.cubemapname[0] = 0;
3887 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
3888 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
3889 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
3890 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
3891 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
3892 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
3893 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
3896 void R_Shadow_EditLights_PasteInfo_f(void)
3898 if (!r_editlights.integer)
3900 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
3903 if (!r_shadow_selectedlight)
3905 Con_Print("No selected light.\n");
3908 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);
3911 void R_Shadow_EditLights_Init(void)
3913 Cvar_RegisterVariable(&r_editlights);
3914 Cvar_RegisterVariable(&r_editlights_cursordistance);
3915 Cvar_RegisterVariable(&r_editlights_cursorpushback);
3916 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
3917 Cvar_RegisterVariable(&r_editlights_cursorgrid);
3918 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
3919 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
3920 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
3921 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)");
3922 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
3923 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
3924 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
3925 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)");
3926 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
3927 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
3928 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
3929 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
3930 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
3931 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
3932 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)");