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(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 GL_Color(0.1, 0.025, 0, 1);
1237 R_Mesh_ColorPointer(NULL);
1238 R_Mesh_ResetTextureState();
1239 RSurf_PrepareVerticesForBatch(false, false, numsurfaces, surfacelist);
1240 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1242 const msurface_t *surface = surfacelist[surfacelistindex];
1243 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1244 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface_model->surfmesh.data_element3i + 3 * surface->num_firsttriangle);
1246 GL_LockArrays(0, 0);
1249 static void R_Shadow_RenderSurfacesLighting_Light_GLSL(int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, qboolean dopants, qboolean doshirt)
1251 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
1252 int surfacelistindex;
1253 RSurf_PrepareVerticesForBatch(true, true, numsurfaces, surfacelist);
1254 R_SetupSurfaceShader(lightcolorbase, false);
1255 R_Mesh_TexCoordPointer(0, 2, rsurface_model->surfmesh.data_texcoordtexture2f);
1256 R_Mesh_TexCoordPointer(1, 3, rsurface_svector3f);
1257 R_Mesh_TexCoordPointer(2, 3, rsurface_tvector3f);
1258 R_Mesh_TexCoordPointer(3, 3, rsurface_normal3f);
1259 if (rsurface_texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1260 qglDepthFunc(GL_EQUAL);
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, rsurface_model->surfmesh.data_element3i + surface->num_firsttriangle * 3);
1267 GL_LockArrays(0, 0);
1268 if (rsurface_texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1269 qglDepthFunc(GL_LEQUAL);
1272 static void R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(const msurface_t *surface, const vec3_t lightcolorbase, rtexture_t *basetexture, float colorscale)
1277 const int *elements = rsurface_model->surfmesh.data_element3i + surface->num_firsttriangle * 3;
1279 // colorscale accounts for how much we multiply the brightness
1282 // mult is how many times the final pass of the lighting will be
1283 // performed to get more brightness than otherwise possible.
1285 // Limit mult to 64 for sanity sake.
1286 if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1288 // 3 3D combine path (Geforce3, Radeon 8500)
1289 memset(&m, 0, sizeof(m));
1290 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1291 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1292 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1293 m.tex[1] = R_GetTexture(basetexture);
1294 m.pointer_texcoord[1] = rsurface_model->surfmesh.data_texcoordtexture2f;
1295 m.texmatrix[1] = rsurface_texture->currenttexmatrix;
1296 m.texcubemap[2] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1297 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1298 m.texmatrix[2] = r_shadow_entitytolight;
1299 GL_BlendFunc(GL_ONE, GL_ONE);
1301 else if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1303 // 2 3D combine path (Geforce3, original Radeon)
1304 memset(&m, 0, sizeof(m));
1305 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1306 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1307 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1308 m.tex[1] = R_GetTexture(basetexture);
1309 m.pointer_texcoord[1] = rsurface_model->surfmesh.data_texcoordtexture2f;
1310 m.texmatrix[1] = rsurface_texture->currenttexmatrix;
1311 GL_BlendFunc(GL_ONE, GL_ONE);
1313 else if (r_textureunits.integer >= 4 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1315 // 4 2D combine path (Geforce3, Radeon 8500)
1316 memset(&m, 0, sizeof(m));
1317 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1318 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1319 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1320 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1321 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1322 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1323 m.tex[2] = R_GetTexture(basetexture);
1324 m.pointer_texcoord[2] = rsurface_model->surfmesh.data_texcoordtexture2f;
1325 m.texmatrix[2] = rsurface_texture->currenttexmatrix;
1326 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1328 m.texcubemap[3] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1329 m.pointer_texcoord3f[3] = rsurface_vertex3f;
1330 m.texmatrix[3] = r_shadow_entitytolight;
1332 GL_BlendFunc(GL_ONE, GL_ONE);
1334 else if (r_textureunits.integer >= 3 && r_shadow_rtlight->currentcubemap == r_texture_whitecube)
1336 // 3 2D combine path (Geforce3, original Radeon)
1337 memset(&m, 0, sizeof(m));
1338 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1339 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1340 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1341 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1342 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1343 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1344 m.tex[2] = R_GetTexture(basetexture);
1345 m.pointer_texcoord[2] = rsurface_model->surfmesh.data_texcoordtexture2f;
1346 m.texmatrix[2] = rsurface_texture->currenttexmatrix;
1347 GL_BlendFunc(GL_ONE, GL_ONE);
1351 // 2/2/2 2D combine path (any dot3 card)
1352 memset(&m, 0, sizeof(m));
1353 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1354 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1355 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1356 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1357 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1358 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1359 R_Mesh_TextureState(&m);
1360 GL_ColorMask(0,0,0,1);
1361 GL_BlendFunc(GL_ONE, GL_ZERO);
1362 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1363 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1364 GL_LockArrays(0, 0);
1366 memset(&m, 0, sizeof(m));
1367 m.tex[0] = R_GetTexture(basetexture);
1368 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1369 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1370 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1372 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1373 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1374 m.texmatrix[1] = r_shadow_entitytolight;
1376 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1378 // this final code is shared
1379 R_Mesh_TextureState(&m);
1380 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1381 VectorScale(lightcolorbase, colorscale, color2);
1382 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1383 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1385 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1386 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1388 GL_LockArrays(0, 0);
1391 static void R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(const msurface_t *surface, const vec3_t lightcolorbase, rtexture_t *basetexture, rtexture_t *normalmaptexture, float colorscale)
1396 const int *elements = rsurface_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] = rsurface_model->surfmesh.data_texcoordtexture2f;
1412 m.texmatrix[0] = rsurface_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] = rsurface_model->surfmesh.data_texcoordtexture2f;
1430 m.texmatrix[0] = rsurface_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] = rsurface_model->surfmesh.data_texcoordtexture2f;
1457 m.texmatrix[0] = rsurface_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] = rsurface_model->surfmesh.data_texcoordtexture2f;
1471 m.texmatrix[0] = rsurface_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] = rsurface_model->surfmesh.data_texcoordtexture2f;
1487 m.texmatrix[0] = rsurface_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] = rsurface_model->surfmesh.data_texcoordtexture2f;
1502 m.texmatrix[0] = rsurface_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] = rsurface_model->surfmesh.data_texcoordtexture2f;
1515 m.texmatrix[0] = rsurface_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] = rsurface_model->surfmesh.data_texcoordtexture2f;
1536 m.texmatrix[0] = rsurface_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] = rsurface_model->surfmesh.data_texcoordtexture2f;
1566 m.texmatrix[0] = rsurface_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] = rsurface_model->surfmesh.data_texcoordtexture2f;
1580 m.texmatrix[0] = rsurface_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 msurface_t *surface, const vec3_t lightcolorbase, rtexture_t *glosstexture, rtexture_t *normalmaptexture, float colorscale)
1607 const int *elements = rsurface_model->surfmesh.data_element3i + surface->num_firsttriangle * 3;
1608 // FIXME: detect blendsquare!
1609 //if (!gl_support_blendsquare)
1612 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap != r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
1614 // 2/0/0/1/2 3D combine blendsquare path
1615 memset(&m, 0, sizeof(m));
1616 m.tex[0] = R_GetTexture(normalmaptexture);
1617 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1618 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1619 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1620 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1621 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1622 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);
1623 R_Mesh_TextureState(&m);
1624 GL_ColorMask(0,0,0,1);
1625 // this squares the result
1626 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1627 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1628 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1629 GL_LockArrays(0, 0);
1631 R_Mesh_ResetTextureState();
1632 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1633 // square alpha in framebuffer a few times to make it shiny
1634 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1635 // these comments are a test run through this math for intensity 0.5
1636 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1637 // 0.25 * 0.25 = 0.0625 (this is another pass)
1638 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1639 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1640 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1641 GL_LockArrays(0, 0);
1643 memset(&m, 0, sizeof(m));
1644 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1645 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1646 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1647 R_Mesh_TextureState(&m);
1648 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1649 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1650 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1651 GL_LockArrays(0, 0);
1653 memset(&m, 0, sizeof(m));
1654 m.tex[0] = R_GetTexture(glosstexture);
1655 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1656 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1657 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1659 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1660 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1661 m.texmatrix[1] = r_shadow_entitytolight;
1663 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1665 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
1667 // 2/0/0/2 3D combine blendsquare path
1668 memset(&m, 0, sizeof(m));
1669 m.tex[0] = R_GetTexture(normalmaptexture);
1670 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1671 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1672 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1673 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1674 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1675 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);
1676 R_Mesh_TextureState(&m);
1677 GL_ColorMask(0,0,0,1);
1678 // this squares the result
1679 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1680 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1681 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1682 GL_LockArrays(0, 0);
1684 R_Mesh_ResetTextureState();
1685 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1686 // square alpha in framebuffer a few times to make it shiny
1687 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1688 // these comments are a test run through this math for intensity 0.5
1689 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1690 // 0.25 * 0.25 = 0.0625 (this is another pass)
1691 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1692 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1693 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1694 GL_LockArrays(0, 0);
1696 memset(&m, 0, sizeof(m));
1697 m.tex[0] = R_GetTexture(glosstexture);
1698 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1699 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1700 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1701 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1702 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
1703 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1707 // 2/0/0/2/2 2D combine blendsquare path
1708 memset(&m, 0, sizeof(m));
1709 m.tex[0] = R_GetTexture(normalmaptexture);
1710 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1711 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1712 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1713 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1714 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1715 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);
1716 R_Mesh_TextureState(&m);
1717 GL_ColorMask(0,0,0,1);
1718 // this squares the result
1719 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1720 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1721 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1722 GL_LockArrays(0, 0);
1724 R_Mesh_ResetTextureState();
1725 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1726 // square alpha in framebuffer a few times to make it shiny
1727 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1728 // these comments are a test run through this math for intensity 0.5
1729 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1730 // 0.25 * 0.25 = 0.0625 (this is another pass)
1731 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1732 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1733 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1734 GL_LockArrays(0, 0);
1736 memset(&m, 0, sizeof(m));
1737 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1738 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1739 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1740 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1741 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1742 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1743 R_Mesh_TextureState(&m);
1744 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1745 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1746 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1747 GL_LockArrays(0, 0);
1749 memset(&m, 0, sizeof(m));
1750 m.tex[0] = R_GetTexture(glosstexture);
1751 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1752 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1753 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1755 m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1756 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1757 m.texmatrix[1] = r_shadow_entitytolight;
1759 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1761 R_Mesh_TextureState(&m);
1762 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1763 VectorScale(lightcolorbase, colorscale, color2);
1764 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1765 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1767 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1768 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1770 GL_LockArrays(0, 0);
1773 static void R_Shadow_RenderSurfacesLighting_Light_Dot3(int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, qboolean dopants, qboolean doshirt)
1775 // ARB path (any Geforce, any Radeon)
1776 int surfacelistindex;
1777 qboolean doambient = r_shadow_rtlight->ambientscale > 0;
1778 qboolean dodiffuse = r_shadow_rtlight->diffusescale > 0;
1779 qboolean dospecular = specularscale > 0;
1780 if (!doambient && !dodiffuse && !dospecular)
1782 RSurf_PrepareVerticesForBatch(true, true, numsurfaces, surfacelist);
1783 R_Mesh_ColorPointer(NULL);
1784 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1786 const msurface_t *surface = surfacelist[surfacelistindex];
1788 R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(surface, lightcolorbase, basetexture, r_shadow_rtlight->ambientscale);
1790 R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(surface, lightcolorbase, basetexture, normalmaptexture, r_shadow_rtlight->diffusescale);
1794 R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(surface, lightcolorpants, pantstexture, r_shadow_rtlight->ambientscale);
1796 R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(surface, lightcolorpants, pantstexture, normalmaptexture, r_shadow_rtlight->diffusescale);
1801 R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(surface, lightcolorshirt, shirttexture, r_shadow_rtlight->ambientscale);
1803 R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(surface, lightcolorshirt, shirttexture, normalmaptexture, r_shadow_rtlight->diffusescale);
1806 R_Shadow_RenderSurfacesLighting_Light_Dot3_SpecularPass(surface, lightcolorbase, glosstexture, normalmaptexture, specularscale);
1810 void R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(const model_t *model, const msurface_t *surface, vec3_t diffusecolor2, vec3_t ambientcolor2)
1813 const int *elements = rsurface_model->surfmesh.data_element3i + surface->num_firsttriangle * 3;
1814 R_Shadow_RenderSurfacesLighting_Light_Vertex_Shading(surface, diffusecolor2, ambientcolor2);
1815 for (renders = 0;renders < 64 && (ambientcolor2[0] > renders || ambientcolor2[1] > renders || ambientcolor2[2] > renders || diffusecolor2[0] > renders || diffusecolor2[1] > renders || diffusecolor2[2] > renders);renders++)
1820 // due to low fillrate on the cards this vertex lighting path is
1821 // designed for, we manually cull all triangles that do not
1822 // contain a lit vertex
1825 int newnumtriangles;
1827 int newelements[3072];
1829 newnumtriangles = 0;
1831 for (i = 0, e = elements;i < surface->num_triangles;i++, e += 3)
1833 if (newnumtriangles >= 1024)
1835 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1836 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, newnumtriangles, newelements);
1837 GL_LockArrays(0, 0);
1838 newnumtriangles = 0;
1841 if (VectorLength2(rsurface_array_color4f + e[0] * 4) + VectorLength2(rsurface_array_color4f + e[1] * 4) + VectorLength2(rsurface_array_color4f + e[2] * 4) >= 0.01)
1851 if (newnumtriangles >= 1)
1853 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1854 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, newnumtriangles, newelements);
1855 GL_LockArrays(0, 0);
1861 for (i = 0, c = rsurface_array_color4f + 4 * surface->num_firstvertex;i < surface->num_vertices;i++, c += 4)
1862 if (VectorLength2(c))
1866 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1867 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, elements);
1868 GL_LockArrays(0, 0);
1870 // now reduce the intensity for the next overbright pass
1871 for (i = 0, c = rsurface_array_color4f + 4 * surface->num_firstvertex;i < surface->num_vertices;i++, c += 4)
1873 c[0] = max(0, c[0] - 1);
1874 c[1] = max(0, c[1] - 1);
1875 c[2] = max(0, c[2] - 1);
1880 static void R_Shadow_RenderSurfacesLighting_Light_Vertex(int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, qboolean dopants, qboolean doshirt)
1882 int surfacelistindex;
1883 model_t *model = rsurface_entity->model;
1884 float ambientcolorbase[3], diffusecolorbase[3];
1885 float ambientcolorpants[3], diffusecolorpants[3];
1886 float ambientcolorshirt[3], diffusecolorshirt[3];
1888 VectorScale(lightcolorbase, r_shadow_rtlight->ambientscale * 2, ambientcolorbase);
1889 VectorScale(lightcolorbase, r_shadow_rtlight->diffusescale * 2, diffusecolorbase);
1890 VectorScale(lightcolorpants, r_shadow_rtlight->ambientscale * 2, ambientcolorpants);
1891 VectorScale(lightcolorpants, r_shadow_rtlight->diffusescale * 2, diffusecolorpants);
1892 VectorScale(lightcolorshirt, r_shadow_rtlight->ambientscale * 2, ambientcolorshirt);
1893 VectorScale(lightcolorshirt, r_shadow_rtlight->diffusescale * 2, diffusecolorshirt);
1894 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1895 R_Mesh_ColorPointer(rsurface_array_color4f);
1896 memset(&m, 0, sizeof(m));
1897 m.tex[0] = R_GetTexture(basetexture);
1898 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1899 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1900 if (r_textureunits.integer >= 2)
1903 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1904 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
1905 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1906 if (r_textureunits.integer >= 3)
1908 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
1909 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1910 m.texmatrix[2] = r_shadow_entitytoattenuationz;
1911 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1914 R_Mesh_TextureState(&m);
1915 RSurf_PrepareVerticesForBatch(true, false, numsurfaces, surfacelist);
1916 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1918 const msurface_t *surface = surfacelist[surfacelistindex];
1919 // OpenGL 1.1 path (anything)
1920 R_Mesh_TexBind(0, R_GetTexture(basetexture));
1921 R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(model, surface, diffusecolorbase, ambientcolorbase);
1924 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
1925 R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(model, surface, diffusecolorpants, ambientcolorpants);
1929 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
1930 R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(model, surface, diffusecolorshirt, ambientcolorshirt);
1935 void R_Shadow_RenderSurfacesLighting(int numsurfaces, msurface_t **surfacelist)
1937 // FIXME: support MATERIALFLAG_NODEPTHTEST
1938 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
1939 // calculate colors to render this texture with
1940 lightcolorbase[0] = r_shadow_rtlight->currentcolor[0] * rsurface_entity->colormod[0] * rsurface_texture->currentalpha;
1941 lightcolorbase[1] = r_shadow_rtlight->currentcolor[1] * rsurface_entity->colormod[1] * rsurface_texture->currentalpha;
1942 lightcolorbase[2] = r_shadow_rtlight->currentcolor[2] * rsurface_entity->colormod[2] * rsurface_texture->currentalpha;
1943 if ((r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorbase) + (r_shadow_rtlight->specularscale * rsurface_texture->specularscale) * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
1945 if ((rsurface_texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) || (rsurface_entity->flags & RENDER_NOCULLFACE))
1946 qglDisable(GL_CULL_FACE);
1948 qglEnable(GL_CULL_FACE);
1949 if (rsurface_texture->colormapping)
1951 qboolean dopants = rsurface_texture->skin.pants != NULL && VectorLength2(rsurface_entity->colormap_pantscolor) >= (1.0f / 1048576.0f);
1952 qboolean doshirt = rsurface_texture->skin.shirt != NULL && VectorLength2(rsurface_entity->colormap_shirtcolor) >= (1.0f / 1048576.0f);
1955 lightcolorpants[0] = lightcolorbase[0] * rsurface_entity->colormap_pantscolor[0];
1956 lightcolorpants[1] = lightcolorbase[1] * rsurface_entity->colormap_pantscolor[1];
1957 lightcolorpants[2] = lightcolorbase[2] * rsurface_entity->colormap_pantscolor[2];
1960 VectorClear(lightcolorpants);
1963 lightcolorshirt[0] = lightcolorbase[0] * rsurface_entity->colormap_shirtcolor[0];
1964 lightcolorshirt[1] = lightcolorbase[1] * rsurface_entity->colormap_shirtcolor[1];
1965 lightcolorshirt[2] = lightcolorbase[2] * rsurface_entity->colormap_shirtcolor[2];
1968 VectorClear(lightcolorshirt);
1969 switch (r_shadow_rendermode)
1971 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
1972 R_Shadow_RenderSurfacesLighting_VisibleLighting(numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->skin.pants, rsurface_texture->skin.shirt, rsurface_texture->skin.nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, dopants, doshirt);
1974 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
1975 R_Shadow_RenderSurfacesLighting_Light_GLSL(numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->skin.pants, rsurface_texture->skin.shirt, rsurface_texture->skin.nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, dopants, doshirt);
1977 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
1978 R_Shadow_RenderSurfacesLighting_Light_Dot3(numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->skin.pants, rsurface_texture->skin.shirt, rsurface_texture->skin.nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, dopants, doshirt);
1980 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
1981 R_Shadow_RenderSurfacesLighting_Light_Vertex(numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->skin.pants, rsurface_texture->skin.shirt, rsurface_texture->skin.nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, dopants, doshirt);
1984 Con_Printf("R_Shadow_RenderSurfacesLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
1990 switch (r_shadow_rendermode)
1992 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
1993 R_Shadow_RenderSurfacesLighting_VisibleLighting(numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->skin.nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, false, false);
1995 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
1996 R_Shadow_RenderSurfacesLighting_Light_GLSL(numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->skin.nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, false, false);
1998 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
1999 R_Shadow_RenderSurfacesLighting_Light_Dot3(numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->skin.nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, false, false);
2001 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2002 R_Shadow_RenderSurfacesLighting_Light_Vertex(numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->skin.nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, false, false);
2005 Con_Printf("R_Shadow_RenderSurfacesLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2011 void R_RTLight_Update(dlight_t *light, int isstatic)
2015 rtlight_t *rtlight = &light->rtlight;
2016 R_RTLight_Uncompile(rtlight);
2017 memset(rtlight, 0, sizeof(*rtlight));
2019 VectorCopy(light->origin, rtlight->shadoworigin);
2020 VectorCopy(light->color, rtlight->color);
2021 rtlight->radius = light->radius;
2022 //rtlight->cullradius = rtlight->radius;
2023 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2024 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2025 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2026 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2027 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2028 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2029 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2030 rtlight->cubemapname[0] = 0;
2031 if (light->cubemapname[0])
2032 strcpy(rtlight->cubemapname, light->cubemapname);
2033 else if (light->cubemapnum > 0)
2034 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
2035 rtlight->shadow = light->shadow;
2036 rtlight->corona = light->corona;
2037 rtlight->style = light->style;
2038 rtlight->isstatic = isstatic;
2039 rtlight->coronasizescale = light->coronasizescale;
2040 rtlight->ambientscale = light->ambientscale;
2041 rtlight->diffusescale = light->diffusescale;
2042 rtlight->specularscale = light->specularscale;
2043 rtlight->flags = light->flags;
2044 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
2045 // ConcatScale won't work here because this needs to scale rotate and
2046 // translate, not just rotate
2047 scale = 1.0f / rtlight->radius;
2048 for (k = 0;k < 3;k++)
2049 for (j = 0;j < 4;j++)
2050 rtlight->matrix_worldtolight.m[k][j] *= scale;
2053 // compiles rtlight geometry
2054 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2055 void R_RTLight_Compile(rtlight_t *rtlight)
2057 int shadowmeshes, shadowtris, numleafs, numleafpvsbytes, numsurfaces;
2058 entity_render_t *ent = r_refdef.worldentity;
2059 model_t *model = r_refdef.worldmodel;
2060 unsigned char *data;
2062 // compile the light
2063 rtlight->compiled = true;
2064 rtlight->static_numleafs = 0;
2065 rtlight->static_numleafpvsbytes = 0;
2066 rtlight->static_leaflist = NULL;
2067 rtlight->static_leafpvs = NULL;
2068 rtlight->static_numsurfaces = 0;
2069 rtlight->static_surfacelist = NULL;
2070 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2071 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2072 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2073 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2074 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2075 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2077 if (model && model->GetLightInfo)
2079 // this variable must be set for the CompileShadowVolume code
2080 r_shadow_compilingrtlight = rtlight;
2081 R_Shadow_EnlargeLeafSurfaceBuffer(model->brush.num_leafs, model->num_surfaces);
2082 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);
2083 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2084 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numleafs + numleafpvsbytes + sizeof(int) * numsurfaces);
2085 rtlight->static_numleafs = numleafs;
2086 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2087 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2088 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2089 rtlight->static_numsurfaces = numsurfaces;
2090 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2092 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2093 if (numleafpvsbytes)
2094 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2096 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2097 if (model->CompileShadowVolume && rtlight->shadow)
2098 model->CompileShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2099 // now we're done compiling the rtlight
2100 r_shadow_compilingrtlight = NULL;
2104 // use smallest available cullradius - box radius or light radius
2105 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2106 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2110 if (rtlight->static_meshchain_shadow)
2113 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2116 shadowtris += mesh->numtriangles;
2120 if (developer.integer >= 10)
2121 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);
2124 void R_RTLight_Uncompile(rtlight_t *rtlight)
2126 if (rtlight->compiled)
2128 if (rtlight->static_meshchain_shadow)
2129 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2130 rtlight->static_meshchain_shadow = NULL;
2131 // these allocations are grouped
2132 if (rtlight->static_leaflist)
2133 Mem_Free(rtlight->static_leaflist);
2134 rtlight->static_numleafs = 0;
2135 rtlight->static_numleafpvsbytes = 0;
2136 rtlight->static_leaflist = NULL;
2137 rtlight->static_leafpvs = NULL;
2138 rtlight->static_numsurfaces = 0;
2139 rtlight->static_surfacelist = NULL;
2140 rtlight->compiled = false;
2144 void R_Shadow_UncompileWorldLights(void)
2147 for (light = r_shadow_worldlightchain;light;light = light->next)
2148 R_RTLight_Uncompile(&light->rtlight);
2151 void R_Shadow_DrawEntityShadow(entity_render_t *ent, int numsurfaces, int *surfacelist)
2153 model_t *model = ent->model;
2154 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
2155 vec_t relativeshadowradius;
2156 if (ent == r_refdef.worldentity)
2158 if (r_shadow_rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2161 R_Mesh_Matrix(&ent->matrix);
2162 for (mesh = r_shadow_rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2164 renderstats.lights_shadowtriangles += mesh->numtriangles;
2165 R_Mesh_VertexPointer(mesh->vertex3f);
2166 GL_LockArrays(0, mesh->numverts);
2167 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
2169 // decrement stencil if backface is behind depthbuffer
2170 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2171 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2172 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2173 // increment stencil if frontface is behind depthbuffer
2174 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2175 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2177 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2178 GL_LockArrays(0, 0);
2181 else if (numsurfaces)
2183 R_Mesh_Matrix(&ent->matrix);
2184 model->DrawShadowVolume(ent, r_shadow_rtlight->shadoworigin, r_shadow_rtlight->radius, numsurfaces, surfacelist, r_shadow_rtlight->cullmins, r_shadow_rtlight->cullmaxs);
2189 Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, relativeshadoworigin);
2190 relativeshadowradius = r_shadow_rtlight->radius / ent->scale;
2191 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
2192 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
2193 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
2194 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
2195 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
2196 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
2197 R_Mesh_Matrix(&ent->matrix);
2198 model->DrawShadowVolume(ent, relativeshadoworigin, relativeshadowradius, model->nummodelsurfaces, model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2202 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
2204 // set up properties for rendering light onto this entity
2205 RSurf_ActiveEntity(ent);
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 VectorCopy(rsurface_modelorg, r_shadow_entityeyeorigin);
2211 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2212 R_Mesh_TexMatrix(3, &r_shadow_entitytolight);
2215 void R_Shadow_DrawEntityLight(entity_render_t *ent, int numsurfaces, int *surfacelist)
2217 model_t *model = ent->model;
2218 if (!model->DrawLight)
2220 R_Shadow_SetupEntityLight(ent);
2221 if (ent == r_refdef.worldentity)
2222 model->DrawLight(ent, numsurfaces, surfacelist);
2224 model->DrawLight(ent, model->nummodelsurfaces, model->surfacelist);
2227 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
2231 int numleafs, numsurfaces;
2232 int *leaflist, *surfacelist;
2233 unsigned char *leafpvs;
2234 int numlightentities;
2235 int numshadowentities;
2236 entity_render_t *lightentities[MAX_EDICTS];
2237 entity_render_t *shadowentities[MAX_EDICTS];
2239 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
2240 // skip lights that are basically invisible (color 0 0 0)
2241 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
2244 // loading is done before visibility checks because loading should happen
2245 // all at once at the start of a level, not when it stalls gameplay.
2246 // (especially important to benchmarks)
2248 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2249 R_RTLight_Compile(rtlight);
2251 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
2253 // look up the light style value at this time
2254 f = (rtlight->style >= 0 ? r_refdef.lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2255 VectorScale(rtlight->color, f, rtlight->currentcolor);
2257 if (rtlight->selected)
2259 f = 2 + sin(realtime * M_PI * 4.0);
2260 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
2264 // if lightstyle is currently off, don't draw the light
2265 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
2268 // if the light box is offscreen, skip it
2269 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2272 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2274 // compiled light, world available and can receive realtime lighting
2275 // retrieve leaf information
2276 numleafs = rtlight->static_numleafs;
2277 leaflist = rtlight->static_leaflist;
2278 leafpvs = rtlight->static_leafpvs;
2279 numsurfaces = rtlight->static_numsurfaces;
2280 surfacelist = rtlight->static_surfacelist;
2282 else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2284 // dynamic light, world available and can receive realtime lighting
2285 // calculate lit surfaces and leafs
2286 R_Shadow_EnlargeLeafSurfaceBuffer(r_refdef.worldmodel->brush.num_leafs, r_refdef.worldmodel->num_surfaces);
2287 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);
2288 leaflist = r_shadow_buffer_leaflist;
2289 leafpvs = r_shadow_buffer_leafpvs;
2290 surfacelist = r_shadow_buffer_surfacelist;
2291 // if the reduced leaf bounds are offscreen, skip it
2292 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2304 // check if light is illuminating any visible leafs
2307 for (i = 0;i < numleafs;i++)
2308 if (r_worldleafvisible[leaflist[i]])
2313 // set up a scissor rectangle for this light
2314 if (R_Shadow_ScissorForBBox(rtlight->cullmins, rtlight->cullmaxs))
2317 // make a list of lit entities and shadow casting entities
2318 numlightentities = 0;
2319 numshadowentities = 0;
2320 // don't count the world unless some surfaces are actually lit
2323 lightentities[numlightentities++] = r_refdef.worldentity;
2324 shadowentities[numshadowentities++] = r_refdef.worldentity;
2326 // add dynamic entities that are lit by the light
2327 if (r_drawentities.integer)
2329 for (i = 0;i < r_refdef.numentities;i++)
2332 entity_render_t *ent = r_refdef.entities[i];
2333 if (BoxesOverlap(ent->mins, ent->maxs, rtlight->cullmins, rtlight->cullmaxs)
2334 && (model = ent->model)
2335 && !(ent->flags & RENDER_TRANSPARENT)
2336 && (r_refdef.worldmodel == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs)))
2338 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2339 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(ent->origin, rtlight->shadoworigin) > 0.1)
2340 shadowentities[numshadowentities++] = ent;
2341 if (ent->visframe == r_framecount && (ent->flags & RENDER_LIGHT) && model->DrawLight)
2342 lightentities[numlightentities++] = ent;
2347 // return if there's nothing at all to light
2348 if (!numlightentities)
2351 // don't let sound skip if going slow
2352 if (r_refdef.extraupdate)
2355 // make this the active rtlight for rendering purposes
2356 R_Shadow_RenderMode_ActiveLight(rtlight);
2357 // count this light in the r_speeds
2358 renderstats.lights++;
2361 if (numshadowentities && rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows))
2363 // draw stencil shadow volumes to mask off pixels that are in shadow
2364 // so that they won't receive lighting
2368 R_Shadow_RenderMode_StencilShadowVolumes();
2369 for (i = 0;i < numshadowentities;i++)
2370 R_Shadow_DrawEntityShadow(shadowentities[i], numsurfaces, surfacelist);
2373 // optionally draw visible shape of the shadow volumes
2374 // for performance analysis by level designers
2375 if (r_showshadowvolumes.integer)
2377 R_Shadow_RenderMode_VisibleShadowVolumes();
2378 for (i = 0;i < numshadowentities;i++)
2379 R_Shadow_DrawEntityShadow(shadowentities[i], numsurfaces, surfacelist);
2383 if (numlightentities)
2385 // draw lighting in the unmasked areas
2386 R_Shadow_RenderMode_Lighting(usestencil, false);
2387 for (i = 0;i < numlightentities;i++)
2388 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
2390 // optionally draw the illuminated areas
2391 // for performance analysis by level designers
2392 if (r_showlighting.integer)
2394 R_Shadow_RenderMode_VisibleLighting(usestencil && !r_showdisabledepthtest.integer, false);
2395 for (i = 0;i < numlightentities;i++)
2396 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
2401 void R_ShadowVolumeLighting(qboolean visible)
2406 if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2407 R_Shadow_EditLights_Reload_f();
2409 R_Shadow_RenderMode_Begin();
2411 flag = r_rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2412 if (r_shadow_debuglight.integer >= 0)
2414 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2415 if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
2416 R_DrawRTLight(&light->rtlight, visible);
2419 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2420 if (light->flags & flag)
2421 R_DrawRTLight(&light->rtlight, visible);
2423 for (lnum = 0;lnum < r_refdef.numlights;lnum++)
2424 R_DrawRTLight(&r_refdef.lights[lnum]->rtlight, visible);
2426 R_Shadow_RenderMode_End();
2429 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2430 typedef struct suffixinfo_s
2433 qboolean flipx, flipy, flipdiagonal;
2436 static suffixinfo_t suffix[3][6] =
2439 {"px", false, false, false},
2440 {"nx", false, false, false},
2441 {"py", false, false, false},
2442 {"ny", false, false, false},
2443 {"pz", false, false, false},
2444 {"nz", false, false, false}
2447 {"posx", false, false, false},
2448 {"negx", false, false, false},
2449 {"posy", false, false, false},
2450 {"negy", false, false, false},
2451 {"posz", false, false, false},
2452 {"negz", false, false, false}
2455 {"rt", true, false, true},
2456 {"lf", false, true, true},
2457 {"ft", true, true, false},
2458 {"bk", false, false, false},
2459 {"up", true, false, true},
2460 {"dn", true, false, true}
2464 static int componentorder[4] = {0, 1, 2, 3};
2466 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2468 int i, j, cubemapsize;
2469 unsigned char *cubemappixels, *image_rgba;
2470 rtexture_t *cubemaptexture;
2472 // must start 0 so the first loadimagepixels has no requested width/height
2474 cubemappixels = NULL;
2475 cubemaptexture = NULL;
2476 // keep trying different suffix groups (posx, px, rt) until one loads
2477 for (j = 0;j < 3 && !cubemappixels;j++)
2479 // load the 6 images in the suffix group
2480 for (i = 0;i < 6;i++)
2482 // generate an image name based on the base and and suffix
2483 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2485 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2487 // an image loaded, make sure width and height are equal
2488 if (image_width == image_height)
2490 // if this is the first image to load successfully, allocate the cubemap memory
2491 if (!cubemappixels && image_width >= 1)
2493 cubemapsize = image_width;
2494 // note this clears to black, so unavailable sides are black
2495 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2497 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2499 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);
2502 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2504 Mem_Free(image_rgba);
2508 // if a cubemap loaded, upload it
2511 if (!r_shadow_filters_texturepool)
2512 r_shadow_filters_texturepool = R_AllocTexturePool();
2513 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
2514 Mem_Free(cubemappixels);
2518 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
2519 for (j = 0;j < 3;j++)
2520 for (i = 0;i < 6;i++)
2521 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2522 Con_Print(" and was unable to find any of them.\n");
2524 return cubemaptexture;
2527 rtexture_t *R_Shadow_Cubemap(const char *basename)
2530 for (i = 0;i < numcubemaps;i++)
2531 if (!strcasecmp(cubemaps[i].basename, basename))
2532 return cubemaps[i].texture;
2533 if (i >= MAX_CUBEMAPS)
2534 return r_texture_whitecube;
2536 strcpy(cubemaps[i].basename, basename);
2537 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
2538 if (!cubemaps[i].texture)
2539 cubemaps[i].texture = r_texture_whitecube;
2540 return cubemaps[i].texture;
2543 void R_Shadow_FreeCubemaps(void)
2546 R_FreeTexturePool(&r_shadow_filters_texturepool);
2549 dlight_t *R_Shadow_NewWorldLight(void)
2552 light = (dlight_t *)Mem_Alloc(r_main_mempool, sizeof(dlight_t));
2553 light->next = r_shadow_worldlightchain;
2554 r_shadow_worldlightchain = light;
2558 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)
2560 VectorCopy(origin, light->origin);
2561 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
2562 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
2563 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
2564 light->color[0] = max(color[0], 0);
2565 light->color[1] = max(color[1], 0);
2566 light->color[2] = max(color[2], 0);
2567 light->radius = max(radius, 0);
2568 light->style = style;
2569 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
2571 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
2574 light->shadow = shadowenable;
2575 light->corona = corona;
2578 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
2579 light->coronasizescale = coronasizescale;
2580 light->ambientscale = ambientscale;
2581 light->diffusescale = diffusescale;
2582 light->specularscale = specularscale;
2583 light->flags = flags;
2584 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
2586 R_RTLight_Update(light, true);
2589 void R_Shadow_FreeWorldLight(dlight_t *light)
2591 dlight_t **lightpointer;
2592 R_RTLight_Uncompile(&light->rtlight);
2593 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
2594 if (*lightpointer != light)
2595 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain");
2596 *lightpointer = light->next;
2600 void R_Shadow_ClearWorldLights(void)
2602 while (r_shadow_worldlightchain)
2603 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
2604 r_shadow_selectedlight = NULL;
2605 R_Shadow_FreeCubemaps();
2608 void R_Shadow_SelectLight(dlight_t *light)
2610 if (r_shadow_selectedlight)
2611 r_shadow_selectedlight->selected = false;
2612 r_shadow_selectedlight = light;
2613 if (r_shadow_selectedlight)
2614 r_shadow_selectedlight->selected = true;
2617 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
2619 float scale = r_editlights_cursorgrid.value * 0.5f;
2620 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);
2623 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
2626 const dlight_t *light = (dlight_t *)ent;
2628 if (light->selected)
2629 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
2632 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);
2635 void R_Shadow_DrawLightSprites(void)
2640 for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
2641 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 1+(i % 5), &light->rtlight);
2642 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
2645 void R_Shadow_SelectLightInView(void)
2647 float bestrating, rating, temp[3];
2648 dlight_t *best, *light;
2651 for (light = r_shadow_worldlightchain;light;light = light->next)
2653 VectorSubtract(light->origin, r_vieworigin, temp);
2654 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
2657 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
2658 if (bestrating < rating && CL_TraceBox(light->origin, vec3_origin, vec3_origin, r_vieworigin, true, NULL, SUPERCONTENTS_SOLID, false).fraction == 1.0f)
2660 bestrating = rating;
2665 R_Shadow_SelectLight(best);
2668 void R_Shadow_LoadWorldLights(void)
2670 int n, a, style, shadow, flags;
2671 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
2672 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
2673 if (r_refdef.worldmodel == NULL)
2675 Con_Print("No map loaded.\n");
2678 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
2679 strlcat (name, ".rtlights", sizeof (name));
2680 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
2690 for (;COM_Parse(t, true) && strcmp(
2691 if (COM_Parse(t, true))
2693 if (com_token[0] == '!')
2696 origin[0] = atof(com_token+1);
2699 origin[0] = atof(com_token);
2704 while (*s && *s != '\n' && *s != '\r')
2710 // check for modifier flags
2717 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);
2720 flags = LIGHTFLAG_REALTIMEMODE;
2728 coronasizescale = 0.25f;
2730 VectorClear(angles);
2733 if (a < 9 || !strcmp(cubemapname, "\"\""))
2735 // remove quotes on cubemapname
2736 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
2738 cubemapname[strlen(cubemapname)-1] = 0;
2739 strcpy(cubemapname, cubemapname + 1);
2743 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);
2746 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
2754 Con_Printf("invalid rtlights file \"%s\"\n", name);
2755 Mem_Free(lightsstring);
2759 void R_Shadow_SaveWorldLights(void)
2762 size_t bufchars, bufmaxchars;
2764 char name[MAX_QPATH];
2765 char line[MAX_INPUTLINE];
2766 if (!r_shadow_worldlightchain)
2768 if (r_refdef.worldmodel == NULL)
2770 Con_Print("No map loaded.\n");
2773 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
2774 strlcat (name, ".rtlights", sizeof (name));
2775 bufchars = bufmaxchars = 0;
2777 for (light = r_shadow_worldlightchain;light;light = light->next)
2779 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
2780 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);
2781 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
2782 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]);
2784 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);
2785 if (bufchars + strlen(line) > bufmaxchars)
2787 bufmaxchars = bufchars + strlen(line) + 2048;
2789 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
2793 memcpy(buf, oldbuf, bufchars);
2799 memcpy(buf + bufchars, line, strlen(line));
2800 bufchars += strlen(line);
2804 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
2809 void R_Shadow_LoadLightsFile(void)
2812 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
2813 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
2814 if (r_refdef.worldmodel == NULL)
2816 Con_Print("No map loaded.\n");
2819 FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
2820 strlcat (name, ".lights", sizeof (name));
2821 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
2829 while (*s && *s != '\n' && *s != '\r')
2835 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);
2839 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);
2842 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
2843 radius = bound(15, radius, 4096);
2844 VectorScale(color, (2.0f / (8388608.0f)), color);
2845 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
2853 Con_Printf("invalid lights file \"%s\"\n", name);
2854 Mem_Free(lightsstring);
2858 // tyrlite/hmap2 light types in the delay field
2859 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
2861 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
2863 int entnum, style, islight, skin, pflags, effects, type, n;
2866 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
2867 char key[256], value[MAX_INPUTLINE];
2869 if (r_refdef.worldmodel == NULL)
2871 Con_Print("No map loaded.\n");
2874 // try to load a .ent file first
2875 FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
2876 strlcat (key, ".ent", sizeof (key));
2877 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
2878 // and if that is not found, fall back to the bsp file entity string
2880 data = r_refdef.worldmodel->brush.entities;
2883 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
2885 type = LIGHTTYPE_MINUSX;
2886 origin[0] = origin[1] = origin[2] = 0;
2887 originhack[0] = originhack[1] = originhack[2] = 0;
2888 angles[0] = angles[1] = angles[2] = 0;
2889 color[0] = color[1] = color[2] = 1;
2890 light[0] = light[1] = light[2] = 1;light[3] = 300;
2891 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
2901 if (!COM_ParseToken(&data, false))
2903 if (com_token[0] == '}')
2904 break; // end of entity
2905 if (com_token[0] == '_')
2906 strcpy(key, com_token + 1);
2908 strcpy(key, com_token);
2909 while (key[strlen(key)-1] == ' ') // remove trailing spaces
2910 key[strlen(key)-1] = 0;
2911 if (!COM_ParseToken(&data, false))
2913 strcpy(value, com_token);
2915 // now that we have the key pair worked out...
2916 if (!strcmp("light", key))
2918 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
2922 light[0] = vec[0] * (1.0f / 256.0f);
2923 light[1] = vec[0] * (1.0f / 256.0f);
2924 light[2] = vec[0] * (1.0f / 256.0f);
2930 light[0] = vec[0] * (1.0f / 255.0f);
2931 light[1] = vec[1] * (1.0f / 255.0f);
2932 light[2] = vec[2] * (1.0f / 255.0f);
2936 else if (!strcmp("delay", key))
2938 else if (!strcmp("origin", key))
2939 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
2940 else if (!strcmp("angle", key))
2941 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
2942 else if (!strcmp("angles", key))
2943 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
2944 else if (!strcmp("color", key))
2945 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
2946 else if (!strcmp("wait", key))
2947 fadescale = atof(value);
2948 else if (!strcmp("classname", key))
2950 if (!strncmp(value, "light", 5))
2953 if (!strcmp(value, "light_fluoro"))
2958 overridecolor[0] = 1;
2959 overridecolor[1] = 1;
2960 overridecolor[2] = 1;
2962 if (!strcmp(value, "light_fluorospark"))
2967 overridecolor[0] = 1;
2968 overridecolor[1] = 1;
2969 overridecolor[2] = 1;
2971 if (!strcmp(value, "light_globe"))
2976 overridecolor[0] = 1;
2977 overridecolor[1] = 0.8;
2978 overridecolor[2] = 0.4;
2980 if (!strcmp(value, "light_flame_large_yellow"))
2985 overridecolor[0] = 1;
2986 overridecolor[1] = 0.5;
2987 overridecolor[2] = 0.1;
2989 if (!strcmp(value, "light_flame_small_yellow"))
2994 overridecolor[0] = 1;
2995 overridecolor[1] = 0.5;
2996 overridecolor[2] = 0.1;
2998 if (!strcmp(value, "light_torch_small_white"))
3003 overridecolor[0] = 1;
3004 overridecolor[1] = 0.5;
3005 overridecolor[2] = 0.1;
3007 if (!strcmp(value, "light_torch_small_walltorch"))
3012 overridecolor[0] = 1;
3013 overridecolor[1] = 0.5;
3014 overridecolor[2] = 0.1;
3018 else if (!strcmp("style", key))
3019 style = atoi(value);
3020 else if (!strcmp("skin", key))
3021 skin = (int)atof(value);
3022 else if (!strcmp("pflags", key))
3023 pflags = (int)atof(value);
3024 else if (!strcmp("effects", key))
3025 effects = (int)atof(value);
3026 else if (r_refdef.worldmodel->type == mod_brushq3)
3028 if (!strcmp("scale", key))
3029 lightscale = atof(value);
3030 if (!strcmp("fade", key))
3031 fadescale = atof(value);
3036 if (lightscale <= 0)
3040 if (color[0] == color[1] && color[0] == color[2])
3042 color[0] *= overridecolor[0];
3043 color[1] *= overridecolor[1];
3044 color[2] *= overridecolor[2];
3046 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3047 color[0] = color[0] * light[0];
3048 color[1] = color[1] * light[1];
3049 color[2] = color[2] * light[2];
3052 case LIGHTTYPE_MINUSX:
3054 case LIGHTTYPE_RECIPX:
3056 VectorScale(color, (1.0f / 16.0f), color);
3058 case LIGHTTYPE_RECIPXX:
3060 VectorScale(color, (1.0f / 16.0f), color);
3063 case LIGHTTYPE_NONE:
3067 case LIGHTTYPE_MINUSXX:
3070 VectorAdd(origin, originhack, origin);
3072 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);
3075 Mem_Free(entfiledata);
3079 void R_Shadow_SetCursorLocationForView(void)
3082 vec3_t dest, endpos;
3084 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
3085 trace = CL_TraceBox(r_vieworigin, vec3_origin, vec3_origin, dest, true, NULL, SUPERCONTENTS_SOLID, false);
3086 if (trace.fraction < 1)
3088 dist = trace.fraction * r_editlights_cursordistance.value;
3089 push = r_editlights_cursorpushback.value;
3093 VectorMA(trace.endpos, push, r_viewforward, endpos);
3094 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
3098 VectorClear( endpos );
3100 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3101 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3102 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3105 void R_Shadow_UpdateWorldLightSelection(void)
3107 if (r_editlights.integer)
3109 R_Shadow_SetCursorLocationForView();
3110 R_Shadow_SelectLightInView();
3111 R_Shadow_DrawLightSprites();
3114 R_Shadow_SelectLight(NULL);
3117 void R_Shadow_EditLights_Clear_f(void)
3119 R_Shadow_ClearWorldLights();
3122 void R_Shadow_EditLights_Reload_f(void)
3124 if (!r_refdef.worldmodel)
3126 strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3127 R_Shadow_ClearWorldLights();
3128 R_Shadow_LoadWorldLights();
3129 if (r_shadow_worldlightchain == NULL)
3131 R_Shadow_LoadLightsFile();
3132 if (r_shadow_worldlightchain == NULL)
3133 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3137 void R_Shadow_EditLights_Save_f(void)
3139 if (!r_refdef.worldmodel)
3141 R_Shadow_SaveWorldLights();
3144 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3146 R_Shadow_ClearWorldLights();
3147 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3150 void R_Shadow_EditLights_ImportLightsFile_f(void)
3152 R_Shadow_ClearWorldLights();
3153 R_Shadow_LoadLightsFile();
3156 void R_Shadow_EditLights_Spawn_f(void)
3159 if (!r_editlights.integer)
3161 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3164 if (Cmd_Argc() != 1)
3166 Con_Print("r_editlights_spawn does not take parameters\n");
3169 color[0] = color[1] = color[2] = 1;
3170 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3173 void R_Shadow_EditLights_Edit_f(void)
3175 vec3_t origin, angles, color;
3176 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3177 int style, shadows, flags, normalmode, realtimemode;
3178 char cubemapname[MAX_INPUTLINE];
3179 if (!r_editlights.integer)
3181 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3184 if (!r_shadow_selectedlight)
3186 Con_Print("No selected light.\n");
3189 VectorCopy(r_shadow_selectedlight->origin, origin);
3190 VectorCopy(r_shadow_selectedlight->angles, angles);
3191 VectorCopy(r_shadow_selectedlight->color, color);
3192 radius = r_shadow_selectedlight->radius;
3193 style = r_shadow_selectedlight->style;
3194 if (r_shadow_selectedlight->cubemapname)
3195 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
3198 shadows = r_shadow_selectedlight->shadow;
3199 corona = r_shadow_selectedlight->corona;
3200 coronasizescale = r_shadow_selectedlight->coronasizescale;
3201 ambientscale = r_shadow_selectedlight->ambientscale;
3202 diffusescale = r_shadow_selectedlight->diffusescale;
3203 specularscale = r_shadow_selectedlight->specularscale;
3204 flags = r_shadow_selectedlight->flags;
3205 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3206 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3207 if (!strcmp(Cmd_Argv(1), "origin"))
3209 if (Cmd_Argc() != 5)
3211 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3214 origin[0] = atof(Cmd_Argv(2));
3215 origin[1] = atof(Cmd_Argv(3));
3216 origin[2] = atof(Cmd_Argv(4));
3218 else if (!strcmp(Cmd_Argv(1), "originx"))
3220 if (Cmd_Argc() != 3)
3222 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3225 origin[0] = atof(Cmd_Argv(2));
3227 else if (!strcmp(Cmd_Argv(1), "originy"))
3229 if (Cmd_Argc() != 3)
3231 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3234 origin[1] = atof(Cmd_Argv(2));
3236 else if (!strcmp(Cmd_Argv(1), "originz"))
3238 if (Cmd_Argc() != 3)
3240 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3243 origin[2] = atof(Cmd_Argv(2));
3245 else if (!strcmp(Cmd_Argv(1), "move"))
3247 if (Cmd_Argc() != 5)
3249 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3252 origin[0] += atof(Cmd_Argv(2));
3253 origin[1] += atof(Cmd_Argv(3));
3254 origin[2] += atof(Cmd_Argv(4));
3256 else if (!strcmp(Cmd_Argv(1), "movex"))
3258 if (Cmd_Argc() != 3)
3260 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3263 origin[0] += atof(Cmd_Argv(2));
3265 else if (!strcmp(Cmd_Argv(1), "movey"))
3267 if (Cmd_Argc() != 3)
3269 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3272 origin[1] += atof(Cmd_Argv(2));
3274 else if (!strcmp(Cmd_Argv(1), "movez"))
3276 if (Cmd_Argc() != 3)
3278 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3281 origin[2] += atof(Cmd_Argv(2));
3283 else if (!strcmp(Cmd_Argv(1), "angles"))
3285 if (Cmd_Argc() != 5)
3287 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3290 angles[0] = atof(Cmd_Argv(2));
3291 angles[1] = atof(Cmd_Argv(3));
3292 angles[2] = atof(Cmd_Argv(4));
3294 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3296 if (Cmd_Argc() != 3)
3298 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3301 angles[0] = atof(Cmd_Argv(2));
3303 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3305 if (Cmd_Argc() != 3)
3307 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3310 angles[1] = atof(Cmd_Argv(2));
3312 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3314 if (Cmd_Argc() != 3)
3316 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3319 angles[2] = atof(Cmd_Argv(2));
3321 else if (!strcmp(Cmd_Argv(1), "color"))
3323 if (Cmd_Argc() != 5)
3325 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3328 color[0] = atof(Cmd_Argv(2));
3329 color[1] = atof(Cmd_Argv(3));
3330 color[2] = atof(Cmd_Argv(4));
3332 else if (!strcmp(Cmd_Argv(1), "radius"))
3334 if (Cmd_Argc() != 3)
3336 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3339 radius = atof(Cmd_Argv(2));
3341 else if (!strcmp(Cmd_Argv(1), "colorscale"))
3343 if (Cmd_Argc() == 3)
3345 double scale = atof(Cmd_Argv(2));
3352 if (Cmd_Argc() != 5)
3354 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
3357 color[0] *= atof(Cmd_Argv(2));
3358 color[1] *= atof(Cmd_Argv(3));
3359 color[2] *= atof(Cmd_Argv(4));
3362 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
3364 if (Cmd_Argc() != 3)
3366 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3369 radius *= atof(Cmd_Argv(2));
3371 else if (!strcmp(Cmd_Argv(1), "style"))
3373 if (Cmd_Argc() != 3)
3375 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3378 style = atoi(Cmd_Argv(2));
3380 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3384 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3387 if (Cmd_Argc() == 3)
3388 strcpy(cubemapname, Cmd_Argv(2));
3392 else if (!strcmp(Cmd_Argv(1), "shadows"))
3394 if (Cmd_Argc() != 3)
3396 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3399 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3401 else if (!strcmp(Cmd_Argv(1), "corona"))
3403 if (Cmd_Argc() != 3)
3405 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3408 corona = atof(Cmd_Argv(2));
3410 else if (!strcmp(Cmd_Argv(1), "coronasize"))
3412 if (Cmd_Argc() != 3)
3414 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3417 coronasizescale = atof(Cmd_Argv(2));
3419 else if (!strcmp(Cmd_Argv(1), "ambient"))
3421 if (Cmd_Argc() != 3)
3423 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3426 ambientscale = atof(Cmd_Argv(2));
3428 else if (!strcmp(Cmd_Argv(1), "diffuse"))
3430 if (Cmd_Argc() != 3)
3432 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3435 diffusescale = atof(Cmd_Argv(2));
3437 else if (!strcmp(Cmd_Argv(1), "specular"))
3439 if (Cmd_Argc() != 3)
3441 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3444 specularscale = atof(Cmd_Argv(2));
3446 else if (!strcmp(Cmd_Argv(1), "normalmode"))
3448 if (Cmd_Argc() != 3)
3450 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3453 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3455 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
3457 if (Cmd_Argc() != 3)
3459 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3462 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3466 Con_Print("usage: r_editlights_edit [property] [value]\n");
3467 Con_Print("Selected light's properties:\n");
3468 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3469 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3470 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3471 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3472 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3473 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3474 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3475 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
3476 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
3477 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
3478 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
3479 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
3480 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
3481 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
3484 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
3485 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3488 void R_Shadow_EditLights_EditAll_f(void)
3492 if (!r_editlights.integer)
3494 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
3498 for (light = r_shadow_worldlightchain;light;light = light->next)
3500 R_Shadow_SelectLight(light);
3501 R_Shadow_EditLights_Edit_f();
3505 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3507 int lightnumber, lightcount;
3511 if (!r_editlights.integer)
3517 for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
3518 if (light == r_shadow_selectedlight)
3519 lightnumber = lightcount;
3520 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;
3521 if (r_shadow_selectedlight == NULL)
3523 sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3524 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;
3525 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;
3526 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;
3527 sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3528 sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3529 sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3530 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;
3531 sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3532 sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3533 sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3534 sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3535 sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3536 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;
3537 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;
3540 void R_Shadow_EditLights_ToggleShadow_f(void)
3542 if (!r_editlights.integer)
3544 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3547 if (!r_shadow_selectedlight)
3549 Con_Print("No selected light.\n");
3552 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);
3555 void R_Shadow_EditLights_ToggleCorona_f(void)
3557 if (!r_editlights.integer)
3559 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3562 if (!r_shadow_selectedlight)
3564 Con_Print("No selected light.\n");
3567 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);
3570 void R_Shadow_EditLights_Remove_f(void)
3572 if (!r_editlights.integer)
3574 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
3577 if (!r_shadow_selectedlight)
3579 Con_Print("No selected light.\n");
3582 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3583 r_shadow_selectedlight = NULL;
3586 void R_Shadow_EditLights_Help_f(void)
3589 "Documentation on r_editlights system:\n"
3591 "r_editlights : enable/disable editing mode\n"
3592 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
3593 "r_editlights_cursorpushback : push back cursor this far from surface\n"
3594 "r_editlights_cursorpushoff : push cursor off surface this far\n"
3595 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
3596 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
3598 "r_editlights_help : this help\n"
3599 "r_editlights_clear : remove all lights\n"
3600 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
3601 "r_editlights_save : save to .rtlights file\n"
3602 "r_editlights_spawn : create a light with default settings\n"
3603 "r_editlights_edit command : edit selected light - more documentation below\n"
3604 "r_editlights_remove : remove selected light\n"
3605 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
3606 "r_editlights_importlightentitiesfrommap : reload light entities\n"
3607 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
3609 "origin x y z : set light location\n"
3610 "originx x: set x component of light location\n"
3611 "originy y: set y component of light location\n"
3612 "originz z: set z component of light location\n"
3613 "move x y z : adjust light location\n"
3614 "movex x: adjust x component of light location\n"
3615 "movey y: adjust y component of light location\n"
3616 "movez z: adjust z component of light location\n"
3617 "angles x y z : set light angles\n"
3618 "anglesx x: set x component of light angles\n"
3619 "anglesy y: set y component of light angles\n"
3620 "anglesz z: set z component of light angles\n"
3621 "color r g b : set color of light (can be brighter than 1 1 1)\n"
3622 "radius radius : set radius (size) of light\n"
3623 "colorscale grey : multiply color of light (1 does nothing)\n"
3624 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
3625 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
3626 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
3627 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
3628 "cubemap basename : set filter cubemap of light (not yet supported)\n"
3629 "shadows 1/0 : turn on/off shadows\n"
3630 "corona n : set corona intensity\n"
3631 "coronasize n : set corona size (0-1)\n"
3632 "ambient n : set ambient intensity (0-1)\n"
3633 "diffuse n : set diffuse intensity (0-1)\n"
3634 "specular n : set specular intensity (0-1)\n"
3635 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
3636 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
3637 "<nothing> : print light properties to console\n"
3641 void R_Shadow_EditLights_CopyInfo_f(void)
3643 if (!r_editlights.integer)
3645 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
3648 if (!r_shadow_selectedlight)
3650 Con_Print("No selected light.\n");
3653 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
3654 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
3655 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
3656 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
3657 if (r_shadow_selectedlight->cubemapname)
3658 strcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname);
3660 r_shadow_bufferlight.cubemapname[0] = 0;
3661 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
3662 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
3663 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
3664 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
3665 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
3666 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
3667 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
3670 void R_Shadow_EditLights_PasteInfo_f(void)
3672 if (!r_editlights.integer)
3674 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
3677 if (!r_shadow_selectedlight)
3679 Con_Print("No selected light.\n");
3682 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);
3685 void R_Shadow_EditLights_Init(void)
3687 Cvar_RegisterVariable(&r_editlights);
3688 Cvar_RegisterVariable(&r_editlights_cursordistance);
3689 Cvar_RegisterVariable(&r_editlights_cursorpushback);
3690 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
3691 Cvar_RegisterVariable(&r_editlights_cursorgrid);
3692 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
3693 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
3694 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
3695 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)");
3696 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
3697 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
3698 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
3699 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)");
3700 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
3701 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
3702 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
3703 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
3704 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
3705 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
3706 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)");