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 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1263 const msurface_t *surface = surfacelist[surfacelistindex];
1264 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1265 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, model->surfmesh.data_element3i + surface->num_firsttriangle * 3);
1267 GL_LockArrays(0, 0);
1270 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)
1273 model_t *model = ent->model;
1276 const int *elements = model->surfmesh.data_element3i + surface->num_firsttriangle * 3;
1278 // colorscale accounts for how much we multiply the brightness
1281 // mult is how many times the final pass of the lighting will be
1282 // performed to get more brightness than otherwise possible.
1284 // Limit mult to 64 for sanity sake.
1285 if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1287 // 3 3D combine path (Geforce3, Radeon 8500)
1288 memset(&m, 0, sizeof(m));
1289 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1290 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1291 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1292 m.tex[1] = R_GetTexture(basetexture);
1293 m.pointer_texcoord[1] = model->surfmesh.data_texcoordtexture2f;
1294 m.texmatrix[1] = texture->currenttexmatrix;
1295 m.texcubemap[2] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1296 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1297 m.texmatrix[2] = r_shadow_entitytolight;
1298 GL_BlendFunc(GL_ONE, GL_ONE);
1300 else if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1302 // 2 3D combine path (Geforce3, original Radeon)
1303 memset(&m, 0, sizeof(m));
1304 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1305 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1306 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1307 m.tex[1] = R_GetTexture(basetexture);
1308 m.pointer_texcoord[1] = model->surfmesh.data_texcoordtexture2f;
1309 m.texmatrix[1] = texture->currenttexmatrix;
1310 GL_BlendFunc(GL_ONE, GL_ONE);
1312 else if (r_textureunits.integer >= 4 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1314 // 4 2D combine path (Geforce3, Radeon 8500)
1315 memset(&m, 0, sizeof(m));
1316 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1317 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1318 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1319 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1320 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1321 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1322 m.tex[2] = R_GetTexture(basetexture);
1323 m.pointer_texcoord[2] = model->surfmesh.data_texcoordtexture2f;
1324 m.texmatrix[2] = texture->currenttexmatrix;
1325 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1327 m.texcubemap[3] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1328 m.pointer_texcoord3f[3] = rsurface_vertex3f;
1329 m.texmatrix[3] = r_shadow_entitytolight;
1331 GL_BlendFunc(GL_ONE, GL_ONE);
1333 else if (r_textureunits.integer >= 3 && r_shadow_rtlight->currentcubemap == r_texture_whitecube)
1335 // 3 2D combine path (Geforce3, original Radeon)
1336 memset(&m, 0, sizeof(m));
1337 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1338 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1339 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1340 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1341 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1342 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1343 m.tex[2] = R_GetTexture(basetexture);
1344 m.pointer_texcoord[2] = model->surfmesh.data_texcoordtexture2f;
1345 m.texmatrix[2] = texture->currenttexmatrix;
1346 GL_BlendFunc(GL_ONE, GL_ONE);
1350 // 2/2/2 2D combine path (any dot3 card)
1351 memset(&m, 0, sizeof(m));
1352 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1353 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1354 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1355 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1356 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1357 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1358 R_Mesh_TextureState(&m);
1359 GL_ColorMask(0,0,0,1);
1360 GL_BlendFunc(GL_ONE, GL_ZERO);
1361 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1362 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1363 GL_LockArrays(0, 0);
1365 memset(&m, 0, sizeof(m));
1366 m.tex[0] = R_GetTexture(basetexture);
1367 m.pointer_texcoord[0] = model->surfmesh.data_texcoordtexture2f;
1368 m.texmatrix[0] = texture->currenttexmatrix;
1369 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1371 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1372 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1373 m.texmatrix[1] = r_shadow_entitytolight;
1375 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1377 // this final code is shared
1378 R_Mesh_TextureState(&m);
1379 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1380 VectorScale(lightcolorbase, colorscale, color2);
1381 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1382 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1384 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1385 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1387 GL_LockArrays(0, 0);
1390 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)
1393 model_t *model = ent->model;
1396 const int *elements = model->surfmesh.data_element3i + surface->num_firsttriangle * 3;
1398 // colorscale accounts for how much we multiply the brightness
1401 // mult is how many times the final pass of the lighting will be
1402 // performed to get more brightness than otherwise possible.
1404 // Limit mult to 64 for sanity sake.
1405 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1407 // 3/2 3D combine path (Geforce3, Radeon 8500)
1408 memset(&m, 0, sizeof(m));
1409 m.tex[0] = R_GetTexture(normalmaptexture);
1410 m.texcombinergb[0] = GL_REPLACE;
1411 m.pointer_texcoord[0] = model->surfmesh.data_texcoordtexture2f;
1412 m.texmatrix[0] = texture->currenttexmatrix;
1413 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1414 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1415 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1416 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);
1417 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1418 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1419 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
1420 R_Mesh_TextureState(&m);
1421 GL_ColorMask(0,0,0,1);
1422 GL_BlendFunc(GL_ONE, GL_ZERO);
1423 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1424 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1425 GL_LockArrays(0, 0);
1427 memset(&m, 0, sizeof(m));
1428 m.tex[0] = R_GetTexture(basetexture);
1429 m.pointer_texcoord[0] = model->surfmesh.data_texcoordtexture2f;
1430 m.texmatrix[0] = texture->currenttexmatrix;
1431 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1433 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1434 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1435 m.texmatrix[1] = r_shadow_entitytolight;
1437 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1439 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1441 // 1/2/2 3D combine path (original Radeon)
1442 memset(&m, 0, sizeof(m));
1443 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1444 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1445 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1446 R_Mesh_TextureState(&m);
1447 GL_ColorMask(0,0,0,1);
1448 GL_BlendFunc(GL_ONE, GL_ZERO);
1449 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1450 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1451 GL_LockArrays(0, 0);
1453 memset(&m, 0, sizeof(m));
1454 m.tex[0] = R_GetTexture(normalmaptexture);
1455 m.texcombinergb[0] = GL_REPLACE;
1456 m.pointer_texcoord[0] = model->surfmesh.data_texcoordtexture2f;
1457 m.texmatrix[0] = texture->currenttexmatrix;
1458 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1459 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1460 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1461 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);
1462 R_Mesh_TextureState(&m);
1463 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1464 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1465 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1466 GL_LockArrays(0, 0);
1468 memset(&m, 0, sizeof(m));
1469 m.tex[0] = R_GetTexture(basetexture);
1470 m.pointer_texcoord[0] = model->surfmesh.data_texcoordtexture2f;
1471 m.texmatrix[0] = texture->currenttexmatrix;
1472 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1474 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1475 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1476 m.texmatrix[1] = r_shadow_entitytolight;
1478 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1480 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap == r_texture_whitecube)
1482 // 2/2 3D combine path (original Radeon)
1483 memset(&m, 0, sizeof(m));
1484 m.tex[0] = R_GetTexture(normalmaptexture);
1485 m.texcombinergb[0] = GL_REPLACE;
1486 m.pointer_texcoord[0] = model->surfmesh.data_texcoordtexture2f;
1487 m.texmatrix[0] = texture->currenttexmatrix;
1488 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1489 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1490 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1491 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);
1492 R_Mesh_TextureState(&m);
1493 GL_ColorMask(0,0,0,1);
1494 GL_BlendFunc(GL_ONE, GL_ZERO);
1495 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1496 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1497 GL_LockArrays(0, 0);
1499 memset(&m, 0, sizeof(m));
1500 m.tex[0] = R_GetTexture(basetexture);
1501 m.pointer_texcoord[0] = model->surfmesh.data_texcoordtexture2f;
1502 m.texmatrix[0] = texture->currenttexmatrix;
1503 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1504 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1505 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
1506 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1508 else if (r_textureunits.integer >= 4)
1510 // 4/2 2D combine path (Geforce3, Radeon 8500)
1511 memset(&m, 0, sizeof(m));
1512 m.tex[0] = R_GetTexture(normalmaptexture);
1513 m.texcombinergb[0] = GL_REPLACE;
1514 m.pointer_texcoord[0] = model->surfmesh.data_texcoordtexture2f;
1515 m.texmatrix[0] = texture->currenttexmatrix;
1516 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1517 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1518 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1519 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);
1520 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1521 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1522 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
1523 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1524 m.pointer_texcoord3f[3] = rsurface_vertex3f;
1525 m.texmatrix[3] = r_shadow_entitytoattenuationz;
1526 R_Mesh_TextureState(&m);
1527 GL_ColorMask(0,0,0,1);
1528 GL_BlendFunc(GL_ONE, GL_ZERO);
1529 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1530 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1531 GL_LockArrays(0, 0);
1533 memset(&m, 0, sizeof(m));
1534 m.tex[0] = R_GetTexture(basetexture);
1535 m.pointer_texcoord[0] = model->surfmesh.data_texcoordtexture2f;
1536 m.texmatrix[0] = texture->currenttexmatrix;
1537 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1539 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1540 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1541 m.texmatrix[1] = r_shadow_entitytolight;
1543 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1547 // 2/2/2 2D combine path (any dot3 card)
1548 memset(&m, 0, sizeof(m));
1549 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1550 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1551 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1552 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1553 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1554 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1555 R_Mesh_TextureState(&m);
1556 GL_ColorMask(0,0,0,1);
1557 GL_BlendFunc(GL_ONE, GL_ZERO);
1558 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1559 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1560 GL_LockArrays(0, 0);
1562 memset(&m, 0, sizeof(m));
1563 m.tex[0] = R_GetTexture(normalmaptexture);
1564 m.texcombinergb[0] = GL_REPLACE;
1565 m.pointer_texcoord[0] = model->surfmesh.data_texcoordtexture2f;
1566 m.texmatrix[0] = texture->currenttexmatrix;
1567 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1568 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1569 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1570 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);
1571 R_Mesh_TextureState(&m);
1572 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1573 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1574 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1575 GL_LockArrays(0, 0);
1577 memset(&m, 0, sizeof(m));
1578 m.tex[0] = R_GetTexture(basetexture);
1579 m.pointer_texcoord[0] = model->surfmesh.data_texcoordtexture2f;
1580 m.texmatrix[0] = texture->currenttexmatrix;
1581 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1583 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1584 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1585 m.texmatrix[1] = r_shadow_entitytolight;
1587 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1589 // this final code is shared
1590 R_Mesh_TextureState(&m);
1591 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1592 VectorScale(lightcolorbase, colorscale, color2);
1593 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1594 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1596 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1597 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1599 GL_LockArrays(0, 0);
1602 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)
1605 model_t *model = ent->model;
1608 const int *elements = model->surfmesh.data_element3i + surface->num_firsttriangle * 3;
1609 // FIXME: detect blendsquare!
1610 //if (!gl_support_blendsquare)
1613 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap != r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
1615 // 2/0/0/1/2 3D combine blendsquare path
1616 memset(&m, 0, sizeof(m));
1617 m.tex[0] = R_GetTexture(normalmaptexture);
1618 m.pointer_texcoord[0] = model->surfmesh.data_texcoordtexture2f;
1619 m.texmatrix[0] = texture->currenttexmatrix;
1620 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1621 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1622 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1623 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);
1624 R_Mesh_TextureState(&m);
1625 GL_ColorMask(0,0,0,1);
1626 // this squares the result
1627 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1628 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1629 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1630 GL_LockArrays(0, 0);
1632 R_Mesh_ResetTextureState();
1633 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1634 // square alpha in framebuffer a few times to make it shiny
1635 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1636 // these comments are a test run through this math for intensity 0.5
1637 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1638 // 0.25 * 0.25 = 0.0625 (this is another pass)
1639 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1640 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1641 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1642 GL_LockArrays(0, 0);
1644 memset(&m, 0, sizeof(m));
1645 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1646 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1647 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1648 R_Mesh_TextureState(&m);
1649 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1650 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1651 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1652 GL_LockArrays(0, 0);
1654 memset(&m, 0, sizeof(m));
1655 m.tex[0] = R_GetTexture(glosstexture);
1656 m.pointer_texcoord[0] = model->surfmesh.data_texcoordtexture2f;
1657 m.texmatrix[0] = texture->currenttexmatrix;
1658 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1660 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1661 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1662 m.texmatrix[1] = r_shadow_entitytolight;
1664 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1666 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
1668 // 2/0/0/2 3D combine blendsquare path
1669 memset(&m, 0, sizeof(m));
1670 m.tex[0] = R_GetTexture(normalmaptexture);
1671 m.pointer_texcoord[0] = model->surfmesh.data_texcoordtexture2f;
1672 m.texmatrix[0] = texture->currenttexmatrix;
1673 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1674 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1675 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1676 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);
1677 R_Mesh_TextureState(&m);
1678 GL_ColorMask(0,0,0,1);
1679 // this squares the result
1680 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1681 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1682 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1683 GL_LockArrays(0, 0);
1685 R_Mesh_ResetTextureState();
1686 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1687 // square alpha in framebuffer a few times to make it shiny
1688 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1689 // these comments are a test run through this math for intensity 0.5
1690 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1691 // 0.25 * 0.25 = 0.0625 (this is another pass)
1692 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1693 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1694 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1695 GL_LockArrays(0, 0);
1697 memset(&m, 0, sizeof(m));
1698 m.tex[0] = R_GetTexture(glosstexture);
1699 m.pointer_texcoord[0] = model->surfmesh.data_texcoordtexture2f;
1700 m.texmatrix[0] = texture->currenttexmatrix;
1701 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1702 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1703 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
1704 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1708 // 2/0/0/2/2 2D combine blendsquare path
1709 memset(&m, 0, sizeof(m));
1710 m.tex[0] = R_GetTexture(normalmaptexture);
1711 m.pointer_texcoord[0] = model->surfmesh.data_texcoordtexture2f;
1712 m.texmatrix[0] = texture->currenttexmatrix;
1713 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1714 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1715 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1716 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);
1717 R_Mesh_TextureState(&m);
1718 GL_ColorMask(0,0,0,1);
1719 // this squares the result
1720 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1721 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1722 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1723 GL_LockArrays(0, 0);
1725 R_Mesh_ResetTextureState();
1726 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1727 // square alpha in framebuffer a few times to make it shiny
1728 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1729 // these comments are a test run through this math for intensity 0.5
1730 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1731 // 0.25 * 0.25 = 0.0625 (this is another pass)
1732 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1733 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1734 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1735 GL_LockArrays(0, 0);
1737 memset(&m, 0, sizeof(m));
1738 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1739 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1740 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1741 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1742 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1743 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1744 R_Mesh_TextureState(&m);
1745 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1746 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1747 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1748 GL_LockArrays(0, 0);
1750 memset(&m, 0, sizeof(m));
1751 m.tex[0] = R_GetTexture(glosstexture);
1752 m.pointer_texcoord[0] = model->surfmesh.data_texcoordtexture2f;
1753 m.texmatrix[0] = texture->currenttexmatrix;
1754 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1756 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1757 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1758 m.texmatrix[1] = r_shadow_entitytolight;
1760 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1762 R_Mesh_TextureState(&m);
1763 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1764 VectorScale(lightcolorbase, colorscale, color2);
1765 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1766 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1768 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1769 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1771 GL_LockArrays(0, 0);
1774 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)
1776 // ARB path (any Geforce, any Radeon)
1777 int surfacelistindex;
1778 qboolean doambient = r_shadow_rtlight->ambientscale > 0;
1779 qboolean dodiffuse = r_shadow_rtlight->diffusescale > 0;
1780 qboolean dospecular = specularscale > 0;
1781 if (!doambient && !dodiffuse && !dospecular)
1783 RSurf_PrepareVerticesForBatch(ent, texture, r_shadow_entityeyeorigin, true, true, numsurfaces, surfacelist);
1784 R_Mesh_ColorPointer(NULL);
1785 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1787 const msurface_t *surface = surfacelist[surfacelistindex];
1789 R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(ent, texture, surface, lightcolorbase, basetexture, r_shadow_rtlight->ambientscale);
1791 R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(ent, texture, surface, lightcolorbase, basetexture, normalmaptexture, r_shadow_rtlight->diffusescale);
1795 R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(ent, texture, surface, lightcolorpants, pantstexture, r_shadow_rtlight->ambientscale);
1797 R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(ent, texture, surface, lightcolorpants, pantstexture, normalmaptexture, r_shadow_rtlight->diffusescale);
1802 R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(ent, texture, surface, lightcolorshirt, shirttexture, r_shadow_rtlight->ambientscale);
1804 R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(ent, texture, surface, lightcolorshirt, shirttexture, normalmaptexture, r_shadow_rtlight->diffusescale);
1807 R_Shadow_RenderSurfacesLighting_Light_Dot3_SpecularPass(ent, texture, surface, lightcolorbase, glosstexture, normalmaptexture, specularscale);
1811 void R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(const model_t *model, const msurface_t *surface, vec3_t diffusecolor2, vec3_t ambientcolor2)
1814 const int *elements = model->surfmesh.data_element3i + surface->num_firsttriangle * 3;
1815 R_Shadow_RenderSurfacesLighting_Light_Vertex_Shading(surface, diffusecolor2, ambientcolor2);
1816 for (renders = 0;renders < 64 && (ambientcolor2[0] > renders || ambientcolor2[1] > renders || ambientcolor2[2] > renders || diffusecolor2[0] > renders || diffusecolor2[1] > renders || diffusecolor2[2] > renders);renders++)
1821 // due to low fillrate on the cards this vertex lighting path is
1822 // designed for, we manually cull all triangles that do not
1823 // contain a lit vertex
1826 int newnumtriangles;
1828 int newelements[3072];
1830 newnumtriangles = 0;
1832 for (i = 0, e = elements;i < surface->num_triangles;i++, e += 3)
1834 if (newnumtriangles >= 1024)
1836 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1837 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, newnumtriangles, newelements);
1838 GL_LockArrays(0, 0);
1839 newnumtriangles = 0;
1842 if (VectorLength2(rsurface_array_color4f + e[0] * 4) + VectorLength2(rsurface_array_color4f + e[1] * 4) + VectorLength2(rsurface_array_color4f + e[2] * 4) >= 0.01)
1852 if (newnumtriangles >= 1)
1854 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1855 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, newnumtriangles, newelements);
1856 GL_LockArrays(0, 0);
1862 for (i = 0, c = rsurface_array_color4f + 4 * surface->num_firstvertex;i < surface->num_vertices;i++, c += 4)
1863 if (VectorLength2(c))
1867 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1868 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1869 GL_LockArrays(0, 0);
1871 // now reduce the intensity for the next overbright pass
1872 for (i = 0, c = rsurface_array_color4f + 4 * surface->num_firstvertex;i < surface->num_vertices;i++, c += 4)
1874 c[0] = max(0, c[0] - 1);
1875 c[1] = max(0, c[1] - 1);
1876 c[2] = max(0, c[2] - 1);
1881 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)
1883 int surfacelistindex;
1884 model_t *model = ent->model;
1885 float ambientcolorbase[3], diffusecolorbase[3];
1886 float ambientcolorpants[3], diffusecolorpants[3];
1887 float ambientcolorshirt[3], diffusecolorshirt[3];
1889 VectorScale(lightcolorbase, r_shadow_rtlight->ambientscale * 2, ambientcolorbase);
1890 VectorScale(lightcolorbase, r_shadow_rtlight->diffusescale * 2, diffusecolorbase);
1891 VectorScale(lightcolorpants, r_shadow_rtlight->ambientscale * 2, ambientcolorpants);
1892 VectorScale(lightcolorpants, r_shadow_rtlight->diffusescale * 2, diffusecolorpants);
1893 VectorScale(lightcolorshirt, r_shadow_rtlight->ambientscale * 2, ambientcolorshirt);
1894 VectorScale(lightcolorshirt, r_shadow_rtlight->diffusescale * 2, diffusecolorshirt);
1895 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1896 R_Mesh_ColorPointer(rsurface_array_color4f);
1897 memset(&m, 0, sizeof(m));
1898 m.tex[0] = R_GetTexture(basetexture);
1899 m.texmatrix[0] = texture->currenttexmatrix;
1900 m.pointer_texcoord[0] = model->surfmesh.data_texcoordtexture2f;
1901 if (r_textureunits.integer >= 2)
1904 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1905 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
1906 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1907 if (r_textureunits.integer >= 3)
1909 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
1910 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1911 m.texmatrix[2] = r_shadow_entitytoattenuationz;
1912 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1915 R_Mesh_TextureState(&m);
1916 RSurf_PrepareVerticesForBatch(ent, texture, r_shadow_entityeyeorigin, true, false, numsurfaces, surfacelist);
1917 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1919 const msurface_t *surface = surfacelist[surfacelistindex];
1920 // OpenGL 1.1 path (anything)
1921 R_Mesh_TexBind(0, R_GetTexture(basetexture));
1922 R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(model, surface, diffusecolorbase, ambientcolorbase);
1925 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
1926 R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(model, surface, diffusecolorpants, ambientcolorpants);
1930 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
1931 R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(model, surface, diffusecolorshirt, ambientcolorshirt);
1936 void R_Shadow_RenderSurfacesLighting(const entity_render_t *ent, const texture_t *texture, int numsurfaces, msurface_t **surfacelist)
1938 // FIXME: support MATERIALFLAG_NODEPTHTEST
1939 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
1940 // calculate colors to render this texture with
1941 lightcolorbase[0] = r_shadow_rtlight->currentcolor[0] * ent->colormod[0] * texture->currentalpha;
1942 lightcolorbase[1] = r_shadow_rtlight->currentcolor[1] * ent->colormod[1] * texture->currentalpha;
1943 lightcolorbase[2] = r_shadow_rtlight->currentcolor[2] * ent->colormod[2] * texture->currentalpha;
1944 if ((r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorbase) + (r_shadow_rtlight->specularscale * texture->specularscale) * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
1946 if ((texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) || (ent->flags & RENDER_NOCULLFACE))
1947 qglDisable(GL_CULL_FACE);
1949 qglEnable(GL_CULL_FACE);
1950 if (texture->colormapping)
1952 qboolean dopants = texture->skin.pants != NULL && VectorLength2(ent->colormap_pantscolor) >= (1.0f / 1048576.0f);
1953 qboolean doshirt = texture->skin.shirt != NULL && VectorLength2(ent->colormap_shirtcolor) >= (1.0f / 1048576.0f);
1956 lightcolorpants[0] = lightcolorbase[0] * ent->colormap_pantscolor[0];
1957 lightcolorpants[1] = lightcolorbase[1] * ent->colormap_pantscolor[1];
1958 lightcolorpants[2] = lightcolorbase[2] * ent->colormap_pantscolor[2];
1961 VectorClear(lightcolorpants);
1964 lightcolorshirt[0] = lightcolorbase[0] * ent->colormap_shirtcolor[0];
1965 lightcolorshirt[1] = lightcolorbase[1] * ent->colormap_shirtcolor[1];
1966 lightcolorshirt[2] = lightcolorbase[2] * ent->colormap_shirtcolor[2];
1969 VectorClear(lightcolorshirt);
1970 switch (r_shadow_rendermode)
1972 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
1973 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);
1975 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
1976 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);
1978 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
1979 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);
1981 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
1982 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);
1985 Con_Printf("R_Shadow_RenderSurfacesLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
1991 switch (r_shadow_rendermode)
1993 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
1994 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);
1996 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
1997 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);
1999 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2000 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);
2002 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2003 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);
2006 Con_Printf("R_Shadow_RenderSurfacesLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2012 void R_RTLight_Update(dlight_t *light, int isstatic)
2016 rtlight_t *rtlight = &light->rtlight;
2017 R_RTLight_Uncompile(rtlight);
2018 memset(rtlight, 0, sizeof(*rtlight));
2020 VectorCopy(light->origin, rtlight->shadoworigin);
2021 VectorCopy(light->color, rtlight->color);
2022 rtlight->radius = light->radius;
2023 //rtlight->cullradius = rtlight->radius;
2024 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2025 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2026 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2027 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2028 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2029 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2030 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2031 rtlight->cubemapname[0] = 0;
2032 if (light->cubemapname[0])
2033 strcpy(rtlight->cubemapname, light->cubemapname);
2034 else if (light->cubemapnum > 0)
2035 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
2036 rtlight->shadow = light->shadow;
2037 rtlight->corona = light->corona;
2038 rtlight->style = light->style;
2039 rtlight->isstatic = isstatic;
2040 rtlight->coronasizescale = light->coronasizescale;
2041 rtlight->ambientscale = light->ambientscale;
2042 rtlight->diffusescale = light->diffusescale;
2043 rtlight->specularscale = light->specularscale;
2044 rtlight->flags = light->flags;
2045 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
2046 // ConcatScale won't work here because this needs to scale rotate and
2047 // translate, not just rotate
2048 scale = 1.0f / rtlight->radius;
2049 for (k = 0;k < 3;k++)
2050 for (j = 0;j < 4;j++)
2051 rtlight->matrix_worldtolight.m[k][j] *= scale;
2054 // compiles rtlight geometry
2055 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2056 void R_RTLight_Compile(rtlight_t *rtlight)
2058 int shadowmeshes, shadowtris, numleafs, numleafpvsbytes, numsurfaces;
2059 entity_render_t *ent = r_refdef.worldentity;
2060 model_t *model = r_refdef.worldmodel;
2061 unsigned char *data;
2063 // compile the light
2064 rtlight->compiled = true;
2065 rtlight->static_numleafs = 0;
2066 rtlight->static_numleafpvsbytes = 0;
2067 rtlight->static_leaflist = NULL;
2068 rtlight->static_leafpvs = NULL;
2069 rtlight->static_numsurfaces = 0;
2070 rtlight->static_surfacelist = NULL;
2071 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2072 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2073 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2074 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2075 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2076 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2078 if (model && model->GetLightInfo)
2080 // this variable must be set for the CompileShadowVolume code
2081 r_shadow_compilingrtlight = rtlight;
2082 R_Shadow_EnlargeLeafSurfaceBuffer(model->brush.num_leafs, model->num_surfaces);
2083 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);
2084 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2085 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numleafs + numleafpvsbytes + sizeof(int) * numsurfaces);
2086 rtlight->static_numleafs = numleafs;
2087 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2088 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2089 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2090 rtlight->static_numsurfaces = numsurfaces;
2091 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2093 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2094 if (numleafpvsbytes)
2095 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2097 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2098 if (model->CompileShadowVolume && rtlight->shadow)
2099 model->CompileShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2100 // now we're done compiling the rtlight
2101 r_shadow_compilingrtlight = NULL;
2105 // use smallest available cullradius - box radius or light radius
2106 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2107 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2111 if (rtlight->static_meshchain_shadow)
2114 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2117 shadowtris += mesh->numtriangles;
2121 if (developer.integer >= 10)
2122 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);
2125 void R_RTLight_Uncompile(rtlight_t *rtlight)
2127 if (rtlight->compiled)
2129 if (rtlight->static_meshchain_shadow)
2130 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2131 rtlight->static_meshchain_shadow = NULL;
2132 // these allocations are grouped
2133 if (rtlight->static_leaflist)
2134 Mem_Free(rtlight->static_leaflist);
2135 rtlight->static_numleafs = 0;
2136 rtlight->static_numleafpvsbytes = 0;
2137 rtlight->static_leaflist = NULL;
2138 rtlight->static_leafpvs = NULL;
2139 rtlight->static_numsurfaces = 0;
2140 rtlight->static_surfacelist = NULL;
2141 rtlight->compiled = false;
2145 void R_Shadow_UncompileWorldLights(void)
2148 for (light = r_shadow_worldlightchain;light;light = light->next)
2149 R_RTLight_Uncompile(&light->rtlight);
2152 void R_Shadow_DrawEntityShadow(entity_render_t *ent, int numsurfaces, int *surfacelist)
2154 model_t *model = ent->model;
2155 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
2156 vec_t relativeshadowradius;
2157 if (ent == r_refdef.worldentity)
2159 if (r_shadow_rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2162 R_Mesh_Matrix(&ent->matrix);
2163 for (mesh = r_shadow_rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2165 renderstats.lights_shadowtriangles += mesh->numtriangles;
2166 R_Mesh_VertexPointer(mesh->vertex3f);
2167 GL_LockArrays(0, mesh->numverts);
2168 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
2170 // decrement stencil if backface is behind depthbuffer
2171 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2172 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2173 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2174 // increment stencil if frontface is behind depthbuffer
2175 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2176 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2178 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2179 GL_LockArrays(0, 0);
2182 else if (numsurfaces)
2184 R_Mesh_Matrix(&ent->matrix);
2185 model->DrawShadowVolume(ent, r_shadow_rtlight->shadoworigin, r_shadow_rtlight->radius, numsurfaces, surfacelist, r_shadow_rtlight->cullmins, r_shadow_rtlight->cullmaxs);
2190 Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, relativeshadoworigin);
2191 relativeshadowradius = r_shadow_rtlight->radius / ent->scale;
2192 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
2193 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
2194 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
2195 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
2196 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
2197 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
2198 R_Mesh_Matrix(&ent->matrix);
2199 model->DrawShadowVolume(ent, relativeshadoworigin, relativeshadowradius, model->nummodelsurfaces, model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2203 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
2205 // set up properties for rendering light onto this entity
2206 Matrix4x4_Concat(&r_shadow_entitytolight, &r_shadow_rtlight->matrix_worldtolight, &ent->matrix);
2207 Matrix4x4_Concat(&r_shadow_entitytoattenuationxyz, &matrix_attenuationxyz, &r_shadow_entitytolight);
2208 Matrix4x4_Concat(&r_shadow_entitytoattenuationz, &matrix_attenuationz, &r_shadow_entitytolight);
2209 Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, r_shadow_entitylightorigin);
2210 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, r_shadow_entityeyeorigin);
2211 R_Mesh_Matrix(&ent->matrix);
2214 void R_Shadow_DrawEntityLight(entity_render_t *ent, int numsurfaces, int *surfacelist)
2216 model_t *model = ent->model;
2217 if (!model->DrawLight)
2219 R_Shadow_SetupEntityLight(ent);
2220 if (ent == r_refdef.worldentity)
2221 model->DrawLight(ent, numsurfaces, surfacelist);
2223 model->DrawLight(ent, model->nummodelsurfaces, model->surfacelist);
2226 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
2230 int numleafs, numsurfaces;
2231 int *leaflist, *surfacelist;
2232 unsigned char *leafpvs;
2233 int numlightentities;
2234 int numshadowentities;
2235 entity_render_t *lightentities[MAX_EDICTS];
2236 entity_render_t *shadowentities[MAX_EDICTS];
2238 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
2239 // skip lights that are basically invisible (color 0 0 0)
2240 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
2243 // loading is done before visibility checks because loading should happen
2244 // all at once at the start of a level, not when it stalls gameplay.
2245 // (especially important to benchmarks)
2247 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2248 R_RTLight_Compile(rtlight);
2250 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
2252 // look up the light style value at this time
2253 f = (rtlight->style >= 0 ? r_refdef.lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2254 VectorScale(rtlight->color, f, rtlight->currentcolor);
2256 if (rtlight->selected)
2258 f = 2 + sin(realtime * M_PI * 4.0);
2259 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
2263 // if lightstyle is currently off, don't draw the light
2264 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
2267 // if the light box is offscreen, skip it
2268 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2271 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2273 // compiled light, world available and can receive realtime lighting
2274 // retrieve leaf information
2275 numleafs = rtlight->static_numleafs;
2276 leaflist = rtlight->static_leaflist;
2277 leafpvs = rtlight->static_leafpvs;
2278 numsurfaces = rtlight->static_numsurfaces;
2279 surfacelist = rtlight->static_surfacelist;
2281 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2283 // dynamic light, world available and can receive realtime lighting
2284 // calculate lit surfaces and leafs
2285 R_Shadow_EnlargeLeafSurfaceBuffer(r_refdef.worldmodel->brush.num_leafs, r_refdef.worldmodel->num_surfaces);
2286 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);
2287 leaflist = r_shadow_buffer_leaflist;
2288 leafpvs = r_shadow_buffer_leafpvs;
2289 surfacelist = r_shadow_buffer_surfacelist;
2290 // if the reduced leaf bounds are offscreen, skip it
2291 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2303 // check if light is illuminating any visible leafs
2306 for (i = 0;i < numleafs;i++)
2307 if (r_worldleafvisible[leaflist[i]])
2312 // set up a scissor rectangle for this light
2313 if (R_Shadow_ScissorForBBox(rtlight->cullmins, rtlight->cullmaxs))
2316 // make a list of lit entities and shadow casting entities
2317 numlightentities = 0;
2318 numshadowentities = 0;
2319 // don't count the world unless some surfaces are actually lit
2322 lightentities[numlightentities++] = r_refdef.worldentity;
2323 shadowentities[numshadowentities++] = r_refdef.worldentity;
2325 // add dynamic entities that are lit by the light
2326 if (r_drawentities.integer)
2328 for (i = 0;i < r_refdef.numentities;i++)
2331 entity_render_t *ent = r_refdef.entities[i];
2332 if (BoxesOverlap(ent->mins, ent->maxs, rtlight->cullmins, rtlight->cullmaxs)
2333 && (model = ent->model)
2334 && !(ent->flags & RENDER_TRANSPARENT)
2335 && (r_refdef.worldmodel == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs)))
2337 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2338 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(ent->origin, rtlight->shadoworigin) > 0.1)
2339 shadowentities[numshadowentities++] = ent;
2340 if (ent->visframe == r_framecount && (ent->flags & RENDER_LIGHT) && model->DrawLight)
2341 lightentities[numlightentities++] = ent;
2346 // return if there's nothing at all to light
2347 if (!numlightentities)
2350 // don't let sound skip if going slow
2351 if (r_refdef.extraupdate)
2354 // make this the active rtlight for rendering purposes
2355 R_Shadow_RenderMode_ActiveLight(rtlight);
2356 // count this light in the r_speeds
2357 renderstats.lights++;
2360 if (numshadowentities && rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows))
2362 // draw stencil shadow volumes to mask off pixels that are in shadow
2363 // so that they won't receive lighting
2367 R_Shadow_RenderMode_StencilShadowVolumes();
2368 for (i = 0;i < numshadowentities;i++)
2369 R_Shadow_DrawEntityShadow(shadowentities[i], numsurfaces, surfacelist);
2372 // optionally draw visible shape of the shadow volumes
2373 // for performance analysis by level designers
2374 if (r_showshadowvolumes.integer)
2376 R_Shadow_RenderMode_VisibleShadowVolumes();
2377 for (i = 0;i < numshadowentities;i++)
2378 R_Shadow_DrawEntityShadow(shadowentities[i], numsurfaces, surfacelist);
2382 if (numlightentities)
2384 // draw lighting in the unmasked areas
2385 R_Shadow_RenderMode_Lighting(usestencil, false);
2386 for (i = 0;i < numlightentities;i++)
2387 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
2389 // optionally draw the illuminated areas
2390 // for performance analysis by level designers
2391 if (r_showlighting.integer)
2393 R_Shadow_RenderMode_VisibleLighting(usestencil && !r_showdisabledepthtest.integer, false);
2394 for (i = 0;i < numlightentities;i++)
2395 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
2400 void R_ShadowVolumeLighting(qboolean visible)
2405 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2406 R_Shadow_EditLights_Reload_f();
2408 R_Shadow_RenderMode_Begin();
2410 flag = r_rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2411 if (r_shadow_debuglight.integer >= 0)
2413 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2414 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
2415 R_DrawRTLight(&light->rtlight, visible);
2418 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2419 if (light->flags & flag)
2420 R_DrawRTLight(&light->rtlight, visible);
2422 for (lnum = 0;lnum < r_refdef.numlights;lnum++)
2423 R_DrawRTLight(&r_refdef.lights[lnum]->rtlight, visible);
2425 R_Shadow_RenderMode_End();
2428 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2429 typedef struct suffixinfo_s
2432 qboolean flipx, flipy, flipdiagonal;
2435 static suffixinfo_t suffix[3][6] =
2438 {"px", false, false, false},
2439 {"nx", false, false, false},
2440 {"py", false, false, false},
2441 {"ny", false, false, false},
2442 {"pz", false, false, false},
2443 {"nz", false, false, false}
2446 {"posx", false, false, false},
2447 {"negx", false, false, false},
2448 {"posy", false, false, false},
2449 {"negy", false, false, false},
2450 {"posz", false, false, false},
2451 {"negz", false, false, false}
2454 {"rt", true, false, true},
2455 {"lf", false, true, true},
2456 {"ft", true, true, false},
2457 {"bk", false, false, false},
2458 {"up", true, false, true},
2459 {"dn", true, false, true}
2463 static int componentorder[4] = {0, 1, 2, 3};
2465 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2467 int i, j, cubemapsize;
2468 unsigned char *cubemappixels, *image_rgba;
2469 rtexture_t *cubemaptexture;
2471 // must start 0 so the first loadimagepixels has no requested width/height
2473 cubemappixels = NULL;
2474 cubemaptexture = NULL;
2475 // keep trying different suffix groups (posx, px, rt) until one loads
2476 for (j = 0;j < 3 && !cubemappixels;j++)
2478 // load the 6 images in the suffix group
2479 for (i = 0;i < 6;i++)
2481 // generate an image name based on the base and and suffix
2482 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2484 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2486 // an image loaded, make sure width and height are equal
2487 if (image_width == image_height)
2489 // if this is the first image to load successfully, allocate the cubemap memory
2490 if (!cubemappixels && image_width >= 1)
2492 cubemapsize = image_width;
2493 // note this clears to black, so unavailable sides are black
2494 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2496 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2498 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);
2501 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2503 Mem_Free(image_rgba);
2507 // if a cubemap loaded, upload it
2510 if (!r_shadow_filters_texturepool)
2511 r_shadow_filters_texturepool = R_AllocTexturePool();
2512 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
2513 Mem_Free(cubemappixels);
2517 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
2518 for (j = 0;j < 3;j++)
2519 for (i = 0;i < 6;i++)
2520 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2521 Con_Print(" and was unable to find any of them.\n");
2523 return cubemaptexture;
2526 rtexture_t *R_Shadow_Cubemap(const char *basename)
2529 for (i = 0;i < numcubemaps;i++)
2530 if (!strcasecmp(cubemaps[i].basename, basename))
2531 return cubemaps[i].texture;
2532 if (i >= MAX_CUBEMAPS)
2533 return r_texture_whitecube;
2535 strcpy(cubemaps[i].basename, basename);
2536 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
2537 if (!cubemaps[i].texture)
2538 cubemaps[i].texture = r_texture_whitecube;
2539 return cubemaps[i].texture;
2542 void R_Shadow_FreeCubemaps(void)
2545 R_FreeTexturePool(&r_shadow_filters_texturepool);
2548 dlight_t *R_Shadow_NewWorldLight(void)
2551 light = (dlight_t *)Mem_Alloc(r_main_mempool, sizeof(dlight_t));
2552 light->next = r_shadow_worldlightchain;
2553 r_shadow_worldlightchain = light;
2557 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)
2559 VectorCopy(origin, light->origin);
2560 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
2561 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
2562 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
2563 light->color[0] = max(color[0], 0);
2564 light->color[1] = max(color[1], 0);
2565 light->color[2] = max(color[2], 0);
2566 light->radius = max(radius, 0);
2567 light->style = style;
2568 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
2570 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
2573 light->shadow = shadowenable;
2574 light->corona = corona;
2577 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
2578 light->coronasizescale = coronasizescale;
2579 light->ambientscale = ambientscale;
2580 light->diffusescale = diffusescale;
2581 light->specularscale = specularscale;
2582 light->flags = flags;
2583 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
2585 R_RTLight_Update(light, true);
2588 void R_Shadow_FreeWorldLight(dlight_t *light)
2590 dlight_t **lightpointer;
2591 R_RTLight_Uncompile(&light->rtlight);
2592 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
2593 if (*lightpointer != light)
2594 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain");
2595 *lightpointer = light->next;
2599 void R_Shadow_ClearWorldLights(void)
2601 while (r_shadow_worldlightchain)
2602 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
2603 r_shadow_selectedlight = NULL;
2604 R_Shadow_FreeCubemaps();
2607 void R_Shadow_SelectLight(dlight_t *light)
2609 if (r_shadow_selectedlight)
2610 r_shadow_selectedlight->selected = false;
2611 r_shadow_selectedlight = light;
2612 if (r_shadow_selectedlight)
2613 r_shadow_selectedlight->selected = true;
2616 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
2618 float scale = r_editlights_cursorgrid.value * 0.5f;
2619 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);
2622 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
2625 const dlight_t *light = (dlight_t *)ent;
2627 if (light->selected)
2628 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
2631 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);
2634 void R_Shadow_DrawLightSprites(void)
2639 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
2640 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 1+(i % 5), &light->rtlight);
2641 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
2644 void R_Shadow_SelectLightInView(void)
2646 float bestrating, rating, temp[3];
2647 dlight_t *best, *light;
2650 for (light = r_shadow_worldlightchain;light;light = light->next)
2652 VectorSubtract(light->origin, r_vieworigin, temp);
2653 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
2656 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
2657 if (bestrating < rating && CL_TraceBox(light->origin, vec3_origin, vec3_origin, r_vieworigin, true, NULL, SUPERCONTENTS_SOLID, false).fraction == 1.0f)
2659 bestrating = rating;
2664 R_Shadow_SelectLight(best);
2667 void R_Shadow_LoadWorldLights(void)
2669 int n, a, style, shadow, flags;
2670 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
2671 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
2672 if (r_refdef.worldmodel == NULL)
2674 Con_Print("No map loaded.\n");
2677 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
2678 strlcat (name, ".rtlights", sizeof (name));
2679 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
2689 for (;COM_Parse(t, true) && strcmp(
2690 if (COM_Parse(t, true))
2692 if (com_token[0] == '!')
2695 origin[0] = atof(com_token+1);
2698 origin[0] = atof(com_token);
2703 while (*s && *s != '\n' && *s != '\r')
2709 // check for modifier flags
2716 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);
2719 flags = LIGHTFLAG_REALTIMEMODE;
2727 coronasizescale = 0.25f;
2729 VectorClear(angles);
2732 if (a < 9 || !strcmp(cubemapname, "\"\""))
2734 // remove quotes on cubemapname
2735 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
2737 cubemapname[strlen(cubemapname)-1] = 0;
2738 strcpy(cubemapname, cubemapname + 1);
2742 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);
2745 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
2753 Con_Printf("invalid rtlights file \"%s\"\n", name);
2754 Mem_Free(lightsstring);
2758 void R_Shadow_SaveWorldLights(void)
2761 size_t bufchars, bufmaxchars;
2763 char name[MAX_QPATH];
2764 char line[MAX_INPUTLINE];
2765 if (!r_shadow_worldlightchain)
2767 if (r_refdef.worldmodel == NULL)
2769 Con_Print("No map loaded.\n");
2772 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
2773 strlcat (name, ".rtlights", sizeof (name));
2774 bufchars = bufmaxchars = 0;
2776 for (light = r_shadow_worldlightchain;light;light = light->next)
2778 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
2779 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);
2780 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
2781 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]);
2783 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);
2784 if (bufchars + strlen(line) > bufmaxchars)
2786 bufmaxchars = bufchars + strlen(line) + 2048;
2788 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
2792 memcpy(buf, oldbuf, bufchars);
2798 memcpy(buf + bufchars, line, strlen(line));
2799 bufchars += strlen(line);
2803 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
2808 void R_Shadow_LoadLightsFile(void)
2811 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
2812 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
2813 if (r_refdef.worldmodel == NULL)
2815 Con_Print("No map loaded.\n");
2818 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
2819 strlcat (name, ".lights", sizeof (name));
2820 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
2828 while (*s && *s != '\n' && *s != '\r')
2834 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);
2838 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);
2841 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
2842 radius = bound(15, radius, 4096);
2843 VectorScale(color, (2.0f / (8388608.0f)), color);
2844 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
2852 Con_Printf("invalid lights file \"%s\"\n", name);
2853 Mem_Free(lightsstring);
2857 // tyrlite/hmap2 light types in the delay field
2858 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
2860 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
2862 int entnum, style, islight, skin, pflags, effects, type, n;
2865 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
2866 char key[256], value[MAX_INPUTLINE];
2868 if (r_refdef.worldmodel == NULL)
2870 Con_Print("No map loaded.\n");
2873 // try to load a .ent file first
2874 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
2875 strlcat (key, ".ent", sizeof (key));
2876 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
2877 // and if that is not found, fall back to the bsp file entity string
2879 data = r_refdef.worldmodel->brush.entities;
2882 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
2884 type = LIGHTTYPE_MINUSX;
2885 origin[0] = origin[1] = origin[2] = 0;
2886 originhack[0] = originhack[1] = originhack[2] = 0;
2887 angles[0] = angles[1] = angles[2] = 0;
2888 color[0] = color[1] = color[2] = 1;
2889 light[0] = light[1] = light[2] = 1;light[3] = 300;
2890 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
2900 if (!COM_ParseToken(&data, false))
2902 if (com_token[0] == '}')
2903 break; // end of entity
2904 if (com_token[0] == '_')
2905 strcpy(key, com_token + 1);
2907 strcpy(key, com_token);
2908 while (key[strlen(key)-1] == ' ') // remove trailing spaces
2909 key[strlen(key)-1] = 0;
2910 if (!COM_ParseToken(&data, false))
2912 strcpy(value, com_token);
2914 // now that we have the key pair worked out...
2915 if (!strcmp("light", key))
2917 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
2921 light[0] = vec[0] * (1.0f / 256.0f);
2922 light[1] = vec[0] * (1.0f / 256.0f);
2923 light[2] = vec[0] * (1.0f / 256.0f);
2929 light[0] = vec[0] * (1.0f / 255.0f);
2930 light[1] = vec[1] * (1.0f / 255.0f);
2931 light[2] = vec[2] * (1.0f / 255.0f);
2935 else if (!strcmp("delay", key))
2937 else if (!strcmp("origin", key))
2938 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
2939 else if (!strcmp("angle", key))
2940 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
2941 else if (!strcmp("angles", key))
2942 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
2943 else if (!strcmp("color", key))
2944 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
2945 else if (!strcmp("wait", key))
2946 fadescale = atof(value);
2947 else if (!strcmp("classname", key))
2949 if (!strncmp(value, "light", 5))
2952 if (!strcmp(value, "light_fluoro"))
2957 overridecolor[0] = 1;
2958 overridecolor[1] = 1;
2959 overridecolor[2] = 1;
2961 if (!strcmp(value, "light_fluorospark"))
2966 overridecolor[0] = 1;
2967 overridecolor[1] = 1;
2968 overridecolor[2] = 1;
2970 if (!strcmp(value, "light_globe"))
2975 overridecolor[0] = 1;
2976 overridecolor[1] = 0.8;
2977 overridecolor[2] = 0.4;
2979 if (!strcmp(value, "light_flame_large_yellow"))
2984 overridecolor[0] = 1;
2985 overridecolor[1] = 0.5;
2986 overridecolor[2] = 0.1;
2988 if (!strcmp(value, "light_flame_small_yellow"))
2993 overridecolor[0] = 1;
2994 overridecolor[1] = 0.5;
2995 overridecolor[2] = 0.1;
2997 if (!strcmp(value, "light_torch_small_white"))
3002 overridecolor[0] = 1;
3003 overridecolor[1] = 0.5;
3004 overridecolor[2] = 0.1;
3006 if (!strcmp(value, "light_torch_small_walltorch"))
3011 overridecolor[0] = 1;
3012 overridecolor[1] = 0.5;
3013 overridecolor[2] = 0.1;
3017 else if (!strcmp("style", key))
3018 style = atoi(value);
3019 else if (!strcmp("skin", key))
3020 skin = (int)atof(value);
3021 else if (!strcmp("pflags", key))
3022 pflags = (int)atof(value);
3023 else if (!strcmp("effects", key))
3024 effects = (int)atof(value);
3025 else if (r_refdef.worldmodel->type == mod_brushq3)
3027 if (!strcmp("scale", key))
3028 lightscale = atof(value);
3029 if (!strcmp("fade", key))
3030 fadescale = atof(value);
3035 if (lightscale <= 0)
3039 if (color[0] == color[1] && color[0] == color[2])
3041 color[0] *= overridecolor[0];
3042 color[1] *= overridecolor[1];
3043 color[2] *= overridecolor[2];
3045 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3046 color[0] = color[0] * light[0];
3047 color[1] = color[1] * light[1];
3048 color[2] = color[2] * light[2];
3051 case LIGHTTYPE_MINUSX:
3053 case LIGHTTYPE_RECIPX:
3055 VectorScale(color, (1.0f / 16.0f), color);
3057 case LIGHTTYPE_RECIPXX:
3059 VectorScale(color, (1.0f / 16.0f), color);
3062 case LIGHTTYPE_NONE:
3066 case LIGHTTYPE_MINUSXX:
3069 VectorAdd(origin, originhack, origin);
3071 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);
3074 Mem_Free(entfiledata);
3078 void R_Shadow_SetCursorLocationForView(void)
3081 vec3_t dest, endpos;
3083 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
3084 trace = CL_TraceBox(r_vieworigin, vec3_origin, vec3_origin, dest, true, NULL, SUPERCONTENTS_SOLID, false);
3085 if (trace.fraction < 1)
3087 dist = trace.fraction * r_editlights_cursordistance.value;
3088 push = r_editlights_cursorpushback.value;
3092 VectorMA(trace.endpos, push, r_viewforward, endpos);
3093 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
3097 VectorClear( endpos );
3099 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3100 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3101 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3104 void R_Shadow_UpdateWorldLightSelection(void)
3106 if (r_editlights.integer)
3108 R_Shadow_SetCursorLocationForView();
3109 R_Shadow_SelectLightInView();
3110 R_Shadow_DrawLightSprites();
3113 R_Shadow_SelectLight(NULL);
3116 void R_Shadow_EditLights_Clear_f(void)
3118 R_Shadow_ClearWorldLights();
3121 void R_Shadow_EditLights_Reload_f(void)
3123 if (!r_refdef.worldmodel)
3125 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3126 R_Shadow_ClearWorldLights();
3127 R_Shadow_LoadWorldLights();
3128 if (r_shadow_worldlightchain == NULL)
3130 R_Shadow_LoadLightsFile();
3131 if (r_shadow_worldlightchain == NULL)
3132 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3136 void R_Shadow_EditLights_Save_f(void)
3138 if (!r_refdef.worldmodel)
3140 R_Shadow_SaveWorldLights();
3143 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3145 R_Shadow_ClearWorldLights();
3146 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3149 void R_Shadow_EditLights_ImportLightsFile_f(void)
3151 R_Shadow_ClearWorldLights();
3152 R_Shadow_LoadLightsFile();
3155 void R_Shadow_EditLights_Spawn_f(void)
3158 if (!r_editlights.integer)
3160 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3163 if (Cmd_Argc() != 1)
3165 Con_Print("r_editlights_spawn does not take parameters\n");
3168 color[0] = color[1] = color[2] = 1;
3169 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3172 void R_Shadow_EditLights_Edit_f(void)
3174 vec3_t origin, angles, color;
3175 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3176 int style, shadows, flags, normalmode, realtimemode;
3177 char cubemapname[MAX_INPUTLINE];
3178 if (!r_editlights.integer)
3180 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3183 if (!r_shadow_selectedlight)
3185 Con_Print("No selected light.\n");
3188 VectorCopy(r_shadow_selectedlight->origin, origin);
3189 VectorCopy(r_shadow_selectedlight->angles, angles);
3190 VectorCopy(r_shadow_selectedlight->color, color);
3191 radius = r_shadow_selectedlight->radius;
3192 style = r_shadow_selectedlight->style;
3193 if (r_shadow_selectedlight->cubemapname)
3194 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
3197 shadows = r_shadow_selectedlight->shadow;
3198 corona = r_shadow_selectedlight->corona;
3199 coronasizescale = r_shadow_selectedlight->coronasizescale;
3200 ambientscale = r_shadow_selectedlight->ambientscale;
3201 diffusescale = r_shadow_selectedlight->diffusescale;
3202 specularscale = r_shadow_selectedlight->specularscale;
3203 flags = r_shadow_selectedlight->flags;
3204 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3205 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3206 if (!strcmp(Cmd_Argv(1), "origin"))
3208 if (Cmd_Argc() != 5)
3210 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3213 origin[0] = atof(Cmd_Argv(2));
3214 origin[1] = atof(Cmd_Argv(3));
3215 origin[2] = atof(Cmd_Argv(4));
3217 else if (!strcmp(Cmd_Argv(1), "originx"))
3219 if (Cmd_Argc() != 3)
3221 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3224 origin[0] = atof(Cmd_Argv(2));
3226 else if (!strcmp(Cmd_Argv(1), "originy"))
3228 if (Cmd_Argc() != 3)
3230 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3233 origin[1] = atof(Cmd_Argv(2));
3235 else if (!strcmp(Cmd_Argv(1), "originz"))
3237 if (Cmd_Argc() != 3)
3239 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3242 origin[2] = atof(Cmd_Argv(2));
3244 else if (!strcmp(Cmd_Argv(1), "move"))
3246 if (Cmd_Argc() != 5)
3248 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3251 origin[0] += atof(Cmd_Argv(2));
3252 origin[1] += atof(Cmd_Argv(3));
3253 origin[2] += atof(Cmd_Argv(4));
3255 else if (!strcmp(Cmd_Argv(1), "movex"))
3257 if (Cmd_Argc() != 3)
3259 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3262 origin[0] += atof(Cmd_Argv(2));
3264 else if (!strcmp(Cmd_Argv(1), "movey"))
3266 if (Cmd_Argc() != 3)
3268 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3271 origin[1] += atof(Cmd_Argv(2));
3273 else if (!strcmp(Cmd_Argv(1), "movez"))
3275 if (Cmd_Argc() != 3)
3277 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3280 origin[2] += atof(Cmd_Argv(2));
3282 else if (!strcmp(Cmd_Argv(1), "angles"))
3284 if (Cmd_Argc() != 5)
3286 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3289 angles[0] = atof(Cmd_Argv(2));
3290 angles[1] = atof(Cmd_Argv(3));
3291 angles[2] = atof(Cmd_Argv(4));
3293 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3295 if (Cmd_Argc() != 3)
3297 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3300 angles[0] = atof(Cmd_Argv(2));
3302 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3304 if (Cmd_Argc() != 3)
3306 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3309 angles[1] = atof(Cmd_Argv(2));
3311 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3313 if (Cmd_Argc() != 3)
3315 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3318 angles[2] = atof(Cmd_Argv(2));
3320 else if (!strcmp(Cmd_Argv(1), "color"))
3322 if (Cmd_Argc() != 5)
3324 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3327 color[0] = atof(Cmd_Argv(2));
3328 color[1] = atof(Cmd_Argv(3));
3329 color[2] = atof(Cmd_Argv(4));
3331 else if (!strcmp(Cmd_Argv(1), "radius"))
3333 if (Cmd_Argc() != 3)
3335 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3338 radius = atof(Cmd_Argv(2));
3340 else if (!strcmp(Cmd_Argv(1), "colorscale"))
3342 if (Cmd_Argc() == 3)
3344 double scale = atof(Cmd_Argv(2));
3351 if (Cmd_Argc() != 5)
3353 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
3356 color[0] *= atof(Cmd_Argv(2));
3357 color[1] *= atof(Cmd_Argv(3));
3358 color[2] *= atof(Cmd_Argv(4));
3361 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
3363 if (Cmd_Argc() != 3)
3365 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3368 radius *= atof(Cmd_Argv(2));
3370 else if (!strcmp(Cmd_Argv(1), "style"))
3372 if (Cmd_Argc() != 3)
3374 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3377 style = atoi(Cmd_Argv(2));
3379 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3383 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3386 if (Cmd_Argc() == 3)
3387 strcpy(cubemapname, Cmd_Argv(2));
3391 else if (!strcmp(Cmd_Argv(1), "shadows"))
3393 if (Cmd_Argc() != 3)
3395 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3398 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3400 else if (!strcmp(Cmd_Argv(1), "corona"))
3402 if (Cmd_Argc() != 3)
3404 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3407 corona = atof(Cmd_Argv(2));
3409 else if (!strcmp(Cmd_Argv(1), "coronasize"))
3411 if (Cmd_Argc() != 3)
3413 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3416 coronasizescale = atof(Cmd_Argv(2));
3418 else if (!strcmp(Cmd_Argv(1), "ambient"))
3420 if (Cmd_Argc() != 3)
3422 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3425 ambientscale = atof(Cmd_Argv(2));
3427 else if (!strcmp(Cmd_Argv(1), "diffuse"))
3429 if (Cmd_Argc() != 3)
3431 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3434 diffusescale = atof(Cmd_Argv(2));
3436 else if (!strcmp(Cmd_Argv(1), "specular"))
3438 if (Cmd_Argc() != 3)
3440 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3443 specularscale = atof(Cmd_Argv(2));
3445 else if (!strcmp(Cmd_Argv(1), "normalmode"))
3447 if (Cmd_Argc() != 3)
3449 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3452 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3454 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
3456 if (Cmd_Argc() != 3)
3458 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3461 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3465 Con_Print("usage: r_editlights_edit [property] [value]\n");
3466 Con_Print("Selected light's properties:\n");
3467 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3468 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3469 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3470 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3471 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3472 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3473 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3474 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
3475 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
3476 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
3477 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
3478 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
3479 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
3480 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
3483 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
3484 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3487 void R_Shadow_EditLights_EditAll_f(void)
3491 if (!r_editlights.integer)
3493 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
3497 for (light = r_shadow_worldlightchain;light;light = light->next)
3499 R_Shadow_SelectLight(light);
3500 R_Shadow_EditLights_Edit_f();
3504 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3506 int lightnumber, lightcount;
3510 if (!r_editlights.integer)
3516 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
3517 if (light == r_shadow_selectedlight)
3518 lightnumber = lightcount;
3519 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;
3520 if (r_shadow_selectedlight == NULL)
3522 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3523 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;
3524 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;
3525 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;
3526 sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3527 sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3528 sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3529 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;
3530 sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3531 sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3532 sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3533 sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3534 sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3535 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;
3536 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;
3539 void R_Shadow_EditLights_ToggleShadow_f(void)
3541 if (!r_editlights.integer)
3543 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3546 if (!r_shadow_selectedlight)
3548 Con_Print("No selected light.\n");
3551 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);
3554 void R_Shadow_EditLights_ToggleCorona_f(void)
3556 if (!r_editlights.integer)
3558 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3561 if (!r_shadow_selectedlight)
3563 Con_Print("No selected light.\n");
3566 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);
3569 void R_Shadow_EditLights_Remove_f(void)
3571 if (!r_editlights.integer)
3573 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
3576 if (!r_shadow_selectedlight)
3578 Con_Print("No selected light.\n");
3581 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3582 r_shadow_selectedlight = NULL;
3585 void R_Shadow_EditLights_Help_f(void)
3588 "Documentation on r_editlights system:\n"
3590 "r_editlights : enable/disable editing mode\n"
3591 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
3592 "r_editlights_cursorpushback : push back cursor this far from surface\n"
3593 "r_editlights_cursorpushoff : push cursor off surface this far\n"
3594 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
3595 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
3597 "r_editlights_help : this help\n"
3598 "r_editlights_clear : remove all lights\n"
3599 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
3600 "r_editlights_save : save to .rtlights file\n"
3601 "r_editlights_spawn : create a light with default settings\n"
3602 "r_editlights_edit command : edit selected light - more documentation below\n"
3603 "r_editlights_remove : remove selected light\n"
3604 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
3605 "r_editlights_importlightentitiesfrommap : reload light entities\n"
3606 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
3608 "origin x y z : set light location\n"
3609 "originx x: set x component of light location\n"
3610 "originy y: set y component of light location\n"
3611 "originz z: set z component of light location\n"
3612 "move x y z : adjust light location\n"
3613 "movex x: adjust x component of light location\n"
3614 "movey y: adjust y component of light location\n"
3615 "movez z: adjust z component of light location\n"
3616 "angles x y z : set light angles\n"
3617 "anglesx x: set x component of light angles\n"
3618 "anglesy y: set y component of light angles\n"
3619 "anglesz z: set z component of light angles\n"
3620 "color r g b : set color of light (can be brighter than 1 1 1)\n"
3621 "radius radius : set radius (size) of light\n"
3622 "colorscale grey : multiply color of light (1 does nothing)\n"
3623 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
3624 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
3625 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
3626 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
3627 "cubemap basename : set filter cubemap of light (not yet supported)\n"
3628 "shadows 1/0 : turn on/off shadows\n"
3629 "corona n : set corona intensity\n"
3630 "coronasize n : set corona size (0-1)\n"
3631 "ambient n : set ambient intensity (0-1)\n"
3632 "diffuse n : set diffuse intensity (0-1)\n"
3633 "specular n : set specular intensity (0-1)\n"
3634 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
3635 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
3636 "<nothing> : print light properties to console\n"
3640 void R_Shadow_EditLights_CopyInfo_f(void)
3642 if (!r_editlights.integer)
3644 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
3647 if (!r_shadow_selectedlight)
3649 Con_Print("No selected light.\n");
3652 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
3653 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
3654 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
3655 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
3656 if (r_shadow_selectedlight->cubemapname)
3657 strcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname);
3659 r_shadow_bufferlight.cubemapname[0] = 0;
3660 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
3661 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
3662 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
3663 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
3664 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
3665 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
3666 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
3669 void R_Shadow_EditLights_PasteInfo_f(void)
3671 if (!r_editlights.integer)
3673 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
3676 if (!r_shadow_selectedlight)
3678 Con_Print("No selected light.\n");
3681 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);
3684 void R_Shadow_EditLights_Init(void)
3686 Cvar_RegisterVariable(&r_editlights);
3687 Cvar_RegisterVariable(&r_editlights_cursordistance);
3688 Cvar_RegisterVariable(&r_editlights_cursorpushback);
3689 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
3690 Cvar_RegisterVariable(&r_editlights_cursorgrid);
3691 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
3692 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
3693 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
3694 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)");
3695 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
3696 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
3697 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
3698 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)");
3699 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
3700 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
3701 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
3702 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
3703 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
3704 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
3705 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)");