]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - r_shadow.c
added r_shadows cvar which renders Quake3 cg_shadows 2 style stencil shadows from...
[xonotic/darkplaces.git] / r_shadow.c
1
2 /*
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)
9
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.
15
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).
22
23 Patent warning:
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).
29
30
31
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).
38
39
40
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
46 in some ideal cases).
47
48
49
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.
60
61
62
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.
69
70
71
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.
80
81
82
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
89 texturing).
90
91
92
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).
96
97
98
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.
103
104
105
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
114 this however).
115
116
117
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
127 other areas).
128
129
130
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.
135 */
136
137 #include "quakedef.h"
138 #include "r_shadow.h"
139 #include "cl_collision.h"
140 #include "portals.h"
141 #include "image.h"
142
143 extern void R_Shadow_EditLights_Init(void);
144
145 typedef enum r_shadow_rendermode_e
146 {
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,
155 }
156 r_shadow_rendermode_t;
157
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;
161
162 int maxshadowtriangles;
163 int *shadowelements;
164
165 int maxshadowvertices;
166 float *shadowvertex3f;
167
168 int maxshadowmark;
169 int numshadowmark;
170 int *shadowmark;
171 int *shadowmarklist;
172 int shadowmarkcount;
173
174 int maxvertexupdate;
175 int *vertexupdate;
176 int *vertexremap;
177 int vertexupdatenum;
178
179 int r_shadow_buffer_numleafpvsbytes;
180 unsigned char *r_shadow_buffer_leafpvs;
181 int *r_shadow_buffer_leaflist;
182
183 int r_shadow_buffer_numsurfacepvsbytes;
184 unsigned char *r_shadow_buffer_surfacepvs;
185 int *r_shadow_buffer_surfacelist;
186
187 rtexturepool_t *r_shadow_texturepool;
188 rtexture_t *r_shadow_attenuation2dtexture;
189 rtexture_t *r_shadow_attenuation3dtexture;
190
191 // lights are reloaded when this changes
192 char r_shadow_mapname[MAX_QPATH];
193
194 // used only for light filters (cubemaps)
195 rtexturepool_t *r_shadow_filters_texturepool;
196
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"};
228
229 float r_shadow_attenpower, r_shadow_attenscale;
230
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;
236
237 extern int con_vislines;
238
239 typedef struct cubemapinfo_s
240 {
241         char basename[64];
242         rtexture_t *texture;
243 }
244 cubemapinfo_t;
245
246 #define MAX_CUBEMAPS 256
247 static int numcubemaps;
248 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
249
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);
260
261 void r_shadow_start(void)
262 {
263         // allocate vertex processing arrays
264         numcubemaps = 0;
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;
275         maxvertexupdate = 0;
276         vertexupdate = NULL;
277         vertexremap = NULL;
278         vertexupdatenum = 0;
279         maxshadowmark = 0;
280         numshadowmark = 0;
281         shadowmark = NULL;
282         shadowmarklist = NULL;
283         shadowmarkcount = 0;
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;
290 }
291
292 void r_shadow_shutdown(void)
293 {
294         R_Shadow_UncompileWorldLights();
295         numcubemaps = 0;
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;
301         if (shadowelements)
302                 Mem_Free(shadowelements);
303         shadowelements = NULL;
304         if (shadowvertex3f)
305                 Mem_Free(shadowvertex3f);
306         shadowvertex3f = NULL;
307         maxvertexupdate = 0;
308         if (vertexupdate)
309                 Mem_Free(vertexupdate);
310         vertexupdate = NULL;
311         if (vertexremap)
312                 Mem_Free(vertexremap);
313         vertexremap = NULL;
314         vertexupdatenum = 0;
315         maxshadowmark = 0;
316         numshadowmark = 0;
317         if (shadowmark)
318                 Mem_Free(shadowmark);
319         shadowmark = NULL;
320         if (shadowmarklist)
321                 Mem_Free(shadowmarklist);
322         shadowmarklist = NULL;
323         shadowmarkcount = 0;
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;
338 }
339
340 void r_shadow_newmap(void)
341 {
342 }
343
344 void R_Shadow_Help_f(void)
345 {
346         Con_Printf(
347 "Documentation on r_shadow system:\n"
348 "Settings:\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"
375 "Commands:\n"
376 "r_shadow_help : this help\n"
377         );
378 }
379
380 void R_Shadow_Init(void)
381 {
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)
408         {
409                 Cvar_SetValue("r_shadow_gloss", 2);
410                 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
411         }
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;
419         maxvertexupdate = 0;
420         vertexupdate = NULL;
421         vertexremap = NULL;
422         vertexupdatenum = 0;
423         maxshadowmark = 0;
424         numshadowmark = 0;
425         shadowmark = NULL;
426         shadowmarklist = NULL;
427         shadowmarkcount = 0;
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);
435 }
436
437 matrix4x4_t matrix_attenuationxyz =
438 {
439         {
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},
443                 {0.0, 0.0, 0.0, 1.0}
444         }
445 };
446
447 matrix4x4_t matrix_attenuationz =
448 {
449         {
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},
453                 {0.0, 0.0, 0.0, 1.0}
454         }
455 };
456
457 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles)
458 {
459         // make sure shadowelements is big enough for this volume
460         if (maxshadowtriangles < numtriangles)
461         {
462                 maxshadowtriangles = numtriangles;
463                 if (shadowelements)
464                         Mem_Free(shadowelements);
465                 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[24]));
466         }
467         // make sure shadowvertex3f is big enough for this volume
468         if (maxshadowvertices < numvertices)
469         {
470                 maxshadowvertices = numvertices;
471                 if (shadowvertex3f)
472                         Mem_Free(shadowvertex3f);
473                 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[6]));
474         }
475 }
476
477 static void R_Shadow_EnlargeLeafSurfaceBuffer(int numleafs, int numsurfaces)
478 {
479         int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
480         int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
481         if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
482         {
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));
490         }
491         if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
492         {
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));
500         }
501 }
502
503 void R_Shadow_PrepareShadowMark(int numtris)
504 {
505         // make sure shadowmark is big enough for this volume
506         if (maxshadowmark < numtris)
507         {
508                 maxshadowmark = numtris;
509                 if (shadowmark)
510                         Mem_Free(shadowmark);
511                 if (shadowmarklist)
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));
515                 shadowmarkcount = 0;
516         }
517         shadowmarkcount++;
518         // if shadowmarkcount wrapped we clear the array and adjust accordingly
519         if (shadowmarkcount == 0)
520         {
521                 shadowmarkcount = 1;
522                 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
523         }
524         numshadowmark = 0;
525 }
526
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, const float *projectdirection, float projectdistance, int numshadowmarktris, const int *shadowmarktris)
528 {
529         int i, j;
530         int outtriangles = 0, outvertices = 0;
531         const int *element;
532         const float *vertex;
533         float ratio, direction[3], projectvector[3];
534
535         if (projectdirection)
536                 VectorScale(projectdirection, projectdistance, projectvector);
537         else
538                 VectorClear(projectvector);
539
540         if (maxvertexupdate < innumvertices)
541         {
542                 maxvertexupdate = innumvertices;
543                 if (vertexupdate)
544                         Mem_Free(vertexupdate);
545                 if (vertexremap)
546                         Mem_Free(vertexremap);
547                 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
548                 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
549                 vertexupdatenum = 0;
550         }
551         vertexupdatenum++;
552         if (vertexupdatenum == 0)
553         {
554                 vertexupdatenum = 1;
555                 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
556                 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
557         }
558
559         for (i = 0;i < numshadowmarktris;i++)
560                 shadowmark[shadowmarktris[i]] = shadowmarkcount;
561
562         // create the vertices
563         if (projectdirection)
564         {
565                 for (i = 0;i < numshadowmarktris;i++)
566                 {
567                         element = inelement3i + shadowmarktris[i] * 3;
568                         for (j = 0;j < 3;j++)
569                         {
570                                 if (vertexupdate[element[j]] != vertexupdatenum)
571                                 {
572                                         vertexupdate[element[j]] = vertexupdatenum;
573                                         vertexremap[element[j]] = outvertices;
574                                         vertex = invertex3f + element[j] * 3;
575                                         // project one copy of the vertex according to projectvector
576                                         VectorCopy(vertex, outvertex3f);
577                                         VectorAdd(vertex, projectvector, (outvertex3f + 3));
578                                         outvertex3f += 6;
579                                         outvertices += 2;
580                                 }
581                         }
582                 }
583         }
584         else
585         {
586                 for (i = 0;i < numshadowmarktris;i++)
587                 {
588                         element = inelement3i + shadowmarktris[i] * 3;
589                         for (j = 0;j < 3;j++)
590                         {
591                                 if (vertexupdate[element[j]] != vertexupdatenum)
592                                 {
593                                         vertexupdate[element[j]] = vertexupdatenum;
594                                         vertexremap[element[j]] = outvertices;
595                                         vertex = invertex3f + element[j] * 3;
596                                         // project one copy of the vertex to the sphere radius of the light
597                                         // (FIXME: would projecting it to the light box be better?)
598                                         VectorSubtract(vertex, projectorigin, direction);
599                                         ratio = projectdistance / VectorLength(direction);
600                                         VectorCopy(vertex, outvertex3f);
601                                         VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
602                                         outvertex3f += 6;
603                                         outvertices += 2;
604                                 }
605                         }
606                 }
607         }
608
609         for (i = 0;i < numshadowmarktris;i++)
610         {
611                 int remappedelement[3];
612                 int markindex;
613                 const int *neighbortriangle;
614
615                 markindex = shadowmarktris[i] * 3;
616                 element = inelement3i + markindex;
617                 neighbortriangle = inneighbor3i + markindex;
618                 // output the front and back triangles
619                 outelement3i[0] = vertexremap[element[0]];
620                 outelement3i[1] = vertexremap[element[1]];
621                 outelement3i[2] = vertexremap[element[2]];
622                 outelement3i[3] = vertexremap[element[2]] + 1;
623                 outelement3i[4] = vertexremap[element[1]] + 1;
624                 outelement3i[5] = vertexremap[element[0]] + 1;
625
626                 outelement3i += 6;
627                 outtriangles += 2;
628                 // output the sides (facing outward from this triangle)
629                 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
630                 {
631                         remappedelement[0] = vertexremap[element[0]];
632                         remappedelement[1] = vertexremap[element[1]];
633                         outelement3i[0] = remappedelement[1];
634                         outelement3i[1] = remappedelement[0];
635                         outelement3i[2] = remappedelement[0] + 1;
636                         outelement3i[3] = remappedelement[1];
637                         outelement3i[4] = remappedelement[0] + 1;
638                         outelement3i[5] = remappedelement[1] + 1;
639
640                         outelement3i += 6;
641                         outtriangles += 2;
642                 }
643                 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
644                 {
645                         remappedelement[1] = vertexremap[element[1]];
646                         remappedelement[2] = vertexremap[element[2]];
647                         outelement3i[0] = remappedelement[2];
648                         outelement3i[1] = remappedelement[1];
649                         outelement3i[2] = remappedelement[1] + 1;
650                         outelement3i[3] = remappedelement[2];
651                         outelement3i[4] = remappedelement[1] + 1;
652                         outelement3i[5] = remappedelement[2] + 1;
653
654                         outelement3i += 6;
655                         outtriangles += 2;
656                 }
657                 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
658                 {
659                         remappedelement[0] = vertexremap[element[0]];
660                         remappedelement[2] = vertexremap[element[2]];
661                         outelement3i[0] = remappedelement[0];
662                         outelement3i[1] = remappedelement[2];
663                         outelement3i[2] = remappedelement[2] + 1;
664                         outelement3i[3] = remappedelement[0];
665                         outelement3i[4] = remappedelement[2] + 1;
666                         outelement3i[5] = remappedelement[0] + 1;
667
668                         outelement3i += 6;
669                         outtriangles += 2;
670                 }
671         }
672         if (outnumvertices)
673                 *outnumvertices = outvertices;
674         return outtriangles;
675 }
676
677 void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, const vec3_t projectdirection, float projectdistance, int nummarktris, const int *marktris)
678 {
679         int tris, outverts;
680         if (projectdistance < 0.1)
681         {
682                 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
683                 return;
684         }
685         if (!numverts || !nummarktris)
686                 return;
687         // make sure shadowelements is big enough for this volume
688         if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
689                 R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
690         tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
691         r_refdef.stats.lights_dynamicshadowtriangles += tris;
692         R_Shadow_RenderVolume(outverts, tris, shadowvertex3f, shadowelements);
693 }
694
695 void R_Shadow_MarkVolumeFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const vec3_t projectorigin, const vec3_t projectdirection, const vec3_t lightmins, const vec3_t lightmaxs, const vec3_t surfacemins, const vec3_t surfacemaxs)
696 {
697         int t, tend;
698         const int *e;
699         const float *v[3];
700         float normal[3];
701         if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
702                 return;
703         tend = firsttriangle + numtris;
704         if (surfacemins[0] >= lightmins[0] && surfacemaxs[0] <= lightmaxs[0]
705          && surfacemins[1] >= lightmins[1] && surfacemaxs[1] <= lightmaxs[1]
706          && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2])
707         {
708                 // surface box entirely inside light box, no box cull
709                 if (projectdirection)
710                 {
711                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
712                         {
713                                 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
714                                 if (DotProduct(normal, projectdirection) < 0)
715                                         shadowmarklist[numshadowmark++] = t;
716                         }
717                 }
718                 else
719                 {
720                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
721                                 if (PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
722                                         shadowmarklist[numshadowmark++] = t;
723                 }
724         }
725         else
726         {
727                 // surface box not entirely inside light box, cull each triangle
728                 if (projectdirection)
729                 {
730                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
731                         {
732                                 v[0] = invertex3f + e[0] * 3;
733                                 v[1] = invertex3f + e[1] * 3;
734                                 v[2] = invertex3f + e[2] * 3;
735                                 TriangleNormal(v[0], v[1], v[2], normal);
736                                 if (DotProduct(normal, projectdirection) < 0
737                                  && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
738                                  && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
739                                  && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
740                                  && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
741                                  && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
742                                  && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
743                                         shadowmarklist[numshadowmark++] = t;
744                         }
745                 }
746                 else
747                 {
748                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
749                         {
750                                 v[0] = invertex3f + e[0] * 3;
751                                 v[1] = invertex3f + e[1] * 3;
752                                 v[2] = invertex3f + e[2] * 3;
753                                 if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
754                                  && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
755                                  && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
756                                  && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
757                                  && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
758                                  && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
759                                  && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
760                                         shadowmarklist[numshadowmark++] = t;
761                         }
762                 }
763         }
764 }
765
766 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
767 {
768         if (r_shadow_compilingrtlight)
769         {
770                 // if we're compiling an rtlight, capture the mesh
771                 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
772                 return;
773         }
774         r_refdef.stats.lights_shadowtriangles += numtriangles;
775         CHECKGLERROR
776         R_Mesh_VertexPointer(vertex3f);
777         GL_LockArrays(0, numvertices);
778         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
779         {
780                 // decrement stencil if backface is behind depthbuffer
781                 GL_CullFace(GL_BACK); // quake is backwards, this culls front faces
782                 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
783                 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
784                 // increment stencil if frontface is behind depthbuffer
785                 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
786                 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
787         }
788         R_Mesh_Draw(0, numvertices, numtriangles, element3i);
789         GL_LockArrays(0, 0);
790         CHECKGLERROR
791 }
792
793 static void R_Shadow_MakeTextures(void)
794 {
795         int x, y, z, d;
796         float v[3], intensity;
797         unsigned char *data;
798         R_FreeTexturePool(&r_shadow_texturepool);
799         r_shadow_texturepool = R_AllocTexturePool();
800         r_shadow_attenpower = r_shadow_lightattenuationpower.value;
801         r_shadow_attenscale = r_shadow_lightattenuationscale.value;
802 #define ATTEN2DSIZE 64
803 #define ATTEN3DSIZE 32
804         data = (unsigned char *)Mem_Alloc(tempmempool, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4));
805         for (y = 0;y < ATTEN2DSIZE;y++)
806         {
807                 for (x = 0;x < ATTEN2DSIZE;x++)
808                 {
809                         v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
810                         v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
811                         v[2] = 0;
812                         intensity = 1.0f - sqrt(DotProduct(v, v));
813                         if (intensity > 0)
814                                 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
815                         d = (int)bound(0, intensity, 255);
816                         data[(y*ATTEN2DSIZE+x)*4+0] = d;
817                         data[(y*ATTEN2DSIZE+x)*4+1] = d;
818                         data[(y*ATTEN2DSIZE+x)*4+2] = d;
819                         data[(y*ATTEN2DSIZE+x)*4+3] = d;
820                 }
821         }
822         r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
823         if (r_shadow_texture3d.integer && gl_texture3d)
824         {
825                 for (z = 0;z < ATTEN3DSIZE;z++)
826                 {
827                         for (y = 0;y < ATTEN3DSIZE;y++)
828                         {
829                                 for (x = 0;x < ATTEN3DSIZE;x++)
830                                 {
831                                         v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
832                                         v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
833                                         v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
834                                         intensity = 1.0f - sqrt(DotProduct(v, v));
835                                         if (intensity > 0)
836                                                 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
837                                         d = (int)bound(0, intensity, 255);
838                                         data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
839                                         data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
840                                         data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
841                                         data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
842                                 }
843                         }
844                 }
845                 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
846         }
847         Mem_Free(data);
848 }
849
850 void R_Shadow_ValidateCvars(void)
851 {
852         if (r_shadow_texture3d.integer && !gl_texture3d)
853                 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
854         if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
855                 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
856 }
857
858 // light currently being rendered
859 rtlight_t *r_shadow_rtlight;
860
861 // this is the location of the light in entity space
862 vec3_t r_shadow_entitylightorigin;
863 // this transforms entity coordinates to light filter cubemap coordinates
864 // (also often used for other purposes)
865 matrix4x4_t r_shadow_entitytolight;
866 // based on entitytolight this transforms -1 to +1 to 0 to 1 for purposes
867 // of attenuation texturing in full 3D (Z result often ignored)
868 matrix4x4_t r_shadow_entitytoattenuationxyz;
869 // this transforms only the Z to S, and T is always 0.5
870 matrix4x4_t r_shadow_entitytoattenuationz;
871
872 void R_Shadow_RenderMode_Begin(void)
873 {
874         R_Shadow_ValidateCvars();
875
876         if (!r_shadow_attenuation2dtexture
877          || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
878          || r_shadow_lightattenuationpower.value != r_shadow_attenpower
879          || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
880                 R_Shadow_MakeTextures();
881
882         CHECKGLERROR
883         R_Mesh_ColorPointer(NULL);
884         R_Mesh_ResetTextureState();
885         GL_BlendFunc(GL_ONE, GL_ZERO);
886         GL_DepthMask(false);
887         GL_Color(0, 0, 0, 1);
888         GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
889
890         r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
891
892         if (gl_ext_stenciltwoside.integer)
893                 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
894         else
895                 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
896
897         if (r_glsl.integer && gl_support_fragment_shader)
898                 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
899         else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
900                 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
901         else
902                 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
903 }
904
905 void R_Shadow_RenderMode_ActiveLight(rtlight_t *rtlight)
906 {
907         r_shadow_rtlight = rtlight;
908 }
909
910 void R_Shadow_RenderMode_Reset(void)
911 {
912         CHECKGLERROR
913         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
914         {
915                 qglUseProgramObjectARB(0);CHECKGLERROR
916         }
917         else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
918         {
919                 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
920         }
921         R_Mesh_ColorPointer(NULL);
922         R_Mesh_ResetTextureState();
923 }
924
925 void R_Shadow_RenderMode_StencilShadowVolumes(void)
926 {
927         CHECKGLERROR
928         R_Shadow_RenderMode_Reset();
929         GL_Color(1, 1, 1, 1);
930         GL_ColorMask(0, 0, 0, 0);
931         GL_BlendFunc(GL_ONE, GL_ZERO);
932         GL_DepthMask(false);
933         qglPolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
934         qglDepthFunc(GL_LESS);CHECKGLERROR
935         qglEnable(GL_STENCIL_TEST);CHECKGLERROR
936         qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
937         r_shadow_rendermode = r_shadow_shadowingrendermode;
938         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
939         {
940                 GL_CullFace(GL_NONE);
941                 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
942                 qglActiveStencilFaceEXT(GL_BACK);CHECKGLERROR // quake is backwards, this is front faces
943                 qglStencilMask(~0);CHECKGLERROR
944                 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
945                 qglActiveStencilFaceEXT(GL_FRONT);CHECKGLERROR // quake is backwards, this is back faces
946                 qglStencilMask(~0);CHECKGLERROR
947                 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
948         }
949         else
950         {
951                 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
952                 qglStencilMask(~0);CHECKGLERROR
953                 // this is changed by every shadow render so its value here is unimportant
954                 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
955         }
956         GL_Clear(GL_STENCIL_BUFFER_BIT);
957         r_refdef.stats.lights_clears++;
958 }
959
960 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent)
961 {
962         CHECKGLERROR
963         R_Shadow_RenderMode_Reset();
964         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
965         GL_DepthMask(false);
966         qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
967         //qglDisable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
968         GL_Color(1, 1, 1, 1);
969         GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
970         if (transparent)
971         {
972                 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
973         }
974         else
975         {
976                 qglDepthFunc(GL_EQUAL);CHECKGLERROR
977         }
978         if (stenciltest)
979         {
980                 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
981         }
982         else
983         {
984                 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
985         }
986         qglStencilMask(~0);CHECKGLERROR
987         qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
988         // only draw light where this geometry was already rendered AND the
989         // stencil is 128 (values other than this mean shadow)
990         qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
991         r_shadow_rendermode = r_shadow_lightingrendermode;
992         // do global setup needed for the chosen lighting mode
993         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
994         {
995                 R_Mesh_TexBind(0, R_GetTexture(r_texture_blanknormalmap)); // normal
996                 R_Mesh_TexBind(1, R_GetTexture(r_texture_white)); // diffuse
997                 R_Mesh_TexBind(2, R_GetTexture(r_texture_white)); // gloss
998                 R_Mesh_TexBindCubeMap(3, R_GetTexture(r_shadow_rtlight->currentcubemap)); // light filter
999                 R_Mesh_TexBind(4, R_GetTexture(r_texture_fogattenuation)); // fog
1000                 R_Mesh_TexBind(5, R_GetTexture(r_texture_white)); // pants
1001                 R_Mesh_TexBind(6, R_GetTexture(r_texture_white)); // shirt
1002                 R_Mesh_TexBind(7, R_GetTexture(r_texture_white)); // lightmap
1003                 R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap)); // deluxemap
1004                 R_Mesh_TexBind(9, R_GetTexture(r_texture_black)); // glow
1005                 //R_Mesh_TexMatrix(3, r_shadow_entitytolight); // light filter matrix
1006                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1007                 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 0);
1008                 CHECKGLERROR
1009         }
1010 }
1011
1012 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
1013 {
1014         CHECKGLERROR
1015         R_Shadow_RenderMode_Reset();
1016         GL_BlendFunc(GL_ONE, GL_ONE);
1017         GL_DepthMask(false);
1018         qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1019         GL_Color(0.0, 0.0125 * r_view.colorscale, 0.1 * r_view.colorscale, 1);
1020         GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
1021         if (r_showshadowvolumes.integer >= 2)
1022         {
1023                 qglDepthFunc(GL_ALWAYS);CHECKGLERROR
1024         }
1025         else
1026         {
1027                 qglDepthFunc(GL_GEQUAL);CHECKGLERROR
1028         }
1029         qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1030         r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
1031 }
1032
1033 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
1034 {
1035         CHECKGLERROR
1036         R_Shadow_RenderMode_Reset();
1037         GL_BlendFunc(GL_ONE, GL_ONE);
1038         GL_DepthMask(false);
1039         qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1040         GL_Color(0.1 * r_view.colorscale, 0.0125 * r_view.colorscale, 0, 1);
1041         GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
1042         if (r_showshadowvolumes.integer >= 2)
1043         {
1044                 qglDepthFunc(GL_ALWAYS);CHECKGLERROR
1045         }
1046         else if (transparent)
1047         {
1048                 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1049         }
1050         else
1051         {
1052                 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1053         }
1054         if (stenciltest)
1055         {
1056                 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1057         }
1058         else
1059         {
1060                 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1061         }
1062         r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
1063 }
1064
1065 void R_Shadow_RenderMode_End(void)
1066 {
1067         CHECKGLERROR
1068         R_Shadow_RenderMode_Reset();
1069         R_Shadow_RenderMode_ActiveLight(NULL);
1070         GL_BlendFunc(GL_ONE, GL_ZERO);
1071         GL_DepthMask(true);
1072         qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1073         //qglDisable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
1074         GL_Color(1, 1, 1, 1);
1075         GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
1076         GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
1077         qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1078         qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1079         qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1080         if (gl_support_stenciltwoside)
1081         {
1082                 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1083         }
1084         qglStencilMask(~0);CHECKGLERROR
1085         qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1086         r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1087 }
1088
1089 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1090 {
1091         int i, ix1, iy1, ix2, iy2;
1092         float x1, y1, x2, y2;
1093         vec4_t v, v2;
1094         rmesh_t mesh;
1095         mplane_t planes[11];
1096         float vertex3f[256*3];
1097
1098         // if view is inside the light box, just say yes it's visible
1099         if (BoxesOverlap(r_view.origin, r_view.origin, mins, maxs))
1100         {
1101                 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
1102                 return false;
1103         }
1104
1105         // create a temporary brush describing the area the light can affect in worldspace
1106         VectorNegate(r_view.frustum[0].normal, planes[ 0].normal);planes[ 0].dist = -r_view.frustum[0].dist;
1107         VectorNegate(r_view.frustum[1].normal, planes[ 1].normal);planes[ 1].dist = -r_view.frustum[1].dist;
1108         VectorNegate(r_view.frustum[2].normal, planes[ 2].normal);planes[ 2].dist = -r_view.frustum[2].dist;
1109         VectorNegate(r_view.frustum[3].normal, planes[ 3].normal);planes[ 3].dist = -r_view.frustum[3].dist;
1110         VectorNegate(r_view.frustum[4].normal, planes[ 4].normal);planes[ 4].dist = -r_view.frustum[4].dist;
1111         VectorSet   (planes[ 5].normal,  1, 0, 0);         planes[ 5].dist =  maxs[0];
1112         VectorSet   (planes[ 6].normal, -1, 0, 0);         planes[ 6].dist = -mins[0];
1113         VectorSet   (planes[ 7].normal, 0,  1, 0);         planes[ 7].dist =  maxs[1];
1114         VectorSet   (planes[ 8].normal, 0, -1, 0);         planes[ 8].dist = -mins[1];
1115         VectorSet   (planes[ 9].normal, 0, 0,  1);         planes[ 9].dist =  maxs[2];
1116         VectorSet   (planes[10].normal, 0, 0, -1);         planes[10].dist = -mins[2];
1117
1118         // turn the brush into a mesh
1119         memset(&mesh, 0, sizeof(rmesh_t));
1120         mesh.maxvertices = 256;
1121         mesh.vertex3f = vertex3f;
1122         mesh.epsilon2 = (1.0f / (32.0f * 32.0f));
1123         R_Mesh_AddBrushMeshFromPlanes(&mesh, 11, planes);
1124
1125         // if that mesh is empty, the light is not visible at all
1126         if (!mesh.numvertices)
1127                 return true;
1128
1129         if (!r_shadow_scissor.integer)
1130                 return false;
1131
1132         // if that mesh is not empty, check what area of the screen it covers
1133         x1 = y1 = x2 = y2 = 0;
1134         v[3] = 1.0f;
1135         //Con_Printf("%i vertices to transform...\n", mesh.numvertices);
1136         for (i = 0;i < mesh.numvertices;i++)
1137         {
1138                 VectorCopy(mesh.vertex3f + i * 3, v);
1139                 GL_TransformToScreen(v, v2);
1140                 //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]);
1141                 if (i)
1142                 {
1143                         if (x1 > v2[0]) x1 = v2[0];
1144                         if (x2 < v2[0]) x2 = v2[0];
1145                         if (y1 > v2[1]) y1 = v2[1];
1146                         if (y2 < v2[1]) y2 = v2[1];
1147                 }
1148                 else
1149                 {
1150                         x1 = x2 = v2[0];
1151                         y1 = y2 = v2[1];
1152                 }
1153         }
1154
1155         // now convert the scissor rectangle to integer screen coordinates
1156         ix1 = (int)(x1 - 1.0f);
1157         iy1 = (int)(y1 - 1.0f);
1158         ix2 = (int)(x2 + 1.0f);
1159         iy2 = (int)(y2 + 1.0f);
1160         //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1161
1162         // clamp it to the screen
1163         if (ix1 < r_view.x) ix1 = r_view.x;
1164         if (iy1 < r_view.y) iy1 = r_view.y;
1165         if (ix2 > r_view.x + r_view.width) ix2 = r_view.x + r_view.width;
1166         if (iy2 > r_view.y + r_view.height) iy2 = r_view.y + r_view.height;
1167
1168         // if it is inside out, it's not visible
1169         if (ix2 <= ix1 || iy2 <= iy1)
1170                 return true;
1171
1172         // the light area is visible, set up the scissor rectangle
1173         GL_Scissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1174         //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);CHECKGLERROR
1175         //qglEnable(GL_SCISSOR_TEST);CHECKGLERROR
1176         r_refdef.stats.lights_scissored++;
1177         return false;
1178 }
1179
1180 static void R_Shadow_RenderSurfacesLighting_Light_Vertex_Shading(const msurface_t *surface, const float *diffusecolor, const float *ambientcolor)
1181 {
1182         int numverts = surface->num_vertices;
1183         float *vertex3f = rsurface_vertex3f + 3 * surface->num_firstvertex;
1184         float *normal3f = rsurface_normal3f + 3 * surface->num_firstvertex;
1185         float *color4f = rsurface_array_color4f + 4 * surface->num_firstvertex;
1186         float dist, dot, distintensity, shadeintensity, v[3], n[3];
1187         if (r_textureunits.integer >= 3)
1188         {
1189                 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1190                 {
1191                         Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1192                         Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1193                         if ((dot = DotProduct(n, v)) < 0)
1194                         {
1195                                 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1196                                 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]);
1197                                 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]);
1198                                 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]);
1199                                 if (r_refdef.fogenabled)
1200                                 {
1201                                         float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
1202                                         VectorScale(color4f, f, color4f);
1203                                 }
1204                         }
1205                         else
1206                                 VectorClear(color4f);
1207                         color4f[3] = 1;
1208                 }
1209         }
1210         else if (r_textureunits.integer >= 2)
1211         {
1212                 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1213                 {
1214                         Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1215                         if ((dist = fabs(v[2])) < 1)
1216                         {
1217                                 distintensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1218                                 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1219                                 if ((dot = DotProduct(n, v)) < 0)
1220                                 {
1221                                         shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1222                                         color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1223                                         color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1224                                         color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1225                                 }
1226                                 else
1227                                 {
1228                                         color4f[0] = ambientcolor[0] * distintensity;
1229                                         color4f[1] = ambientcolor[1] * distintensity;
1230                                         color4f[2] = ambientcolor[2] * distintensity;
1231                                 }
1232                                 if (r_refdef.fogenabled)
1233                                 {
1234                                         float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
1235                                         VectorScale(color4f, f, color4f);
1236                                 }
1237                         }
1238                         else
1239                                 VectorClear(color4f);
1240                         color4f[3] = 1;
1241                 }
1242         }
1243         else
1244         {
1245                 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1246                 {
1247                         Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1248                         if ((dist = DotProduct(v, v)) < 1)
1249                         {
1250                                 dist = sqrt(dist);
1251                                 distintensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1252                                 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1253                                 if ((dot = DotProduct(n, v)) < 0)
1254                                 {
1255                                         shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1256                                         color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1257                                         color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1258                                         color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1259                                 }
1260                                 else
1261                                 {
1262                                         color4f[0] = ambientcolor[0] * distintensity;
1263                                         color4f[1] = ambientcolor[1] * distintensity;
1264                                         color4f[2] = ambientcolor[2] * distintensity;
1265                                 }
1266                                 if (r_refdef.fogenabled)
1267                                 {
1268                                         float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
1269                                         VectorScale(color4f, f, color4f);
1270                                 }
1271                         }
1272                         else
1273                                 VectorClear(color4f);
1274                         color4f[3] = 1;
1275                 }
1276         }
1277 }
1278
1279 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1280
1281 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int numsurfaces, msurface_t **surfacelist)
1282 {
1283         int surfacelistindex;
1284         for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1285         {
1286                 const msurface_t *surface = surfacelist[surfacelistindex];
1287                 int i;
1288                 float *out3f = rsurface_array_texcoord3f + 3 * surface->num_firstvertex;
1289                 const float *vertex3f = rsurface_vertex3f + 3 * surface->num_firstvertex;
1290                 const float *svector3f = rsurface_svector3f + 3 * surface->num_firstvertex;
1291                 const float *tvector3f = rsurface_tvector3f + 3 * surface->num_firstvertex;
1292                 const float *normal3f = rsurface_normal3f + 3 * surface->num_firstvertex;
1293                 float lightdir[3];
1294                 for (i = 0;i < surface->num_vertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1295                 {
1296                         VectorSubtract(r_shadow_entitylightorigin, vertex3f, lightdir);
1297                         // the cubemap normalizes this for us
1298                         out3f[0] = DotProduct(svector3f, lightdir);
1299                         out3f[1] = DotProduct(tvector3f, lightdir);
1300                         out3f[2] = DotProduct(normal3f, lightdir);
1301                 }
1302         }
1303 }
1304
1305 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int numsurfaces, msurface_t **surfacelist)
1306 {
1307         int surfacelistindex;
1308         for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1309         {
1310                 const msurface_t *surface = surfacelist[surfacelistindex];
1311                 int i;
1312                 float *out3f = rsurface_array_texcoord3f + 3 * surface->num_firstvertex;
1313                 const float *vertex3f = rsurface_vertex3f + 3 * surface->num_firstvertex;
1314                 const float *svector3f = rsurface_svector3f + 3 * surface->num_firstvertex;
1315                 const float *tvector3f = rsurface_tvector3f + 3 * surface->num_firstvertex;
1316                 const float *normal3f = rsurface_normal3f + 3 * surface->num_firstvertex;
1317                 float lightdir[3], eyedir[3], halfdir[3];
1318                 for (i = 0;i < surface->num_vertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1319                 {
1320                         VectorSubtract(r_shadow_entitylightorigin, vertex3f, lightdir);
1321                         VectorNormalize(lightdir);
1322                         VectorSubtract(rsurface_modelorg, vertex3f, eyedir);
1323                         VectorNormalize(eyedir);
1324                         VectorAdd(lightdir, eyedir, halfdir);
1325                         // the cubemap normalizes this for us
1326                         out3f[0] = DotProduct(svector3f, halfdir);
1327                         out3f[1] = DotProduct(tvector3f, halfdir);
1328                         out3f[2] = DotProduct(normal3f, halfdir);
1329                 }
1330         }
1331 }
1332
1333 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)
1334 {
1335         // used to display how many times a surface is lit for level design purposes
1336         GL_Color(0.1 * r_view.colorscale, 0.025 * r_view.colorscale, 0, 1);
1337         R_Mesh_ColorPointer(NULL);
1338         R_Mesh_ResetTextureState();
1339         RSurf_PrepareVerticesForBatch(false, false, numsurfaces, surfacelist);
1340         RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1341         GL_LockArrays(0, 0);
1342 }
1343
1344 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)
1345 {
1346         // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
1347         RSurf_PrepareVerticesForBatch(true, true, numsurfaces, surfacelist);
1348         R_SetupSurfaceShader(lightcolorbase, false);
1349         R_Mesh_TexCoordPointer(0, 2, rsurface_model->surfmesh.data_texcoordtexture2f);
1350         R_Mesh_TexCoordPointer(1, 3, rsurface_svector3f);
1351         R_Mesh_TexCoordPointer(2, 3, rsurface_tvector3f);
1352         R_Mesh_TexCoordPointer(3, 3, rsurface_normal3f);
1353         if (rsurface_texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1354         {
1355                 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1356         }
1357         RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1358         GL_LockArrays(0, 0);
1359         if (rsurface_texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1360         {
1361                 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1362         }
1363 }
1364
1365 static void R_Shadow_RenderSurfacesLighting_Light_Dot3_Finalize(int numsurfaces, msurface_t **surfacelist, float r, float g, float b)
1366 {
1367         // shared final code for all the dot3 layers
1368         int renders;
1369         GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 0);
1370         for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
1371         {
1372                 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
1373                 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1374                 GL_LockArrays(0, 0);
1375         }
1376 }
1377
1378 static void R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, rtexture_t *basetexture, float colorscale)
1379 {
1380         rmeshstate_t m;
1381         // colorscale accounts for how much we multiply the brightness
1382         // during combine.
1383         //
1384         // mult is how many times the final pass of the lighting will be
1385         // performed to get more brightness than otherwise possible.
1386         //
1387         // Limit mult to 64 for sanity sake.
1388         GL_Color(1,1,1,1);
1389         if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1390         {
1391                 // 3 3D combine path (Geforce3, Radeon 8500)
1392                 memset(&m, 0, sizeof(m));
1393                 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1394                 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1395                 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1396                 m.tex[1] = R_GetTexture(basetexture);
1397                 m.pointer_texcoord[1] = rsurface_model->surfmesh.data_texcoordtexture2f;
1398                 m.texmatrix[1] = rsurface_texture->currenttexmatrix;
1399                 m.texcubemap[2] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1400                 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1401                 m.texmatrix[2] = r_shadow_entitytolight;
1402                 GL_BlendFunc(GL_ONE, GL_ONE);
1403         }
1404         else if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1405         {
1406                 // 2 3D combine path (Geforce3, original Radeon)
1407                 memset(&m, 0, sizeof(m));
1408                 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1409                 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1410                 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1411                 m.tex[1] = R_GetTexture(basetexture);
1412                 m.pointer_texcoord[1] = rsurface_model->surfmesh.data_texcoordtexture2f;
1413                 m.texmatrix[1] = rsurface_texture->currenttexmatrix;
1414                 GL_BlendFunc(GL_ONE, GL_ONE);
1415         }
1416         else if (r_textureunits.integer >= 4 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1417         {
1418                 // 4 2D combine path (Geforce3, Radeon 8500)
1419                 memset(&m, 0, sizeof(m));
1420                 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1421                 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1422                 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1423                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1424                 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1425                 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1426                 m.tex[2] = R_GetTexture(basetexture);
1427                 m.pointer_texcoord[2] = rsurface_model->surfmesh.data_texcoordtexture2f;
1428                 m.texmatrix[2] = rsurface_texture->currenttexmatrix;
1429                 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1430                 {
1431                         m.texcubemap[3] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1432                         m.pointer_texcoord3f[3] = rsurface_vertex3f;
1433                         m.texmatrix[3] = r_shadow_entitytolight;
1434                 }
1435                 GL_BlendFunc(GL_ONE, GL_ONE);
1436         }
1437         else if (r_textureunits.integer >= 3 && r_shadow_rtlight->currentcubemap == r_texture_whitecube)
1438         {
1439                 // 3 2D combine path (Geforce3, original Radeon)
1440                 memset(&m, 0, sizeof(m));
1441                 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1442                 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1443                 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1444                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1445                 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1446                 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1447                 m.tex[2] = R_GetTexture(basetexture);
1448                 m.pointer_texcoord[2] = rsurface_model->surfmesh.data_texcoordtexture2f;
1449                 m.texmatrix[2] = rsurface_texture->currenttexmatrix;
1450                 GL_BlendFunc(GL_ONE, GL_ONE);
1451         }
1452         else
1453         {
1454                 // 2/2/2 2D combine path (any dot3 card)
1455                 memset(&m, 0, sizeof(m));
1456                 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1457                 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1458                 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1459                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1460                 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1461                 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1462                 R_Mesh_TextureState(&m);
1463                 GL_ColorMask(0,0,0,1);
1464                 GL_BlendFunc(GL_ONE, GL_ZERO);
1465                 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1466                 GL_LockArrays(0, 0);
1467
1468                 // second pass
1469                 memset(&m, 0, sizeof(m));
1470                 m.tex[0] = R_GetTexture(basetexture);
1471                 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1472                 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1473                 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1474                 {
1475                         m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1476                         m.pointer_texcoord3f[1] = rsurface_vertex3f;
1477                         m.texmatrix[1] = r_shadow_entitytolight;
1478                 }
1479                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1480         }
1481         // this final code is shared
1482         R_Mesh_TextureState(&m);
1483         R_Shadow_RenderSurfacesLighting_Light_Dot3_Finalize(numsurfaces, surfacelist, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1484 }
1485
1486 static void R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, rtexture_t *basetexture, rtexture_t *normalmaptexture, float colorscale)
1487 {
1488         rmeshstate_t m;
1489         // colorscale accounts for how much we multiply the brightness
1490         // during combine.
1491         //
1492         // mult is how many times the final pass of the lighting will be
1493         // performed to get more brightness than otherwise possible.
1494         //
1495         // Limit mult to 64 for sanity sake.
1496         GL_Color(1,1,1,1);
1497         // generate normalization cubemap texcoords
1498         R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(numsurfaces, surfacelist);
1499         if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1500         {
1501                 // 3/2 3D combine path (Geforce3, Radeon 8500)
1502                 memset(&m, 0, sizeof(m));
1503                 m.tex[0] = R_GetTexture(normalmaptexture);
1504                 m.texcombinergb[0] = GL_REPLACE;
1505                 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1506                 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1507                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1508                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1509                 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1510                 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1511                 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1512                 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
1513                 R_Mesh_TextureState(&m);
1514                 GL_ColorMask(0,0,0,1);
1515                 GL_BlendFunc(GL_ONE, GL_ZERO);
1516                 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1517                 GL_LockArrays(0, 0);
1518
1519                 // second pass
1520                 memset(&m, 0, sizeof(m));
1521                 m.tex[0] = R_GetTexture(basetexture);
1522                 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1523                 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1524                 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1525                 {
1526                         m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1527                         m.pointer_texcoord3f[1] = rsurface_vertex3f;
1528                         m.texmatrix[1] = r_shadow_entitytolight;
1529                 }
1530                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1531         }
1532         else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1533         {
1534                 // 1/2/2 3D combine path (original Radeon)
1535                 memset(&m, 0, sizeof(m));
1536                 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1537                 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1538                 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1539                 R_Mesh_TextureState(&m);
1540                 GL_ColorMask(0,0,0,1);
1541                 GL_BlendFunc(GL_ONE, GL_ZERO);
1542                 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1543                 GL_LockArrays(0, 0);
1544
1545                 // second pass
1546                 memset(&m, 0, sizeof(m));
1547                 m.tex[0] = R_GetTexture(normalmaptexture);
1548                 m.texcombinergb[0] = GL_REPLACE;
1549                 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1550                 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1551                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1552                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1553                 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1554                 R_Mesh_TextureState(&m);
1555                 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1556                 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1557                 GL_LockArrays(0, 0);
1558
1559                 // second pass
1560                 memset(&m, 0, sizeof(m));
1561                 m.tex[0] = R_GetTexture(basetexture);
1562                 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1563                 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1564                 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1565                 {
1566                         m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1567                         m.pointer_texcoord3f[1] = rsurface_vertex3f;
1568                         m.texmatrix[1] = r_shadow_entitytolight;
1569                 }
1570                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1571         }
1572         else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap == r_texture_whitecube)
1573         {
1574                 // 2/2 3D combine path (original Radeon)
1575                 memset(&m, 0, sizeof(m));
1576                 m.tex[0] = R_GetTexture(normalmaptexture);
1577                 m.texcombinergb[0] = GL_REPLACE;
1578                 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1579                 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1580                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1581                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1582                 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1583                 R_Mesh_TextureState(&m);
1584                 GL_ColorMask(0,0,0,1);
1585                 GL_BlendFunc(GL_ONE, GL_ZERO);
1586                 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1587                 GL_LockArrays(0, 0);
1588
1589                 // second pass
1590                 memset(&m, 0, sizeof(m));
1591                 m.tex[0] = R_GetTexture(basetexture);
1592                 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1593                 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1594                 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1595                 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1596                 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
1597                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1598         }
1599         else if (r_textureunits.integer >= 4)
1600         {
1601                 // 4/2 2D combine path (Geforce3, Radeon 8500)
1602                 memset(&m, 0, sizeof(m));
1603                 m.tex[0] = R_GetTexture(normalmaptexture);
1604                 m.texcombinergb[0] = GL_REPLACE;
1605                 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1606                 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1607                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1608                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1609                 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1610                 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1611                 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1612                 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
1613                 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1614                 m.pointer_texcoord3f[3] = rsurface_vertex3f;
1615                 m.texmatrix[3] = r_shadow_entitytoattenuationz;
1616                 R_Mesh_TextureState(&m);
1617                 GL_ColorMask(0,0,0,1);
1618                 GL_BlendFunc(GL_ONE, GL_ZERO);
1619                 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1620                 GL_LockArrays(0, 0);
1621
1622                 // second pass
1623                 memset(&m, 0, sizeof(m));
1624                 m.tex[0] = R_GetTexture(basetexture);
1625                 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1626                 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1627                 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1628                 {
1629                         m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1630                         m.pointer_texcoord3f[1] = rsurface_vertex3f;
1631                         m.texmatrix[1] = r_shadow_entitytolight;
1632                 }
1633                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1634         }
1635         else
1636         {
1637                 // 2/2/2 2D combine path (any dot3 card)
1638                 memset(&m, 0, sizeof(m));
1639                 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1640                 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1641                 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1642                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1643                 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1644                 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1645                 R_Mesh_TextureState(&m);
1646                 GL_ColorMask(0,0,0,1);
1647                 GL_BlendFunc(GL_ONE, GL_ZERO);
1648                 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1649                 GL_LockArrays(0, 0);
1650
1651                 // second pass
1652                 memset(&m, 0, sizeof(m));
1653                 m.tex[0] = R_GetTexture(normalmaptexture);
1654                 m.texcombinergb[0] = GL_REPLACE;
1655                 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1656                 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1657                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1658                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1659                 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1660                 R_Mesh_TextureState(&m);
1661                 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1662                 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1663                 GL_LockArrays(0, 0);
1664
1665                 // second pass
1666                 memset(&m, 0, sizeof(m));
1667                 m.tex[0] = R_GetTexture(basetexture);
1668                 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1669                 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1670                 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1671                 {
1672                         m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1673                         m.pointer_texcoord3f[1] = rsurface_vertex3f;
1674                         m.texmatrix[1] = r_shadow_entitytolight;
1675                 }
1676                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1677         }
1678         // this final code is shared
1679         R_Mesh_TextureState(&m);
1680         R_Shadow_RenderSurfacesLighting_Light_Dot3_Finalize(numsurfaces, surfacelist, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1681 }
1682
1683 static void R_Shadow_RenderSurfacesLighting_Light_Dot3_SpecularPass(int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, rtexture_t *glosstexture, rtexture_t *normalmaptexture, float colorscale)
1684 {
1685         rmeshstate_t m;
1686         // FIXME: detect blendsquare!
1687         //if (!gl_support_blendsquare)
1688         //      return;
1689         GL_Color(1,1,1,1);
1690         // generate normalization cubemap texcoords
1691         R_Shadow_GenTexCoords_Specular_NormalCubeMap(numsurfaces, surfacelist);
1692         if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1693         {
1694                 // 2/0/0/1/2 3D combine blendsquare path
1695                 memset(&m, 0, sizeof(m));
1696                 m.tex[0] = R_GetTexture(normalmaptexture);
1697                 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1698                 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1699                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1700                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1701                 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1702                 R_Mesh_TextureState(&m);
1703                 GL_ColorMask(0,0,0,1);
1704                 // this squares the result
1705                 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1706                 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1707                 GL_LockArrays(0, 0);
1708
1709                 // second and third pass
1710                 R_Mesh_ResetTextureState();
1711                 // square alpha in framebuffer a few times to make it shiny
1712                 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1713                 // these comments are a test run through this math for intensity 0.5
1714                 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1715                 // 0.25 * 0.25 = 0.0625 (this is another pass)
1716                 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1717                 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1718                 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1719                 GL_LockArrays(0, 0);
1720
1721                 // fourth pass
1722                 memset(&m, 0, sizeof(m));
1723                 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1724                 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1725                 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1726                 R_Mesh_TextureState(&m);
1727                 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1728                 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1729                 GL_LockArrays(0, 0);
1730
1731                 // fifth pass
1732                 memset(&m, 0, sizeof(m));
1733                 m.tex[0] = R_GetTexture(glosstexture);
1734                 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1735                 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1736                 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1737                 {
1738                         m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1739                         m.pointer_texcoord3f[1] = rsurface_vertex3f;
1740                         m.texmatrix[1] = r_shadow_entitytolight;
1741                 }
1742                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1743         }
1744         else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
1745         {
1746                 // 2/0/0/2 3D combine blendsquare path
1747                 memset(&m, 0, sizeof(m));
1748                 m.tex[0] = R_GetTexture(normalmaptexture);
1749                 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1750                 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1751                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1752                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1753                 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1754                 R_Mesh_TextureState(&m);
1755                 GL_ColorMask(0,0,0,1);
1756                 // this squares the result
1757                 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1758                 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1759                 GL_LockArrays(0, 0);
1760
1761                 // second and third pass
1762                 R_Mesh_ResetTextureState();
1763                 // square alpha in framebuffer a few times to make it shiny
1764                 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1765                 // these comments are a test run through this math for intensity 0.5
1766                 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1767                 // 0.25 * 0.25 = 0.0625 (this is another pass)
1768                 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1769                 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1770                 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1771                 GL_LockArrays(0, 0);
1772
1773                 // fourth pass
1774                 memset(&m, 0, sizeof(m));
1775                 m.tex[0] = R_GetTexture(glosstexture);
1776                 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1777                 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1778                 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1779                 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1780                 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
1781                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1782         }
1783         else
1784         {
1785                 // 2/0/0/2/2 2D combine blendsquare path
1786                 memset(&m, 0, sizeof(m));
1787                 m.tex[0] = R_GetTexture(normalmaptexture);
1788                 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1789                 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1790                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1791                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1792                 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1793                 R_Mesh_TextureState(&m);
1794                 GL_ColorMask(0,0,0,1);
1795                 // this squares the result
1796                 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1797                 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1798                 GL_LockArrays(0, 0);
1799
1800                 // second and third pass
1801                 R_Mesh_ResetTextureState();
1802                 // square alpha in framebuffer a few times to make it shiny
1803                 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1804                 // these comments are a test run through this math for intensity 0.5
1805                 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1806                 // 0.25 * 0.25 = 0.0625 (this is another pass)
1807                 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1808                 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1809                 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1810                 GL_LockArrays(0, 0);
1811
1812                 // fourth pass
1813                 memset(&m, 0, sizeof(m));
1814                 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1815                 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1816                 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1817                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1818                 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1819                 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1820                 R_Mesh_TextureState(&m);
1821                 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1822                 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1823                 GL_LockArrays(0, 0);
1824
1825                 // fifth pass
1826                 memset(&m, 0, sizeof(m));
1827                 m.tex[0] = R_GetTexture(glosstexture);
1828                 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1829                 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1830                 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1831                 {
1832                         m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1833                         m.pointer_texcoord3f[1] = rsurface_vertex3f;
1834                         m.texmatrix[1] = r_shadow_entitytolight;
1835                 }
1836                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1837         }
1838         // this final code is shared
1839         R_Mesh_TextureState(&m);
1840         R_Shadow_RenderSurfacesLighting_Light_Dot3_Finalize(numsurfaces, surfacelist, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1841 }
1842
1843 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)
1844 {
1845         // ARB path (any Geforce, any Radeon)
1846         qboolean doambient = r_shadow_rtlight->ambientscale > 0;
1847         qboolean dodiffuse = r_shadow_rtlight->diffusescale > 0;
1848         qboolean dospecular = specularscale > 0;
1849         if (!doambient && !dodiffuse && !dospecular)
1850                 return;
1851         RSurf_PrepareVerticesForBatch(true, true, numsurfaces, surfacelist);
1852         R_Mesh_ColorPointer(NULL);
1853         if (doambient)
1854                 R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(numsurfaces, surfacelist, lightcolorbase, basetexture, r_shadow_rtlight->ambientscale * r_view.colorscale);
1855         if (dodiffuse)
1856                 R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(numsurfaces, surfacelist, lightcolorbase, basetexture, normalmaptexture, r_shadow_rtlight->diffusescale * r_view.colorscale);
1857         if (dopants)
1858         {
1859                 if (doambient)
1860                         R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(numsurfaces, surfacelist, lightcolorpants, pantstexture, r_shadow_rtlight->ambientscale * r_view.colorscale);
1861                 if (dodiffuse)
1862                         R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(numsurfaces, surfacelist, lightcolorpants, pantstexture, normalmaptexture, r_shadow_rtlight->diffusescale * r_view.colorscale);
1863         }
1864         if (doshirt)
1865         {
1866                 if (doambient)
1867                         R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(numsurfaces, surfacelist, lightcolorshirt, shirttexture, r_shadow_rtlight->ambientscale * r_view.colorscale);
1868                 if (dodiffuse)
1869                         R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(numsurfaces, surfacelist, lightcolorshirt, shirttexture, normalmaptexture, r_shadow_rtlight->diffusescale * r_view.colorscale);
1870         }
1871         if (dospecular)
1872                 R_Shadow_RenderSurfacesLighting_Light_Dot3_SpecularPass(numsurfaces, surfacelist, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_view.colorscale);
1873 }
1874
1875 void R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(const model_t *model, int numsurfaces, msurface_t **surfacelist, vec3_t diffusecolor2, vec3_t ambientcolor2)
1876 {
1877         int surfacelistindex;
1878         int renders;
1879         for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1880         {
1881                 const msurface_t *surface = surfacelist[surfacelistindex];
1882                 R_Shadow_RenderSurfacesLighting_Light_Vertex_Shading(surface, diffusecolor2, ambientcolor2);
1883         }
1884         for (renders = 0;renders < 64;renders++)
1885         {
1886                 const int *e;
1887                 int stop;
1888                 int firstvertex;
1889                 int lastvertex;
1890                 int newnumtriangles;
1891                 int *newe;
1892                 int newelements[3072];
1893                 stop = true;
1894                 firstvertex = 0;
1895                 lastvertex = 0;
1896                 newnumtriangles = 0;
1897                 newe = newelements;
1898                 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1899                 {
1900                         const msurface_t *surface = surfacelist[surfacelistindex];
1901                         const int *elements = rsurface_model->surfmesh.data_element3i + surface->num_firsttriangle * 3;
1902                         int i;
1903                         // due to low fillrate on the cards this vertex lighting path is
1904                         // designed for, we manually cull all triangles that do not
1905                         // contain a lit vertex
1906                         // this builds batches of triangles from multiple surfaces and
1907                         // renders them at once
1908                         for (i = 0, e = elements;i < surface->num_triangles;i++, e += 3)
1909                         {
1910                                 if (VectorLength2(rsurface_array_color4f + e[0] * 4) + VectorLength2(rsurface_array_color4f + e[1] * 4) + VectorLength2(rsurface_array_color4f + e[2] * 4) >= 0.01)
1911                                 {
1912                                         if (newnumtriangles)
1913                                         {
1914                                                 firstvertex = min(firstvertex, e[0]);
1915                                                 lastvertex = max(lastvertex, e[0]);
1916                                         }
1917                                         else
1918                                         {
1919                                                 firstvertex = e[0];
1920                                                 lastvertex = e[0];
1921                                         }
1922                                         firstvertex = min(firstvertex, e[1]);
1923                                         lastvertex = max(lastvertex, e[1]);
1924                                         firstvertex = min(firstvertex, e[2]);
1925                                         lastvertex = max(lastvertex, e[2]);
1926                                         newe[0] = e[0];
1927                                         newe[1] = e[1];
1928                                         newe[2] = e[2];
1929                                         newnumtriangles++;
1930                                         newe += 3;
1931                                         if (newnumtriangles >= 1024)
1932                                         {
1933                                                 GL_LockArrays(firstvertex, lastvertex - firstvertex + 1);
1934                                                 R_Mesh_Draw(firstvertex, lastvertex - firstvertex + 1, newnumtriangles, newelements);
1935                                                 newnumtriangles = 0;
1936                                                 newe = newelements;
1937                                                 stop = false;
1938                                         }
1939                                 }
1940                         }
1941                 }
1942                 if (newnumtriangles >= 1)
1943                 {
1944                         GL_LockArrays(firstvertex, lastvertex - firstvertex + 1);
1945                         R_Mesh_Draw(firstvertex, lastvertex - firstvertex + 1, newnumtriangles, newelements);
1946                         stop = false;
1947                 }
1948                 GL_LockArrays(0, 0);
1949                 // if we couldn't find any lit triangles, exit early
1950                 if (stop)
1951                         break;
1952                 // now reduce the intensity for the next overbright pass
1953                 // we have to clamp to 0 here incase the drivers have improper
1954                 // handling of negative colors
1955                 // (some old drivers even have improper handling of >1 color)
1956                 stop = true;
1957                 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1958                 {
1959                         int i;
1960                         float *c;
1961                         const msurface_t *surface = surfacelist[surfacelistindex];
1962                         for (i = 0, c = rsurface_array_color4f + 4 * surface->num_firstvertex;i < surface->num_vertices;i++, c += 4)
1963                         {
1964                                 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
1965                                 {
1966                                         c[0] = max(0, c[0] - 1);
1967                                         c[1] = max(0, c[1] - 1);
1968                                         c[2] = max(0, c[2] - 1);
1969                                         stop = false;
1970                                 }
1971                                 else
1972                                         VectorClear(c);
1973                         }
1974                 }
1975                 // another check...
1976                 if (stop)
1977                         break;
1978         }
1979 }
1980
1981 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)
1982 {
1983         // OpenGL 1.1 path (anything)
1984         model_t *model = rsurface_entity->model;
1985         float ambientcolorbase[3], diffusecolorbase[3];
1986         float ambientcolorpants[3], diffusecolorpants[3];
1987         float ambientcolorshirt[3], diffusecolorshirt[3];
1988         rmeshstate_t m;
1989         VectorScale(lightcolorbase, r_shadow_rtlight->ambientscale * 2 * r_view.colorscale, ambientcolorbase);
1990         VectorScale(lightcolorbase, r_shadow_rtlight->diffusescale * 2 * r_view.colorscale, diffusecolorbase);
1991         VectorScale(lightcolorpants, r_shadow_rtlight->ambientscale * 2 * r_view.colorscale, ambientcolorpants);
1992         VectorScale(lightcolorpants, r_shadow_rtlight->diffusescale * 2 * r_view.colorscale, diffusecolorpants);
1993         VectorScale(lightcolorshirt, r_shadow_rtlight->ambientscale * 2 * r_view.colorscale, ambientcolorshirt);
1994         VectorScale(lightcolorshirt, r_shadow_rtlight->diffusescale * 2 * r_view.colorscale, diffusecolorshirt);
1995         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1996         R_Mesh_ColorPointer(rsurface_array_color4f);
1997         memset(&m, 0, sizeof(m));
1998         m.tex[0] = R_GetTexture(basetexture);
1999         m.texmatrix[0] = rsurface_texture->currenttexmatrix;
2000         m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
2001         if (r_textureunits.integer >= 2)
2002         {
2003                 // voodoo2 or TNT
2004                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2005                 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2006                 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2007                 if (r_textureunits.integer >= 3)
2008                 {
2009                         // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
2010                         m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2011                         m.texmatrix[2] = r_shadow_entitytoattenuationz;
2012                         m.pointer_texcoord3f[2] = rsurface_vertex3f;
2013                 }
2014         }
2015         R_Mesh_TextureState(&m);
2016         RSurf_PrepareVerticesForBatch(true, false, numsurfaces, surfacelist);
2017         R_Mesh_TexBind(0, R_GetTexture(basetexture));
2018         R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(model, numsurfaces, surfacelist, diffusecolorbase, ambientcolorbase);
2019         if (dopants)
2020         {
2021                 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
2022                 R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(model, numsurfaces, surfacelist, diffusecolorpants, ambientcolorpants);
2023         }
2024         if (doshirt)
2025         {
2026                 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
2027                 R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(model, numsurfaces, surfacelist, diffusecolorshirt, ambientcolorshirt);
2028         }
2029 }
2030
2031 void R_Shadow_RenderSurfacesLighting(int numsurfaces, msurface_t **surfacelist)
2032 {
2033         // FIXME: support MATERIALFLAG_NODEPTHTEST
2034         vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
2035         // calculate colors to render this texture with
2036         lightcolorbase[0] = r_shadow_rtlight->currentcolor[0] * rsurface_entity->colormod[0] * rsurface_texture->currentalpha;
2037         lightcolorbase[1] = r_shadow_rtlight->currentcolor[1] * rsurface_entity->colormod[1] * rsurface_texture->currentalpha;
2038         lightcolorbase[2] = r_shadow_rtlight->currentcolor[2] * rsurface_entity->colormod[2] * rsurface_texture->currentalpha;
2039         if ((r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorbase) + (r_shadow_rtlight->specularscale * rsurface_texture->specularscale) * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
2040                 return;
2041         GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
2042         GL_CullFace(((rsurface_texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) || (rsurface_entity->flags & RENDER_NOCULLFACE)) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
2043         if (rsurface_texture->colormapping)
2044         {
2045                 qboolean dopants = rsurface_texture->currentskinframe->pants != NULL && VectorLength2(rsurface_entity->colormap_pantscolor) >= (1.0f / 1048576.0f);
2046                 qboolean doshirt = rsurface_texture->currentskinframe->shirt != NULL && VectorLength2(rsurface_entity->colormap_shirtcolor) >= (1.0f / 1048576.0f);
2047                 if (dopants)
2048                 {
2049                         lightcolorpants[0] = lightcolorbase[0] * rsurface_entity->colormap_pantscolor[0];
2050                         lightcolorpants[1] = lightcolorbase[1] * rsurface_entity->colormap_pantscolor[1];
2051                         lightcolorpants[2] = lightcolorbase[2] * rsurface_entity->colormap_pantscolor[2];
2052                 }
2053                 else
2054                         VectorClear(lightcolorpants);
2055                 if (doshirt)
2056                 {
2057                         lightcolorshirt[0] = lightcolorbase[0] * rsurface_entity->colormap_shirtcolor[0];
2058                         lightcolorshirt[1] = lightcolorbase[1] * rsurface_entity->colormap_shirtcolor[1];
2059                         lightcolorshirt[2] = lightcolorbase[2] * rsurface_entity->colormap_shirtcolor[2];
2060                 }
2061                 else
2062                         VectorClear(lightcolorshirt);
2063                 switch (r_shadow_rendermode)
2064                 {
2065                 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2066                         GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2067                         R_Shadow_RenderSurfacesLighting_VisibleLighting(numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->currentskinframe->pants, rsurface_texture->currentskinframe->shirt, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, dopants, doshirt);
2068                         break;
2069                 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2070                         R_Shadow_RenderSurfacesLighting_Light_GLSL(numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->currentskinframe->pants, rsurface_texture->currentskinframe->shirt, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, dopants, doshirt);
2071                         break;
2072                 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2073                         R_Shadow_RenderSurfacesLighting_Light_Dot3(numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->currentskinframe->pants, rsurface_texture->currentskinframe->shirt, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, dopants, doshirt);
2074                         break;
2075                 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2076                         R_Shadow_RenderSurfacesLighting_Light_Vertex(numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->currentskinframe->pants, rsurface_texture->currentskinframe->shirt, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, dopants, doshirt);
2077                         break;
2078                 default:
2079                         Con_Printf("R_Shadow_RenderSurfacesLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2080                         break;
2081                 }
2082         }
2083         else
2084         {
2085                 switch (r_shadow_rendermode)
2086                 {
2087                 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2088                         GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2089                         R_Shadow_RenderSurfacesLighting_VisibleLighting(numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, false, false);
2090                         break;
2091                 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2092                         R_Shadow_RenderSurfacesLighting_Light_GLSL(numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, false, false);
2093                         break;
2094                 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2095                         R_Shadow_RenderSurfacesLighting_Light_Dot3(numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, false, false);
2096                         break;
2097                 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2098                         R_Shadow_RenderSurfacesLighting_Light_Vertex(numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, false, false);
2099                         break;
2100                 default:
2101                         Con_Printf("R_Shadow_RenderSurfacesLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2102                         break;
2103                 }
2104         }
2105 }
2106
2107 void R_RTLight_Update(dlight_t *light, int isstatic)
2108 {
2109         double scale;
2110         rtlight_t *rtlight = &light->rtlight;
2111         R_RTLight_Uncompile(rtlight);
2112         memset(rtlight, 0, sizeof(*rtlight));
2113
2114         VectorCopy(light->origin, rtlight->shadoworigin);
2115         VectorCopy(light->color, rtlight->color);
2116         rtlight->radius = light->radius;
2117         //rtlight->cullradius = rtlight->radius;
2118         //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2119         rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2120         rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2121         rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2122         rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2123         rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2124         rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2125         rtlight->cubemapname[0] = 0;
2126         if (light->cubemapname[0])
2127                 strlcpy(rtlight->cubemapname, light->cubemapname, sizeof(rtlight->cubemapname));
2128         else if (light->cubemapnum > 0)
2129                 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
2130         rtlight->shadow = light->shadow;
2131         rtlight->corona = light->corona;
2132         rtlight->style = light->style;
2133         rtlight->isstatic = isstatic;
2134         rtlight->coronasizescale = light->coronasizescale;
2135         rtlight->ambientscale = light->ambientscale;
2136         rtlight->diffusescale = light->diffusescale;
2137         rtlight->specularscale = light->specularscale;
2138         rtlight->flags = light->flags;
2139         Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
2140         // this has to scale both rotate and translate because this is an already
2141         // inverted matrix (it transforms from world to light space, not the other
2142         // way around)
2143         scale = 1.0 / rtlight->radius;
2144         Matrix4x4_Scale(&rtlight->matrix_worldtolight, scale, scale);
2145 }
2146
2147 // compiles rtlight geometry
2148 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2149 void R_RTLight_Compile(rtlight_t *rtlight)
2150 {
2151         int shadowmeshes, shadowtris, numleafs, numleafpvsbytes, numsurfaces;
2152         entity_render_t *ent = r_refdef.worldentity;
2153         model_t *model = r_refdef.worldmodel;
2154         unsigned char *data;
2155
2156         // compile the light
2157         rtlight->compiled = true;
2158         rtlight->static_numleafs = 0;
2159         rtlight->static_numleafpvsbytes = 0;
2160         rtlight->static_leaflist = NULL;
2161         rtlight->static_leafpvs = NULL;
2162         rtlight->static_numsurfaces = 0;
2163         rtlight->static_surfacelist = NULL;
2164         rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2165         rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2166         rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2167         rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2168         rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2169         rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2170
2171         if (model && model->GetLightInfo)
2172         {
2173                 // this variable must be set for the CompileShadowVolume code
2174                 r_shadow_compilingrtlight = rtlight;
2175                 R_Shadow_EnlargeLeafSurfaceBuffer(model->brush.num_leafs, model->num_surfaces);
2176                 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);
2177                 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2178                 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numleafs + numleafpvsbytes + sizeof(int) * numsurfaces);
2179                 rtlight->static_numleafs = numleafs;
2180                 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2181                 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2182                 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2183                 rtlight->static_numsurfaces = numsurfaces;
2184                 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2185                 if (numleafs)
2186                         memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2187                 if (numleafpvsbytes)
2188                         memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2189                 if (numsurfaces)
2190                         memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2191                 if (model->CompileShadowVolume && rtlight->shadow)
2192                         model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2193                 // now we're done compiling the rtlight
2194                 r_shadow_compilingrtlight = NULL;
2195         }
2196
2197
2198         // use smallest available cullradius - box radius or light radius
2199         //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2200         //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2201
2202         shadowmeshes = 0;
2203         shadowtris = 0;
2204         if (rtlight->static_meshchain_shadow)
2205         {
2206                 shadowmesh_t *mesh;
2207                 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2208                 {
2209                         shadowmeshes++;
2210                         shadowtris += mesh->numtriangles;
2211                 }
2212         }
2213
2214         if (developer.integer >= 10)
2215                 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);
2216 }
2217
2218 void R_RTLight_Uncompile(rtlight_t *rtlight)
2219 {
2220         if (rtlight->compiled)
2221         {
2222                 if (rtlight->static_meshchain_shadow)
2223                         Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2224                 rtlight->static_meshchain_shadow = NULL;
2225                 // these allocations are grouped
2226                 if (rtlight->static_leaflist)
2227                         Mem_Free(rtlight->static_leaflist);
2228                 rtlight->static_numleafs = 0;
2229                 rtlight->static_numleafpvsbytes = 0;
2230                 rtlight->static_leaflist = NULL;
2231                 rtlight->static_leafpvs = NULL;
2232                 rtlight->static_numsurfaces = 0;
2233                 rtlight->static_surfacelist = NULL;
2234                 rtlight->compiled = false;
2235         }
2236 }
2237
2238 void R_Shadow_UncompileWorldLights(void)
2239 {
2240         dlight_t *light;
2241         for (light = r_shadow_worldlightchain;light;light = light->next)
2242                 R_RTLight_Uncompile(&light->rtlight);
2243 }
2244
2245 void R_Shadow_DrawEntityShadow(entity_render_t *ent, int numsurfaces, int *surfacelist)
2246 {
2247         model_t *model = ent->model;
2248         vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
2249         vec_t relativeshadowradius;
2250         if (ent == r_refdef.worldentity)
2251         {
2252                 if (r_shadow_rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2253                 {
2254                         shadowmesh_t *mesh;
2255                         R_Mesh_Matrix(&ent->matrix);
2256                         CHECKGLERROR
2257                         for (mesh = r_shadow_rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2258                         {
2259                                 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
2260                                 R_Mesh_VertexPointer(mesh->vertex3f);
2261                                 GL_LockArrays(0, mesh->numverts);
2262                                 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
2263                                 {
2264                                         // decrement stencil if backface is behind depthbuffer
2265                                         GL_CullFace(GL_BACK); // quake is backwards, this culls front faces
2266                                         qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2267                                         R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2268                                         // increment stencil if frontface is behind depthbuffer
2269                                         GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
2270                                         qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2271                                 }
2272                                 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2273                                 GL_LockArrays(0, 0);
2274                         }
2275                         CHECKGLERROR
2276                 }
2277                 else if (numsurfaces)
2278                 {
2279                         R_Mesh_Matrix(&ent->matrix);
2280                         model->DrawShadowVolume(ent, r_shadow_rtlight->shadoworigin, NULL, r_shadow_rtlight->radius, numsurfaces, surfacelist, r_shadow_rtlight->cullmins, r_shadow_rtlight->cullmaxs);
2281                 }
2282         }
2283         else
2284         {
2285                 Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, relativeshadoworigin);
2286                 relativeshadowradius = r_shadow_rtlight->radius / ent->scale;
2287                 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
2288                 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
2289                 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
2290                 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
2291                 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
2292                 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
2293                 R_Mesh_Matrix(&ent->matrix);
2294                 model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, model->nummodelsurfaces, model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2295         }
2296 }
2297
2298 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
2299 {
2300         // set up properties for rendering light onto this entity
2301         RSurf_ActiveEntity(ent, true, true);
2302         Matrix4x4_Concat(&r_shadow_entitytolight, &r_shadow_rtlight->matrix_worldtolight, &ent->matrix);
2303         Matrix4x4_Concat(&r_shadow_entitytoattenuationxyz, &matrix_attenuationxyz, &r_shadow_entitytolight);
2304         Matrix4x4_Concat(&r_shadow_entitytoattenuationz, &matrix_attenuationz, &r_shadow_entitytolight);
2305         Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, r_shadow_entitylightorigin);
2306         if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2307                 R_Mesh_TexMatrix(3, &r_shadow_entitytolight);
2308 }
2309
2310 void R_Shadow_DrawEntityLight(entity_render_t *ent, int numsurfaces, int *surfacelist)
2311 {
2312         model_t *model = ent->model;
2313         if (!model->DrawLight)
2314                 return;
2315         R_Shadow_SetupEntityLight(ent);
2316         if (ent == r_refdef.worldentity)
2317                 model->DrawLight(ent, numsurfaces, surfacelist);
2318         else
2319                 model->DrawLight(ent, model->nummodelsurfaces, model->surfacelist);
2320 }
2321
2322 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
2323 {
2324         int i, usestencil;
2325         float f;
2326         int numleafs, numsurfaces;
2327         int *leaflist, *surfacelist;
2328         unsigned char *leafpvs;
2329         int numlightentities;
2330         int numshadowentities;
2331         entity_render_t *lightentities[MAX_EDICTS];
2332         entity_render_t *shadowentities[MAX_EDICTS];
2333
2334         // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
2335         // skip lights that are basically invisible (color 0 0 0)
2336         if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
2337                 return;
2338
2339         // loading is done before visibility checks because loading should happen
2340         // all at once at the start of a level, not when it stalls gameplay.
2341         // (especially important to benchmarks)
2342         // compile light
2343         if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2344                 R_RTLight_Compile(rtlight);
2345         // load cubemap
2346         rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
2347
2348         // look up the light style value at this time
2349         f = (rtlight->style >= 0 ? r_refdef.lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2350         VectorScale(rtlight->color, f, rtlight->currentcolor);
2351         /*
2352         if (rtlight->selected)
2353         {
2354                 f = 2 + sin(realtime * M_PI * 4.0);
2355                 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
2356         }
2357         */
2358
2359         // if lightstyle is currently off, don't draw the light
2360         if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
2361                 return;
2362
2363         // if the light box is offscreen, skip it
2364         if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2365                 return;
2366
2367         if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2368         {
2369                 // compiled light, world available and can receive realtime lighting
2370                 // retrieve leaf information
2371                 numleafs = rtlight->static_numleafs;
2372                 leaflist = rtlight->static_leaflist;
2373                 leafpvs = rtlight->static_leafpvs;
2374                 numsurfaces = rtlight->static_numsurfaces;
2375                 surfacelist = rtlight->static_surfacelist;
2376         }
2377         else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2378         {
2379                 // dynamic light, world available and can receive realtime lighting
2380                 // calculate lit surfaces and leafs
2381                 R_Shadow_EnlargeLeafSurfaceBuffer(r_refdef.worldmodel->brush.num_leafs, r_refdef.worldmodel->num_surfaces);
2382                 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);
2383                 leaflist = r_shadow_buffer_leaflist;
2384                 leafpvs = r_shadow_buffer_leafpvs;
2385                 surfacelist = r_shadow_buffer_surfacelist;
2386                 // if the reduced leaf bounds are offscreen, skip it
2387                 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2388                         return;
2389         }
2390         else
2391         {
2392                 // no world
2393                 numleafs = 0;
2394                 leaflist = NULL;
2395                 leafpvs = NULL;
2396                 numsurfaces = 0;
2397                 surfacelist = NULL;
2398         }
2399         // check if light is illuminating any visible leafs
2400         if (numleafs)
2401         {
2402                 for (i = 0;i < numleafs;i++)
2403                         if (r_viewcache.world_leafvisible[leaflist[i]])
2404                                 break;
2405                 if (i == numleafs)
2406                         return;
2407         }
2408         // set up a scissor rectangle for this light
2409         if (R_Shadow_ScissorForBBox(rtlight->cullmins, rtlight->cullmaxs))
2410                 return;
2411
2412         // make a list of lit entities and shadow casting entities
2413         numlightentities = 0;
2414         numshadowentities = 0;
2415         // don't count the world unless some surfaces are actually lit
2416         if (numsurfaces)
2417         {
2418                 lightentities[numlightentities++] = r_refdef.worldentity;
2419                 shadowentities[numshadowentities++] = r_refdef.worldentity;
2420         }
2421         // add dynamic entities that are lit by the light
2422         if (r_drawentities.integer)
2423         {
2424                 for (i = 0;i < r_refdef.numentities;i++)
2425                 {
2426                         model_t *model;
2427                         entity_render_t *ent = r_refdef.entities[i];
2428                         if (BoxesOverlap(ent->mins, ent->maxs, rtlight->cullmins, rtlight->cullmaxs)
2429                          && (model = ent->model)
2430                          && !(ent->flags & RENDER_TRANSPARENT)
2431                          && (r_refdef.worldmodel == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs)))
2432                         {
2433                                 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2434                                 vec3_t org;
2435                                 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
2436                                 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
2437                                         shadowentities[numshadowentities++] = ent;
2438                                 if (r_viewcache.entityvisible[i] && (ent->flags & RENDER_LIGHT) && model->DrawLight)
2439                                         lightentities[numlightentities++] = ent;
2440                         }
2441                 }
2442         }
2443
2444         // return if there's nothing at all to light
2445         if (!numlightentities)
2446                 return;
2447
2448         // don't let sound skip if going slow
2449         if (r_refdef.extraupdate)
2450                 S_ExtraUpdate ();
2451
2452         // make this the active rtlight for rendering purposes
2453         R_Shadow_RenderMode_ActiveLight(rtlight);
2454         // count this light in the r_speeds
2455         r_refdef.stats.lights++;
2456
2457         usestencil = false;
2458         if (numshadowentities && rtlight->shadow && (rtlight->isstatic ? r_refdef.rtworldshadows : r_refdef.rtdlightshadows))
2459         {
2460                 // draw stencil shadow volumes to mask off pixels that are in shadow
2461                 // so that they won't receive lighting
2462                 if (gl_stencil)
2463                 {
2464                         usestencil = true;
2465                         R_Shadow_RenderMode_StencilShadowVolumes();
2466                         for (i = 0;i < numshadowentities;i++)
2467                                 R_Shadow_DrawEntityShadow(shadowentities[i], numsurfaces, surfacelist);
2468                 }
2469
2470                 // optionally draw visible shape of the shadow volumes
2471                 // for performance analysis by level designers
2472                 if (r_showshadowvolumes.integer)
2473                 {
2474                         R_Shadow_RenderMode_VisibleShadowVolumes();
2475                         for (i = 0;i < numshadowentities;i++)
2476                                 R_Shadow_DrawEntityShadow(shadowentities[i], numsurfaces, surfacelist);
2477                 }
2478         }
2479
2480         if (numlightentities)
2481         {
2482                 // draw lighting in the unmasked areas
2483                 R_Shadow_RenderMode_Lighting(usestencil, false);
2484                 for (i = 0;i < numlightentities;i++)
2485                         R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
2486
2487                 // optionally draw the illuminated areas
2488                 // for performance analysis by level designers
2489                 if (r_showlighting.integer)
2490                 {
2491                         R_Shadow_RenderMode_VisibleLighting(usestencil && !r_showdisabledepthtest.integer, false);
2492                         for (i = 0;i < numlightentities;i++)
2493                                 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
2494                 }
2495         }
2496 }
2497
2498 void R_ShadowVolumeLighting(qboolean visible)
2499 {
2500         int lnum, flag;
2501         dlight_t *light;
2502
2503         if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2504                 R_Shadow_EditLights_Reload_f();
2505
2506         R_Shadow_RenderMode_Begin();
2507
2508         flag = r_refdef.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2509         if (r_shadow_debuglight.integer >= 0)
2510         {
2511                 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2512                         if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
2513                                 R_DrawRTLight(&light->rtlight, visible);
2514         }
2515         else
2516                 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2517                         if (light->flags & flag)
2518                                 R_DrawRTLight(&light->rtlight, visible);
2519         if (r_refdef.rtdlight)
2520                 for (lnum = 0;lnum < r_refdef.numlights;lnum++)
2521                         R_DrawRTLight(&r_refdef.lights[lnum]->rtlight, visible);
2522
2523         R_Shadow_RenderMode_End();
2524 }
2525
2526 extern void R_SetupView(const matrix4x4_t *matrix);
2527 extern cvar_t r_shadows_throwdistance;
2528 void R_DrawModelShadows(void)
2529 {
2530         int i;
2531         float relativethrowdistance;
2532         entity_render_t *ent;
2533         vec3_t relativelightorigin;
2534         vec3_t relativelightdirection;
2535         vec3_t relativeshadowmins, relativeshadowmaxs;
2536         float vertex3f[12];
2537
2538         if (!r_drawentities.integer || !gl_stencil)
2539                 return;
2540
2541         CHECKGLERROR
2542         GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
2543
2544         r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2545
2546         if (gl_ext_stenciltwoside.integer)
2547                 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
2548         else
2549                 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
2550
2551         R_Shadow_RenderMode_StencilShadowVolumes();
2552
2553         for (i = 0;i < r_refdef.numentities;i++)
2554         {
2555                 ent = r_refdef.entities[i];
2556                 // cast shadows from anything that is not a submodel of the map
2557                 if (ent->model && ent->model->DrawShadowVolume != NULL && !ent->model->brush.submodel && (ent->flags & RENDER_SHADOW))
2558                 {
2559                         relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
2560                         VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
2561                         VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
2562                         VectorNegate(ent->modellight_lightdir, relativelightdirection);
2563                         VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
2564                         ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2565                 }
2566         }
2567
2568         // not really the right mode, but this will disable any silly stencil features
2569         R_Shadow_RenderMode_VisibleLighting(true, true);
2570
2571         // vertex coordinates for a quad that covers the screen exactly
2572         vertex3f[0] = 0;vertex3f[1] = 0;vertex3f[2] = 0;
2573         vertex3f[3] = 1;vertex3f[4] = 0;vertex3f[5] = 0;
2574         vertex3f[6] = 1;vertex3f[7] = 1;vertex3f[8] = 0;
2575         vertex3f[9] = 0;vertex3f[10] = 1;vertex3f[11] = 0;
2576
2577         // set up ortho view for rendering this pass
2578         GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
2579         GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
2580         GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
2581         GL_ScissorTest(true);
2582         R_Mesh_Matrix(&identitymatrix);
2583         R_Mesh_ResetTextureState();
2584         R_Mesh_VertexPointer(vertex3f);
2585         R_Mesh_ColorPointer(NULL);
2586
2587         // set up a 50% darkening blend on shadowed areas
2588         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2589         GL_DepthTest(false);
2590         GL_DepthMask(false);
2591         qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
2592         GL_Color(0, 0, 0, 0.5);
2593         GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
2594         qglDepthFunc(GL_ALWAYS);CHECKGLERROR
2595         qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2596         qglStencilMask(~0);CHECKGLERROR
2597         qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
2598         qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
2599
2600         // apply the blend to the shadowed areas
2601         R_Mesh_Draw(0, 4, 2, polygonelements);
2602
2603         // restore perspective view
2604         R_SetupView(&r_view.matrix);
2605
2606         // restore other state to normal
2607         GL_DepthTest(true);
2608         R_Shadow_RenderMode_End();
2609 }
2610
2611
2612 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2613 typedef struct suffixinfo_s
2614 {
2615         char *suffix;
2616         qboolean flipx, flipy, flipdiagonal;
2617 }
2618 suffixinfo_t;
2619 static suffixinfo_t suffix[3][6] =
2620 {
2621         {
2622                 {"px",   false, false, false},
2623                 {"nx",   false, false, false},
2624                 {"py",   false, false, false},
2625                 {"ny",   false, false, false},
2626                 {"pz",   false, false, false},
2627                 {"nz",   false, false, false}
2628         },
2629         {
2630                 {"posx", false, false, false},
2631                 {"negx", false, false, false},
2632                 {"posy", false, false, false},
2633                 {"negy", false, false, false},
2634                 {"posz", false, false, false},
2635                 {"negz", false, false, false}
2636         },
2637         {
2638                 {"rt",    true, false,  true},
2639                 {"lf",   false,  true,  true},
2640                 {"ft",    true,  true, false},
2641                 {"bk",   false, false, false},
2642                 {"up",    true, false,  true},
2643                 {"dn",    true, false,  true}
2644         }
2645 };
2646
2647 static int componentorder[4] = {0, 1, 2, 3};
2648
2649 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2650 {
2651         int i, j, cubemapsize;
2652         unsigned char *cubemappixels, *image_rgba;
2653         rtexture_t *cubemaptexture;
2654         char name[256];
2655         // must start 0 so the first loadimagepixels has no requested width/height
2656         cubemapsize = 0;
2657         cubemappixels = NULL;
2658         cubemaptexture = NULL;
2659         // keep trying different suffix groups (posx, px, rt) until one loads
2660         for (j = 0;j < 3 && !cubemappixels;j++)
2661         {
2662                 // load the 6 images in the suffix group
2663                 for (i = 0;i < 6;i++)
2664                 {
2665                         // generate an image name based on the base and and suffix
2666                         dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2667                         // load it
2668                         if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2669                         {
2670                                 // an image loaded, make sure width and height are equal
2671                                 if (image_width == image_height)
2672                                 {
2673                                         // if this is the first image to load successfully, allocate the cubemap memory
2674                                         if (!cubemappixels && image_width >= 1)
2675                                         {
2676                                                 cubemapsize = image_width;
2677                                                 // note this clears to black, so unavailable sides are black
2678                                                 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2679                                         }
2680                                         // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2681                                         if (cubemappixels)
2682                                                 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);
2683                                 }
2684                                 else
2685                                         Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2686                                 // free the image
2687                                 Mem_Free(image_rgba);
2688                         }
2689                 }
2690         }
2691         // if a cubemap loaded, upload it
2692         if (cubemappixels)
2693         {
2694                 if (!r_shadow_filters_texturepool)
2695                         r_shadow_filters_texturepool = R_AllocTexturePool();
2696                 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
2697                 Mem_Free(cubemappixels);
2698         }
2699         else
2700         {
2701                 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
2702                 for (j = 0;j < 3;j++)
2703                         for (i = 0;i < 6;i++)
2704                                 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2705                 Con_Print(" and was unable to find any of them.\n");
2706         }
2707         return cubemaptexture;
2708 }
2709
2710 rtexture_t *R_Shadow_Cubemap(const char *basename)
2711 {
2712         int i;
2713         for (i = 0;i < numcubemaps;i++)
2714                 if (!strcasecmp(cubemaps[i].basename, basename))
2715                         return cubemaps[i].texture;
2716         if (i >= MAX_CUBEMAPS)
2717                 return r_texture_whitecube;
2718         numcubemaps++;
2719         strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
2720         cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
2721         if (!cubemaps[i].texture)
2722                 cubemaps[i].texture = r_texture_whitecube;
2723         return cubemaps[i].texture;
2724 }
2725
2726 void R_Shadow_FreeCubemaps(void)
2727 {
2728         numcubemaps = 0;
2729         R_FreeTexturePool(&r_shadow_filters_texturepool);
2730 }
2731
2732 dlight_t *R_Shadow_NewWorldLight(void)
2733 {
2734         dlight_t *light;
2735         light = (dlight_t *)Mem_Alloc(r_main_mempool, sizeof(dlight_t));
2736         light->next = r_shadow_worldlightchain;
2737         r_shadow_worldlightchain = light;
2738         return light;
2739 }
2740
2741 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)
2742 {
2743         VectorCopy(origin, light->origin);
2744         light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
2745         light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
2746         light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
2747         light->color[0] = max(color[0], 0);
2748         light->color[1] = max(color[1], 0);
2749         light->color[2] = max(color[2], 0);
2750         light->radius = max(radius, 0);
2751         light->style = style;
2752         if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
2753         {
2754                 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
2755                 light->style = 0;
2756         }
2757         light->shadow = shadowenable;
2758         light->corona = corona;
2759         if (!cubemapname)
2760                 cubemapname = "";
2761         strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
2762         light->coronasizescale = coronasizescale;
2763         light->ambientscale = ambientscale;
2764         light->diffusescale = diffusescale;
2765         light->specularscale = specularscale;
2766         light->flags = flags;
2767         Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
2768
2769         R_RTLight_Update(light, true);
2770 }
2771
2772 void R_Shadow_FreeWorldLight(dlight_t *light)
2773 {
2774         dlight_t **lightpointer;
2775         R_RTLight_Uncompile(&light->rtlight);
2776         for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
2777         if (*lightpointer != light)
2778                 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain");
2779         *lightpointer = light->next;
2780         Mem_Free(light);
2781 }
2782
2783 void R_Shadow_ClearWorldLights(void)
2784 {
2785         while (r_shadow_worldlightchain)
2786                 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
2787         r_shadow_selectedlight = NULL;
2788         R_Shadow_FreeCubemaps();
2789 }
2790
2791 void R_Shadow_SelectLight(dlight_t *light)
2792 {
2793         if (r_shadow_selectedlight)
2794                 r_shadow_selectedlight->selected = false;
2795         r_shadow_selectedlight = light;
2796         if (r_shadow_selectedlight)
2797                 r_shadow_selectedlight->selected = true;
2798 }
2799
2800 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2801 {
2802         // this is never batched (there can be only one)
2803         float scale = r_editlights_cursorgrid.value * 0.5f;
2804         R_DrawSprite(GL_SRC_ALPHA, GL_ONE, r_crosshairs[1]->tex, NULL, false, r_editlights_cursorlocation, r_view.right, r_view.up, scale, -scale, -scale, scale, 1, 1, 1, 0.5f);
2805 }
2806
2807 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2808 {
2809         // this is never batched (due to the ent parameter changing every time)
2810         // so numsurfaces == 1 and surfacelist[0] == lightnumber
2811         float intensity;
2812         const dlight_t *light = (dlight_t *)ent;
2813         intensity = 0.5;
2814         if (light->selected)
2815                 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
2816         if (!light->shadow)
2817                 intensity *= 0.5f;
2818         R_DrawSprite(GL_SRC_ALPHA, GL_ONE, r_crosshairs[surfacelist[0]]->tex, NULL, false, light->origin, r_view.right, r_view.up, 8, -8, -8, 8, intensity, intensity, intensity, 0.5);
2819 }
2820
2821 void R_Shadow_DrawLightSprites(void)
2822 {
2823         int i;
2824         dlight_t *light;
2825
2826         for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
2827                 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 1+(i % 5), &light->rtlight);
2828         R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
2829 }
2830
2831 void R_Shadow_SelectLightInView(void)
2832 {
2833         float bestrating, rating, temp[3];
2834         dlight_t *best, *light;
2835         best = NULL;
2836         bestrating = 0;
2837         for (light = r_shadow_worldlightchain;light;light = light->next)
2838         {
2839                 VectorSubtract(light->origin, r_view.origin, temp);
2840                 rating = (DotProduct(temp, r_view.forward) / sqrt(DotProduct(temp, temp)));
2841                 if (rating >= 0.95)
2842                 {
2843                         rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
2844                         if (bestrating < rating && CL_TraceBox(light->origin, vec3_origin, vec3_origin, r_view.origin, true, NULL, SUPERCONTENTS_SOLID, false).fraction == 1.0f)
2845                         {
2846                                 bestrating = rating;
2847                                 best = light;
2848                         }
2849                 }
2850         }
2851         R_Shadow_SelectLight(best);
2852 }
2853
2854 void R_Shadow_LoadWorldLights(void)
2855 {
2856         int n, a, style, shadow, flags;
2857         char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
2858         float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
2859         if (r_refdef.worldmodel == NULL)
2860         {
2861                 Con_Print("No map loaded.\n");
2862                 return;
2863         }
2864         FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
2865         strlcat (name, ".rtlights", sizeof (name));
2866         lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
2867         if (lightsstring)
2868         {
2869                 s = lightsstring;
2870                 n = 0;
2871                 while (*s)
2872                 {
2873                         t = s;
2874                         /*
2875                         shadow = true;
2876                         for (;COM_Parse(t, true) && strcmp(
2877                         if (COM_Parse(t, true))
2878                         {
2879                                 if (com_token[0] == '!')
2880                                 {
2881                                         shadow = false;
2882                                         origin[0] = atof(com_token+1);
2883                                 }
2884                                 else
2885                                         origin[0] = atof(com_token);
2886                                 if (Com_Parse(t
2887                         }
2888                         */
2889                         t = s;
2890                         while (*s && *s != '\n' && *s != '\r')
2891                                 s++;
2892                         if (!*s)
2893                                 break;
2894                         tempchar = *s;
2895                         shadow = true;
2896                         // check for modifier flags
2897                         if (*t == '!')
2898                         {
2899                                 shadow = false;
2900                                 t++;
2901                         }
2902                         *s = 0;
2903                         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);
2904                         *s = tempchar;
2905                         if (a < 18)
2906                                 flags = LIGHTFLAG_REALTIMEMODE;
2907                         if (a < 17)
2908                                 specularscale = 1;
2909                         if (a < 16)
2910                                 diffusescale = 1;
2911                         if (a < 15)
2912                                 ambientscale = 0;
2913                         if (a < 14)
2914                                 coronasizescale = 0.25f;
2915                         if (a < 13)
2916                                 VectorClear(angles);
2917                         if (a < 10)
2918                                 corona = 0;
2919                         if (a < 9 || !strcmp(cubemapname, "\"\""))
2920                                 cubemapname[0] = 0;
2921                         // remove quotes on cubemapname
2922                         if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
2923                         {
2924                                 size_t namelen;
2925                                 namelen = strlen(cubemapname) - 2;
2926                                 memmove(cubemapname, cubemapname + 1, namelen);
2927                                 cubemapname[namelen] = '\0';
2928                         }
2929                         if (a < 8)
2930                         {
2931                                 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);
2932                                 break;
2933                         }
2934                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
2935                         if (*s == '\r')
2936                                 s++;
2937                         if (*s == '\n')
2938                                 s++;
2939                         n++;
2940                 }
2941                 if (*s)
2942                         Con_Printf("invalid rtlights file \"%s\"\n", name);
2943                 Mem_Free(lightsstring);
2944         }
2945 }
2946
2947 void R_Shadow_SaveWorldLights(void)
2948 {
2949         dlight_t *light;
2950         size_t bufchars, bufmaxchars;
2951         char *buf, *oldbuf;
2952         char name[MAX_QPATH];
2953         char line[MAX_INPUTLINE];
2954         if (!r_shadow_worldlightchain)
2955                 return;
2956         if (r_refdef.worldmodel == NULL)
2957         {
2958                 Con_Print("No map loaded.\n");
2959                 return;
2960         }
2961         FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
2962         strlcat (name, ".rtlights", sizeof (name));
2963         bufchars = bufmaxchars = 0;
2964         buf = NULL;
2965         for (light = r_shadow_worldlightchain;light;light = light->next)
2966         {
2967                 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
2968                         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);
2969                 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
2970                         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]);
2971                 else
2972                         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);
2973                 if (bufchars + strlen(line) > bufmaxchars)
2974                 {
2975                         bufmaxchars = bufchars + strlen(line) + 2048;
2976                         oldbuf = buf;
2977                         buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
2978                         if (oldbuf)
2979                         {
2980                                 if (bufchars)
2981                                         memcpy(buf, oldbuf, bufchars);
2982                                 Mem_Free(oldbuf);
2983                         }
2984                 }
2985                 if (strlen(line))
2986                 {
2987                         memcpy(buf + bufchars, line, strlen(line));
2988                         bufchars += strlen(line);
2989                 }
2990         }
2991         if (bufchars)
2992                 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
2993         if (buf)
2994                 Mem_Free(buf);
2995 }
2996
2997 void R_Shadow_LoadLightsFile(void)
2998 {
2999         int n, a, style;
3000         char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3001         float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3002         if (r_refdef.worldmodel == NULL)
3003         {
3004                 Con_Print("No map loaded.\n");
3005                 return;
3006         }
3007         FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3008         strlcat (name, ".lights", sizeof (name));
3009         lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3010         if (lightsstring)
3011         {
3012                 s = lightsstring;
3013                 n = 0;
3014                 while (*s)
3015                 {
3016                         t = s;
3017                         while (*s && *s != '\n' && *s != '\r')
3018                                 s++;
3019                         if (!*s)
3020                                 break;
3021                         tempchar = *s;
3022                         *s = 0;
3023                         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);
3024                         *s = tempchar;
3025                         if (a < 14)
3026                         {
3027                                 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);
3028                                 break;
3029                         }
3030                         radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3031                         radius = bound(15, radius, 4096);
3032                         VectorScale(color, (2.0f / (8388608.0f)), color);
3033                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3034                         if (*s == '\r')
3035                                 s++;
3036                         if (*s == '\n')
3037                                 s++;
3038                         n++;
3039                 }
3040                 if (*s)
3041                         Con_Printf("invalid lights file \"%s\"\n", name);
3042                 Mem_Free(lightsstring);
3043         }
3044 }
3045
3046 // tyrlite/hmap2 light types in the delay field
3047 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3048
3049 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3050 {
3051         int entnum, style, islight, skin, pflags, effects, type, n;
3052         char *entfiledata;
3053         const char *data;
3054         float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3055         char key[256], value[MAX_INPUTLINE];
3056
3057         if (r_refdef.worldmodel == NULL)
3058         {
3059                 Con_Print("No map loaded.\n");
3060                 return;
3061         }
3062         // try to load a .ent file first
3063         FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3064         strlcat (key, ".ent", sizeof (key));
3065         data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
3066         // and if that is not found, fall back to the bsp file entity string
3067         if (!data)
3068                 data = r_refdef.worldmodel->brush.entities;
3069         if (!data)
3070                 return;
3071         for (entnum = 0;COM_ParseTokenConsole(&data) && com_token[0] == '{';entnum++)
3072         {
3073                 type = LIGHTTYPE_MINUSX;
3074                 origin[0] = origin[1] = origin[2] = 0;
3075                 originhack[0] = originhack[1] = originhack[2] = 0;
3076                 angles[0] = angles[1] = angles[2] = 0;
3077                 color[0] = color[1] = color[2] = 1;
3078                 light[0] = light[1] = light[2] = 1;light[3] = 300;
3079                 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3080                 fadescale = 1;
3081                 lightscale = 1;
3082                 style = 0;
3083                 skin = 0;
3084                 pflags = 0;
3085                 effects = 0;
3086                 islight = false;
3087                 while (1)
3088                 {
3089                         if (!COM_ParseTokenConsole(&data))
3090                                 break; // error
3091                         if (com_token[0] == '}')
3092                                 break; // end of entity
3093                         if (com_token[0] == '_')
3094                                 strlcpy(key, com_token + 1, sizeof(key));
3095                         else
3096                                 strlcpy(key, com_token, sizeof(key));
3097                         while (key[strlen(key)-1] == ' ') // remove trailing spaces
3098                                 key[strlen(key)-1] = 0;
3099                         if (!COM_ParseTokenConsole(&data))
3100                                 break; // error
3101                         strlcpy(value, com_token, sizeof(value));
3102
3103                         // now that we have the key pair worked out...
3104                         if (!strcmp("light", key))
3105                         {
3106                                 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3107                                 if (n == 1)
3108                                 {
3109                                         // quake
3110                                         light[0] = vec[0] * (1.0f / 256.0f);
3111                                         light[1] = vec[0] * (1.0f / 256.0f);
3112                                         light[2] = vec[0] * (1.0f / 256.0f);
3113                                         light[3] = vec[0];
3114                                 }
3115                                 else if (n == 4)
3116                                 {
3117                                         // halflife
3118                                         light[0] = vec[0] * (1.0f / 255.0f);
3119                                         light[1] = vec[1] * (1.0f / 255.0f);
3120                                         light[2] = vec[2] * (1.0f / 255.0f);
3121                                         light[3] = vec[3];
3122                                 }
3123                         }
3124                         else if (!strcmp("delay", key))
3125                                 type = atoi(value);
3126                         else if (!strcmp("origin", key))
3127                                 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3128                         else if (!strcmp("angle", key))
3129                                 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3130                         else if (!strcmp("angles", key))
3131                                 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3132                         else if (!strcmp("color", key))
3133                                 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3134                         else if (!strcmp("wait", key))
3135                                 fadescale = atof(value);
3136                         else if (!strcmp("classname", key))
3137                         {
3138                                 if (!strncmp(value, "light", 5))
3139                                 {
3140                                         islight = true;
3141                                         if (!strcmp(value, "light_fluoro"))
3142                                         {
3143                                                 originhack[0] = 0;
3144                                                 originhack[1] = 0;
3145                                                 originhack[2] = 0;
3146                                                 overridecolor[0] = 1;
3147                                                 overridecolor[1] = 1;
3148                                                 overridecolor[2] = 1;
3149                                         }
3150                                         if (!strcmp(value, "light_fluorospark"))
3151                                         {
3152                                                 originhack[0] = 0;
3153                                                 originhack[1] = 0;
3154                                                 originhack[2] = 0;
3155                                                 overridecolor[0] = 1;
3156                                                 overridecolor[1] = 1;
3157                                                 overridecolor[2] = 1;
3158                                         }
3159                                         if (!strcmp(value, "light_globe"))
3160                                         {
3161                                                 originhack[0] = 0;
3162                                                 originhack[1] = 0;
3163                                                 originhack[2] = 0;
3164                                                 overridecolor[0] = 1;
3165                                                 overridecolor[1] = 0.8;
3166                                                 overridecolor[2] = 0.4;
3167                                         }
3168                                         if (!strcmp(value, "light_flame_large_yellow"))
3169                                         {
3170                                                 originhack[0] = 0;
3171                                                 originhack[1] = 0;
3172                                                 originhack[2] = 0;
3173                                                 overridecolor[0] = 1;
3174                                                 overridecolor[1] = 0.5;
3175                                                 overridecolor[2] = 0.1;
3176                                         }
3177                                         if (!strcmp(value, "light_flame_small_yellow"))
3178                                         {
3179                                                 originhack[0] = 0;
3180                                                 originhack[1] = 0;
3181                                                 originhack[2] = 0;
3182                                                 overridecolor[0] = 1;
3183                                                 overridecolor[1] = 0.5;
3184                                                 overridecolor[2] = 0.1;
3185                                         }
3186                                         if (!strcmp(value, "light_torch_small_white"))
3187                                         {
3188                                                 originhack[0] = 0;
3189                                                 originhack[1] = 0;
3190                                                 originhack[2] = 0;
3191                                                 overridecolor[0] = 1;
3192                                                 overridecolor[1] = 0.5;
3193                                                 overridecolor[2] = 0.1;
3194                                         }
3195                                         if (!strcmp(value, "light_torch_small_walltorch"))
3196                                         {
3197                                                 originhack[0] = 0;
3198                                                 originhack[1] = 0;
3199                                                 originhack[2] = 0;
3200                                                 overridecolor[0] = 1;
3201                                                 overridecolor[1] = 0.5;
3202                                                 overridecolor[2] = 0.1;
3203                                         }
3204                                 }
3205                         }
3206                         else if (!strcmp("style", key))
3207                                 style = atoi(value);
3208                         else if (!strcmp("skin", key))
3209                                 skin = (int)atof(value);
3210                         else if (!strcmp("pflags", key))
3211                                 pflags = (int)atof(value);
3212                         else if (!strcmp("effects", key))
3213                                 effects = (int)atof(value);
3214                         else if (r_refdef.worldmodel->type == mod_brushq3)
3215                         {
3216                                 if (!strcmp("scale", key))
3217                                         lightscale = atof(value);
3218                                 if (!strcmp("fade", key))
3219                                         fadescale = atof(value);
3220                         }
3221                 }
3222                 if (!islight)
3223                         continue;
3224                 if (lightscale <= 0)
3225                         lightscale = 1;
3226                 if (fadescale <= 0)
3227                         fadescale = 1;
3228                 if (color[0] == color[1] && color[0] == color[2])
3229                 {
3230                         color[0] *= overridecolor[0];
3231                         color[1] *= overridecolor[1];
3232                         color[2] *= overridecolor[2];
3233                 }
3234                 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3235                 color[0] = color[0] * light[0];
3236                 color[1] = color[1] * light[1];
3237                 color[2] = color[2] * light[2];
3238                 switch (type)
3239                 {
3240                 case LIGHTTYPE_MINUSX:
3241                         break;
3242                 case LIGHTTYPE_RECIPX:
3243                         radius *= 2;
3244                         VectorScale(color, (1.0f / 16.0f), color);
3245                         break;
3246                 case LIGHTTYPE_RECIPXX:
3247                         radius *= 2;
3248                         VectorScale(color, (1.0f / 16.0f), color);
3249                         break;
3250                 default:
3251                 case LIGHTTYPE_NONE:
3252                         break;
3253                 case LIGHTTYPE_SUN:
3254                         break;
3255                 case LIGHTTYPE_MINUSXX:
3256                         break;
3257                 }
3258                 VectorAdd(origin, originhack, origin);
3259                 if (radius >= 1)
3260                         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);
3261         }
3262         if (entfiledata)
3263                 Mem_Free(entfiledata);
3264 }
3265
3266
3267 void R_Shadow_SetCursorLocationForView(void)
3268 {
3269         vec_t dist, push;
3270         vec3_t dest, endpos;
3271         trace_t trace;
3272         VectorMA(r_view.origin, r_editlights_cursordistance.value, r_view.forward, dest);
3273         trace = CL_TraceBox(r_view.origin, vec3_origin, vec3_origin, dest, true, NULL, SUPERCONTENTS_SOLID, false);
3274         if (trace.fraction < 1)
3275         {
3276                 dist = trace.fraction * r_editlights_cursordistance.value;
3277                 push = r_editlights_cursorpushback.value;
3278                 if (push > dist)
3279                         push = dist;
3280                 push = -push;
3281                 VectorMA(trace.endpos, push, r_view.forward, endpos);
3282                 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
3283         }
3284         else
3285         {
3286                 VectorClear( endpos );
3287         }
3288         r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3289         r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3290         r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3291 }
3292
3293 void R_Shadow_UpdateWorldLightSelection(void)
3294 {
3295         if (r_editlights.integer)
3296         {
3297                 R_Shadow_SetCursorLocationForView();
3298                 R_Shadow_SelectLightInView();
3299                 R_Shadow_DrawLightSprites();
3300         }
3301         else
3302                 R_Shadow_SelectLight(NULL);
3303 }
3304
3305 void R_Shadow_EditLights_Clear_f(void)
3306 {
3307         R_Shadow_ClearWorldLights();
3308 }
3309
3310 void R_Shadow_EditLights_Reload_f(void)
3311 {
3312         if (!r_refdef.worldmodel)
3313                 return;
3314         strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3315         R_Shadow_ClearWorldLights();
3316         R_Shadow_LoadWorldLights();
3317         if (r_shadow_worldlightchain == NULL)
3318         {
3319                 R_Shadow_LoadLightsFile();
3320                 if (r_shadow_worldlightchain == NULL)
3321                         R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3322         }
3323 }
3324
3325 void R_Shadow_EditLights_Save_f(void)
3326 {
3327         if (!r_refdef.worldmodel)
3328                 return;
3329         R_Shadow_SaveWorldLights();
3330 }
3331
3332 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3333 {
3334         R_Shadow_ClearWorldLights();
3335         R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3336 }
3337
3338 void R_Shadow_EditLights_ImportLightsFile_f(void)
3339 {
3340         R_Shadow_ClearWorldLights();
3341         R_Shadow_LoadLightsFile();
3342 }
3343
3344 void R_Shadow_EditLights_Spawn_f(void)
3345 {
3346         vec3_t color;
3347         if (!r_editlights.integer)
3348         {
3349                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
3350                 return;
3351         }
3352         if (Cmd_Argc() != 1)
3353         {
3354                 Con_Print("r_editlights_spawn does not take parameters\n");
3355                 return;
3356         }
3357         color[0] = color[1] = color[2] = 1;
3358         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3359 }
3360
3361 void R_Shadow_EditLights_Edit_f(void)
3362 {
3363         vec3_t origin, angles, color;
3364         vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3365         int style, shadows, flags, normalmode, realtimemode;
3366         char cubemapname[MAX_INPUTLINE];
3367         if (!r_editlights.integer)
3368         {
3369                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
3370                 return;
3371         }
3372         if (!r_shadow_selectedlight)
3373         {
3374                 Con_Print("No selected light.\n");
3375                 return;
3376         }
3377         VectorCopy(r_shadow_selectedlight->origin, origin);
3378         VectorCopy(r_shadow_selectedlight->angles, angles);
3379         VectorCopy(r_shadow_selectedlight->color, color);
3380         radius = r_shadow_selectedlight->radius;
3381         style = r_shadow_selectedlight->style;
3382         if (r_shadow_selectedlight->cubemapname)
3383                 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
3384         else
3385                 cubemapname[0] = 0;
3386         shadows = r_shadow_selectedlight->shadow;
3387         corona = r_shadow_selectedlight->corona;
3388         coronasizescale = r_shadow_selectedlight->coronasizescale;
3389         ambientscale = r_shadow_selectedlight->ambientscale;
3390         diffusescale = r_shadow_selectedlight->diffusescale;
3391         specularscale = r_shadow_selectedlight->specularscale;
3392         flags = r_shadow_selectedlight->flags;
3393         normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3394         realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3395         if (!strcmp(Cmd_Argv(1), "origin"))
3396         {
3397                 if (Cmd_Argc() != 5)
3398                 {
3399                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3400                         return;
3401                 }
3402                 origin[0] = atof(Cmd_Argv(2));
3403                 origin[1] = atof(Cmd_Argv(3));
3404                 origin[2] = atof(Cmd_Argv(4));
3405         }
3406         else if (!strcmp(Cmd_Argv(1), "originx"))
3407         {
3408                 if (Cmd_Argc() != 3)
3409                 {
3410                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3411                         return;
3412                 }
3413                 origin[0] = atof(Cmd_Argv(2));
3414         }
3415         else if (!strcmp(Cmd_Argv(1), "originy"))
3416         {
3417                 if (Cmd_Argc() != 3)
3418                 {
3419                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3420                         return;
3421                 }
3422                 origin[1] = atof(Cmd_Argv(2));
3423         }
3424         else if (!strcmp(Cmd_Argv(1), "originz"))
3425         {
3426                 if (Cmd_Argc() != 3)
3427                 {
3428                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3429                         return;
3430                 }
3431                 origin[2] = atof(Cmd_Argv(2));
3432         }
3433         else if (!strcmp(Cmd_Argv(1), "move"))
3434         {
3435                 if (Cmd_Argc() != 5)
3436                 {
3437                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3438                         return;
3439                 }
3440                 origin[0] += atof(Cmd_Argv(2));
3441                 origin[1] += atof(Cmd_Argv(3));
3442                 origin[2] += atof(Cmd_Argv(4));
3443         }
3444         else if (!strcmp(Cmd_Argv(1), "movex"))
3445         {
3446                 if (Cmd_Argc() != 3)
3447                 {
3448                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3449                         return;
3450                 }
3451                 origin[0] += atof(Cmd_Argv(2));
3452         }
3453         else if (!strcmp(Cmd_Argv(1), "movey"))
3454         {
3455                 if (Cmd_Argc() != 3)
3456                 {
3457                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3458                         return;
3459                 }
3460                 origin[1] += atof(Cmd_Argv(2));
3461         }
3462         else if (!strcmp(Cmd_Argv(1), "movez"))
3463         {
3464                 if (Cmd_Argc() != 3)
3465                 {
3466                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3467                         return;
3468                 }
3469                 origin[2] += atof(Cmd_Argv(2));
3470         }
3471         else if (!strcmp(Cmd_Argv(1), "angles"))
3472         {
3473                 if (Cmd_Argc() != 5)
3474                 {
3475                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3476                         return;
3477                 }
3478                 angles[0] = atof(Cmd_Argv(2));
3479                 angles[1] = atof(Cmd_Argv(3));
3480                 angles[2] = atof(Cmd_Argv(4));
3481         }
3482         else if (!strcmp(Cmd_Argv(1), "anglesx"))
3483         {
3484                 if (Cmd_Argc() != 3)
3485                 {
3486                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3487                         return;
3488                 }
3489                 angles[0] = atof(Cmd_Argv(2));
3490         }
3491         else if (!strcmp(Cmd_Argv(1), "anglesy"))
3492         {
3493                 if (Cmd_Argc() != 3)
3494                 {
3495                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3496                         return;
3497                 }
3498                 angles[1] = atof(Cmd_Argv(2));
3499         }
3500         else if (!strcmp(Cmd_Argv(1), "anglesz"))
3501         {
3502                 if (Cmd_Argc() != 3)
3503                 {
3504                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3505                         return;
3506                 }
3507                 angles[2] = atof(Cmd_Argv(2));
3508         }
3509         else if (!strcmp(Cmd_Argv(1), "color"))
3510         {
3511                 if (Cmd_Argc() != 5)
3512                 {
3513                         Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3514                         return;
3515                 }
3516                 color[0] = atof(Cmd_Argv(2));
3517                 color[1] = atof(Cmd_Argv(3));
3518                 color[2] = atof(Cmd_Argv(4));
3519         }
3520         else if (!strcmp(Cmd_Argv(1), "radius"))
3521         {
3522                 if (Cmd_Argc() != 3)
3523                 {
3524                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3525                         return;
3526                 }
3527                 radius = atof(Cmd_Argv(2));
3528         }
3529         else if (!strcmp(Cmd_Argv(1), "colorscale"))
3530         {
3531                 if (Cmd_Argc() == 3)
3532                 {
3533                         double scale = atof(Cmd_Argv(2));
3534                         color[0] *= scale;
3535                         color[1] *= scale;
3536                         color[2] *= scale;
3537                 }
3538                 else
3539                 {
3540                         if (Cmd_Argc() != 5)
3541                         {
3542                                 Con_Printf("usage: r_editlights_edit %s red green blue  (OR grey instead of red green blue)\n", Cmd_Argv(1));
3543                                 return;
3544                         }
3545                         color[0] *= atof(Cmd_Argv(2));
3546                         color[1] *= atof(Cmd_Argv(3));
3547                         color[2] *= atof(Cmd_Argv(4));
3548                 }
3549         }
3550         else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
3551         {
3552                 if (Cmd_Argc() != 3)
3553                 {
3554                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3555                         return;
3556                 }
3557                 radius *= atof(Cmd_Argv(2));
3558         }
3559         else if (!strcmp(Cmd_Argv(1), "style"))
3560         {
3561                 if (Cmd_Argc() != 3)
3562                 {
3563                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3564                         return;
3565                 }
3566                 style = atoi(Cmd_Argv(2));
3567         }
3568         else if (!strcmp(Cmd_Argv(1), "cubemap"))
3569         {
3570                 if (Cmd_Argc() > 3)
3571                 {
3572                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3573                         return;
3574                 }
3575                 if (Cmd_Argc() == 3)
3576                         strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
3577                 else
3578                         cubemapname[0] = 0;
3579         }
3580         else if (!strcmp(Cmd_Argv(1), "shadows"))
3581         {
3582                 if (Cmd_Argc() != 3)
3583                 {
3584                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3585                         return;
3586                 }
3587                 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3588         }
3589         else if (!strcmp(Cmd_Argv(1), "corona"))
3590         {
3591                 if (Cmd_Argc() != 3)
3592                 {
3593                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3594                         return;
3595                 }
3596                 corona = atof(Cmd_Argv(2));
3597         }
3598         else if (!strcmp(Cmd_Argv(1), "coronasize"))
3599         {
3600                 if (Cmd_Argc() != 3)
3601                 {
3602                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3603                         return;
3604                 }
3605                 coronasizescale = atof(Cmd_Argv(2));
3606         }
3607         else if (!strcmp(Cmd_Argv(1), "ambient"))
3608         {
3609                 if (Cmd_Argc() != 3)
3610                 {
3611                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3612                         return;
3613                 }
3614                 ambientscale = atof(Cmd_Argv(2));
3615         }
3616         else if (!strcmp(Cmd_Argv(1), "diffuse"))
3617         {
3618                 if (Cmd_Argc() != 3)
3619                 {
3620                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3621                         return;
3622                 }
3623                 diffusescale = atof(Cmd_Argv(2));
3624         }
3625         else if (!strcmp(Cmd_Argv(1), "specular"))
3626         {
3627                 if (Cmd_Argc() != 3)
3628                 {
3629                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3630                         return;
3631                 }
3632                 specularscale = atof(Cmd_Argv(2));
3633         }
3634         else if (!strcmp(Cmd_Argv(1), "normalmode"))
3635         {
3636                 if (Cmd_Argc() != 3)
3637                 {
3638                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3639                         return;
3640                 }
3641                 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3642         }
3643         else if (!strcmp(Cmd_Argv(1), "realtimemode"))
3644         {
3645                 if (Cmd_Argc() != 3)
3646                 {
3647                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3648                         return;
3649                 }
3650                 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3651         }
3652         else
3653         {
3654                 Con_Print("usage: r_editlights_edit [property] [value]\n");
3655                 Con_Print("Selected light's properties:\n");
3656                 Con_Printf("Origin       : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3657                 Con_Printf("Angles       : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3658                 Con_Printf("Color        : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3659                 Con_Printf("Radius       : %f\n", r_shadow_selectedlight->radius);
3660                 Con_Printf("Corona       : %f\n", r_shadow_selectedlight->corona);
3661                 Con_Printf("Style        : %i\n", r_shadow_selectedlight->style);
3662                 Con_Printf("Shadows      : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3663                 Con_Printf("Cubemap      : %s\n", r_shadow_selectedlight->cubemapname);
3664                 Con_Printf("CoronaSize   : %f\n", r_shadow_selectedlight->coronasizescale);
3665                 Con_Printf("Ambient      : %f\n", r_shadow_selectedlight->ambientscale);
3666                 Con_Printf("Diffuse      : %f\n", r_shadow_selectedlight->diffusescale);
3667                 Con_Printf("Specular     : %f\n", r_shadow_selectedlight->specularscale);
3668                 Con_Printf("NormalMode   : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
3669                 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
3670                 return;
3671         }
3672         flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
3673         R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3674 }
3675
3676 void R_Shadow_EditLights_EditAll_f(void)
3677 {
3678         dlight_t *light;
3679
3680         if (!r_editlights.integer)
3681         {
3682                 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
3683                 return;
3684         }
3685
3686         for (light = r_shadow_worldlightchain;light;light = light->next)
3687         {
3688                 R_Shadow_SelectLight(light);
3689                 R_Shadow_EditLights_Edit_f();
3690         }
3691 }
3692
3693 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3694 {
3695         int lightnumber, lightcount;
3696         dlight_t *light;
3697         float x, y;
3698         char temp[256];
3699         if (!r_editlights.integer)
3700                 return;
3701         x = 0;
3702         y = con_vislines;
3703         lightnumber = -1;
3704         lightcount = 0;
3705         for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
3706                 if (light == r_shadow_selectedlight)
3707                         lightnumber = lightcount;
3708         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;
3709         if (r_shadow_selectedlight == NULL)
3710                 return;
3711         sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3712         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;
3713         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;
3714         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;
3715         sprintf(temp, "Radius       : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3716         sprintf(temp, "Corona       : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3717         sprintf(temp, "Style        : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3718         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;
3719         sprintf(temp, "Cubemap      : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3720         sprintf(temp, "CoronaSize   : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3721         sprintf(temp, "Ambient      : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3722         sprintf(temp, "Diffuse      : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3723         sprintf(temp, "Specular     : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3724         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;
3725         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;
3726 }
3727
3728 void R_Shadow_EditLights_ToggleShadow_f(void)
3729 {
3730         if (!r_editlights.integer)
3731         {
3732                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
3733                 return;
3734         }
3735         if (!r_shadow_selectedlight)
3736         {
3737                 Con_Print("No selected light.\n");
3738                 return;
3739         }
3740         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);
3741 }
3742
3743 void R_Shadow_EditLights_ToggleCorona_f(void)
3744 {
3745         if (!r_editlights.integer)
3746         {
3747                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
3748                 return;
3749         }
3750         if (!r_shadow_selectedlight)
3751         {
3752                 Con_Print("No selected light.\n");
3753                 return;
3754         }
3755         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);
3756 }
3757
3758 void R_Shadow_EditLights_Remove_f(void)
3759 {
3760         if (!r_editlights.integer)
3761         {
3762                 Con_Print("Cannot remove light when not in editing mode.  Set r_editlights to 1.\n");
3763                 return;
3764         }
3765         if (!r_shadow_selectedlight)
3766         {
3767                 Con_Print("No selected light.\n");
3768                 return;
3769         }
3770         R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3771         r_shadow_selectedlight = NULL;
3772 }
3773
3774 void R_Shadow_EditLights_Help_f(void)
3775 {
3776         Con_Print(
3777 "Documentation on r_editlights system:\n"
3778 "Settings:\n"
3779 "r_editlights : enable/disable editing mode\n"
3780 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
3781 "r_editlights_cursorpushback : push back cursor this far from surface\n"
3782 "r_editlights_cursorpushoff : push cursor off surface this far\n"
3783 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
3784 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
3785 "Commands:\n"
3786 "r_editlights_help : this help\n"
3787 "r_editlights_clear : remove all lights\n"
3788 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
3789 "r_editlights_save : save to .rtlights file\n"
3790 "r_editlights_spawn : create a light with default settings\n"
3791 "r_editlights_edit command : edit selected light - more documentation below\n"
3792 "r_editlights_remove : remove selected light\n"
3793 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
3794 "r_editlights_importlightentitiesfrommap : reload light entities\n"
3795 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
3796 "Edit commands:\n"
3797 "origin x y z : set light location\n"
3798 "originx x: set x component of light location\n"
3799 "originy y: set y component of light location\n"
3800 "originz z: set z component of light location\n"
3801 "move x y z : adjust light location\n"
3802 "movex x: adjust x component of light location\n"
3803 "movey y: adjust y component of light location\n"
3804 "movez z: adjust z component of light location\n"
3805 "angles x y z : set light angles\n"
3806 "anglesx x: set x component of light angles\n"
3807 "anglesy y: set y component of light angles\n"
3808 "anglesz z: set z component of light angles\n"
3809 "color r g b : set color of light (can be brighter than 1 1 1)\n"
3810 "radius radius : set radius (size) of light\n"
3811 "colorscale grey : multiply color of light (1 does nothing)\n"
3812 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
3813 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
3814 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
3815 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
3816 "cubemap basename : set filter cubemap of light (not yet supported)\n"
3817 "shadows 1/0 : turn on/off shadows\n"
3818 "corona n : set corona intensity\n"
3819 "coronasize n : set corona size (0-1)\n"
3820 "ambient n : set ambient intensity (0-1)\n"
3821 "diffuse n : set diffuse intensity (0-1)\n"
3822 "specular n : set specular intensity (0-1)\n"
3823 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
3824 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
3825 "<nothing> : print light properties to console\n"
3826         );
3827 }
3828
3829 void R_Shadow_EditLights_CopyInfo_f(void)
3830 {
3831         if (!r_editlights.integer)
3832         {
3833                 Con_Print("Cannot copy light info when not in editing mode.  Set r_editlights to 1.\n");
3834                 return;
3835         }
3836         if (!r_shadow_selectedlight)
3837         {
3838                 Con_Print("No selected light.\n");
3839                 return;
3840         }
3841         VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
3842         VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
3843         r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
3844         r_shadow_bufferlight.style = r_shadow_selectedlight->style;
3845         if (r_shadow_selectedlight->cubemapname)
3846                 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
3847         else
3848                 r_shadow_bufferlight.cubemapname[0] = 0;
3849         r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
3850         r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
3851         r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
3852         r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
3853         r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
3854         r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
3855         r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
3856 }
3857
3858 void R_Shadow_EditLights_PasteInfo_f(void)
3859 {
3860         if (!r_editlights.integer)
3861         {
3862                 Con_Print("Cannot paste light info when not in editing mode.  Set r_editlights to 1.\n");
3863                 return;
3864         }
3865         if (!r_shadow_selectedlight)
3866         {
3867                 Con_Print("No selected light.\n");
3868                 return;
3869         }
3870         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);
3871 }
3872
3873 void R_Shadow_EditLights_Init(void)
3874 {
3875         Cvar_RegisterVariable(&r_editlights);
3876         Cvar_RegisterVariable(&r_editlights_cursordistance);
3877         Cvar_RegisterVariable(&r_editlights_cursorpushback);
3878         Cvar_RegisterVariable(&r_editlights_cursorpushoff);
3879         Cvar_RegisterVariable(&r_editlights_cursorgrid);
3880         Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
3881         Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
3882         Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
3883         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)");
3884         Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
3885         Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
3886         Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
3887         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)");
3888         Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
3889         Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
3890         Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
3891         Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
3892         Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
3893         Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
3894         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)");
3895 }
3896