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_STENCILTWOSIDE,
150 R_SHADOW_RENDERMODE_LIGHT_VERTEX,
151 R_SHADOW_RENDERMODE_LIGHT_DOT3,
152 R_SHADOW_RENDERMODE_LIGHT_GLSL,
153 R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
154 R_SHADOW_RENDERMODE_VISIBLELIGHTING,
156 r_shadow_rendermode_t;
158 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
159 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
160 r_shadow_rendermode_t r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_NONE;
162 int maxshadowtriangles;
165 int maxshadowvertices;
166 float *shadowvertex3f;
179 int r_shadow_buffer_numleafpvsbytes;
180 unsigned char *r_shadow_buffer_leafpvs;
181 int *r_shadow_buffer_leaflist;
183 int r_shadow_buffer_numsurfacepvsbytes;
184 unsigned char *r_shadow_buffer_surfacepvs;
185 int *r_shadow_buffer_surfacelist;
187 rtexturepool_t *r_shadow_texturepool;
188 rtexture_t *r_shadow_attenuation2dtexture;
189 rtexture_t *r_shadow_attenuation3dtexture;
191 // lights are reloaded when this changes
192 char r_shadow_mapname[MAX_QPATH];
194 // used only for light filters (cubemaps)
195 rtexturepool_t *r_shadow_filters_texturepool;
197 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"};
198 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"};
199 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
200 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)"};
201 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.25", "how bright the forced flat gloss should look if r_shadow_gloss is 2"};
202 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
203 cvar_t r_shadow_lightattenuationpower = {0, "r_shadow_lightattenuationpower", "0.5", "changes attenuation texture generation (does not affect r_glsl lighting)"};
204 cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1", "changes attenuation texture generation (does not affect r_glsl lighting)"};
205 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
206 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"};
207 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000", "how far to cast shadows"};
208 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
209 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
210 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal culling optimizations on dynamic lights (slow! you probably don't want this!)"};
211 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)"};
212 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"};
213 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"};
214 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
215 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
216 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"};
217 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)"};
218 cvar_t r_shadow_shadow_polygonfactor = {0, "r_shadow_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
219 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)"};
220 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)"};
221 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
222 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
223 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
224 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
225 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
226 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
227 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
229 float r_shadow_attenpower, r_shadow_attenscale;
231 rtlight_t *r_shadow_compilingrtlight;
232 dlight_t *r_shadow_worldlightchain;
233 dlight_t *r_shadow_selectedlight;
234 dlight_t r_shadow_bufferlight;
235 vec3_t r_editlights_cursorlocation;
237 extern int con_vislines;
239 typedef struct cubemapinfo_s
246 #define MAX_CUBEMAPS 256
247 static int numcubemaps;
248 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
250 void R_Shadow_UncompileWorldLights(void);
251 void R_Shadow_ClearWorldLights(void);
252 void R_Shadow_SaveWorldLights(void);
253 void R_Shadow_LoadWorldLights(void);
254 void R_Shadow_LoadLightsFile(void);
255 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
256 void R_Shadow_EditLights_Reload_f(void);
257 void R_Shadow_ValidateCvars(void);
258 static void R_Shadow_MakeTextures(void);
259 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light);
261 void r_shadow_start(void)
263 // allocate vertex processing arrays
265 r_shadow_attenuation2dtexture = NULL;
266 r_shadow_attenuation3dtexture = NULL;
267 r_shadow_texturepool = NULL;
268 r_shadow_filters_texturepool = NULL;
269 R_Shadow_ValidateCvars();
270 R_Shadow_MakeTextures();
271 maxshadowtriangles = 0;
272 shadowelements = NULL;
273 maxshadowvertices = 0;
274 shadowvertex3f = NULL;
282 shadowmarklist = NULL;
284 r_shadow_buffer_numleafpvsbytes = 0;
285 r_shadow_buffer_leafpvs = NULL;
286 r_shadow_buffer_leaflist = NULL;
287 r_shadow_buffer_numsurfacepvsbytes = 0;
288 r_shadow_buffer_surfacepvs = NULL;
289 r_shadow_buffer_surfacelist = NULL;
292 void r_shadow_shutdown(void)
294 R_Shadow_UncompileWorldLights();
296 r_shadow_attenuation2dtexture = NULL;
297 r_shadow_attenuation3dtexture = NULL;
298 R_FreeTexturePool(&r_shadow_texturepool);
299 R_FreeTexturePool(&r_shadow_filters_texturepool);
300 maxshadowtriangles = 0;
302 Mem_Free(shadowelements);
303 shadowelements = NULL;
305 Mem_Free(shadowvertex3f);
306 shadowvertex3f = NULL;
309 Mem_Free(vertexupdate);
312 Mem_Free(vertexremap);
318 Mem_Free(shadowmark);
321 Mem_Free(shadowmarklist);
322 shadowmarklist = NULL;
324 r_shadow_buffer_numleafpvsbytes = 0;
325 if (r_shadow_buffer_leafpvs)
326 Mem_Free(r_shadow_buffer_leafpvs);
327 r_shadow_buffer_leafpvs = NULL;
328 if (r_shadow_buffer_leaflist)
329 Mem_Free(r_shadow_buffer_leaflist);
330 r_shadow_buffer_leaflist = NULL;
331 r_shadow_buffer_numsurfacepvsbytes = 0;
332 if (r_shadow_buffer_surfacepvs)
333 Mem_Free(r_shadow_buffer_surfacepvs);
334 r_shadow_buffer_surfacepvs = NULL;
335 if (r_shadow_buffer_surfacelist)
336 Mem_Free(r_shadow_buffer_surfacelist);
337 r_shadow_buffer_surfacelist = NULL;
340 void r_shadow_newmap(void)
344 void R_Shadow_Help_f(void)
347 "Documentation on r_shadow system:\n"
349 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
350 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
351 "r_shadow_debuglight : render only this light number (-1 = all)\n"
352 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
353 "r_shadow_gloss2intensity : brightness of forced gloss\n"
354 "r_shadow_glossintensity : brightness of textured gloss\n"
355 "r_shadow_lightattenuationpower : used to generate attenuation texture\n"
356 "r_shadow_lightattenuationscale : used to generate attenuation texture\n"
357 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
358 "r_shadow_portallight : use portal visibility for static light precomputation\n"
359 "r_shadow_projectdistance : shadow volume projection distance\n"
360 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
361 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
362 "r_shadow_realtime_dlight_portalculling : work hard to reduce graphics work\n"
363 "r_shadow_realtime_world : use high quality world lighting mode\n"
364 "r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n"
365 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
366 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
367 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
368 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
369 "r_shadow_scissor : use scissor optimization\n"
370 "r_shadow_shadow_polygonfactor : nudge shadow volumes closer/further\n"
371 "r_shadow_shadow_polygonoffset : nudge shadow volumes closer/further\n"
372 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
373 "r_showlighting : useful for performance testing; bright = slow!\n"
374 "r_showshadowvolumes : useful for performance testing; bright = slow!\n"
376 "r_shadow_help : this help\n"
380 void R_Shadow_Init(void)
382 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
383 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
384 Cvar_RegisterVariable(&r_shadow_debuglight);
385 Cvar_RegisterVariable(&r_shadow_gloss);
386 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
387 Cvar_RegisterVariable(&r_shadow_glossintensity);
388 Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
389 Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
390 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
391 Cvar_RegisterVariable(&r_shadow_portallight);
392 Cvar_RegisterVariable(&r_shadow_projectdistance);
393 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
394 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
395 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
396 Cvar_RegisterVariable(&r_shadow_realtime_world);
397 Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows);
398 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
399 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
400 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
401 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
402 Cvar_RegisterVariable(&r_shadow_scissor);
403 Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor);
404 Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset);
405 Cvar_RegisterVariable(&r_shadow_texture3d);
406 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
407 if (gamemode == GAME_TENEBRAE)
409 Cvar_SetValue("r_shadow_gloss", 2);
410 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
412 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f, "prints documentation on console commands and variables used by realtime lighting and shadowing system");
413 R_Shadow_EditLights_Init();
414 r_shadow_worldlightchain = NULL;
415 maxshadowtriangles = 0;
416 shadowelements = NULL;
417 maxshadowvertices = 0;
418 shadowvertex3f = NULL;
426 shadowmarklist = NULL;
428 r_shadow_buffer_numleafpvsbytes = 0;
429 r_shadow_buffer_leafpvs = NULL;
430 r_shadow_buffer_leaflist = NULL;
431 r_shadow_buffer_numsurfacepvsbytes = 0;
432 r_shadow_buffer_surfacepvs = NULL;
433 r_shadow_buffer_surfacelist = NULL;
434 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
437 matrix4x4_t matrix_attenuationxyz =
440 {0.5, 0.0, 0.0, 0.5},
441 {0.0, 0.5, 0.0, 0.5},
442 {0.0, 0.0, 0.5, 0.5},
447 matrix4x4_t matrix_attenuationz =
450 {0.0, 0.0, 0.5, 0.5},
451 {0.0, 0.0, 0.0, 0.5},
452 {0.0, 0.0, 0.0, 0.5},
457 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles)
459 // make sure shadowelements is big enough for this volume
460 if (maxshadowtriangles < numtriangles)
462 maxshadowtriangles = numtriangles;
464 Mem_Free(shadowelements);
465 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[24]));
467 // make sure shadowvertex3f is big enough for this volume
468 if (maxshadowvertices < numvertices)
470 maxshadowvertices = numvertices;
472 Mem_Free(shadowvertex3f);
473 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[6]));
477 static void R_Shadow_EnlargeLeafSurfaceBuffer(int numleafs, int numsurfaces)
479 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
480 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
481 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
483 if (r_shadow_buffer_leafpvs)
484 Mem_Free(r_shadow_buffer_leafpvs);
485 if (r_shadow_buffer_leaflist)
486 Mem_Free(r_shadow_buffer_leaflist);
487 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
488 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
489 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
491 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
493 if (r_shadow_buffer_surfacepvs)
494 Mem_Free(r_shadow_buffer_surfacepvs);
495 if (r_shadow_buffer_surfacelist)
496 Mem_Free(r_shadow_buffer_surfacelist);
497 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
498 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
499 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
503 void R_Shadow_PrepareShadowMark(int numtris)
505 // make sure shadowmark is big enough for this volume
506 if (maxshadowmark < numtris)
508 maxshadowmark = numtris;
510 Mem_Free(shadowmark);
512 Mem_Free(shadowmarklist);
513 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
514 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
518 // if shadowmarkcount wrapped we clear the array and adjust accordingly
519 if (shadowmarkcount == 0)
522 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
527 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, float projectdistance, int numshadowmarktris, const int *shadowmarktris)
530 int outtriangles = 0, outvertices = 0;
534 if (maxvertexupdate < innumvertices)
536 maxvertexupdate = innumvertices;
538 Mem_Free(vertexupdate);
540 Mem_Free(vertexremap);
541 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
542 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
546 if (vertexupdatenum == 0)
549 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
550 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
553 for (i = 0;i < numshadowmarktris;i++)
554 shadowmark[shadowmarktris[i]] = shadowmarkcount;
556 for (i = 0;i < numshadowmarktris;i++)
558 element = inelement3i + shadowmarktris[i] * 3;
559 // make sure the vertices are created
560 for (j = 0;j < 3;j++)
562 if (vertexupdate[element[j]] != vertexupdatenum)
564 float ratio, direction[3];
565 vertexupdate[element[j]] = vertexupdatenum;
566 vertexremap[element[j]] = outvertices;
567 vertex = invertex3f + element[j] * 3;
568 // project one copy of the vertex to the sphere radius of the light
569 // (FIXME: would projecting it to the light box be better?)
570 VectorSubtract(vertex, projectorigin, direction);
571 ratio = projectdistance / VectorLength(direction);
572 VectorCopy(vertex, outvertex3f);
573 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
580 for (i = 0;i < numshadowmarktris;i++)
582 int remappedelement[3];
584 const int *neighbortriangle;
586 markindex = shadowmarktris[i] * 3;
587 element = inelement3i + markindex;
588 neighbortriangle = inneighbor3i + markindex;
589 // output the front and back triangles
590 outelement3i[0] = vertexremap[element[0]];
591 outelement3i[1] = vertexremap[element[1]];
592 outelement3i[2] = vertexremap[element[2]];
593 outelement3i[3] = vertexremap[element[2]] + 1;
594 outelement3i[4] = vertexremap[element[1]] + 1;
595 outelement3i[5] = vertexremap[element[0]] + 1;
599 // output the sides (facing outward from this triangle)
600 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
602 remappedelement[0] = vertexremap[element[0]];
603 remappedelement[1] = vertexremap[element[1]];
604 outelement3i[0] = remappedelement[1];
605 outelement3i[1] = remappedelement[0];
606 outelement3i[2] = remappedelement[0] + 1;
607 outelement3i[3] = remappedelement[1];
608 outelement3i[4] = remappedelement[0] + 1;
609 outelement3i[5] = remappedelement[1] + 1;
614 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
616 remappedelement[1] = vertexremap[element[1]];
617 remappedelement[2] = vertexremap[element[2]];
618 outelement3i[0] = remappedelement[2];
619 outelement3i[1] = remappedelement[1];
620 outelement3i[2] = remappedelement[1] + 1;
621 outelement3i[3] = remappedelement[2];
622 outelement3i[4] = remappedelement[1] + 1;
623 outelement3i[5] = remappedelement[2] + 1;
628 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
630 remappedelement[0] = vertexremap[element[0]];
631 remappedelement[2] = vertexremap[element[2]];
632 outelement3i[0] = remappedelement[0];
633 outelement3i[1] = remappedelement[2];
634 outelement3i[2] = remappedelement[2] + 1;
635 outelement3i[3] = remappedelement[0];
636 outelement3i[4] = remappedelement[2] + 1;
637 outelement3i[5] = remappedelement[0] + 1;
644 *outnumvertices = outvertices;
648 void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, float projectdistance, int nummarktris, const int *marktris)
651 if (projectdistance < 0.1)
653 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
656 if (!numverts || !nummarktris)
658 // make sure shadowelements is big enough for this volume
659 if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
660 R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
661 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdistance, nummarktris, marktris);
662 renderstats.lights_dynamicshadowtriangles += tris;
663 R_Shadow_RenderVolume(outverts, tris, shadowvertex3f, shadowelements);
666 void R_Shadow_MarkVolumeFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const vec3_t projectorigin, const vec3_t lightmins, const vec3_t lightmaxs, const vec3_t surfacemins, const vec3_t surfacemaxs)
671 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
673 tend = firsttriangle + numtris;
674 if (surfacemins[0] >= lightmins[0] && surfacemaxs[0] <= lightmaxs[0]
675 && surfacemins[1] >= lightmins[1] && surfacemaxs[1] <= lightmaxs[1]
676 && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2])
678 // surface box entirely inside light box, no box cull
679 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
680 if (PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
681 shadowmarklist[numshadowmark++] = t;
685 // surface box not entirely inside light box, cull each triangle
686 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
688 v[0] = invertex3f + e[0] * 3;
689 v[1] = invertex3f + e[1] * 3;
690 v[2] = invertex3f + e[2] * 3;
691 if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
692 && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
693 && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
694 && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
695 && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
696 && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
697 && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
698 shadowmarklist[numshadowmark++] = t;
703 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
705 if (r_shadow_compilingrtlight)
707 // if we're compiling an rtlight, capture the mesh
708 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
711 renderstats.lights_shadowtriangles += numtriangles;
712 R_Mesh_VertexPointer(vertex3f);
713 GL_LockArrays(0, numvertices);
714 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
716 // decrement stencil if backface is behind depthbuffer
717 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
718 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
719 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
720 // increment stencil if frontface is behind depthbuffer
721 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
722 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
724 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
728 static void R_Shadow_MakeTextures(void)
731 float v[3], intensity;
733 R_FreeTexturePool(&r_shadow_texturepool);
734 r_shadow_texturepool = R_AllocTexturePool();
735 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
736 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
737 #define ATTEN2DSIZE 64
738 #define ATTEN3DSIZE 32
739 data = (unsigned char *)Mem_Alloc(tempmempool, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4));
740 for (y = 0;y < ATTEN2DSIZE;y++)
742 for (x = 0;x < ATTEN2DSIZE;x++)
744 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
745 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
747 intensity = 1.0f - sqrt(DotProduct(v, v));
749 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
750 d = (int)bound(0, intensity, 255);
751 data[(y*ATTEN2DSIZE+x)*4+0] = d;
752 data[(y*ATTEN2DSIZE+x)*4+1] = d;
753 data[(y*ATTEN2DSIZE+x)*4+2] = d;
754 data[(y*ATTEN2DSIZE+x)*4+3] = d;
757 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
758 if (r_shadow_texture3d.integer)
760 for (z = 0;z < ATTEN3DSIZE;z++)
762 for (y = 0;y < ATTEN3DSIZE;y++)
764 for (x = 0;x < ATTEN3DSIZE;x++)
766 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
767 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
768 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
769 intensity = 1.0f - sqrt(DotProduct(v, v));
771 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
772 d = (int)bound(0, intensity, 255);
773 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
774 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
775 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
776 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
780 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
785 void R_Shadow_ValidateCvars(void)
787 if (r_shadow_texture3d.integer && !gl_texture3d)
788 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
789 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
790 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
793 // light currently being rendered
794 rtlight_t *r_shadow_rtlight;
796 // this is the location of the eye in entity space
797 vec3_t r_shadow_entityeyeorigin;
798 // this is the location of the light in entity space
799 vec3_t r_shadow_entitylightorigin;
800 // this transforms entity coordinates to light filter cubemap coordinates
801 // (also often used for other purposes)
802 matrix4x4_t r_shadow_entitytolight;
803 // based on entitytolight this transforms -1 to +1 to 0 to 1 for purposes
804 // of attenuation texturing in full 3D (Z result often ignored)
805 matrix4x4_t r_shadow_entitytoattenuationxyz;
806 // this transforms only the Z to S, and T is always 0.5
807 matrix4x4_t r_shadow_entitytoattenuationz;
809 void R_Shadow_RenderMode_Begin(void)
811 R_Shadow_ValidateCvars();
813 if (!r_shadow_attenuation2dtexture
814 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
815 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
816 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
817 R_Shadow_MakeTextures();
819 R_Mesh_ColorPointer(NULL);
820 R_Mesh_ResetTextureState();
821 GL_BlendFunc(GL_ONE, GL_ZERO);
824 GL_Color(0, 0, 0, 1);
825 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
826 qglEnable(GL_CULL_FACE);
827 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
829 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
831 if (gl_ext_stenciltwoside.integer)
832 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
834 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
836 if (r_glsl.integer && gl_support_fragment_shader)
837 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
838 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
839 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
841 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
844 void R_Shadow_RenderMode_ActiveLight(rtlight_t *rtlight)
846 r_shadow_rtlight = rtlight;
849 void R_Shadow_RenderMode_Reset(void)
851 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
853 qglUseProgramObjectARB(0);
854 // HACK HACK HACK: work around for bug in NVIDIAI 6xxx drivers that causes GL_OUT_OF_MEMORY and/or software rendering
855 qglBegin(GL_TRIANGLES);
859 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
860 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
861 R_Mesh_ColorPointer(NULL);
862 R_Mesh_ResetTextureState();
865 void R_Shadow_RenderMode_StencilShadowVolumes(void)
867 R_Shadow_RenderMode_Reset();
868 GL_Color(1, 1, 1, 1);
869 GL_ColorMask(0, 0, 0, 0);
870 GL_BlendFunc(GL_ONE, GL_ZERO);
873 qglPolygonOffset(r_shadowpolygonfactor, r_shadowpolygonoffset);
874 qglDepthFunc(GL_LESS);
875 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
876 qglEnable(GL_STENCIL_TEST);
877 qglStencilFunc(GL_ALWAYS, 128, ~0);
878 r_shadow_rendermode = r_shadow_shadowingrendermode;
879 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
881 qglDisable(GL_CULL_FACE);
882 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
883 qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
885 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
886 qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
888 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
892 qglEnable(GL_CULL_FACE);
894 // this is changed by every shadow render so its value here is unimportant
895 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
897 GL_Clear(GL_STENCIL_BUFFER_BIT);
898 renderstats.lights_clears++;
901 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent)
903 R_Shadow_RenderMode_Reset();
904 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
907 qglPolygonOffset(r_polygonfactor, r_polygonoffset);
908 //qglDisable(GL_POLYGON_OFFSET_FILL);
909 GL_Color(1, 1, 1, 1);
910 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
912 qglDepthFunc(GL_LEQUAL);
914 qglDepthFunc(GL_EQUAL);
915 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
916 qglEnable(GL_CULL_FACE);
918 qglEnable(GL_STENCIL_TEST);
920 qglDisable(GL_STENCIL_TEST);
922 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
923 // only draw light where this geometry was already rendered AND the
924 // stencil is 128 (values other than this mean shadow)
925 qglStencilFunc(GL_EQUAL, 128, ~0);
926 r_shadow_rendermode = r_shadow_lightingrendermode;
927 // do global setup needed for the chosen lighting mode
928 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
930 R_Mesh_TexBind(0, R_GetTexture(r_texture_blanknormalmap)); // normal
931 R_Mesh_TexBind(1, R_GetTexture(r_texture_white)); // diffuse
932 R_Mesh_TexBind(2, R_GetTexture(r_texture_white)); // gloss
933 R_Mesh_TexBindCubeMap(3, R_GetTexture(r_shadow_rtlight->currentcubemap)); // light filter
934 R_Mesh_TexBind(4, R_GetTexture(r_texture_fogattenuation)); // fog
935 R_Mesh_TexBind(5, R_GetTexture(r_texture_white)); // pants
936 R_Mesh_TexBind(6, R_GetTexture(r_texture_white)); // shirt
937 R_Mesh_TexBind(7, R_GetTexture(r_texture_white)); // lightmap
938 R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap)); // deluxemap
939 R_Mesh_TexBind(9, R_GetTexture(r_texture_black)); // glow
940 //R_Mesh_TexMatrix(3, r_shadow_entitytolight); // light filter matrix
941 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
942 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
947 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
949 R_Shadow_RenderMode_Reset();
950 GL_BlendFunc(GL_ONE, GL_ONE);
952 GL_DepthTest(!r_showdisabledepthtest.integer);
953 qglPolygonOffset(r_polygonfactor, r_polygonoffset);
954 GL_Color(0.0, 0.0125, 0.1, 1);
955 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
956 qglDepthFunc(GL_GEQUAL);
957 qglCullFace(GL_FRONT); // this culls back
958 qglDisable(GL_CULL_FACE);
959 qglDisable(GL_STENCIL_TEST);
960 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
963 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
965 R_Shadow_RenderMode_Reset();
966 GL_BlendFunc(GL_ONE, GL_ONE);
968 GL_DepthTest(!r_showdisabledepthtest.integer);
969 qglPolygonOffset(r_polygonfactor, r_polygonoffset);
970 GL_Color(0.1, 0.0125, 0, 1);
971 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
973 qglDepthFunc(GL_LEQUAL);
975 qglDepthFunc(GL_EQUAL);
976 qglCullFace(GL_FRONT); // this culls back
977 qglEnable(GL_CULL_FACE);
979 qglEnable(GL_STENCIL_TEST);
981 qglDisable(GL_STENCIL_TEST);
982 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
985 void R_Shadow_RenderMode_End(void)
987 R_Shadow_RenderMode_Reset();
988 R_Shadow_RenderMode_ActiveLight(NULL);
989 GL_BlendFunc(GL_ONE, GL_ZERO);
992 qglPolygonOffset(r_polygonfactor, r_polygonoffset);
993 //qglDisable(GL_POLYGON_OFFSET_FILL);
994 GL_Color(1, 1, 1, 1);
995 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
996 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
997 qglDepthFunc(GL_LEQUAL);
998 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
999 qglEnable(GL_CULL_FACE);
1000 qglDisable(GL_STENCIL_TEST);
1001 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1002 if (gl_support_stenciltwoside)
1003 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1005 qglStencilFunc(GL_ALWAYS, 128, ~0);
1006 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1009 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1011 int i, ix1, iy1, ix2, iy2;
1012 float x1, y1, x2, y2;
1015 mplane_t planes[11];
1016 float vertex3f[256*3];
1018 // if view is inside the light box, just say yes it's visible
1019 if (BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
1021 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1025 // create a temporary brush describing the area the light can affect in worldspace
1026 VectorNegate(frustum[0].normal, planes[ 0].normal);planes[ 0].dist = -frustum[0].dist;
1027 VectorNegate(frustum[1].normal, planes[ 1].normal);planes[ 1].dist = -frustum[1].dist;
1028 VectorNegate(frustum[2].normal, planes[ 2].normal);planes[ 2].dist = -frustum[2].dist;
1029 VectorNegate(frustum[3].normal, planes[ 3].normal);planes[ 3].dist = -frustum[3].dist;
1030 VectorNegate(frustum[4].normal, planes[ 4].normal);planes[ 4].dist = -frustum[4].dist;
1031 VectorSet (planes[ 5].normal, 1, 0, 0); planes[ 5].dist = maxs[0];
1032 VectorSet (planes[ 6].normal, -1, 0, 0); planes[ 6].dist = -mins[0];
1033 VectorSet (planes[ 7].normal, 0, 1, 0); planes[ 7].dist = maxs[1];
1034 VectorSet (planes[ 8].normal, 0, -1, 0); planes[ 8].dist = -mins[1];
1035 VectorSet (planes[ 9].normal, 0, 0, 1); planes[ 9].dist = maxs[2];
1036 VectorSet (planes[10].normal, 0, 0, -1); planes[10].dist = -mins[2];
1038 // turn the brush into a mesh
1039 memset(&mesh, 0, sizeof(rmesh_t));
1040 mesh.maxvertices = 256;
1041 mesh.vertex3f = vertex3f;
1042 mesh.epsilon2 = (1.0f / (32.0f * 32.0f));
1043 R_Mesh_AddBrushMeshFromPlanes(&mesh, 11, planes);
1045 // if that mesh is empty, the light is not visible at all
1046 if (!mesh.numvertices)
1049 if (!r_shadow_scissor.integer)
1052 // if that mesh is not empty, check what area of the screen it covers
1053 x1 = y1 = x2 = y2 = 0;
1055 for (i = 0;i < mesh.numvertices;i++)
1057 VectorCopy(mesh.vertex3f + i * 3, v);
1058 GL_TransformToScreen(v, v2);
1059 //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]);
1062 if (x1 > v2[0]) x1 = v2[0];
1063 if (x2 < v2[0]) x2 = v2[0];
1064 if (y1 > v2[1]) y1 = v2[1];
1065 if (y2 < v2[1]) y2 = v2[1];
1074 // now convert the scissor rectangle to integer screen coordinates
1075 ix1 = (int)(x1 - 1.0f);
1076 iy1 = (int)(y1 - 1.0f);
1077 ix2 = (int)(x2 + 1.0f);
1078 iy2 = (int)(y2 + 1.0f);
1079 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1081 // clamp it to the screen
1082 if (ix1 < r_view_x) ix1 = r_view_x;
1083 if (iy1 < r_view_y) iy1 = r_view_y;
1084 if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
1085 if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
1087 // if it is inside out, it's not visible
1088 if (ix2 <= ix1 || iy2 <= iy1)
1091 // the light area is visible, set up the scissor rectangle
1092 GL_Scissor(ix1, vid.height - iy2, ix2 - ix1, iy2 - iy1);
1093 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1094 //qglEnable(GL_SCISSOR_TEST);
1095 renderstats.lights_scissored++;
1099 static void R_Shadow_RenderSurfacesLighting_Light_Vertex_Shading(const msurface_t *surface, const float *diffusecolor, const float *ambientcolor)
1101 int numverts = surface->num_vertices;
1102 float *vertex3f = rsurface_vertex3f + 3 * surface->num_firstvertex;
1103 float *normal3f = rsurface_normal3f + 3 * surface->num_firstvertex;
1104 float *color4f = rsurface_array_color4f + 4 * surface->num_firstvertex;
1105 float dist, dot, distintensity, shadeintensity, v[3], n[3];
1106 if (r_textureunits.integer >= 3)
1108 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1110 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1111 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1112 if ((dot = DotProduct(n, v)) < 0)
1114 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1115 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]);
1116 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]);
1117 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]);
1120 float f = VERTEXFOGTABLE(VectorDistance(v, r_shadow_entityeyeorigin));
1121 VectorScale(color4f, f, color4f);
1125 VectorClear(color4f);
1129 else if (r_textureunits.integer >= 2)
1131 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1133 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1134 if ((dist = fabs(v[2])) < 1)
1136 distintensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1137 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1138 if ((dot = DotProduct(n, v)) < 0)
1140 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1141 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1142 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1143 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1147 color4f[0] = ambientcolor[0] * distintensity;
1148 color4f[1] = ambientcolor[1] * distintensity;
1149 color4f[2] = ambientcolor[2] * distintensity;
1153 float f = VERTEXFOGTABLE(VectorDistance(v, r_shadow_entityeyeorigin));
1154 VectorScale(color4f, f, color4f);
1158 VectorClear(color4f);
1164 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1166 Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1167 if ((dist = DotProduct(v, v)) < 1)
1170 distintensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1171 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1172 if ((dot = DotProduct(n, v)) < 0)
1174 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1175 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1176 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1177 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1181 color4f[0] = ambientcolor[0] * distintensity;
1182 color4f[1] = ambientcolor[1] * distintensity;
1183 color4f[2] = ambientcolor[2] * distintensity;
1187 float f = VERTEXFOGTABLE(VectorDistance(v, r_shadow_entityeyeorigin));
1188 VectorScale(color4f, f, color4f);
1192 VectorClear(color4f);
1198 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1200 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(float *out3f, int numverts, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const vec3_t relativelightorigin)
1204 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1206 VectorSubtract(relativelightorigin, vertex3f, lightdir);
1207 // the cubemap normalizes this for us
1208 out3f[0] = DotProduct(svector3f, lightdir);
1209 out3f[1] = DotProduct(tvector3f, lightdir);
1210 out3f[2] = DotProduct(normal3f, lightdir);
1214 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(float *out3f, int numverts, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const vec3_t relativelightorigin, const vec3_t relativeeyeorigin)
1217 float lightdir[3], eyedir[3], halfdir[3];
1218 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1220 VectorSubtract(relativelightorigin, vertex3f, lightdir);
1221 VectorNormalize(lightdir);
1222 VectorSubtract(relativeeyeorigin, vertex3f, eyedir);
1223 VectorNormalize(eyedir);
1224 VectorAdd(lightdir, eyedir, halfdir);
1225 // the cubemap normalizes this for us
1226 out3f[0] = DotProduct(svector3f, halfdir);
1227 out3f[1] = DotProduct(tvector3f, halfdir);
1228 out3f[2] = DotProduct(normal3f, halfdir);
1232 static void R_Shadow_RenderSurfacesLighting_VisibleLighting(const entity_render_t *ent, const texture_t *texture, 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)
1234 // used to display how many times a surface is lit for level design purposes
1235 int surfacelistindex;
1236 model_t *model = ent->model;
1237 GL_Color(0.1, 0.025, 0, 1);
1238 R_Mesh_ColorPointer(NULL);
1239 R_Mesh_ResetTextureState();
1240 RSurf_PrepareVerticesForBatch(ent, texture, r_shadow_entityeyeorigin, false, false, numsurfaces, surfacelist);
1241 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1243 const msurface_t *surface = surfacelist[surfacelistindex];
1244 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1245 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, model->surfmesh.data_element3i + 3 * surface->num_firsttriangle);
1246 GL_LockArrays(0, 0);
1250 static void R_Shadow_RenderSurfacesLighting_Light_GLSL(const entity_render_t *ent, const texture_t *texture, 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)
1252 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
1253 int surfacelistindex;
1254 model_t *model = ent->model;
1255 RSurf_PrepareVerticesForBatch(ent, texture, r_shadow_entityeyeorigin, true, true, numsurfaces, surfacelist);
1256 R_SetupSurfaceShader(ent, texture, NULL, r_shadow_entityeyeorigin, lightcolorbase, false);
1257 R_Mesh_TexCoordPointer(0, 2, model->surfmesh.data_texcoordtexture2f);
1258 R_Mesh_TexCoordPointer(1, 3, rsurface_svector3f);
1259 R_Mesh_TexCoordPointer(2, 3, rsurface_tvector3f);
1260 R_Mesh_TexCoordPointer(3, 3, rsurface_normal3f);
1261 if (texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1262 qglDepthFunc(GL_EQUAL);
1263 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1265 const msurface_t *surface = surfacelist[surfacelistindex];
1266 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1267 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, model->surfmesh.data_element3i + surface->num_firsttriangle * 3);
1269 if (texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1270 qglDepthFunc(GL_LEQUAL);
1271 GL_LockArrays(0, 0);
1274 static void R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(const entity_render_t *ent, const texture_t *texture, const msurface_t *surface, const vec3_t lightcolorbase, rtexture_t *basetexture, float colorscale)
1277 model_t *model = ent->model;
1280 const int *elements = model->surfmesh.data_element3i + surface->num_firsttriangle * 3;
1282 // colorscale accounts for how much we multiply the brightness
1285 // mult is how many times the final pass of the lighting will be
1286 // performed to get more brightness than otherwise possible.
1288 // Limit mult to 64 for sanity sake.
1289 if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1291 // 3 3D combine path (Geforce3, Radeon 8500)
1292 memset(&m, 0, sizeof(m));
1293 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1294 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1295 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1296 m.tex[1] = R_GetTexture(basetexture);
1297 m.pointer_texcoord[1] = model->surfmesh.data_texcoordtexture2f;
1298 m.texmatrix[1] = texture->currenttexmatrix;
1299 m.texcubemap[2] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1300 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1301 m.texmatrix[2] = r_shadow_entitytolight;
1302 GL_BlendFunc(GL_ONE, GL_ONE);
1304 else if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1306 // 2 3D combine path (Geforce3, original Radeon)
1307 memset(&m, 0, sizeof(m));
1308 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1309 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1310 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1311 m.tex[1] = R_GetTexture(basetexture);
1312 m.pointer_texcoord[1] = model->surfmesh.data_texcoordtexture2f;
1313 m.texmatrix[1] = texture->currenttexmatrix;
1314 GL_BlendFunc(GL_ONE, GL_ONE);
1316 else if (r_textureunits.integer >= 4 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1318 // 4 2D combine path (Geforce3, Radeon 8500)
1319 memset(&m, 0, sizeof(m));
1320 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1321 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1322 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1323 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1324 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1325 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1326 m.tex[2] = R_GetTexture(basetexture);
1327 m.pointer_texcoord[2] = model->surfmesh.data_texcoordtexture2f;
1328 m.texmatrix[2] = texture->currenttexmatrix;
1329 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1331 m.texcubemap[3] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1332 m.pointer_texcoord3f[3] = rsurface_vertex3f;
1333 m.texmatrix[3] = r_shadow_entitytolight;
1335 GL_BlendFunc(GL_ONE, GL_ONE);
1337 else if (r_textureunits.integer >= 3 && r_shadow_rtlight->currentcubemap == r_texture_whitecube)
1339 // 3 2D combine path (Geforce3, original Radeon)
1340 memset(&m, 0, sizeof(m));
1341 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1342 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1343 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1344 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1345 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1346 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1347 m.tex[2] = R_GetTexture(basetexture);
1348 m.pointer_texcoord[2] = model->surfmesh.data_texcoordtexture2f;
1349 m.texmatrix[2] = texture->currenttexmatrix;
1350 GL_BlendFunc(GL_ONE, GL_ONE);
1354 // 2/2/2 2D combine path (any dot3 card)
1355 memset(&m, 0, sizeof(m));
1356 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1357 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1358 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1359 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1360 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1361 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1362 R_Mesh_TextureState(&m);
1363 GL_ColorMask(0,0,0,1);
1364 GL_BlendFunc(GL_ONE, GL_ZERO);
1365 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1366 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1367 GL_LockArrays(0, 0);
1369 memset(&m, 0, sizeof(m));
1370 m.tex[0] = R_GetTexture(basetexture);
1371 m.pointer_texcoord[0] = model->surfmesh.data_texcoordtexture2f;
1372 m.texmatrix[0] = texture->currenttexmatrix;
1373 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1375 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1376 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1377 m.texmatrix[1] = r_shadow_entitytolight;
1379 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1381 // this final code is shared
1382 R_Mesh_TextureState(&m);
1383 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1384 VectorScale(lightcolorbase, colorscale, color2);
1385 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1386 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1388 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1389 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1391 GL_LockArrays(0, 0);
1394 static void R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(const entity_render_t *ent, const texture_t *texture, const msurface_t *surface, const vec3_t lightcolorbase, rtexture_t *basetexture, rtexture_t *normalmaptexture, float colorscale)
1397 model_t *model = ent->model;
1400 const int *elements = model->surfmesh.data_element3i + surface->num_firsttriangle * 3;
1402 // colorscale accounts for how much we multiply the brightness
1405 // mult is how many times the final pass of the lighting will be
1406 // performed to get more brightness than otherwise possible.
1408 // Limit mult to 64 for sanity sake.
1409 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1411 // 3/2 3D combine path (Geforce3, Radeon 8500)
1412 memset(&m, 0, sizeof(m));
1413 m.tex[0] = R_GetTexture(normalmaptexture);
1414 m.texcombinergb[0] = GL_REPLACE;
1415 m.pointer_texcoord[0] = model->surfmesh.data_texcoordtexture2f;
1416 m.texmatrix[0] = texture->currenttexmatrix;
1417 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1418 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1419 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1420 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(rsurface_array_texcoord3f + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin);
1421 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1422 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1423 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
1424 R_Mesh_TextureState(&m);
1425 GL_ColorMask(0,0,0,1);
1426 GL_BlendFunc(GL_ONE, GL_ZERO);
1427 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1428 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1429 GL_LockArrays(0, 0);
1431 memset(&m, 0, sizeof(m));
1432 m.tex[0] = R_GetTexture(basetexture);
1433 m.pointer_texcoord[0] = model->surfmesh.data_texcoordtexture2f;
1434 m.texmatrix[0] = texture->currenttexmatrix;
1435 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1437 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1438 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1439 m.texmatrix[1] = r_shadow_entitytolight;
1441 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1443 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1445 // 1/2/2 3D combine path (original Radeon)
1446 memset(&m, 0, sizeof(m));
1447 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1448 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1449 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1450 R_Mesh_TextureState(&m);
1451 GL_ColorMask(0,0,0,1);
1452 GL_BlendFunc(GL_ONE, GL_ZERO);
1453 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1454 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1455 GL_LockArrays(0, 0);
1457 memset(&m, 0, sizeof(m));
1458 m.tex[0] = R_GetTexture(normalmaptexture);
1459 m.texcombinergb[0] = GL_REPLACE;
1460 m.pointer_texcoord[0] = model->surfmesh.data_texcoordtexture2f;
1461 m.texmatrix[0] = texture->currenttexmatrix;
1462 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1463 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1464 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1465 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(rsurface_array_texcoord3f + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin);
1466 R_Mesh_TextureState(&m);
1467 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1468 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1469 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1470 GL_LockArrays(0, 0);
1472 memset(&m, 0, sizeof(m));
1473 m.tex[0] = R_GetTexture(basetexture);
1474 m.pointer_texcoord[0] = model->surfmesh.data_texcoordtexture2f;
1475 m.texmatrix[0] = texture->currenttexmatrix;
1476 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1478 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1479 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1480 m.texmatrix[1] = r_shadow_entitytolight;
1482 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1484 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap == r_texture_whitecube)
1486 // 2/2 3D combine path (original Radeon)
1487 memset(&m, 0, sizeof(m));
1488 m.tex[0] = R_GetTexture(normalmaptexture);
1489 m.texcombinergb[0] = GL_REPLACE;
1490 m.pointer_texcoord[0] = model->surfmesh.data_texcoordtexture2f;
1491 m.texmatrix[0] = texture->currenttexmatrix;
1492 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1493 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1494 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1495 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(rsurface_array_texcoord3f + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin);
1496 R_Mesh_TextureState(&m);
1497 GL_ColorMask(0,0,0,1);
1498 GL_BlendFunc(GL_ONE, GL_ZERO);
1499 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1500 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1501 GL_LockArrays(0, 0);
1503 memset(&m, 0, sizeof(m));
1504 m.tex[0] = R_GetTexture(basetexture);
1505 m.pointer_texcoord[0] = model->surfmesh.data_texcoordtexture2f;
1506 m.texmatrix[0] = texture->currenttexmatrix;
1507 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1508 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1509 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
1510 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1512 else if (r_textureunits.integer >= 4)
1514 // 4/2 2D combine path (Geforce3, Radeon 8500)
1515 memset(&m, 0, sizeof(m));
1516 m.tex[0] = R_GetTexture(normalmaptexture);
1517 m.texcombinergb[0] = GL_REPLACE;
1518 m.pointer_texcoord[0] = model->surfmesh.data_texcoordtexture2f;
1519 m.texmatrix[0] = texture->currenttexmatrix;
1520 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1521 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1522 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1523 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(rsurface_array_texcoord3f + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin);
1524 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1525 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1526 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
1527 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1528 m.pointer_texcoord3f[3] = rsurface_vertex3f;
1529 m.texmatrix[3] = r_shadow_entitytoattenuationz;
1530 R_Mesh_TextureState(&m);
1531 GL_ColorMask(0,0,0,1);
1532 GL_BlendFunc(GL_ONE, GL_ZERO);
1533 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1534 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1535 GL_LockArrays(0, 0);
1537 memset(&m, 0, sizeof(m));
1538 m.tex[0] = R_GetTexture(basetexture);
1539 m.pointer_texcoord[0] = model->surfmesh.data_texcoordtexture2f;
1540 m.texmatrix[0] = texture->currenttexmatrix;
1541 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1543 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1544 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1545 m.texmatrix[1] = r_shadow_entitytolight;
1547 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1551 // 2/2/2 2D combine path (any dot3 card)
1552 memset(&m, 0, sizeof(m));
1553 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1554 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1555 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1556 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1557 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1558 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1559 R_Mesh_TextureState(&m);
1560 GL_ColorMask(0,0,0,1);
1561 GL_BlendFunc(GL_ONE, GL_ZERO);
1562 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1563 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1564 GL_LockArrays(0, 0);
1566 memset(&m, 0, sizeof(m));
1567 m.tex[0] = R_GetTexture(normalmaptexture);
1568 m.texcombinergb[0] = GL_REPLACE;
1569 m.pointer_texcoord[0] = model->surfmesh.data_texcoordtexture2f;
1570 m.texmatrix[0] = texture->currenttexmatrix;
1571 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1572 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1573 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1574 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(rsurface_array_texcoord3f + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin);
1575 R_Mesh_TextureState(&m);
1576 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1577 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1578 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1579 GL_LockArrays(0, 0);
1581 memset(&m, 0, sizeof(m));
1582 m.tex[0] = R_GetTexture(basetexture);
1583 m.pointer_texcoord[0] = model->surfmesh.data_texcoordtexture2f;
1584 m.texmatrix[0] = texture->currenttexmatrix;
1585 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1587 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1588 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1589 m.texmatrix[1] = r_shadow_entitytolight;
1591 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1593 // this final code is shared
1594 R_Mesh_TextureState(&m);
1595 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1596 VectorScale(lightcolorbase, colorscale, color2);
1597 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1598 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1600 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1601 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1603 GL_LockArrays(0, 0);
1606 static void R_Shadow_RenderSurfacesLighting_Light_Dot3_SpecularPass(const entity_render_t *ent, const texture_t *texture, const msurface_t *surface, const vec3_t lightcolorbase, rtexture_t *glosstexture, rtexture_t *normalmaptexture, float colorscale)
1609 model_t *model = ent->model;
1612 const int *elements = model->surfmesh.data_element3i + surface->num_firsttriangle * 3;
1613 // FIXME: detect blendsquare!
1614 //if (!gl_support_blendsquare)
1617 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap != r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
1619 // 2/0/0/1/2 3D combine blendsquare path
1620 memset(&m, 0, sizeof(m));
1621 m.tex[0] = R_GetTexture(normalmaptexture);
1622 m.pointer_texcoord[0] = model->surfmesh.data_texcoordtexture2f;
1623 m.texmatrix[0] = texture->currenttexmatrix;
1624 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1625 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1626 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1627 R_Shadow_GenTexCoords_Specular_NormalCubeMap(rsurface_array_texcoord3f + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin, r_shadow_entityeyeorigin);
1628 R_Mesh_TextureState(&m);
1629 GL_ColorMask(0,0,0,1);
1630 // this squares the result
1631 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1632 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1633 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1634 GL_LockArrays(0, 0);
1636 R_Mesh_ResetTextureState();
1637 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1638 // square alpha in framebuffer a few times to make it shiny
1639 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1640 // these comments are a test run through this math for intensity 0.5
1641 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1642 // 0.25 * 0.25 = 0.0625 (this is another pass)
1643 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1644 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1645 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1646 GL_LockArrays(0, 0);
1648 memset(&m, 0, sizeof(m));
1649 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1650 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1651 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1652 R_Mesh_TextureState(&m);
1653 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1654 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1655 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1656 GL_LockArrays(0, 0);
1658 memset(&m, 0, sizeof(m));
1659 m.tex[0] = R_GetTexture(glosstexture);
1660 m.pointer_texcoord[0] = model->surfmesh.data_texcoordtexture2f;
1661 m.texmatrix[0] = texture->currenttexmatrix;
1662 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1664 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1665 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1666 m.texmatrix[1] = r_shadow_entitytolight;
1668 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1670 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
1672 // 2/0/0/2 3D combine blendsquare path
1673 memset(&m, 0, sizeof(m));
1674 m.tex[0] = R_GetTexture(normalmaptexture);
1675 m.pointer_texcoord[0] = model->surfmesh.data_texcoordtexture2f;
1676 m.texmatrix[0] = texture->currenttexmatrix;
1677 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1678 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1679 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1680 R_Shadow_GenTexCoords_Specular_NormalCubeMap(rsurface_array_texcoord3f + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin, r_shadow_entityeyeorigin);
1681 R_Mesh_TextureState(&m);
1682 GL_ColorMask(0,0,0,1);
1683 // this squares the result
1684 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1685 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1686 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1687 GL_LockArrays(0, 0);
1689 R_Mesh_ResetTextureState();
1690 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1691 // square alpha in framebuffer a few times to make it shiny
1692 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1693 // these comments are a test run through this math for intensity 0.5
1694 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1695 // 0.25 * 0.25 = 0.0625 (this is another pass)
1696 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1697 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1698 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1699 GL_LockArrays(0, 0);
1701 memset(&m, 0, sizeof(m));
1702 m.tex[0] = R_GetTexture(glosstexture);
1703 m.pointer_texcoord[0] = model->surfmesh.data_texcoordtexture2f;
1704 m.texmatrix[0] = texture->currenttexmatrix;
1705 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1706 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1707 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
1708 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1712 // 2/0/0/2/2 2D combine blendsquare path
1713 memset(&m, 0, sizeof(m));
1714 m.tex[0] = R_GetTexture(normalmaptexture);
1715 m.pointer_texcoord[0] = model->surfmesh.data_texcoordtexture2f;
1716 m.texmatrix[0] = texture->currenttexmatrix;
1717 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1718 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1719 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1720 R_Shadow_GenTexCoords_Specular_NormalCubeMap(rsurface_array_texcoord3f + 3 * surface->num_firstvertex, surface->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_svector3f + 3 * surface->num_firstvertex, rsurface_tvector3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, r_shadow_entitylightorigin, r_shadow_entityeyeorigin);
1721 R_Mesh_TextureState(&m);
1722 GL_ColorMask(0,0,0,1);
1723 // this squares the result
1724 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1725 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1726 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1727 GL_LockArrays(0, 0);
1729 R_Mesh_ResetTextureState();
1730 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1731 // square alpha in framebuffer a few times to make it shiny
1732 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1733 // these comments are a test run through this math for intensity 0.5
1734 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1735 // 0.25 * 0.25 = 0.0625 (this is another pass)
1736 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1737 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1738 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1739 GL_LockArrays(0, 0);
1741 memset(&m, 0, sizeof(m));
1742 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1743 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1744 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1745 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1746 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1747 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1748 R_Mesh_TextureState(&m);
1749 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1750 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1751 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1752 GL_LockArrays(0, 0);
1754 memset(&m, 0, sizeof(m));
1755 m.tex[0] = R_GetTexture(glosstexture);
1756 m.pointer_texcoord[0] = model->surfmesh.data_texcoordtexture2f;
1757 m.texmatrix[0] = texture->currenttexmatrix;
1758 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1760 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1761 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1762 m.texmatrix[1] = r_shadow_entitytolight;
1764 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1766 R_Mesh_TextureState(&m);
1767 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1768 VectorScale(lightcolorbase, colorscale, color2);
1769 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1770 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1772 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1773 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1775 GL_LockArrays(0, 0);
1778 static void R_Shadow_RenderSurfacesLighting_Light_Dot3(const entity_render_t *ent, const texture_t *texture, 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)
1780 // ARB path (any Geforce, any Radeon)
1781 int surfacelistindex;
1782 qboolean doambient = r_shadow_rtlight->ambientscale > 0;
1783 qboolean dodiffuse = r_shadow_rtlight->diffusescale > 0;
1784 qboolean dospecular = specularscale > 0;
1785 if (!doambient && !dodiffuse && !dospecular)
1787 RSurf_PrepareVerticesForBatch(ent, texture, r_shadow_entityeyeorigin, true, true, numsurfaces, surfacelist);
1788 R_Mesh_ColorPointer(NULL);
1789 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1791 const msurface_t *surface = surfacelist[surfacelistindex];
1793 R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(ent, texture, surface, lightcolorbase, basetexture, r_shadow_rtlight->ambientscale);
1795 R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(ent, texture, surface, lightcolorbase, basetexture, normalmaptexture, r_shadow_rtlight->diffusescale);
1799 R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(ent, texture, surface, lightcolorpants, pantstexture, r_shadow_rtlight->ambientscale);
1801 R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(ent, texture, surface, lightcolorpants, pantstexture, normalmaptexture, r_shadow_rtlight->diffusescale);
1806 R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(ent, texture, surface, lightcolorshirt, shirttexture, r_shadow_rtlight->ambientscale);
1808 R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(ent, texture, surface, lightcolorshirt, shirttexture, normalmaptexture, r_shadow_rtlight->diffusescale);
1811 R_Shadow_RenderSurfacesLighting_Light_Dot3_SpecularPass(ent, texture, surface, lightcolorbase, glosstexture, normalmaptexture, specularscale);
1815 void R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(const model_t *model, const msurface_t *surface, vec3_t diffusecolor2, vec3_t ambientcolor2)
1818 const int *elements = model->surfmesh.data_element3i + surface->num_firsttriangle * 3;
1819 R_Shadow_RenderSurfacesLighting_Light_Vertex_Shading(surface, diffusecolor2, ambientcolor2);
1820 for (renders = 0;renders < 64 && (ambientcolor2[0] > renders || ambientcolor2[1] > renders || ambientcolor2[2] > renders || diffusecolor2[0] > renders || diffusecolor2[1] > renders || diffusecolor2[2] > renders);renders++)
1825 // due to low fillrate on the cards this vertex lighting path is
1826 // designed for, we manually cull all triangles that do not
1827 // contain a lit vertex
1830 int newnumtriangles;
1832 int newelements[3072];
1834 newnumtriangles = 0;
1836 for (i = 0, e = elements;i < surface->num_triangles;i++, e += 3)
1838 if (newnumtriangles >= 1024)
1840 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1841 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, newnumtriangles, newelements);
1842 GL_LockArrays(0, 0);
1843 newnumtriangles = 0;
1846 if (VectorLength2(rsurface_array_color4f + e[0] * 4) + VectorLength2(rsurface_array_color4f + e[1] * 4) + VectorLength2(rsurface_array_color4f + e[2] * 4) >= 0.01)
1856 if (newnumtriangles >= 1)
1858 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1859 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, newnumtriangles, newelements);
1860 GL_LockArrays(0, 0);
1866 for (i = 0, c = rsurface_array_color4f + 4 * surface->num_firstvertex;i < surface->num_vertices;i++, c += 4)
1867 if (VectorLength2(c))
1871 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1872 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1873 GL_LockArrays(0, 0);
1875 // now reduce the intensity for the next overbright pass
1876 for (i = 0, c = rsurface_array_color4f + 4 * surface->num_firstvertex;i < surface->num_vertices;i++, c += 4)
1878 c[0] = max(0, c[0] - 1);
1879 c[1] = max(0, c[1] - 1);
1880 c[2] = max(0, c[2] - 1);
1885 static void R_Shadow_RenderSurfacesLighting_Light_Vertex(const entity_render_t *ent, const texture_t *texture, 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)
1887 int surfacelistindex;
1888 model_t *model = ent->model;
1889 float ambientcolorbase[3], diffusecolorbase[3];
1890 float ambientcolorpants[3], diffusecolorpants[3];
1891 float ambientcolorshirt[3], diffusecolorshirt[3];
1893 VectorScale(lightcolorbase, r_shadow_rtlight->ambientscale * 2, ambientcolorbase);
1894 VectorScale(lightcolorbase, r_shadow_rtlight->diffusescale * 2, diffusecolorbase);
1895 VectorScale(lightcolorpants, r_shadow_rtlight->ambientscale * 2, ambientcolorpants);
1896 VectorScale(lightcolorpants, r_shadow_rtlight->diffusescale * 2, diffusecolorpants);
1897 VectorScale(lightcolorshirt, r_shadow_rtlight->ambientscale * 2, ambientcolorshirt);
1898 VectorScale(lightcolorshirt, r_shadow_rtlight->diffusescale * 2, diffusecolorshirt);
1899 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1900 R_Mesh_ColorPointer(rsurface_array_color4f);
1901 memset(&m, 0, sizeof(m));
1902 m.tex[0] = R_GetTexture(basetexture);
1903 m.texmatrix[0] = texture->currenttexmatrix;
1904 m.pointer_texcoord[0] = model->surfmesh.data_texcoordtexture2f;
1905 if (r_textureunits.integer >= 2)
1908 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1909 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
1910 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1911 if (r_textureunits.integer >= 3)
1913 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
1914 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1915 m.texmatrix[2] = r_shadow_entitytoattenuationz;
1916 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1919 R_Mesh_TextureState(&m);
1920 RSurf_PrepareVerticesForBatch(ent, texture, r_shadow_entityeyeorigin, true, false, numsurfaces, surfacelist);
1921 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1923 const msurface_t *surface = surfacelist[surfacelistindex];
1924 // OpenGL 1.1 path (anything)
1925 R_Mesh_TexBind(0, R_GetTexture(basetexture));
1926 R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(model, surface, diffusecolorbase, ambientcolorbase);
1929 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
1930 R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(model, surface, diffusecolorpants, ambientcolorpants);
1934 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
1935 R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(model, surface, diffusecolorshirt, ambientcolorshirt);
1940 void R_Shadow_RenderSurfacesLighting(const entity_render_t *ent, const texture_t *texture, int numsurfaces, msurface_t **surfacelist)
1942 // FIXME: support MATERIALFLAG_NODEPTHTEST
1943 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
1944 // calculate colors to render this texture with
1945 lightcolorbase[0] = r_shadow_rtlight->currentcolor[0] * ent->colormod[0] * texture->currentalpha;
1946 lightcolorbase[1] = r_shadow_rtlight->currentcolor[1] * ent->colormod[1] * texture->currentalpha;
1947 lightcolorbase[2] = r_shadow_rtlight->currentcolor[2] * ent->colormod[2] * texture->currentalpha;
1948 if ((r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorbase) + (r_shadow_rtlight->specularscale * texture->specularscale) * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
1950 if ((texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) || (ent->flags & RENDER_NOCULLFACE))
1951 qglDisable(GL_CULL_FACE);
1953 qglEnable(GL_CULL_FACE);
1954 if (texture->colormapping)
1956 qboolean dopants = texture->skin.pants != NULL && VectorLength2(ent->colormap_pantscolor) >= (1.0f / 1048576.0f);
1957 qboolean doshirt = texture->skin.shirt != NULL && VectorLength2(ent->colormap_shirtcolor) >= (1.0f / 1048576.0f);
1960 lightcolorpants[0] = lightcolorbase[0] * ent->colormap_pantscolor[0];
1961 lightcolorpants[1] = lightcolorbase[1] * ent->colormap_pantscolor[1];
1962 lightcolorpants[2] = lightcolorbase[2] * ent->colormap_pantscolor[2];
1965 VectorClear(lightcolorpants);
1968 lightcolorshirt[0] = lightcolorbase[0] * ent->colormap_shirtcolor[0];
1969 lightcolorshirt[1] = lightcolorbase[1] * ent->colormap_shirtcolor[1];
1970 lightcolorshirt[2] = lightcolorbase[2] * ent->colormap_shirtcolor[2];
1973 VectorClear(lightcolorshirt);
1974 switch (r_shadow_rendermode)
1976 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
1977 R_Shadow_RenderSurfacesLighting_VisibleLighting(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, texture->basetexture, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, texture->glosstexture, r_shadow_rtlight->specularscale * texture->specularscale, dopants, doshirt);
1979 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
1980 R_Shadow_RenderSurfacesLighting_Light_GLSL(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, texture->basetexture, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, texture->glosstexture, r_shadow_rtlight->specularscale * texture->specularscale, dopants, doshirt);
1982 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
1983 R_Shadow_RenderSurfacesLighting_Light_Dot3(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, texture->basetexture, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, texture->glosstexture, r_shadow_rtlight->specularscale * texture->specularscale, dopants, doshirt);
1985 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
1986 R_Shadow_RenderSurfacesLighting_Light_Vertex(ent, texture, numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, texture->basetexture, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, texture->glosstexture, r_shadow_rtlight->specularscale * texture->specularscale, dopants, doshirt);
1989 Con_Printf("R_Shadow_RenderSurfacesLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
1995 switch (r_shadow_rendermode)
1997 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
1998 R_Shadow_RenderSurfacesLighting_VisibleLighting(ent, texture, numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, texture->basetexture, r_texture_black, r_texture_black, texture->skin.nmap, texture->glosstexture, r_shadow_rtlight->specularscale * texture->specularscale, false, false);
2000 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2001 R_Shadow_RenderSurfacesLighting_Light_GLSL(ent, texture, numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, texture->basetexture, r_texture_black, r_texture_black, texture->skin.nmap, texture->glosstexture, r_shadow_rtlight->specularscale * texture->specularscale, false, false);
2003 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2004 R_Shadow_RenderSurfacesLighting_Light_Dot3(ent, texture, numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, texture->basetexture, r_texture_black, r_texture_black, texture->skin.nmap, texture->glosstexture, r_shadow_rtlight->specularscale * texture->specularscale, false, false);
2006 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2007 R_Shadow_RenderSurfacesLighting_Light_Vertex(ent, texture, numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, texture->basetexture, r_texture_black, r_texture_black, texture->skin.nmap, texture->glosstexture, r_shadow_rtlight->specularscale * texture->specularscale, false, false);
2010 Con_Printf("R_Shadow_RenderSurfacesLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2016 void R_RTLight_Update(dlight_t *light, int isstatic)
2020 rtlight_t *rtlight = &light->rtlight;
2021 R_RTLight_Uncompile(rtlight);
2022 memset(rtlight, 0, sizeof(*rtlight));
2024 VectorCopy(light->origin, rtlight->shadoworigin);
2025 VectorCopy(light->color, rtlight->color);
2026 rtlight->radius = light->radius;
2027 //rtlight->cullradius = rtlight->radius;
2028 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2029 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2030 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2031 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2032 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2033 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2034 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2035 rtlight->cubemapname[0] = 0;
2036 if (light->cubemapname[0])
2037 strcpy(rtlight->cubemapname, light->cubemapname);
2038 else if (light->cubemapnum > 0)
2039 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
2040 rtlight->shadow = light->shadow;
2041 rtlight->corona = light->corona;
2042 rtlight->style = light->style;
2043 rtlight->isstatic = isstatic;
2044 rtlight->coronasizescale = light->coronasizescale;
2045 rtlight->ambientscale = light->ambientscale;
2046 rtlight->diffusescale = light->diffusescale;
2047 rtlight->specularscale = light->specularscale;
2048 rtlight->flags = light->flags;
2049 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
2050 // ConcatScale won't work here because this needs to scale rotate and
2051 // translate, not just rotate
2052 scale = 1.0f / rtlight->radius;
2053 for (k = 0;k < 3;k++)
2054 for (j = 0;j < 4;j++)
2055 rtlight->matrix_worldtolight.m[k][j] *= scale;
2058 // compiles rtlight geometry
2059 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2060 void R_RTLight_Compile(rtlight_t *rtlight)
2062 int shadowmeshes, shadowtris, numleafs, numleafpvsbytes, numsurfaces;
2063 entity_render_t *ent = r_refdef.worldentity;
2064 model_t *model = r_refdef.worldmodel;
2065 unsigned char *data;
2067 // compile the light
2068 rtlight->compiled = true;
2069 rtlight->static_numleafs = 0;
2070 rtlight->static_numleafpvsbytes = 0;
2071 rtlight->static_leaflist = NULL;
2072 rtlight->static_leafpvs = NULL;
2073 rtlight->static_numsurfaces = 0;
2074 rtlight->static_surfacelist = NULL;
2075 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2076 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2077 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2078 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2079 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2080 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2082 if (model && model->GetLightInfo)
2084 // this variable must be set for the CompileShadowVolume code
2085 r_shadow_compilingrtlight = rtlight;
2086 R_Shadow_EnlargeLeafSurfaceBuffer(model->brush.num_leafs, model->num_surfaces);
2087 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);
2088 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2089 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numleafs + numleafpvsbytes + sizeof(int) * numsurfaces);
2090 rtlight->static_numleafs = numleafs;
2091 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2092 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2093 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2094 rtlight->static_numsurfaces = numsurfaces;
2095 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2097 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2098 if (numleafpvsbytes)
2099 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2101 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2102 if (model->CompileShadowVolume && rtlight->shadow)
2103 model->CompileShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2104 // now we're done compiling the rtlight
2105 r_shadow_compilingrtlight = NULL;
2109 // use smallest available cullradius - box radius or light radius
2110 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2111 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2115 if (rtlight->static_meshchain_shadow)
2118 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2121 shadowtris += mesh->numtriangles;
2125 if (developer.integer >= 10)
2126 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);
2129 void R_RTLight_Uncompile(rtlight_t *rtlight)
2131 if (rtlight->compiled)
2133 if (rtlight->static_meshchain_shadow)
2134 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2135 rtlight->static_meshchain_shadow = NULL;
2136 // these allocations are grouped
2137 if (rtlight->static_leaflist)
2138 Mem_Free(rtlight->static_leaflist);
2139 rtlight->static_numleafs = 0;
2140 rtlight->static_numleafpvsbytes = 0;
2141 rtlight->static_leaflist = NULL;
2142 rtlight->static_leafpvs = NULL;
2143 rtlight->static_numsurfaces = 0;
2144 rtlight->static_surfacelist = NULL;
2145 rtlight->compiled = false;
2149 void R_Shadow_UncompileWorldLights(void)
2152 for (light = r_shadow_worldlightchain;light;light = light->next)
2153 R_RTLight_Uncompile(&light->rtlight);
2156 void R_Shadow_DrawEntityShadow(entity_render_t *ent, int numsurfaces, int *surfacelist)
2158 model_t *model = ent->model;
2159 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
2160 vec_t relativeshadowradius;
2161 if (ent == r_refdef.worldentity)
2163 if (r_shadow_rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2166 R_Mesh_Matrix(&ent->matrix);
2167 for (mesh = r_shadow_rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2169 renderstats.lights_shadowtriangles += mesh->numtriangles;
2170 R_Mesh_VertexPointer(mesh->vertex3f);
2171 GL_LockArrays(0, mesh->numverts);
2172 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
2174 // decrement stencil if backface is behind depthbuffer
2175 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2176 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2177 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2178 // increment stencil if frontface is behind depthbuffer
2179 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2180 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2182 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2183 GL_LockArrays(0, 0);
2186 else if (numsurfaces)
2188 R_Mesh_Matrix(&ent->matrix);
2189 model->DrawShadowVolume(ent, r_shadow_rtlight->shadoworigin, r_shadow_rtlight->radius, numsurfaces, surfacelist, r_shadow_rtlight->cullmins, r_shadow_rtlight->cullmaxs);
2194 Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, relativeshadoworigin);
2195 relativeshadowradius = r_shadow_rtlight->radius / ent->scale;
2196 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
2197 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
2198 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
2199 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
2200 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
2201 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
2202 R_Mesh_Matrix(&ent->matrix);
2203 model->DrawShadowVolume(ent, relativeshadoworigin, relativeshadowradius, model->nummodelsurfaces, model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2207 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
2209 // set up properties for rendering light onto this entity
2210 Matrix4x4_Concat(&r_shadow_entitytolight, &r_shadow_rtlight->matrix_worldtolight, &ent->matrix);
2211 Matrix4x4_Concat(&r_shadow_entitytoattenuationxyz, &matrix_attenuationxyz, &r_shadow_entitytolight);
2212 Matrix4x4_Concat(&r_shadow_entitytoattenuationz, &matrix_attenuationz, &r_shadow_entitytolight);
2213 Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, r_shadow_entitylightorigin);
2214 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, r_shadow_entityeyeorigin);
2215 R_Mesh_Matrix(&ent->matrix);
2218 void R_Shadow_DrawEntityLight(entity_render_t *ent, int numsurfaces, int *surfacelist)
2220 model_t *model = ent->model;
2221 if (!model->DrawLight)
2223 R_Shadow_SetupEntityLight(ent);
2224 if (ent == r_refdef.worldentity)
2225 model->DrawLight(ent, numsurfaces, surfacelist);
2227 model->DrawLight(ent, model->nummodelsurfaces, model->surfacelist);
2230 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
2234 int numleafs, numsurfaces;
2235 int *leaflist, *surfacelist;
2236 unsigned char *leafpvs;
2237 int numlightentities;
2238 int numshadowentities;
2239 entity_render_t *lightentities[MAX_EDICTS];
2240 entity_render_t *shadowentities[MAX_EDICTS];
2242 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
2243 // skip lights that are basically invisible (color 0 0 0)
2244 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
2247 // loading is done before visibility checks because loading should happen
2248 // all at once at the start of a level, not when it stalls gameplay.
2249 // (especially important to benchmarks)
2251 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2252 R_RTLight_Compile(rtlight);
2254 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
2256 // look up the light style value at this time
2257 f = (rtlight->style >= 0 ? r_refdef.lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2258 VectorScale(rtlight->color, f, rtlight->currentcolor);
2260 if (rtlight->selected)
2262 f = 2 + sin(realtime * M_PI * 4.0);
2263 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
2267 // if lightstyle is currently off, don't draw the light
2268 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
2271 // if the light box is offscreen, skip it
2272 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2275 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2277 // compiled light, world available and can receive realtime lighting
2278 // retrieve leaf information
2279 numleafs = rtlight->static_numleafs;
2280 leaflist = rtlight->static_leaflist;
2281 leafpvs = rtlight->static_leafpvs;
2282 numsurfaces = rtlight->static_numsurfaces;
2283 surfacelist = rtlight->static_surfacelist;
2285 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2287 // dynamic light, world available and can receive realtime lighting
2288 // calculate lit surfaces and leafs
2289 R_Shadow_EnlargeLeafSurfaceBuffer(r_refdef.worldmodel->brush.num_leafs, r_refdef.worldmodel->num_surfaces);
2290 r_refdef.worldmodel->GetLightInfo(r_refdef.worldentity, 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);
2291 leaflist = r_shadow_buffer_leaflist;
2292 leafpvs = r_shadow_buffer_leafpvs;
2293 surfacelist = r_shadow_buffer_surfacelist;
2294 // if the reduced leaf bounds are offscreen, skip it
2295 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2307 // check if light is illuminating any visible leafs
2310 for (i = 0;i < numleafs;i++)
2311 if (r_worldleafvisible[leaflist[i]])
2316 // set up a scissor rectangle for this light
2317 if (R_Shadow_ScissorForBBox(rtlight->cullmins, rtlight->cullmaxs))
2320 // make a list of lit entities and shadow casting entities
2321 numlightentities = 0;
2322 numshadowentities = 0;
2323 // don't count the world unless some surfaces are actually lit
2326 lightentities[numlightentities++] = r_refdef.worldentity;
2327 shadowentities[numshadowentities++] = r_refdef.worldentity;
2329 // add dynamic entities that are lit by the light
2330 if (r_drawentities.integer)
2332 for (i = 0;i < r_refdef.numentities;i++)
2335 entity_render_t *ent = r_refdef.entities[i];
2336 if (BoxesOverlap(ent->mins, ent->maxs, rtlight->cullmins, rtlight->cullmaxs)
2337 && (model = ent->model)
2338 && !(ent->flags & RENDER_TRANSPARENT)
2339 && (r_refdef.worldmodel == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs)))
2341 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2342 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(ent->origin, rtlight->shadoworigin) > 0.1)
2343 shadowentities[numshadowentities++] = ent;
2344 if (ent->visframe == r_framecount && (ent->flags & RENDER_LIGHT) && model->DrawLight)
2345 lightentities[numlightentities++] = ent;
2350 // return if there's nothing at all to light
2351 if (!numlightentities)
2354 // don't let sound skip if going slow
2355 if (r_refdef.extraupdate)
2358 // make this the active rtlight for rendering purposes
2359 R_Shadow_RenderMode_ActiveLight(rtlight);
2360 // count this light in the r_speeds
2361 renderstats.lights++;
2364 if (numshadowentities && rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows))
2366 // draw stencil shadow volumes to mask off pixels that are in shadow
2367 // so that they won't receive lighting
2371 R_Shadow_RenderMode_StencilShadowVolumes();
2372 for (i = 0;i < numshadowentities;i++)
2373 R_Shadow_DrawEntityShadow(shadowentities[i], numsurfaces, surfacelist);
2376 // optionally draw visible shape of the shadow volumes
2377 // for performance analysis by level designers
2378 if (r_showshadowvolumes.integer)
2380 R_Shadow_RenderMode_VisibleShadowVolumes();
2381 for (i = 0;i < numshadowentities;i++)
2382 R_Shadow_DrawEntityShadow(shadowentities[i], numsurfaces, surfacelist);
2386 if (numlightentities)
2388 // draw lighting in the unmasked areas
2389 R_Shadow_RenderMode_Lighting(usestencil, false);
2390 for (i = 0;i < numlightentities;i++)
2391 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
2393 // optionally draw the illuminated areas
2394 // for performance analysis by level designers
2395 if (r_showlighting.integer)
2397 R_Shadow_RenderMode_VisibleLighting(usestencil && !r_showdisabledepthtest.integer, false);
2398 for (i = 0;i < numlightentities;i++)
2399 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
2404 void R_ShadowVolumeLighting(qboolean visible)
2409 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2410 R_Shadow_EditLights_Reload_f();
2412 R_Shadow_RenderMode_Begin();
2414 flag = r_rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2415 if (r_shadow_debuglight.integer >= 0)
2417 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2418 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
2419 R_DrawRTLight(&light->rtlight, visible);
2422 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2423 if (light->flags & flag)
2424 R_DrawRTLight(&light->rtlight, visible);
2426 for (lnum = 0;lnum < r_refdef.numlights;lnum++)
2427 R_DrawRTLight(&r_refdef.lights[lnum]->rtlight, visible);
2429 R_Shadow_RenderMode_End();
2432 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2433 typedef struct suffixinfo_s
2436 qboolean flipx, flipy, flipdiagonal;
2439 static suffixinfo_t suffix[3][6] =
2442 {"px", false, false, false},
2443 {"nx", false, false, false},
2444 {"py", false, false, false},
2445 {"ny", false, false, false},
2446 {"pz", false, false, false},
2447 {"nz", false, false, false}
2450 {"posx", false, false, false},
2451 {"negx", false, false, false},
2452 {"posy", false, false, false},
2453 {"negy", false, false, false},
2454 {"posz", false, false, false},
2455 {"negz", false, false, false}
2458 {"rt", true, false, true},
2459 {"lf", false, true, true},
2460 {"ft", true, true, false},
2461 {"bk", false, false, false},
2462 {"up", true, false, true},
2463 {"dn", true, false, true}
2467 static int componentorder[4] = {0, 1, 2, 3};
2469 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2471 int i, j, cubemapsize;
2472 unsigned char *cubemappixels, *image_rgba;
2473 rtexture_t *cubemaptexture;
2475 // must start 0 so the first loadimagepixels has no requested width/height
2477 cubemappixels = NULL;
2478 cubemaptexture = NULL;
2479 // keep trying different suffix groups (posx, px, rt) until one loads
2480 for (j = 0;j < 3 && !cubemappixels;j++)
2482 // load the 6 images in the suffix group
2483 for (i = 0;i < 6;i++)
2485 // generate an image name based on the base and and suffix
2486 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2488 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2490 // an image loaded, make sure width and height are equal
2491 if (image_width == image_height)
2493 // if this is the first image to load successfully, allocate the cubemap memory
2494 if (!cubemappixels && image_width >= 1)
2496 cubemapsize = image_width;
2497 // note this clears to black, so unavailable sides are black
2498 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2500 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2502 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);
2505 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2507 Mem_Free(image_rgba);
2511 // if a cubemap loaded, upload it
2514 if (!r_shadow_filters_texturepool)
2515 r_shadow_filters_texturepool = R_AllocTexturePool();
2516 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
2517 Mem_Free(cubemappixels);
2521 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
2522 for (j = 0;j < 3;j++)
2523 for (i = 0;i < 6;i++)
2524 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2525 Con_Print(" and was unable to find any of them.\n");
2527 return cubemaptexture;
2530 rtexture_t *R_Shadow_Cubemap(const char *basename)
2533 for (i = 0;i < numcubemaps;i++)
2534 if (!strcasecmp(cubemaps[i].basename, basename))
2535 return cubemaps[i].texture;
2536 if (i >= MAX_CUBEMAPS)
2537 return r_texture_whitecube;
2539 strcpy(cubemaps[i].basename, basename);
2540 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
2541 if (!cubemaps[i].texture)
2542 cubemaps[i].texture = r_texture_whitecube;
2543 return cubemaps[i].texture;
2546 void R_Shadow_FreeCubemaps(void)
2549 R_FreeTexturePool(&r_shadow_filters_texturepool);
2552 dlight_t *R_Shadow_NewWorldLight(void)
2555 light = (dlight_t *)Mem_Alloc(r_main_mempool, sizeof(dlight_t));
2556 light->next = r_shadow_worldlightchain;
2557 r_shadow_worldlightchain = light;
2561 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)
2563 VectorCopy(origin, light->origin);
2564 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
2565 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
2566 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
2567 light->color[0] = max(color[0], 0);
2568 light->color[1] = max(color[1], 0);
2569 light->color[2] = max(color[2], 0);
2570 light->radius = max(radius, 0);
2571 light->style = style;
2572 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
2574 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
2577 light->shadow = shadowenable;
2578 light->corona = corona;
2581 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
2582 light->coronasizescale = coronasizescale;
2583 light->ambientscale = ambientscale;
2584 light->diffusescale = diffusescale;
2585 light->specularscale = specularscale;
2586 light->flags = flags;
2587 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
2589 R_RTLight_Update(light, true);
2592 void R_Shadow_FreeWorldLight(dlight_t *light)
2594 dlight_t **lightpointer;
2595 R_RTLight_Uncompile(&light->rtlight);
2596 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
2597 if (*lightpointer != light)
2598 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain");
2599 *lightpointer = light->next;
2603 void R_Shadow_ClearWorldLights(void)
2605 while (r_shadow_worldlightchain)
2606 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
2607 r_shadow_selectedlight = NULL;
2608 R_Shadow_FreeCubemaps();
2611 void R_Shadow_SelectLight(dlight_t *light)
2613 if (r_shadow_selectedlight)
2614 r_shadow_selectedlight->selected = false;
2615 r_shadow_selectedlight = light;
2616 if (r_shadow_selectedlight)
2617 r_shadow_selectedlight->selected = true;
2620 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
2622 float scale = r_editlights_cursorgrid.value * 0.5f;
2623 R_DrawSprite(GL_SRC_ALPHA, GL_ONE, r_crosshairs[1]->tex, NULL, false, r_editlights_cursorlocation, r_viewright, r_viewup, scale, -scale, -scale, scale, 1, 1, 1, 0.5f);
2626 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
2629 const dlight_t *light = (dlight_t *)ent;
2631 if (light->selected)
2632 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
2635 R_DrawSprite(GL_SRC_ALPHA, GL_ONE, r_crosshairs[surfacenumber]->tex, NULL, false, light->origin, r_viewright, r_viewup, 8, -8, -8, 8, intensity, intensity, intensity, 0.5);
2638 void R_Shadow_DrawLightSprites(void)
2643 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
2644 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 1+(i % 5), &light->rtlight);
2645 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
2648 void R_Shadow_SelectLightInView(void)
2650 float bestrating, rating, temp[3];
2651 dlight_t *best, *light;
2654 for (light = r_shadow_worldlightchain;light;light = light->next)
2656 VectorSubtract(light->origin, r_vieworigin, temp);
2657 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
2660 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
2661 if (bestrating < rating && CL_TraceBox(light->origin, vec3_origin, vec3_origin, r_vieworigin, true, NULL, SUPERCONTENTS_SOLID, false).fraction == 1.0f)
2663 bestrating = rating;
2668 R_Shadow_SelectLight(best);
2671 void R_Shadow_LoadWorldLights(void)
2673 int n, a, style, shadow, flags;
2674 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
2675 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
2676 if (r_refdef.worldmodel == NULL)
2678 Con_Print("No map loaded.\n");
2681 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
2682 strlcat (name, ".rtlights", sizeof (name));
2683 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
2693 for (;COM_Parse(t, true) && strcmp(
2694 if (COM_Parse(t, true))
2696 if (com_token[0] == '!')
2699 origin[0] = atof(com_token+1);
2702 origin[0] = atof(com_token);
2707 while (*s && *s != '\n' && *s != '\r')
2713 // check for modifier flags
2720 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);
2723 flags = LIGHTFLAG_REALTIMEMODE;
2731 coronasizescale = 0.25f;
2733 VectorClear(angles);
2736 if (a < 9 || !strcmp(cubemapname, "\"\""))
2738 // remove quotes on cubemapname
2739 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
2741 cubemapname[strlen(cubemapname)-1] = 0;
2742 strcpy(cubemapname, cubemapname + 1);
2746 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);
2749 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
2757 Con_Printf("invalid rtlights file \"%s\"\n", name);
2758 Mem_Free(lightsstring);
2762 void R_Shadow_SaveWorldLights(void)
2765 size_t bufchars, bufmaxchars;
2767 char name[MAX_QPATH];
2768 char line[MAX_INPUTLINE];
2769 if (!r_shadow_worldlightchain)
2771 if (r_refdef.worldmodel == NULL)
2773 Con_Print("No map loaded.\n");
2776 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
2777 strlcat (name, ".rtlights", sizeof (name));
2778 bufchars = bufmaxchars = 0;
2780 for (light = r_shadow_worldlightchain;light;light = light->next)
2782 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
2783 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);
2784 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
2785 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]);
2787 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);
2788 if (bufchars + strlen(line) > bufmaxchars)
2790 bufmaxchars = bufchars + strlen(line) + 2048;
2792 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
2796 memcpy(buf, oldbuf, bufchars);
2802 memcpy(buf + bufchars, line, strlen(line));
2803 bufchars += strlen(line);
2807 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
2812 void R_Shadow_LoadLightsFile(void)
2815 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
2816 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
2817 if (r_refdef.worldmodel == NULL)
2819 Con_Print("No map loaded.\n");
2822 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
2823 strlcat (name, ".lights", sizeof (name));
2824 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
2832 while (*s && *s != '\n' && *s != '\r')
2838 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);
2842 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);
2845 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
2846 radius = bound(15, radius, 4096);
2847 VectorScale(color, (2.0f / (8388608.0f)), color);
2848 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
2856 Con_Printf("invalid lights file \"%s\"\n", name);
2857 Mem_Free(lightsstring);
2861 // tyrlite/hmap2 light types in the delay field
2862 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
2864 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
2866 int entnum, style, islight, skin, pflags, effects, type, n;
2869 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
2870 char key[256], value[MAX_INPUTLINE];
2872 if (r_refdef.worldmodel == NULL)
2874 Con_Print("No map loaded.\n");
2877 // try to load a .ent file first
2878 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
2879 strlcat (key, ".ent", sizeof (key));
2880 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
2881 // and if that is not found, fall back to the bsp file entity string
2883 data = r_refdef.worldmodel->brush.entities;
2886 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
2888 type = LIGHTTYPE_MINUSX;
2889 origin[0] = origin[1] = origin[2] = 0;
2890 originhack[0] = originhack[1] = originhack[2] = 0;
2891 angles[0] = angles[1] = angles[2] = 0;
2892 color[0] = color[1] = color[2] = 1;
2893 light[0] = light[1] = light[2] = 1;light[3] = 300;
2894 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
2904 if (!COM_ParseToken(&data, false))
2906 if (com_token[0] == '}')
2907 break; // end of entity
2908 if (com_token[0] == '_')
2909 strcpy(key, com_token + 1);
2911 strcpy(key, com_token);
2912 while (key[strlen(key)-1] == ' ') // remove trailing spaces
2913 key[strlen(key)-1] = 0;
2914 if (!COM_ParseToken(&data, false))
2916 strcpy(value, com_token);
2918 // now that we have the key pair worked out...
2919 if (!strcmp("light", key))
2921 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
2925 light[0] = vec[0] * (1.0f / 256.0f);
2926 light[1] = vec[0] * (1.0f / 256.0f);
2927 light[2] = vec[0] * (1.0f / 256.0f);
2933 light[0] = vec[0] * (1.0f / 255.0f);
2934 light[1] = vec[1] * (1.0f / 255.0f);
2935 light[2] = vec[2] * (1.0f / 255.0f);
2939 else if (!strcmp("delay", key))
2941 else if (!strcmp("origin", key))
2942 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
2943 else if (!strcmp("angle", key))
2944 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
2945 else if (!strcmp("angles", key))
2946 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
2947 else if (!strcmp("color", key))
2948 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
2949 else if (!strcmp("wait", key))
2950 fadescale = atof(value);
2951 else if (!strcmp("classname", key))
2953 if (!strncmp(value, "light", 5))
2956 if (!strcmp(value, "light_fluoro"))
2961 overridecolor[0] = 1;
2962 overridecolor[1] = 1;
2963 overridecolor[2] = 1;
2965 if (!strcmp(value, "light_fluorospark"))
2970 overridecolor[0] = 1;
2971 overridecolor[1] = 1;
2972 overridecolor[2] = 1;
2974 if (!strcmp(value, "light_globe"))
2979 overridecolor[0] = 1;
2980 overridecolor[1] = 0.8;
2981 overridecolor[2] = 0.4;
2983 if (!strcmp(value, "light_flame_large_yellow"))
2988 overridecolor[0] = 1;
2989 overridecolor[1] = 0.5;
2990 overridecolor[2] = 0.1;
2992 if (!strcmp(value, "light_flame_small_yellow"))
2997 overridecolor[0] = 1;
2998 overridecolor[1] = 0.5;
2999 overridecolor[2] = 0.1;
3001 if (!strcmp(value, "light_torch_small_white"))
3006 overridecolor[0] = 1;
3007 overridecolor[1] = 0.5;
3008 overridecolor[2] = 0.1;
3010 if (!strcmp(value, "light_torch_small_walltorch"))
3015 overridecolor[0] = 1;
3016 overridecolor[1] = 0.5;
3017 overridecolor[2] = 0.1;
3021 else if (!strcmp("style", key))
3022 style = atoi(value);
3023 else if (!strcmp("skin", key))
3024 skin = (int)atof(value);
3025 else if (!strcmp("pflags", key))
3026 pflags = (int)atof(value);
3027 else if (!strcmp("effects", key))
3028 effects = (int)atof(value);
3029 else if (r_refdef.worldmodel->type == mod_brushq3)
3031 if (!strcmp("scale", key))
3032 lightscale = atof(value);
3033 if (!strcmp("fade", key))
3034 fadescale = atof(value);
3039 if (lightscale <= 0)
3043 if (color[0] == color[1] && color[0] == color[2])
3045 color[0] *= overridecolor[0];
3046 color[1] *= overridecolor[1];
3047 color[2] *= overridecolor[2];
3049 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3050 color[0] = color[0] * light[0];
3051 color[1] = color[1] * light[1];
3052 color[2] = color[2] * light[2];
3055 case LIGHTTYPE_MINUSX:
3057 case LIGHTTYPE_RECIPX:
3059 VectorScale(color, (1.0f / 16.0f), color);
3061 case LIGHTTYPE_RECIPXX:
3063 VectorScale(color, (1.0f / 16.0f), color);
3066 case LIGHTTYPE_NONE:
3070 case LIGHTTYPE_MINUSXX:
3073 VectorAdd(origin, originhack, origin);
3075 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);
3078 Mem_Free(entfiledata);
3082 void R_Shadow_SetCursorLocationForView(void)
3085 vec3_t dest, endpos;
3087 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
3088 trace = CL_TraceBox(r_vieworigin, vec3_origin, vec3_origin, dest, true, NULL, SUPERCONTENTS_SOLID, false);
3089 if (trace.fraction < 1)
3091 dist = trace.fraction * r_editlights_cursordistance.value;
3092 push = r_editlights_cursorpushback.value;
3096 VectorMA(trace.endpos, push, r_viewforward, endpos);
3097 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
3101 VectorClear( endpos );
3103 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3104 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3105 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3108 void R_Shadow_UpdateWorldLightSelection(void)
3110 if (r_editlights.integer)
3112 R_Shadow_SetCursorLocationForView();
3113 R_Shadow_SelectLightInView();
3114 R_Shadow_DrawLightSprites();
3117 R_Shadow_SelectLight(NULL);
3120 void R_Shadow_EditLights_Clear_f(void)
3122 R_Shadow_ClearWorldLights();
3125 void R_Shadow_EditLights_Reload_f(void)
3127 if (!r_refdef.worldmodel)
3129 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3130 R_Shadow_ClearWorldLights();
3131 R_Shadow_LoadWorldLights();
3132 if (r_shadow_worldlightchain == NULL)
3134 R_Shadow_LoadLightsFile();
3135 if (r_shadow_worldlightchain == NULL)
3136 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3140 void R_Shadow_EditLights_Save_f(void)
3142 if (!r_refdef.worldmodel)
3144 R_Shadow_SaveWorldLights();
3147 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3149 R_Shadow_ClearWorldLights();
3150 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3153 void R_Shadow_EditLights_ImportLightsFile_f(void)
3155 R_Shadow_ClearWorldLights();
3156 R_Shadow_LoadLightsFile();
3159 void R_Shadow_EditLights_Spawn_f(void)
3162 if (!r_editlights.integer)
3164 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3167 if (Cmd_Argc() != 1)
3169 Con_Print("r_editlights_spawn does not take parameters\n");
3172 color[0] = color[1] = color[2] = 1;
3173 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3176 void R_Shadow_EditLights_Edit_f(void)
3178 vec3_t origin, angles, color;
3179 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3180 int style, shadows, flags, normalmode, realtimemode;
3181 char cubemapname[MAX_INPUTLINE];
3182 if (!r_editlights.integer)
3184 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3187 if (!r_shadow_selectedlight)
3189 Con_Print("No selected light.\n");
3192 VectorCopy(r_shadow_selectedlight->origin, origin);
3193 VectorCopy(r_shadow_selectedlight->angles, angles);
3194 VectorCopy(r_shadow_selectedlight->color, color);
3195 radius = r_shadow_selectedlight->radius;
3196 style = r_shadow_selectedlight->style;
3197 if (r_shadow_selectedlight->cubemapname)
3198 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
3201 shadows = r_shadow_selectedlight->shadow;
3202 corona = r_shadow_selectedlight->corona;
3203 coronasizescale = r_shadow_selectedlight->coronasizescale;
3204 ambientscale = r_shadow_selectedlight->ambientscale;
3205 diffusescale = r_shadow_selectedlight->diffusescale;
3206 specularscale = r_shadow_selectedlight->specularscale;
3207 flags = r_shadow_selectedlight->flags;
3208 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3209 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3210 if (!strcmp(Cmd_Argv(1), "origin"))
3212 if (Cmd_Argc() != 5)
3214 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3217 origin[0] = atof(Cmd_Argv(2));
3218 origin[1] = atof(Cmd_Argv(3));
3219 origin[2] = atof(Cmd_Argv(4));
3221 else if (!strcmp(Cmd_Argv(1), "originx"))
3223 if (Cmd_Argc() != 3)
3225 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3228 origin[0] = atof(Cmd_Argv(2));
3230 else if (!strcmp(Cmd_Argv(1), "originy"))
3232 if (Cmd_Argc() != 3)
3234 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3237 origin[1] = atof(Cmd_Argv(2));
3239 else if (!strcmp(Cmd_Argv(1), "originz"))
3241 if (Cmd_Argc() != 3)
3243 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3246 origin[2] = atof(Cmd_Argv(2));
3248 else if (!strcmp(Cmd_Argv(1), "move"))
3250 if (Cmd_Argc() != 5)
3252 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3255 origin[0] += atof(Cmd_Argv(2));
3256 origin[1] += atof(Cmd_Argv(3));
3257 origin[2] += atof(Cmd_Argv(4));
3259 else if (!strcmp(Cmd_Argv(1), "movex"))
3261 if (Cmd_Argc() != 3)
3263 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3266 origin[0] += atof(Cmd_Argv(2));
3268 else if (!strcmp(Cmd_Argv(1), "movey"))
3270 if (Cmd_Argc() != 3)
3272 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3275 origin[1] += atof(Cmd_Argv(2));
3277 else if (!strcmp(Cmd_Argv(1), "movez"))
3279 if (Cmd_Argc() != 3)
3281 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3284 origin[2] += atof(Cmd_Argv(2));
3286 else if (!strcmp(Cmd_Argv(1), "angles"))
3288 if (Cmd_Argc() != 5)
3290 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3293 angles[0] = atof(Cmd_Argv(2));
3294 angles[1] = atof(Cmd_Argv(3));
3295 angles[2] = atof(Cmd_Argv(4));
3297 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3299 if (Cmd_Argc() != 3)
3301 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3304 angles[0] = atof(Cmd_Argv(2));
3306 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3308 if (Cmd_Argc() != 3)
3310 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3313 angles[1] = atof(Cmd_Argv(2));
3315 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3317 if (Cmd_Argc() != 3)
3319 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3322 angles[2] = atof(Cmd_Argv(2));
3324 else if (!strcmp(Cmd_Argv(1), "color"))
3326 if (Cmd_Argc() != 5)
3328 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3331 color[0] = atof(Cmd_Argv(2));
3332 color[1] = atof(Cmd_Argv(3));
3333 color[2] = atof(Cmd_Argv(4));
3335 else if (!strcmp(Cmd_Argv(1), "radius"))
3337 if (Cmd_Argc() != 3)
3339 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3342 radius = atof(Cmd_Argv(2));
3344 else if (!strcmp(Cmd_Argv(1), "colorscale"))
3346 if (Cmd_Argc() == 3)
3348 double scale = atof(Cmd_Argv(2));
3355 if (Cmd_Argc() != 5)
3357 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
3360 color[0] *= atof(Cmd_Argv(2));
3361 color[1] *= atof(Cmd_Argv(3));
3362 color[2] *= atof(Cmd_Argv(4));
3365 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
3367 if (Cmd_Argc() != 3)
3369 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3372 radius *= atof(Cmd_Argv(2));
3374 else if (!strcmp(Cmd_Argv(1), "style"))
3376 if (Cmd_Argc() != 3)
3378 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3381 style = atoi(Cmd_Argv(2));
3383 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3387 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3390 if (Cmd_Argc() == 3)
3391 strcpy(cubemapname, Cmd_Argv(2));
3395 else if (!strcmp(Cmd_Argv(1), "shadows"))
3397 if (Cmd_Argc() != 3)
3399 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3402 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3404 else if (!strcmp(Cmd_Argv(1), "corona"))
3406 if (Cmd_Argc() != 3)
3408 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3411 corona = atof(Cmd_Argv(2));
3413 else if (!strcmp(Cmd_Argv(1), "coronasize"))
3415 if (Cmd_Argc() != 3)
3417 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3420 coronasizescale = atof(Cmd_Argv(2));
3422 else if (!strcmp(Cmd_Argv(1), "ambient"))
3424 if (Cmd_Argc() != 3)
3426 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3429 ambientscale = atof(Cmd_Argv(2));
3431 else if (!strcmp(Cmd_Argv(1), "diffuse"))
3433 if (Cmd_Argc() != 3)
3435 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3438 diffusescale = atof(Cmd_Argv(2));
3440 else if (!strcmp(Cmd_Argv(1), "specular"))
3442 if (Cmd_Argc() != 3)
3444 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3447 specularscale = atof(Cmd_Argv(2));
3449 else if (!strcmp(Cmd_Argv(1), "normalmode"))
3451 if (Cmd_Argc() != 3)
3453 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3456 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3458 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
3460 if (Cmd_Argc() != 3)
3462 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3465 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3469 Con_Print("usage: r_editlights_edit [property] [value]\n");
3470 Con_Print("Selected light's properties:\n");
3471 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3472 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3473 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3474 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3475 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3476 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3477 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3478 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
3479 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
3480 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
3481 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
3482 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
3483 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
3484 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
3487 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
3488 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3491 void R_Shadow_EditLights_EditAll_f(void)
3495 if (!r_editlights.integer)
3497 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
3501 for (light = r_shadow_worldlightchain;light;light = light->next)
3503 R_Shadow_SelectLight(light);
3504 R_Shadow_EditLights_Edit_f();
3508 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3510 int lightnumber, lightcount;
3514 if (!r_editlights.integer)
3520 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
3521 if (light == r_shadow_selectedlight)
3522 lightnumber = lightcount;
3523 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;
3524 if (r_shadow_selectedlight == NULL)
3526 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3527 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;
3528 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;
3529 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;
3530 sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3531 sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3532 sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3533 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;
3534 sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3535 sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3536 sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3537 sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3538 sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3539 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;
3540 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;
3543 void R_Shadow_EditLights_ToggleShadow_f(void)
3545 if (!r_editlights.integer)
3547 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3550 if (!r_shadow_selectedlight)
3552 Con_Print("No selected light.\n");
3555 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);
3558 void R_Shadow_EditLights_ToggleCorona_f(void)
3560 if (!r_editlights.integer)
3562 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3565 if (!r_shadow_selectedlight)
3567 Con_Print("No selected light.\n");
3570 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);
3573 void R_Shadow_EditLights_Remove_f(void)
3575 if (!r_editlights.integer)
3577 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
3580 if (!r_shadow_selectedlight)
3582 Con_Print("No selected light.\n");
3585 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3586 r_shadow_selectedlight = NULL;
3589 void R_Shadow_EditLights_Help_f(void)
3592 "Documentation on r_editlights system:\n"
3594 "r_editlights : enable/disable editing mode\n"
3595 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
3596 "r_editlights_cursorpushback : push back cursor this far from surface\n"
3597 "r_editlights_cursorpushoff : push cursor off surface this far\n"
3598 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
3599 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
3601 "r_editlights_help : this help\n"
3602 "r_editlights_clear : remove all lights\n"
3603 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
3604 "r_editlights_save : save to .rtlights file\n"
3605 "r_editlights_spawn : create a light with default settings\n"
3606 "r_editlights_edit command : edit selected light - more documentation below\n"
3607 "r_editlights_remove : remove selected light\n"
3608 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
3609 "r_editlights_importlightentitiesfrommap : reload light entities\n"
3610 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
3612 "origin x y z : set light location\n"
3613 "originx x: set x component of light location\n"
3614 "originy y: set y component of light location\n"
3615 "originz z: set z component of light location\n"
3616 "move x y z : adjust light location\n"
3617 "movex x: adjust x component of light location\n"
3618 "movey y: adjust y component of light location\n"
3619 "movez z: adjust z component of light location\n"
3620 "angles x y z : set light angles\n"
3621 "anglesx x: set x component of light angles\n"
3622 "anglesy y: set y component of light angles\n"
3623 "anglesz z: set z component of light angles\n"
3624 "color r g b : set color of light (can be brighter than 1 1 1)\n"
3625 "radius radius : set radius (size) of light\n"
3626 "colorscale grey : multiply color of light (1 does nothing)\n"
3627 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
3628 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
3629 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
3630 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
3631 "cubemap basename : set filter cubemap of light (not yet supported)\n"
3632 "shadows 1/0 : turn on/off shadows\n"
3633 "corona n : set corona intensity\n"
3634 "coronasize n : set corona size (0-1)\n"
3635 "ambient n : set ambient intensity (0-1)\n"
3636 "diffuse n : set diffuse intensity (0-1)\n"
3637 "specular n : set specular intensity (0-1)\n"
3638 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
3639 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
3640 "<nothing> : print light properties to console\n"
3644 void R_Shadow_EditLights_CopyInfo_f(void)
3646 if (!r_editlights.integer)
3648 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
3651 if (!r_shadow_selectedlight)
3653 Con_Print("No selected light.\n");
3656 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
3657 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
3658 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
3659 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
3660 if (r_shadow_selectedlight->cubemapname)
3661 strcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname);
3663 r_shadow_bufferlight.cubemapname[0] = 0;
3664 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
3665 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
3666 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
3667 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
3668 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
3669 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
3670 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
3673 void R_Shadow_EditLights_PasteInfo_f(void)
3675 if (!r_editlights.integer)
3677 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
3680 if (!r_shadow_selectedlight)
3682 Con_Print("No selected light.\n");
3685 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);
3688 void R_Shadow_EditLights_Init(void)
3690 Cvar_RegisterVariable(&r_editlights);
3691 Cvar_RegisterVariable(&r_editlights_cursordistance);
3692 Cvar_RegisterVariable(&r_editlights_cursorpushback);
3693 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
3694 Cvar_RegisterVariable(&r_editlights_cursorgrid);
3695 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
3696 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
3697 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
3698 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)");
3699 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
3700 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
3701 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
3702 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)");
3703 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
3704 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
3705 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
3706 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
3707 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
3708 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
3709 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)");