]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - r_shadow.c
shadowmap projection fixes
[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 #define R_SHADOW_SHADOWMAP_NUMCUBEMAPS 8
144
145 extern void R_Shadow_EditLights_Init(void);
146
147 typedef enum r_shadow_rendermode_e
148 {
149         R_SHADOW_RENDERMODE_NONE,
150         R_SHADOW_RENDERMODE_ZPASS_STENCIL,
151         R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL,
152         R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE,
153         R_SHADOW_RENDERMODE_ZFAIL_STENCIL,
154         R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL,
155         R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE,
156         R_SHADOW_RENDERMODE_LIGHT_VERTEX,
157         R_SHADOW_RENDERMODE_LIGHT_DOT3,
158         R_SHADOW_RENDERMODE_LIGHT_GLSL,
159         R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
160         R_SHADOW_RENDERMODE_VISIBLELIGHTING,
161         R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE,
162         R_SHADOW_RENDERMODE_SHADOWMAP2D,
163         R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE,
164 }
165 r_shadow_rendermode_t;
166
167 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
168 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
169 r_shadow_rendermode_t r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_NONE;
170 r_shadow_rendermode_t r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_NONE;
171 qboolean r_shadow_usingshadowmaprect;
172 qboolean r_shadow_usingshadowmap2d;
173 qboolean r_shadow_usingshadowmapcube;
174 float r_shadow_shadowmap_texturescale[4];
175 float r_shadow_shadowmap_parameters[4];
176 int r_shadow_drawbuffer;
177 int r_shadow_readbuffer;
178 GLuint r_shadow_fborectangle;
179 GLuint r_shadow_fbocubeside[R_SHADOW_SHADOWMAP_NUMCUBEMAPS][6];
180 GLuint r_shadow_fbo2d;
181 int r_shadow_shadowmode;
182 int r_shadow_shadowmapvsdct;
183 int r_shadow_shadowmapmaxsize;
184 int r_shadow_shadowmapfilter;
185 int r_shadow_shadowmapborder;
186 int r_shadow_lightscissor[4];
187
188 int maxshadowtriangles;
189 int *shadowelements;
190
191 int maxshadowvertices;
192 float *shadowvertex3f;
193
194 int maxshadowmark;
195 int numshadowmark;
196 int *shadowmark;
197 int *shadowmarklist;
198 int shadowmarkcount;
199
200 int maxvertexupdate;
201 int *vertexupdate;
202 int *vertexremap;
203 int vertexupdatenum;
204
205 int r_shadow_buffer_numleafpvsbytes;
206 unsigned char *r_shadow_buffer_visitingleafpvs;
207 unsigned char *r_shadow_buffer_leafpvs;
208 int *r_shadow_buffer_leaflist;
209
210 int r_shadow_buffer_numsurfacepvsbytes;
211 unsigned char *r_shadow_buffer_surfacepvs;
212 int *r_shadow_buffer_surfacelist;
213
214 int r_shadow_buffer_numshadowtrispvsbytes;
215 unsigned char *r_shadow_buffer_shadowtrispvs;
216 int r_shadow_buffer_numlighttrispvsbytes;
217 unsigned char *r_shadow_buffer_lighttrispvs;
218
219 rtexturepool_t *r_shadow_texturepool;
220 rtexture_t *r_shadow_attenuationgradienttexture;
221 rtexture_t *r_shadow_attenuation2dtexture;
222 rtexture_t *r_shadow_attenuation3dtexture;
223 rtexture_t *r_shadow_lightcorona;
224 rtexture_t *r_shadow_shadowmaprectangletexture;
225 rtexture_t *r_shadow_shadowmap2dtexture;
226 rtexture_t *r_shadow_shadowmapcubetexture[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
227 rtexture_t *r_shadow_shadowmapcubeprojectiontexture[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
228 int r_shadow_shadowmapsize; // changes for each light based on distance
229 int r_shadow_shadowmaplod; // changes for each light based on distance
230
231 // lights are reloaded when this changes
232 char r_shadow_mapname[MAX_QPATH];
233
234 // used only for light filters (cubemaps)
235 rtexturepool_t *r_shadow_filters_texturepool;
236
237 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"};
238 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"};
239 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
240 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
241 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)"};
242 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.125", "how bright the forced flat gloss should look if r_shadow_gloss is 2"};
243 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
244 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
245 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
246 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
247 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
248 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
249 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
250 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"};
251 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000", "how far to cast shadows"};
252 cvar_t r_shadow_frontsidecasting = {0, "r_shadow_frontsidecasting", "1", "whether to cast shadows from illuminated triangles (front side of model) or unlit triangles (back side of model)"};
253 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
254 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
255 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
256 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
257 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)"};
258 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"};
259 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
260 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
261 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"};
262 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation"};
263 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation"};
264 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)"};
265 cvar_t r_shadow_shadowmapping = {CVAR_SAVE, "r_shadow_shadowmapping", "0", "enables use of shadowmapping (depth texture sampling) instead of stencil shadow volumes, requires gl_fbo 1"};
266 cvar_t r_shadow_shadowmapping_filterquality = {CVAR_SAVE, "r_shadow_shadowmapping_filterquality", "0", "shadowmap filter modes: 0 = no filtering, 1 = bilinear, 2 = bilinear small blur (fast), 3 = bilinear large blur (slow)"};
267 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
268 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
269 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"};
270 cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
271 cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
272 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"};
273 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
274 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
275 cvar_t r_shadow_culltriangles = {0, "r_shadow_culltriangles", "1", "performs more expensive tests to remove unnecessary triangles of lit surfaces"};
276 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
277 cvar_t r_shadow_polygonoffset = {0, "r_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)"};
278 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)"};
279 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
280 cvar_t r_coronas_occlusionsizescale = {CVAR_SAVE, "r_coronas_occlusionsizescale", "0.1", "size of light source for corona occlusion checksm the proportion of hidden pixels controls corona intensity"};
281 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
282 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
283 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
284 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
285 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
286 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
287 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
288 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
289 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
290 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
291
292 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
293 #define ATTENTABLESIZE 256
294 // 1D gradient, 2D circle and 3D sphere attenuation textures
295 #define ATTEN1DSIZE 32
296 #define ATTEN2DSIZE 64
297 #define ATTEN3DSIZE 32
298
299 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
300 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
301 static float r_shadow_attentable[ATTENTABLESIZE+1];
302
303 rtlight_t *r_shadow_compilingrtlight;
304 static memexpandablearray_t r_shadow_worldlightsarray;
305 dlight_t *r_shadow_selectedlight;
306 dlight_t r_shadow_bufferlight;
307 vec3_t r_editlights_cursorlocation;
308
309 extern int con_vislines;
310
311 typedef struct cubemapinfo_s
312 {
313         char basename[64];
314         rtexture_t *texture;
315 }
316 cubemapinfo_t;
317
318 #define MAX_CUBEMAPS 256
319 static int numcubemaps;
320 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
321
322 void R_Shadow_UncompileWorldLights(void);
323 void R_Shadow_ClearWorldLights(void);
324 void R_Shadow_SaveWorldLights(void);
325 void R_Shadow_LoadWorldLights(void);
326 void R_Shadow_LoadLightsFile(void);
327 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
328 void R_Shadow_EditLights_Reload_f(void);
329 void R_Shadow_ValidateCvars(void);
330 static void R_Shadow_MakeTextures(void);
331
332 // VorteX: custom editor light sprites
333 #define EDLIGHTSPRSIZE                  8
334 cachepic_t *r_editlights_sprcursor;
335 cachepic_t *r_editlights_sprlight;
336 cachepic_t *r_editlights_sprnoshadowlight;
337 cachepic_t *r_editlights_sprcubemaplight;
338 cachepic_t *r_editlights_sprcubemapnoshadowlight;
339 cachepic_t *r_editlights_sprselection;
340
341 void R_Shadow_FreeShadowMaps(void)
342 {
343         int i;
344
345         r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, 2048);
346         r_shadow_shadowmode = r_shadow_shadowmapping.integer;
347         r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer;
348         r_shadow_shadowmapfilter = r_shadow_shadowmapping_filterquality.integer;
349         r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
350         r_shadow_shadowmaplod = -1;
351
352         CHECKGLERROR
353         if (r_shadow_fborectangle)
354                 qglDeleteFramebuffersEXT(1, &r_shadow_fborectangle);
355         r_shadow_fborectangle = 0;
356         CHECKGLERROR
357
358         if (r_shadow_fbo2d)
359                 qglDeleteFramebuffersEXT(1, &r_shadow_fbo2d);
360         r_shadow_fbo2d = 0;
361         CHECKGLERROR
362         for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
363                 if (r_shadow_fbocubeside[i][0])
364                         qglDeleteFramebuffersEXT(6, r_shadow_fbocubeside[i]);
365         memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
366         CHECKGLERROR
367
368         if (r_shadow_shadowmaprectangletexture)
369                 R_FreeTexture(r_shadow_shadowmaprectangletexture);
370         r_shadow_shadowmaprectangletexture = NULL;
371
372         if (r_shadow_shadowmap2dtexture)
373                 R_FreeTexture(r_shadow_shadowmap2dtexture);
374         r_shadow_shadowmap2dtexture = NULL;
375
376         for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
377                 if (r_shadow_shadowmapcubetexture[i])
378                         R_FreeTexture(r_shadow_shadowmapcubetexture[i]);
379         memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
380
381         for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
382                 if (r_shadow_shadowmapcubeprojectiontexture[i])
383                         R_FreeTexture(r_shadow_shadowmapcubeprojectiontexture[i]);
384         memset(r_shadow_shadowmapcubeprojectiontexture, 0, sizeof(r_shadow_shadowmapcubeprojectiontexture));
385
386         CHECKGLERROR
387 }
388
389 void r_shadow_start(void)
390 {
391         // allocate vertex processing arrays
392         numcubemaps = 0;
393         r_shadow_attenuationgradienttexture = NULL;
394         r_shadow_attenuation2dtexture = NULL;
395         r_shadow_attenuation3dtexture = NULL;
396         r_shadow_shadowmode = 0;
397         r_shadow_shadowmaprectangletexture = NULL;
398         r_shadow_shadowmap2dtexture = NULL;
399         memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
400         memset(r_shadow_shadowmapcubeprojectiontexture, 0, sizeof(r_shadow_shadowmapcubeprojectiontexture));
401         r_shadow_shadowmapmaxsize = 0;
402         r_shadow_shadowmapsize = 0;
403         r_shadow_shadowmaplod = 0;
404         r_shadow_shadowmapvsdct = 0;
405         r_shadow_shadowmapfilter = 0;
406         r_shadow_fborectangle = 0;
407         r_shadow_fbo2d = 0;
408         memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
409
410         R_Shadow_FreeShadowMaps();
411
412         r_shadow_texturepool = NULL;
413         r_shadow_filters_texturepool = NULL;
414         R_Shadow_ValidateCvars();
415         R_Shadow_MakeTextures();
416         maxshadowtriangles = 0;
417         shadowelements = NULL;
418         maxshadowvertices = 0;
419         shadowvertex3f = NULL;
420         maxvertexupdate = 0;
421         vertexupdate = NULL;
422         vertexremap = NULL;
423         vertexupdatenum = 0;
424         maxshadowmark = 0;
425         numshadowmark = 0;
426         shadowmark = NULL;
427         shadowmarklist = NULL;
428         shadowmarkcount = 0;
429         r_shadow_buffer_numleafpvsbytes = 0;
430         r_shadow_buffer_visitingleafpvs = NULL;
431         r_shadow_buffer_leafpvs = NULL;
432         r_shadow_buffer_leaflist = NULL;
433         r_shadow_buffer_numsurfacepvsbytes = 0;
434         r_shadow_buffer_surfacepvs = NULL;
435         r_shadow_buffer_surfacelist = NULL;
436         r_shadow_buffer_numshadowtrispvsbytes = 0;
437         r_shadow_buffer_shadowtrispvs = NULL;
438         r_shadow_buffer_numlighttrispvsbytes = 0;
439         r_shadow_buffer_lighttrispvs = NULL;
440 }
441
442 void r_shadow_shutdown(void)
443 {
444         CHECKGLERROR
445         R_Shadow_UncompileWorldLights();
446
447         R_Shadow_FreeShadowMaps();
448
449         CHECKGLERROR
450         numcubemaps = 0;
451         r_shadow_attenuationgradienttexture = NULL;
452         r_shadow_attenuation2dtexture = NULL;
453         r_shadow_attenuation3dtexture = NULL;
454         R_FreeTexturePool(&r_shadow_texturepool);
455         R_FreeTexturePool(&r_shadow_filters_texturepool);
456         maxshadowtriangles = 0;
457         if (shadowelements)
458                 Mem_Free(shadowelements);
459         shadowelements = NULL;
460         if (shadowvertex3f)
461                 Mem_Free(shadowvertex3f);
462         shadowvertex3f = NULL;
463         maxvertexupdate = 0;
464         if (vertexupdate)
465                 Mem_Free(vertexupdate);
466         vertexupdate = NULL;
467         if (vertexremap)
468                 Mem_Free(vertexremap);
469         vertexremap = NULL;
470         vertexupdatenum = 0;
471         maxshadowmark = 0;
472         numshadowmark = 0;
473         if (shadowmark)
474                 Mem_Free(shadowmark);
475         shadowmark = NULL;
476         if (shadowmarklist)
477                 Mem_Free(shadowmarklist);
478         shadowmarklist = NULL;
479         shadowmarkcount = 0;
480         r_shadow_buffer_numleafpvsbytes = 0;
481         if (r_shadow_buffer_visitingleafpvs)
482                 Mem_Free(r_shadow_buffer_visitingleafpvs);
483         r_shadow_buffer_visitingleafpvs = NULL;
484         if (r_shadow_buffer_leafpvs)
485                 Mem_Free(r_shadow_buffer_leafpvs);
486         r_shadow_buffer_leafpvs = NULL;
487         if (r_shadow_buffer_leaflist)
488                 Mem_Free(r_shadow_buffer_leaflist);
489         r_shadow_buffer_leaflist = NULL;
490         r_shadow_buffer_numsurfacepvsbytes = 0;
491         if (r_shadow_buffer_surfacepvs)
492                 Mem_Free(r_shadow_buffer_surfacepvs);
493         r_shadow_buffer_surfacepvs = NULL;
494         if (r_shadow_buffer_surfacelist)
495                 Mem_Free(r_shadow_buffer_surfacelist);
496         r_shadow_buffer_surfacelist = NULL;
497         r_shadow_buffer_numshadowtrispvsbytes = 0;
498         if (r_shadow_buffer_shadowtrispvs)
499                 Mem_Free(r_shadow_buffer_shadowtrispvs);
500         r_shadow_buffer_numlighttrispvsbytes = 0;
501         if (r_shadow_buffer_lighttrispvs)
502                 Mem_Free(r_shadow_buffer_lighttrispvs);
503 }
504
505 void r_shadow_newmap(void)
506 {
507         if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
508                 R_Shadow_EditLights_Reload_f();
509 }
510
511 void R_Shadow_Help_f(void)
512 {
513         Con_Printf(
514 "Documentation on r_shadow system:\n"
515 "Settings:\n"
516 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
517 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
518 "r_shadow_debuglight : render only this light number (-1 = all)\n"
519 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
520 "r_shadow_gloss2intensity : brightness of forced gloss\n"
521 "r_shadow_glossintensity : brightness of textured gloss\n"
522 "r_shadow_lightattenuationlinearscale : used to generate attenuation texture\n"
523 "r_shadow_lightattenuationdividebias : used to generate attenuation texture\n"
524 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
525 "r_shadow_lightradiusscale : scale rendering radius of all lights\n"
526 "r_shadow_portallight : use portal visibility for static light precomputation\n"
527 "r_shadow_projectdistance : shadow volume projection distance\n"
528 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
529 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
530 "r_shadow_realtime_world : use high quality world lighting mode\n"
531 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
532 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
533 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
534 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
535 "r_shadow_scissor : use scissor optimization\n"
536 "r_shadow_polygonfactor : nudge shadow volumes closer/further\n"
537 "r_shadow_polygonoffset : nudge shadow volumes closer/further\n"
538 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
539 "r_showlighting : useful for performance testing; bright = slow!\n"
540 "r_showshadowvolumes : useful for performance testing; bright = slow!\n"
541 "Commands:\n"
542 "r_shadow_help : this help\n"
543         );
544 }
545
546 void R_Shadow_Init(void)
547 {
548         Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
549         Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
550         Cvar_RegisterVariable(&r_shadow_usenormalmap);
551         Cvar_RegisterVariable(&r_shadow_debuglight);
552         Cvar_RegisterVariable(&r_shadow_gloss);
553         Cvar_RegisterVariable(&r_shadow_gloss2intensity);
554         Cvar_RegisterVariable(&r_shadow_glossintensity);
555         Cvar_RegisterVariable(&r_shadow_glossexponent);
556         Cvar_RegisterVariable(&r_shadow_glossexact);
557         Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
558         Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
559         Cvar_RegisterVariable(&r_shadow_lightintensityscale);
560         Cvar_RegisterVariable(&r_shadow_lightradiusscale);
561         Cvar_RegisterVariable(&r_shadow_portallight);
562         Cvar_RegisterVariable(&r_shadow_projectdistance);
563         Cvar_RegisterVariable(&r_shadow_frontsidecasting);
564         Cvar_RegisterVariable(&r_shadow_realtime_dlight);
565         Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
566         Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
567         Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
568         Cvar_RegisterVariable(&r_shadow_realtime_world);
569         Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
570         Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
571         Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
572         Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
573         Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
574         Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
575         Cvar_RegisterVariable(&r_shadow_scissor);
576         Cvar_RegisterVariable(&r_shadow_shadowmapping);
577         Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
578         Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
579         Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
580         Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
581         Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
582         Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
583         Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
584         Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
585         Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
586         Cvar_RegisterVariable(&r_shadow_culltriangles);
587         Cvar_RegisterVariable(&r_shadow_polygonfactor);
588         Cvar_RegisterVariable(&r_shadow_polygonoffset);
589         Cvar_RegisterVariable(&r_shadow_texture3d);
590         Cvar_RegisterVariable(&r_coronas);
591         Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
592         Cvar_RegisterVariable(&r_coronas_occlusionquery);
593         Cvar_RegisterVariable(&gl_flashblend);
594         Cvar_RegisterVariable(&gl_ext_separatestencil);
595         Cvar_RegisterVariable(&gl_ext_stenciltwoside);
596         if (gamemode == GAME_TENEBRAE)
597         {
598                 Cvar_SetValue("r_shadow_gloss", 2);
599                 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
600         }
601         Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f, "prints documentation on console commands and variables used by realtime lighting and shadowing system");
602         R_Shadow_EditLights_Init();
603         Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
604         maxshadowtriangles = 0;
605         shadowelements = NULL;
606         maxshadowvertices = 0;
607         shadowvertex3f = NULL;
608         maxvertexupdate = 0;
609         vertexupdate = NULL;
610         vertexremap = NULL;
611         vertexupdatenum = 0;
612         maxshadowmark = 0;
613         numshadowmark = 0;
614         shadowmark = NULL;
615         shadowmarklist = NULL;
616         shadowmarkcount = 0;
617         r_shadow_buffer_numleafpvsbytes = 0;
618         r_shadow_buffer_visitingleafpvs = NULL;
619         r_shadow_buffer_leafpvs = NULL;
620         r_shadow_buffer_leaflist = NULL;
621         r_shadow_buffer_numsurfacepvsbytes = 0;
622         r_shadow_buffer_surfacepvs = NULL;
623         r_shadow_buffer_surfacelist = NULL;
624         r_shadow_buffer_shadowtrispvs = NULL;
625         r_shadow_buffer_lighttrispvs = NULL;
626         R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
627 }
628
629 matrix4x4_t matrix_attenuationxyz =
630 {
631         {
632                 {0.5, 0.0, 0.0, 0.5},
633                 {0.0, 0.5, 0.0, 0.5},
634                 {0.0, 0.0, 0.5, 0.5},
635                 {0.0, 0.0, 0.0, 1.0}
636         }
637 };
638
639 matrix4x4_t matrix_attenuationz =
640 {
641         {
642                 {0.0, 0.0, 0.5, 0.5},
643                 {0.0, 0.0, 0.0, 0.5},
644                 {0.0, 0.0, 0.0, 0.5},
645                 {0.0, 0.0, 0.0, 1.0}
646         }
647 };
648
649 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles)
650 {
651         // make sure shadowelements is big enough for this volume
652         if (maxshadowtriangles < numtriangles)
653         {
654                 maxshadowtriangles = numtriangles;
655                 if (shadowelements)
656                         Mem_Free(shadowelements);
657                 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[24]));
658         }
659         // make sure shadowvertex3f is big enough for this volume
660         if (maxshadowvertices < numvertices)
661         {
662                 maxshadowvertices = numvertices;
663                 if (shadowvertex3f)
664                         Mem_Free(shadowvertex3f);
665                 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[6]));
666         }
667 }
668
669 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
670 {
671         int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
672         int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
673         int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
674         int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
675         if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
676         {
677                 if (r_shadow_buffer_visitingleafpvs)
678                         Mem_Free(r_shadow_buffer_visitingleafpvs);
679                 if (r_shadow_buffer_leafpvs)
680                         Mem_Free(r_shadow_buffer_leafpvs);
681                 if (r_shadow_buffer_leaflist)
682                         Mem_Free(r_shadow_buffer_leaflist);
683                 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
684                 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
685                 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
686                 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
687         }
688         if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
689         {
690                 if (r_shadow_buffer_surfacepvs)
691                         Mem_Free(r_shadow_buffer_surfacepvs);
692                 if (r_shadow_buffer_surfacelist)
693                         Mem_Free(r_shadow_buffer_surfacelist);
694                 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
695                 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
696                 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
697         }
698         if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
699         {
700                 if (r_shadow_buffer_shadowtrispvs)
701                         Mem_Free(r_shadow_buffer_shadowtrispvs);
702                 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
703                 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
704         }
705         if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
706         {
707                 if (r_shadow_buffer_lighttrispvs)
708                         Mem_Free(r_shadow_buffer_lighttrispvs);
709                 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
710                 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
711         }
712 }
713
714 void R_Shadow_PrepareShadowMark(int numtris)
715 {
716         // make sure shadowmark is big enough for this volume
717         if (maxshadowmark < numtris)
718         {
719                 maxshadowmark = numtris;
720                 if (shadowmark)
721                         Mem_Free(shadowmark);
722                 if (shadowmarklist)
723                         Mem_Free(shadowmarklist);
724                 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
725                 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
726                 shadowmarkcount = 0;
727         }
728         shadowmarkcount++;
729         // if shadowmarkcount wrapped we clear the array and adjust accordingly
730         if (shadowmarkcount == 0)
731         {
732                 shadowmarkcount = 1;
733                 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
734         }
735         numshadowmark = 0;
736 }
737
738 static int R_Shadow_ConstructShadowVolume_ZFail(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)
739 {
740         int i, j;
741         int outtriangles = 0, outvertices = 0;
742         const int *element;
743         const float *vertex;
744         float ratio, direction[3], projectvector[3];
745
746         if (projectdirection)
747                 VectorScale(projectdirection, projectdistance, projectvector);
748         else
749                 VectorClear(projectvector);
750
751         // create the vertices
752         if (projectdirection)
753         {
754                 for (i = 0;i < numshadowmarktris;i++)
755                 {
756                         element = inelement3i + shadowmarktris[i] * 3;
757                         for (j = 0;j < 3;j++)
758                         {
759                                 if (vertexupdate[element[j]] != vertexupdatenum)
760                                 {
761                                         vertexupdate[element[j]] = vertexupdatenum;
762                                         vertexremap[element[j]] = outvertices;
763                                         vertex = invertex3f + element[j] * 3;
764                                         // project one copy of the vertex according to projectvector
765                                         VectorCopy(vertex, outvertex3f);
766                                         VectorAdd(vertex, projectvector, (outvertex3f + 3));
767                                         outvertex3f += 6;
768                                         outvertices += 2;
769                                 }
770                         }
771                 }
772         }
773         else
774         {
775                 for (i = 0;i < numshadowmarktris;i++)
776                 {
777                         element = inelement3i + shadowmarktris[i] * 3;
778                         for (j = 0;j < 3;j++)
779                         {
780                                 if (vertexupdate[element[j]] != vertexupdatenum)
781                                 {
782                                         vertexupdate[element[j]] = vertexupdatenum;
783                                         vertexremap[element[j]] = outvertices;
784                                         vertex = invertex3f + element[j] * 3;
785                                         // project one copy of the vertex to the sphere radius of the light
786                                         // (FIXME: would projecting it to the light box be better?)
787                                         VectorSubtract(vertex, projectorigin, direction);
788                                         ratio = projectdistance / VectorLength(direction);
789                                         VectorCopy(vertex, outvertex3f);
790                                         VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
791                                         outvertex3f += 6;
792                                         outvertices += 2;
793                                 }
794                         }
795                 }
796         }
797
798         if (r_shadow_frontsidecasting.integer)
799         {
800                 for (i = 0;i < numshadowmarktris;i++)
801                 {
802                         int remappedelement[3];
803                         int markindex;
804                         const int *neighbortriangle;
805
806                         markindex = shadowmarktris[i] * 3;
807                         element = inelement3i + markindex;
808                         neighbortriangle = inneighbor3i + markindex;
809                         // output the front and back triangles
810                         outelement3i[0] = vertexremap[element[0]];
811                         outelement3i[1] = vertexremap[element[1]];
812                         outelement3i[2] = vertexremap[element[2]];
813                         outelement3i[3] = vertexremap[element[2]] + 1;
814                         outelement3i[4] = vertexremap[element[1]] + 1;
815                         outelement3i[5] = vertexremap[element[0]] + 1;
816
817                         outelement3i += 6;
818                         outtriangles += 2;
819                         // output the sides (facing outward from this triangle)
820                         if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
821                         {
822                                 remappedelement[0] = vertexremap[element[0]];
823                                 remappedelement[1] = vertexremap[element[1]];
824                                 outelement3i[0] = remappedelement[1];
825                                 outelement3i[1] = remappedelement[0];
826                                 outelement3i[2] = remappedelement[0] + 1;
827                                 outelement3i[3] = remappedelement[1];
828                                 outelement3i[4] = remappedelement[0] + 1;
829                                 outelement3i[5] = remappedelement[1] + 1;
830
831                                 outelement3i += 6;
832                                 outtriangles += 2;
833                         }
834                         if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
835                         {
836                                 remappedelement[1] = vertexremap[element[1]];
837                                 remappedelement[2] = vertexremap[element[2]];
838                                 outelement3i[0] = remappedelement[2];
839                                 outelement3i[1] = remappedelement[1];
840                                 outelement3i[2] = remappedelement[1] + 1;
841                                 outelement3i[3] = remappedelement[2];
842                                 outelement3i[4] = remappedelement[1] + 1;
843                                 outelement3i[5] = remappedelement[2] + 1;
844
845                                 outelement3i += 6;
846                                 outtriangles += 2;
847                         }
848                         if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
849                         {
850                                 remappedelement[0] = vertexremap[element[0]];
851                                 remappedelement[2] = vertexremap[element[2]];
852                                 outelement3i[0] = remappedelement[0];
853                                 outelement3i[1] = remappedelement[2];
854                                 outelement3i[2] = remappedelement[2] + 1;
855                                 outelement3i[3] = remappedelement[0];
856                                 outelement3i[4] = remappedelement[2] + 1;
857                                 outelement3i[5] = remappedelement[0] + 1;
858
859                                 outelement3i += 6;
860                                 outtriangles += 2;
861                         }
862                 }
863         }
864         else
865         {
866                 for (i = 0;i < numshadowmarktris;i++)
867                 {
868                         int remappedelement[3];
869                         int markindex;
870                         const int *neighbortriangle;
871
872                         markindex = shadowmarktris[i] * 3;
873                         element = inelement3i + markindex;
874                         neighbortriangle = inneighbor3i + markindex;
875                         // output the front and back triangles
876                         outelement3i[0] = vertexremap[element[2]];
877                         outelement3i[1] = vertexremap[element[1]];
878                         outelement3i[2] = vertexremap[element[0]];
879                         outelement3i[3] = vertexremap[element[0]] + 1;
880                         outelement3i[4] = vertexremap[element[1]] + 1;
881                         outelement3i[5] = vertexremap[element[2]] + 1;
882
883                         outelement3i += 6;
884                         outtriangles += 2;
885                         // output the sides (facing outward from this triangle)
886                         if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
887                         {
888                                 remappedelement[0] = vertexremap[element[0]];
889                                 remappedelement[1] = vertexremap[element[1]];
890                                 outelement3i[0] = remappedelement[0];
891                                 outelement3i[1] = remappedelement[1];
892                                 outelement3i[2] = remappedelement[1] + 1;
893                                 outelement3i[3] = remappedelement[0];
894                                 outelement3i[4] = remappedelement[1] + 1;
895                                 outelement3i[5] = remappedelement[0] + 1;
896
897                                 outelement3i += 6;
898                                 outtriangles += 2;
899                         }
900                         if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
901                         {
902                                 remappedelement[1] = vertexremap[element[1]];
903                                 remappedelement[2] = vertexremap[element[2]];
904                                 outelement3i[0] = remappedelement[1];
905                                 outelement3i[1] = remappedelement[2];
906                                 outelement3i[2] = remappedelement[2] + 1;
907                                 outelement3i[3] = remappedelement[1];
908                                 outelement3i[4] = remappedelement[2] + 1;
909                                 outelement3i[5] = remappedelement[1] + 1;
910
911                                 outelement3i += 6;
912                                 outtriangles += 2;
913                         }
914                         if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
915                         {
916                                 remappedelement[0] = vertexremap[element[0]];
917                                 remappedelement[2] = vertexremap[element[2]];
918                                 outelement3i[0] = remappedelement[2];
919                                 outelement3i[1] = remappedelement[0];
920                                 outelement3i[2] = remappedelement[0] + 1;
921                                 outelement3i[3] = remappedelement[2];
922                                 outelement3i[4] = remappedelement[0] + 1;
923                                 outelement3i[5] = remappedelement[2] + 1;
924
925                                 outelement3i += 6;
926                                 outtriangles += 2;
927                         }
928                 }
929         }
930         if (outnumvertices)
931                 *outnumvertices = outvertices;
932         return outtriangles;
933 }
934
935 static int R_Shadow_ConstructShadowVolume_ZPass(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)
936 {
937         int i, j, k;
938         int outtriangles = 0, outvertices = 0;
939         const int *element;
940         const float *vertex;
941         float ratio, direction[3], projectvector[3];
942         qboolean side[4];
943
944         if (projectdirection)
945                 VectorScale(projectdirection, projectdistance, projectvector);
946         else
947                 VectorClear(projectvector);
948
949         for (i = 0;i < numshadowmarktris;i++)
950         {
951                 int remappedelement[3];
952                 int markindex;
953                 const int *neighbortriangle;
954
955                 markindex = shadowmarktris[i] * 3;
956                 neighbortriangle = inneighbor3i + markindex;
957                 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
958                 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
959                 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
960                 if (side[0] + side[1] + side[2] == 0)
961                         continue;
962
963                 side[3] = side[0];
964                 element = inelement3i + markindex;
965
966                 // create the vertices
967                 for (j = 0;j < 3;j++)
968                 {
969                         if (side[j] + side[j+1] == 0)
970                                 continue;
971                         k = element[j];
972                         if (vertexupdate[k] != vertexupdatenum)
973                         {
974                                 vertexupdate[k] = vertexupdatenum;
975                                 vertexremap[k] = outvertices;
976                                 vertex = invertex3f + k * 3;
977                                 VectorCopy(vertex, outvertex3f);
978                                 if (projectdirection)
979                                 {
980                                         // project one copy of the vertex according to projectvector
981                                         VectorAdd(vertex, projectvector, (outvertex3f + 3));
982                                 }
983                                 else
984                                 {
985                                         // project one copy of the vertex to the sphere radius of the light
986                                         // (FIXME: would projecting it to the light box be better?)
987                                         VectorSubtract(vertex, projectorigin, direction);
988                                         ratio = projectdistance / VectorLength(direction);
989                                         VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
990                                 }
991                                 outvertex3f += 6;
992                                 outvertices += 2;
993                         }
994                 }
995
996                 // output the sides (facing outward from this triangle)
997                 if (!side[0])
998                 {
999                         remappedelement[0] = vertexremap[element[0]];
1000                         remappedelement[1] = vertexremap[element[1]];
1001                         outelement3i[0] = remappedelement[1];
1002                         outelement3i[1] = remappedelement[0];
1003                         outelement3i[2] = remappedelement[0] + 1;
1004                         outelement3i[3] = remappedelement[1];
1005                         outelement3i[4] = remappedelement[0] + 1;
1006                         outelement3i[5] = remappedelement[1] + 1;
1007
1008                         outelement3i += 6;
1009                         outtriangles += 2;
1010                 }
1011                 if (!side[1])
1012                 {
1013                         remappedelement[1] = vertexremap[element[1]];
1014                         remappedelement[2] = vertexremap[element[2]];
1015                         outelement3i[0] = remappedelement[2];
1016                         outelement3i[1] = remappedelement[1];
1017                         outelement3i[2] = remappedelement[1] + 1;
1018                         outelement3i[3] = remappedelement[2];
1019                         outelement3i[4] = remappedelement[1] + 1;
1020                         outelement3i[5] = remappedelement[2] + 1;
1021
1022                         outelement3i += 6;
1023                         outtriangles += 2;
1024                 }
1025                 if (!side[2])
1026                 {
1027                         remappedelement[0] = vertexremap[element[0]];
1028                         remappedelement[2] = vertexremap[element[2]];
1029                         outelement3i[0] = remappedelement[0];
1030                         outelement3i[1] = remappedelement[2];
1031                         outelement3i[2] = remappedelement[2] + 1;
1032                         outelement3i[3] = remappedelement[0];
1033                         outelement3i[4] = remappedelement[2] + 1;
1034                         outelement3i[5] = remappedelement[0] + 1;
1035
1036                         outelement3i += 6;
1037                         outtriangles += 2;
1038                 }
1039         }
1040         if (outnumvertices)
1041                 *outnumvertices = outvertices;
1042         return outtriangles;
1043 }
1044
1045 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)
1046 {
1047         int t, tend;
1048         const int *e;
1049         const float *v[3];
1050         float normal[3];
1051         if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1052                 return;
1053         tend = firsttriangle + numtris;
1054         if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1055         {
1056                 // surface box entirely inside light box, no box cull
1057                 if (projectdirection)
1058                 {
1059                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1060                         {
1061                                 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1062                                 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1063                                         shadowmarklist[numshadowmark++] = t;
1064                         }
1065                 }
1066                 else
1067                 {
1068                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1069                                 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1070                                         shadowmarklist[numshadowmark++] = t;
1071                 }
1072         }
1073         else
1074         {
1075                 // surface box not entirely inside light box, cull each triangle
1076                 if (projectdirection)
1077                 {
1078                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1079                         {
1080                                 v[0] = invertex3f + e[0] * 3;
1081                                 v[1] = invertex3f + e[1] * 3;
1082                                 v[2] = invertex3f + e[2] * 3;
1083                                 TriangleNormal(v[0], v[1], v[2], normal);
1084                                 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1085                                  && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1086                                         shadowmarklist[numshadowmark++] = t;
1087                         }
1088                 }
1089                 else
1090                 {
1091                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1092                         {
1093                                 v[0] = invertex3f + e[0] * 3;
1094                                 v[1] = invertex3f + e[1] * 3;
1095                                 v[2] = invertex3f + e[2] * 3;
1096                                 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1097                                  && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1098                                         shadowmarklist[numshadowmark++] = t;
1099                         }
1100                 }
1101         }
1102 }
1103
1104 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1105 {
1106 #if 1
1107         return false;
1108 #else
1109         if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1110                 return false;
1111         // check if the shadow volume intersects the near plane
1112         //
1113         // a ray between the eye and light origin may intersect the caster,
1114         // indicating that the shadow may touch the eye location, however we must
1115         // test the near plane (a polygon), not merely the eye location, so it is
1116         // easiest to enlarge the caster bounding shape slightly for this.
1117         // TODO
1118         return true;
1119 #endif
1120 }
1121
1122 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, vec3_t trismins, vec3_t trismaxs)
1123 {
1124         int i, tris, outverts;
1125         if (projectdistance < 0.1)
1126         {
1127                 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1128                 return;
1129         }
1130         if (!numverts || !nummarktris)
1131                 return;
1132         // make sure shadowelements is big enough for this volume
1133         if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
1134                 R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
1135
1136         if (maxvertexupdate < numverts)
1137         {
1138                 maxvertexupdate = numverts;
1139                 if (vertexupdate)
1140                         Mem_Free(vertexupdate);
1141                 if (vertexremap)
1142                         Mem_Free(vertexremap);
1143                 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1144                 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1145                 vertexupdatenum = 0;
1146         }
1147         vertexupdatenum++;
1148         if (vertexupdatenum == 0)
1149         {
1150                 vertexupdatenum = 1;
1151                 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1152                 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1153         }
1154
1155         for (i = 0;i < nummarktris;i++)
1156                 shadowmark[marktris[i]] = shadowmarkcount;
1157
1158         if (r_shadow_compilingrtlight)
1159         {
1160                 // if we're compiling an rtlight, capture the mesh
1161                 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1162                 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1163                 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1164                 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1165         }
1166         else
1167         {
1168                 // decide which type of shadow to generate and set stencil mode
1169                 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1170                 // generate the sides or a solid volume, depending on type
1171                 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1172                         tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1173                 else
1174                         tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1175                 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1176                 r_refdef.stats.lights_shadowtriangles += tris;
1177                 CHECKGLERROR
1178                 R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
1179                 GL_LockArrays(0, outverts);
1180                 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1181                 {
1182                         // increment stencil if frontface is infront of depthbuffer
1183                         GL_CullFace(r_refdef.view.cullface_front);
1184                         qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1185                         R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1186                         // decrement stencil if backface is infront of depthbuffer
1187                         GL_CullFace(r_refdef.view.cullface_back);
1188                         qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1189                 }
1190                 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1191                 {
1192                         // decrement stencil if backface is behind depthbuffer
1193                         GL_CullFace(r_refdef.view.cullface_front);
1194                         qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1195                         R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1196                         // increment stencil if frontface is behind depthbuffer
1197                         GL_CullFace(r_refdef.view.cullface_back);
1198                         qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1199                 }
1200                 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1201                 GL_LockArrays(0, 0);
1202                 CHECKGLERROR
1203         }
1204 }
1205
1206 void R_Shadow_ShadowMapFromList(int numverts, int numtris, const float *vertex3f, int vertex3f_bufferobject, int vertex3f_bufferoffset, const int *elements, int nummarktris, const int *marktris)
1207 {
1208         int i, tris = nummarktris;
1209         int *outelement3i;
1210         const int *element;
1211         if (!numverts || !nummarktris)
1212                 return;
1213         // make sure shadowelements is big enough for this mesh
1214         if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
1215                 R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
1216
1217         // gather up the (sparse) triangles into one array
1218         outelement3i = shadowelements;
1219         for (i = 0;i < nummarktris;i++)
1220         {
1221                 element = elements + marktris[i] * 3;
1222                 outelement3i[0] = element[0];
1223                 outelement3i[1] = element[1];
1224                 outelement3i[2] = element[2];
1225                 outelement3i += 3;
1226         }
1227
1228         r_refdef.stats.lights_dynamicshadowtriangles += tris;
1229         r_refdef.stats.lights_shadowtriangles += tris;
1230         R_Mesh_VertexPointer(vertex3f, vertex3f_bufferobject, vertex3f_bufferoffset);
1231         R_Mesh_Draw(0, numverts, 0, tris, shadowelements, NULL, 0, 0);
1232 }
1233
1234 static void R_Shadow_MakeTextures_MakeCorona(void)
1235 {
1236         float dx, dy;
1237         int x, y, a;
1238         unsigned char pixels[32][32][4];
1239         for (y = 0;y < 32;y++)
1240         {
1241                 dy = (y - 15.5f) * (1.0f / 16.0f);
1242                 for (x = 0;x < 32;x++)
1243                 {
1244                         dx = (x - 15.5f) * (1.0f / 16.0f);
1245                         a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1246                         a = bound(0, a, 255);
1247                         pixels[y][x][0] = a;
1248                         pixels[y][x][1] = a;
1249                         pixels[y][x][2] = a;
1250                         pixels[y][x][3] = 255;
1251                 }
1252         }
1253         r_shadow_lightcorona = R_LoadTexture2D(r_shadow_texturepool, "lightcorona", 32, 32, &pixels[0][0][0], TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_FORCELINEAR, NULL);
1254 }
1255
1256 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1257 {
1258         float dist = sqrt(x*x+y*y+z*z);
1259         float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1260         // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1261         return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1262 }
1263
1264 static void R_Shadow_MakeTextures(void)
1265 {
1266         int x, y, z;
1267         float intensity, dist;
1268         unsigned int *data;
1269         R_FreeTexturePool(&r_shadow_texturepool);
1270         r_shadow_texturepool = R_AllocTexturePool();
1271         r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1272         r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1273         data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1274         // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1275         for (x = 0;x <= ATTENTABLESIZE;x++)
1276         {
1277                 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1278                 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1279                 r_shadow_attentable[x] = bound(0, intensity, 1);
1280         }
1281         // 1D gradient texture
1282         for (x = 0;x < ATTEN1DSIZE;x++)
1283                 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1284         r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, NULL);
1285         // 2D circle texture
1286         for (y = 0;y < ATTEN2DSIZE;y++)
1287                 for (x = 0;x < ATTEN2DSIZE;x++)
1288                         data[y*ATTEN2DSIZE+x] = R_Shadow_MakeTextures_SamplePoint(((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375), ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375), 0);
1289         r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, NULL);
1290         // 3D sphere texture
1291         if (r_shadow_texture3d.integer && gl_texture3d)
1292         {
1293                 for (z = 0;z < ATTEN3DSIZE;z++)
1294                         for (y = 0;y < ATTEN3DSIZE;y++)
1295                                 for (x = 0;x < ATTEN3DSIZE;x++)
1296                                         data[(z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x] = R_Shadow_MakeTextures_SamplePoint(((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375), ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375), ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375));
1297                 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, NULL);
1298         }
1299         else
1300                 r_shadow_attenuation3dtexture = NULL;
1301         Mem_Free(data);
1302
1303         R_Shadow_MakeTextures_MakeCorona();
1304
1305         // Editor light sprites
1306         r_editlights_sprcursor = Draw_CachePic ("gfx/editlights/cursor");
1307         r_editlights_sprlight = Draw_CachePic ("gfx/editlights/light");
1308         r_editlights_sprnoshadowlight = Draw_CachePic ("gfx/editlights/noshadow");
1309         r_editlights_sprcubemaplight = Draw_CachePic ("gfx/editlights/cubemaplight");
1310         r_editlights_sprcubemapnoshadowlight = Draw_CachePic ("gfx/editlights/cubemapnoshadowlight");
1311         r_editlights_sprselection = Draw_CachePic ("gfx/editlights/selection");
1312 }
1313
1314 void R_Shadow_ValidateCvars(void)
1315 {
1316         if (r_shadow_texture3d.integer && !gl_texture3d)
1317                 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1318         if (gl_ext_separatestencil.integer && !gl_support_separatestencil)
1319                 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1320         if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1321                 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1322 }
1323
1324 void R_Shadow_RenderMode_Begin(void)
1325 {
1326         GLint drawbuffer;
1327         GLint readbuffer;
1328         R_Shadow_ValidateCvars();
1329
1330         if (!r_shadow_attenuation2dtexture
1331          || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1332          || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1333          || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1334                 R_Shadow_MakeTextures();
1335
1336         CHECKGLERROR
1337         R_Mesh_ColorPointer(NULL, 0, 0);
1338         R_Mesh_ResetTextureState();
1339         GL_BlendFunc(GL_ONE, GL_ZERO);
1340         GL_DepthRange(0, 1);
1341         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1342         GL_DepthTest(true);
1343         GL_DepthMask(false);
1344         GL_Color(0, 0, 0, 1);
1345         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1346
1347         r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1348
1349         if (gl_ext_separatestencil.integer)
1350         {
1351                 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1352                 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1353         }
1354         else if (gl_ext_stenciltwoside.integer)
1355         {
1356                 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1357                 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1358         }
1359         else
1360         {
1361                 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1362                 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1363         }
1364
1365         if (r_glsl.integer && gl_support_fragment_shader)
1366                 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1367         else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
1368                 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
1369         else
1370                 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1371
1372         CHECKGLERROR
1373         qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1374         qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1375         r_shadow_drawbuffer = drawbuffer;
1376         r_shadow_readbuffer = readbuffer;
1377 }
1378
1379 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1380 {
1381         rsurface.rtlight = rtlight;
1382 }
1383
1384 void R_Shadow_RenderMode_Reset(void)
1385 {
1386         CHECKGLERROR
1387         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE)
1388         {
1389                 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1390         }
1391         if (gl_support_ext_framebuffer_object)
1392         {
1393                 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
1394         }
1395         qglDrawBuffer(r_shadow_drawbuffer);CHECKGLERROR
1396         qglReadBuffer(r_shadow_readbuffer);CHECKGLERROR
1397         R_SetViewport(&r_refdef.view.viewport);
1398         GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1399         R_Mesh_ColorPointer(NULL, 0, 0);
1400         R_Mesh_ResetTextureState();
1401         GL_DepthRange(0, 1);
1402         GL_DepthTest(true);
1403         GL_DepthMask(false);
1404         qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1405         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1406         qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1407         qglStencilMask(~0);CHECKGLERROR
1408         qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1409         qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1410         GL_CullFace(r_refdef.view.cullface_back);
1411         GL_Color(1, 1, 1, 1);
1412         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1413         GL_BlendFunc(GL_ONE, GL_ZERO);
1414         R_SetupGenericShader(false);
1415         r_shadow_usingshadowmaprect = false;
1416         r_shadow_usingshadowmapcube = false;
1417         r_shadow_usingshadowmap2d = false;
1418         CHECKGLERROR
1419 }
1420
1421 void R_Shadow_ClearStencil(void)
1422 {
1423         CHECKGLERROR
1424         GL_Clear(GL_STENCIL_BUFFER_BIT);
1425         r_refdef.stats.lights_clears++;
1426 }
1427
1428 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
1429 {
1430         r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
1431         if (r_shadow_rendermode == mode)
1432                 return;
1433         CHECKGLERROR
1434         R_Shadow_RenderMode_Reset();
1435         GL_ColorMask(0, 0, 0, 0);
1436         GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1437         R_SetupDepthOrShadowShader();
1438         qglDepthFunc(GL_LESS);CHECKGLERROR
1439         qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1440         r_shadow_rendermode = mode;
1441         switch(mode)
1442         {
1443         default:
1444                 break;
1445         case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
1446                 GL_CullFace(GL_NONE);
1447                 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1448                 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1449                 break;
1450         case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
1451                 GL_CullFace(GL_NONE);
1452                 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1453                 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1454                 break;
1455         case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
1456                 GL_CullFace(GL_NONE);
1457                 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1458                 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1459                 qglStencilMask(~0);CHECKGLERROR
1460                 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1461                 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1462                 qglStencilMask(~0);CHECKGLERROR
1463                 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1464                 break;
1465         case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
1466                 GL_CullFace(GL_NONE);
1467                 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1468                 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1469                 qglStencilMask(~0);CHECKGLERROR
1470                 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1471                 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1472                 qglStencilMask(~0);CHECKGLERROR
1473                 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1474                 break;
1475         }
1476 }
1477
1478 void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size)
1479 {
1480         int i;
1481         int status;
1482         int maxsize;
1483         float nearclip, farclip, bias;
1484         r_viewport_t viewport;
1485         CHECKGLERROR
1486         maxsize = r_shadow_shadowmapmaxsize;
1487         nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
1488         farclip = 1.0f;
1489         bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
1490         r_shadow_shadowmap_parameters[2] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
1491         r_shadow_shadowmap_parameters[3] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
1492         if (r_shadow_shadowmode == 1)
1493         {
1494                 // complex unrolled cube approach (more flexible)
1495                 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapcubeprojectiontexture[r_shadow_shadowmaplod])
1496                         r_shadow_shadowmapcubeprojectiontexture[r_shadow_shadowmaplod] = R_LoadTextureCubeProjection(r_shadow_texturepool, "shadowmapcubeprojection", size, r_shadow_shadowmapborder);
1497                 if (!r_shadow_shadowmap2dtexture)
1498                 {
1499 #if 1
1500                         r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", maxsize*2, maxsize*4, r_shadow_shadowmapfilter == 1 || r_shadow_shadowmapfilter == 2);
1501                         qglGenFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
1502                         qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
1503                         qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_shadowmap2dtexture), 0);CHECKGLERROR
1504 #endif
1505                 }
1506                 CHECKGLERROR
1507                 R_Shadow_RenderMode_Reset();
1508                 if (r_shadow_shadowmap2dtexture)
1509                 {
1510                         // render depth into the fbo, do not render color at all
1511                         qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
1512                         qglDrawBuffer(GL_NONE);CHECKGLERROR
1513                         qglReadBuffer(GL_NONE);CHECKGLERROR
1514                         status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1515                         if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
1516                         {
1517                                 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1518                                 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1519                         }
1520                         R_SetupDepthOrShadowShader();
1521                 }
1522                 else
1523                 {
1524                         R_SetupShowDepthShader();
1525                         qglClearColor(1,1,1,1);CHECKGLERROR
1526                 }
1527                 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapping_bordersize.integer, nearclip, farclip, NULL);
1528                 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
1529                 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
1530                 r_shadow_shadowmap_parameters[0] = r_shadow_shadowmapvsdct ? size / (float)maxsize : 0.5f * (size - r_shadow_shadowmapborder);
1531                 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 0.75f * size / (float)maxsize : size;
1532                 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
1533         }
1534         else if (r_shadow_shadowmode == 2)
1535         {
1536                 // complex unrolled cube approach (more flexible)
1537                 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapcubeprojectiontexture[r_shadow_shadowmaplod])
1538                         r_shadow_shadowmapcubeprojectiontexture[r_shadow_shadowmaplod] = R_LoadTextureCubeProjection(r_shadow_texturepool, "shadowmapcubeprojection", size, r_shadow_shadowmapborder);
1539                 if (!r_shadow_shadowmaprectangletexture)
1540                 {
1541 #if 1
1542                         r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", maxsize*2, maxsize*3, r_shadow_shadowmapfilter == 1 || r_shadow_shadowmapfilter == 2);
1543                         qglGenFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
1544                         qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
1545                         qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_shadowmaprectangletexture), 0);CHECKGLERROR
1546 #endif
1547                 }
1548                 CHECKGLERROR
1549                 R_Shadow_RenderMode_Reset();
1550                 if (r_shadow_shadowmaprectangletexture)
1551                 {
1552                         // render depth into the fbo, do not render color at all
1553                         qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
1554                         qglDrawBuffer(GL_NONE);CHECKGLERROR
1555                         qglReadBuffer(GL_NONE);CHECKGLERROR
1556                         status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1557                         if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
1558                         {
1559                                 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1560                                 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1561                         }
1562                         R_SetupDepthOrShadowShader();
1563                 }
1564                 else
1565                 {
1566                         R_SetupShowDepthShader();
1567                         qglClearColor(1,1,1,1);CHECKGLERROR
1568                 }
1569                 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
1570                 r_shadow_shadowmap_texturescale[0] = 1.0f;
1571                 r_shadow_shadowmap_texturescale[1] = 1.0f;
1572                 r_shadow_shadowmap_parameters[0] = r_shadow_shadowmapvsdct ? 2*size : 0.5f * (size - r_shadow_shadowmapborder);
1573                 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 3*size : size;
1574                 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
1575         }
1576         else if (r_shadow_shadowmode == 3)
1577         {
1578                 // simple cube approach
1579                 if (!r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
1580                 {
1581  #if 1
1582                         r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", bound(1, maxsize >> r_shadow_shadowmaplod, 2048), r_shadow_shadowmapfilter == 1 || r_shadow_shadowmapfilter == 2);
1583                         qglGenFramebuffersEXT(6, r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
1584                         for (i = 0;i < 6;i++)
1585                         {
1586                                 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod][i]);CHECKGLERROR
1587                                 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + i, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]), 0);CHECKGLERROR
1588                         }
1589  #endif
1590                 }
1591                 CHECKGLERROR
1592                 R_Shadow_RenderMode_Reset();
1593                 if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
1594                 {
1595                         // render depth into the fbo, do not render color at all
1596                         qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod][side]);CHECKGLERROR
1597                         qglDrawBuffer(GL_NONE);CHECKGLERROR
1598                         qglReadBuffer(GL_NONE);CHECKGLERROR
1599                         status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1600                         if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
1601                         {
1602                                 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1603                                 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1604                         }
1605                         R_SetupDepthOrShadowShader();
1606                 }
1607                 else
1608                 {
1609                         R_SetupShowDepthShader();
1610                         qglClearColor(1,1,1,1);CHECKGLERROR
1611                 }
1612                 R_Viewport_InitCubeSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, nearclip, farclip, NULL);
1613                 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]);
1614                 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureWidth(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]);
1615                 r_shadow_shadowmap_parameters[0] = 1.0f;
1616                 r_shadow_shadowmap_parameters[1] = 1.0f;
1617                 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE;
1618         }
1619         r_shadow_shadowmap_texturescale[2] = 1.0f / r_shadow_shadowmap_texturescale[0];
1620         r_shadow_shadowmap_texturescale[3] = 1.0f / r_shadow_shadowmap_texturescale[1];
1621         CHECKGLERROR
1622         R_SetViewport(&viewport);
1623         GL_PolygonOffset(0, 0);
1624         GL_CullFace(GL_NONE); // quake is backwards
1625         GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
1626         GL_DepthMask(true);
1627         GL_DepthTest(true);
1628         qglClearDepth(1);CHECKGLERROR
1629         CHECKGLERROR
1630         if (clear)
1631                 qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |  GL_STENCIL_BUFFER_BIT);
1632         CHECKGLERROR
1633 }
1634
1635 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
1636 {
1637         CHECKGLERROR
1638         R_Shadow_RenderMode_Reset();
1639         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1640         if (!transparent)
1641         {
1642                 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1643         }
1644         if (stenciltest)
1645         {
1646                 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1647                 // only draw light where this geometry was already rendered AND the
1648                 // stencil is 128 (values other than this mean shadow)
1649                 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1650         }
1651         r_shadow_rendermode = r_shadow_lightingrendermode;
1652         // do global setup needed for the chosen lighting mode
1653         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1654         {
1655                 R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap)); // light filter
1656                 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
1657                 CHECKGLERROR
1658                 if (shadowmapping)
1659                 {
1660                         if (r_shadow_shadowmode == 1)
1661                         {
1662                                 r_shadow_usingshadowmap2d = true;
1663                                 R_Mesh_TexBind(GL20TU_SHADOWMAP2D, R_GetTexture(r_shadow_shadowmap2dtexture));
1664                                 CHECKGLERROR
1665                         }
1666                         else if (r_shadow_shadowmode == 2)
1667                         {
1668                                 r_shadow_usingshadowmaprect = true;
1669                                 R_Mesh_TexBindRectangle(GL20TU_SHADOWMAPRECT, R_GetTexture(r_shadow_shadowmaprectangletexture));
1670                                 CHECKGLERROR
1671                         }
1672                         else if (r_shadow_shadowmode == 3)
1673                         {
1674                                 r_shadow_usingshadowmapcube = true;
1675                                 R_Mesh_TexBindCubeMap(GL20TU_SHADOWMAPCUBE, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]));
1676                                 CHECKGLERROR
1677                         }
1678
1679                         if (r_shadow_shadowmapvsdct && (r_shadow_usingshadowmap2d || r_shadow_usingshadowmaprect))
1680                         {
1681                                 R_Mesh_TexBindCubeMap(GL20TU_CUBEPROJECTION, R_GetTexture(r_shadow_shadowmapcubeprojectiontexture[r_shadow_shadowmaplod]));
1682                                 CHECKGLERROR
1683                         }
1684                 }
1685         }
1686         else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_VERTEX)
1687                 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
1688         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1689         CHECKGLERROR
1690 }
1691
1692 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
1693 {
1694         CHECKGLERROR
1695         R_Shadow_RenderMode_Reset();
1696         GL_BlendFunc(GL_ONE, GL_ONE);
1697         GL_DepthRange(0, 1);
1698         GL_DepthTest(r_showshadowvolumes.integer < 2);
1699         GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
1700         GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1701         GL_CullFace(GL_NONE);
1702         r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
1703 }
1704
1705 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
1706 {
1707         CHECKGLERROR
1708         R_Shadow_RenderMode_Reset();
1709         GL_BlendFunc(GL_ONE, GL_ONE);
1710         GL_DepthRange(0, 1);
1711         GL_DepthTest(r_showlighting.integer < 2);
1712         GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
1713         if (!transparent)
1714         {
1715                 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1716         }
1717         if (stenciltest)
1718         {
1719                 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1720                 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1721         }
1722         r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
1723 }
1724
1725 void R_Shadow_RenderMode_End(void)
1726 {
1727         CHECKGLERROR
1728         R_Shadow_RenderMode_Reset();
1729         R_Shadow_RenderMode_ActiveLight(NULL);
1730         GL_DepthMask(true);
1731         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1732         r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1733 }
1734
1735 int bboxedges[12][2] =
1736 {
1737         // top
1738         {0, 1}, // +X
1739         {0, 2}, // +Y
1740         {1, 3}, // Y, +X
1741         {2, 3}, // X, +Y
1742         // bottom
1743         {4, 5}, // +X
1744         {4, 6}, // +Y
1745         {5, 7}, // Y, +X
1746         {6, 7}, // X, +Y
1747         // verticals
1748         {0, 4}, // +Z
1749         {1, 5}, // X, +Z
1750         {2, 6}, // Y, +Z
1751         {3, 7}, // XY, +Z
1752 };
1753
1754 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1755 {
1756         int i, ix1, iy1, ix2, iy2;
1757         float x1, y1, x2, y2;
1758         vec4_t v, v2;
1759         float vertex[20][3];
1760         int j, k;
1761         vec4_t plane4f;
1762         int numvertices;
1763         float corner[8][4];
1764         float dist[8];
1765         int sign[8];
1766         float f;
1767
1768         r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
1769         r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
1770         r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
1771         r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
1772
1773         if (!r_shadow_scissor.integer)
1774                 return false;
1775
1776         // if view is inside the light box, just say yes it's visible
1777         if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
1778                 return false;
1779
1780         x1 = y1 = x2 = y2 = 0;
1781
1782         // transform all corners that are infront of the nearclip plane
1783         VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
1784         plane4f[3] = r_refdef.view.frustum[4].dist;
1785         numvertices = 0;
1786         for (i = 0;i < 8;i++)
1787         {
1788                 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
1789                 dist[i] = DotProduct4(corner[i], plane4f);
1790                 sign[i] = dist[i] > 0;
1791                 if (!sign[i])
1792                 {
1793                         VectorCopy(corner[i], vertex[numvertices]);
1794                         numvertices++;
1795                 }
1796         }
1797         // if some points are behind the nearclip, add clipped edge points to make
1798         // sure that the scissor boundary is complete
1799         if (numvertices > 0 && numvertices < 8)
1800         {
1801                 // add clipped edge points
1802                 for (i = 0;i < 12;i++)
1803                 {
1804                         j = bboxedges[i][0];
1805                         k = bboxedges[i][1];
1806                         if (sign[j] != sign[k])
1807                         {
1808                                 f = dist[j] / (dist[j] - dist[k]);
1809                                 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
1810                                 numvertices++;
1811                         }
1812                 }
1813         }
1814
1815         // if we have no points to check, the light is behind the view plane
1816         if (!numvertices)
1817                 return true;
1818
1819         // if we have some points to transform, check what screen area is covered
1820         x1 = y1 = x2 = y2 = 0;
1821         v[3] = 1.0f;
1822         //Con_Printf("%i vertices to transform...\n", numvertices);
1823         for (i = 0;i < numvertices;i++)
1824         {
1825                 VectorCopy(vertex[i], v);
1826                 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
1827                 //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]);
1828                 if (i)
1829                 {
1830                         if (x1 > v2[0]) x1 = v2[0];
1831                         if (x2 < v2[0]) x2 = v2[0];
1832                         if (y1 > v2[1]) y1 = v2[1];
1833                         if (y2 < v2[1]) y2 = v2[1];
1834                 }
1835                 else
1836                 {
1837                         x1 = x2 = v2[0];
1838                         y1 = y2 = v2[1];
1839                 }
1840         }
1841
1842         // now convert the scissor rectangle to integer screen coordinates
1843         ix1 = (int)(x1 - 1.0f);
1844         iy1 = vid.height - (int)(y2 - 1.0f);
1845         ix2 = (int)(x2 + 1.0f);
1846         iy2 = vid.height - (int)(y1 + 1.0f);
1847         //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1848
1849         // clamp it to the screen
1850         if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
1851         if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
1852         if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
1853         if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
1854
1855         // if it is inside out, it's not visible
1856         if (ix2 <= ix1 || iy2 <= iy1)
1857                 return true;
1858
1859         // the light area is visible, set up the scissor rectangle
1860         r_shadow_lightscissor[0] = ix1;
1861         r_shadow_lightscissor[1] = iy1;
1862         r_shadow_lightscissor[2] = ix2 - ix1;
1863         r_shadow_lightscissor[3] = iy2 - iy1;
1864
1865         r_refdef.stats.lights_scissored++;
1866         return false;
1867 }
1868
1869 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
1870 {
1871         float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1872         float *normal3f = rsurface.normal3f + 3 * firstvertex;
1873         float *color4f = rsurface.array_color4f + 4 * firstvertex;
1874         float dist, dot, distintensity, shadeintensity, v[3], n[3];
1875         if (r_textureunits.integer >= 3)
1876         {
1877                 if (VectorLength2(diffusecolor) > 0)
1878                 {
1879                         for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1880                         {
1881                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1882                                 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1883                                 if ((dot = DotProduct(n, v)) < 0)
1884                                 {
1885                                         shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1886                                         VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
1887                                 }
1888                                 else
1889                                         VectorCopy(ambientcolor, color4f);
1890                                 if (r_refdef.fogenabled)
1891                                 {
1892                                         float f;
1893                                         f = FogPoint_Model(vertex3f);
1894                                         VectorScale(color4f, f, color4f);
1895                                 }
1896                                 color4f[3] = 1;
1897                         }
1898                 }
1899                 else
1900                 {
1901                         for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1902                         {
1903                                 VectorCopy(ambientcolor, color4f);
1904                                 if (r_refdef.fogenabled)
1905                                 {
1906                                         float f;
1907                                         Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1908                                         f = FogPoint_Model(vertex3f);
1909                                         VectorScale(color4f, f, color4f);
1910                                 }
1911                                 color4f[3] = 1;
1912                         }
1913                 }
1914         }
1915         else if (r_textureunits.integer >= 2)
1916         {
1917                 if (VectorLength2(diffusecolor) > 0)
1918                 {
1919                         for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1920                         {
1921                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1922                                 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1923                                 {
1924                                         Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1925                                         if ((dot = DotProduct(n, v)) < 0)
1926                                         {
1927                                                 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1928                                                 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1929                                                 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1930                                                 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1931                                         }
1932                                         else
1933                                         {
1934                                                 color4f[0] = ambientcolor[0] * distintensity;
1935                                                 color4f[1] = ambientcolor[1] * distintensity;
1936                                                 color4f[2] = ambientcolor[2] * distintensity;
1937                                         }
1938                                         if (r_refdef.fogenabled)
1939                                         {
1940                                                 float f;
1941                                                 f = FogPoint_Model(vertex3f);
1942                                                 VectorScale(color4f, f, color4f);
1943                                         }
1944                                 }
1945                                 else
1946                                         VectorClear(color4f);
1947                                 color4f[3] = 1;
1948                         }
1949                 }
1950                 else
1951                 {
1952                         for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1953                         {
1954                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1955                                 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1956                                 {
1957                                         color4f[0] = ambientcolor[0] * distintensity;
1958                                         color4f[1] = ambientcolor[1] * distintensity;
1959                                         color4f[2] = ambientcolor[2] * distintensity;
1960                                         if (r_refdef.fogenabled)
1961                                         {
1962                                                 float f;
1963                                                 f = FogPoint_Model(vertex3f);
1964                                                 VectorScale(color4f, f, color4f);
1965                                         }
1966                                 }
1967                                 else
1968                                         VectorClear(color4f);
1969                                 color4f[3] = 1;
1970                         }
1971                 }
1972         }
1973         else
1974         {
1975                 if (VectorLength2(diffusecolor) > 0)
1976                 {
1977                         for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1978                         {
1979                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1980                                 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1981                                 {
1982                                         distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
1983                                         Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1984                                         if ((dot = DotProduct(n, v)) < 0)
1985                                         {
1986                                                 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1987                                                 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1988                                                 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1989                                                 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1990                                         }
1991                                         else
1992                                         {
1993                                                 color4f[0] = ambientcolor[0] * distintensity;
1994                                                 color4f[1] = ambientcolor[1] * distintensity;
1995                                                 color4f[2] = ambientcolor[2] * distintensity;
1996                                         }
1997                                         if (r_refdef.fogenabled)
1998                                         {
1999                                                 float f;
2000                                                 f = FogPoint_Model(vertex3f);
2001                                                 VectorScale(color4f, f, color4f);
2002                                         }
2003                                 }
2004                                 else
2005                                         VectorClear(color4f);
2006                                 color4f[3] = 1;
2007                         }
2008                 }
2009                 else
2010                 {
2011                         for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2012                         {
2013                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2014                                 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2015                                 {
2016                                         distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2017                                         color4f[0] = ambientcolor[0] * distintensity;
2018                                         color4f[1] = ambientcolor[1] * distintensity;
2019                                         color4f[2] = ambientcolor[2] * distintensity;
2020                                         if (r_refdef.fogenabled)
2021                                         {
2022                                                 float f;
2023                                                 f = FogPoint_Model(vertex3f);
2024                                                 VectorScale(color4f, f, color4f);
2025                                         }
2026                                 }
2027                                 else
2028                                         VectorClear(color4f);
2029                                 color4f[3] = 1;
2030                         }
2031                 }
2032         }
2033 }
2034
2035 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
2036
2037 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2038 {
2039         int i;
2040         float       *out3f     = rsurface.array_texcoord3f + 3 * firstvertex;
2041         const float *vertex3f  = rsurface.vertex3f         + 3 * firstvertex;
2042         const float *svector3f = rsurface.svector3f        + 3 * firstvertex;
2043         const float *tvector3f = rsurface.tvector3f        + 3 * firstvertex;
2044         const float *normal3f  = rsurface.normal3f         + 3 * firstvertex;
2045         float lightdir[3];
2046         for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2047         {
2048                 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2049                 // the cubemap normalizes this for us
2050                 out3f[0] = DotProduct(svector3f, lightdir);
2051                 out3f[1] = DotProduct(tvector3f, lightdir);
2052                 out3f[2] = DotProduct(normal3f, lightdir);
2053         }
2054 }
2055
2056 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2057 {
2058         int i;
2059         float       *out3f     = rsurface.array_texcoord3f + 3 * firstvertex;
2060         const float *vertex3f  = rsurface.vertex3f         + 3 * firstvertex;
2061         const float *svector3f = rsurface.svector3f        + 3 * firstvertex;
2062         const float *tvector3f = rsurface.tvector3f        + 3 * firstvertex;
2063         const float *normal3f  = rsurface.normal3f         + 3 * firstvertex;
2064         float lightdir[3], eyedir[3], halfdir[3];
2065         for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2066         {
2067                 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2068                 VectorNormalize(lightdir);
2069                 VectorSubtract(rsurface.modelorg, vertex3f, eyedir);
2070                 VectorNormalize(eyedir);
2071                 VectorAdd(lightdir, eyedir, halfdir);
2072                 // the cubemap normalizes this for us
2073                 out3f[0] = DotProduct(svector3f, halfdir);
2074                 out3f[1] = DotProduct(tvector3f, halfdir);
2075                 out3f[2] = DotProduct(normal3f, halfdir);
2076         }
2077 }
2078
2079 static void R_Shadow_RenderLighting_VisibleLighting(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject, 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 ambientscale, float diffusescale, float specularscale, qboolean dopants, qboolean doshirt)
2080 {
2081         // used to display how many times a surface is lit for level design purposes
2082         R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2083 }
2084
2085 static void R_Shadow_RenderLighting_Light_GLSL(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject, 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 ambientscale, float diffusescale, float specularscale, qboolean dopants, qboolean doshirt)
2086 {
2087         // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2088         R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
2089         if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND))
2090                 R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
2091         else
2092                 R_Mesh_ColorPointer(NULL, 0, 0);
2093         R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2094         R_Mesh_TexMatrix(1, &rsurface.texture->currentbackgroundtexmatrix);
2095         R_Mesh_TexBind(GL20TU_NORMAL, R_GetTexture(rsurface.texture->currentskinframe->nmap));
2096         R_Mesh_TexBind(GL20TU_COLOR, R_GetTexture(rsurface.texture->basetexture));
2097         R_Mesh_TexBind(GL20TU_GLOSS, R_GetTexture(rsurface.texture->glosstexture));
2098         if (rsurface.texture->backgroundcurrentskinframe)
2099         {
2100                 R_Mesh_TexBind(GL20TU_SECONDARY_NORMAL, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->nmap));
2101                 R_Mesh_TexBind(GL20TU_SECONDARY_COLOR, R_GetTexture(rsurface.texture->backgroundbasetexture));
2102                 R_Mesh_TexBind(GL20TU_SECONDARY_GLOSS, R_GetTexture(rsurface.texture->backgroundglosstexture));
2103                 R_Mesh_TexBind(GL20TU_SECONDARY_GLOW, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->glow));
2104         }
2105         //R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap));
2106         R_Mesh_TexBind(GL20TU_FOGMASK, R_GetTexture(r_texture_fogattenuation));
2107         if(rsurface.texture->colormapping)
2108         {
2109                 R_Mesh_TexBind(GL20TU_PANTS, R_GetTexture(rsurface.texture->currentskinframe->pants));
2110                 R_Mesh_TexBind(GL20TU_SHIRT, R_GetTexture(rsurface.texture->currentskinframe->shirt));
2111         }
2112         R_Mesh_TexBind(GL20TU_ATTENUATION, R_GetTexture(r_shadow_attenuationgradienttexture));
2113         R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
2114         R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
2115         R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
2116         R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
2117         if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2118         {
2119                 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2120         }
2121         R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2122         if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2123         {
2124                 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2125         }
2126 }
2127
2128 static void R_Shadow_RenderLighting_Light_Dot3_Finalize(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject, float r, float g, float b)
2129 {
2130         // shared final code for all the dot3 layers
2131         int renders;
2132         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2133         for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
2134         {
2135                 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
2136                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2137         }
2138 }
2139
2140 static void R_Shadow_RenderLighting_Light_Dot3_AmbientPass(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject, const vec3_t lightcolorbase, rtexture_t *basetexture, float colorscale)
2141 {
2142         rmeshstate_t m;
2143         // colorscale accounts for how much we multiply the brightness
2144         // during combine.
2145         //
2146         // mult is how many times the final pass of the lighting will be
2147         // performed to get more brightness than otherwise possible.
2148         //
2149         // Limit mult to 64 for sanity sake.
2150         GL_Color(1,1,1,1);
2151         if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
2152         {
2153                 // 3 3D combine path (Geforce3, Radeon 8500)
2154                 memset(&m, 0, sizeof(m));
2155                 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2156                 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2157                 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2158                 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2159                 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2160                 m.tex[1] = R_GetTexture(basetexture);
2161                 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2162                 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2163                 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2164                 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2165                 m.texcubemap[2] = R_GetTexture(rsurface.rtlight->currentcubemap);
2166                 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2167                 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2168                 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2169                 m.texmatrix[2] = rsurface.entitytolight;
2170                 GL_BlendFunc(GL_ONE, GL_ONE);
2171         }
2172         else if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
2173         {
2174                 // 2 3D combine path (Geforce3, original Radeon)
2175                 memset(&m, 0, sizeof(m));
2176                 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2177                 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2178                 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2179                 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2180                 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2181                 m.tex[1] = R_GetTexture(basetexture);
2182                 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2183                 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2184                 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2185                 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2186                 GL_BlendFunc(GL_ONE, GL_ONE);
2187         }
2188         else if (r_textureunits.integer >= 4 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2189         {
2190                 // 4 2D combine path (Geforce3, Radeon 8500)
2191                 memset(&m, 0, sizeof(m));
2192                 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2193                 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2194                 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2195                 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2196                 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2197                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2198                 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2199                 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2200                 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2201                 m.texmatrix[1] = rsurface.entitytoattenuationz;
2202                 m.tex[2] = R_GetTexture(basetexture);
2203                 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2204                 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2205                 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2206                 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2207                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2208                 {
2209                         m.texcubemap[3] = R_GetTexture(rsurface.rtlight->currentcubemap);
2210                         m.pointer_texcoord3f[3] = rsurface.vertex3f;
2211                         m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2212                         m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2213                         m.texmatrix[3] = rsurface.entitytolight;
2214                 }
2215                 GL_BlendFunc(GL_ONE, GL_ONE);
2216         }
2217         else if (r_textureunits.integer >= 3 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2218         {
2219                 // 3 2D combine path (Geforce3, original Radeon)
2220                 memset(&m, 0, sizeof(m));
2221                 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2222                 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2223                 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2224                 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2225                 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2226                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2227                 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2228                 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2229                 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2230                 m.texmatrix[1] = rsurface.entitytoattenuationz;
2231                 m.tex[2] = R_GetTexture(basetexture);
2232                 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2233                 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2234                 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2235                 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2236                 GL_BlendFunc(GL_ONE, GL_ONE);
2237         }
2238         else
2239         {
2240                 // 2/2/2 2D combine path (any dot3 card)
2241                 memset(&m, 0, sizeof(m));
2242                 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2243                 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2244                 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2245                 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2246                 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2247                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2248                 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2249                 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2250                 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2251                 m.texmatrix[1] = rsurface.entitytoattenuationz;
2252                 R_Mesh_TextureState(&m);
2253                 GL_ColorMask(0,0,0,1);
2254                 GL_BlendFunc(GL_ONE, GL_ZERO);
2255                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2256
2257                 // second pass
2258                 memset(&m, 0, sizeof(m));
2259                 m.tex[0] = R_GetTexture(basetexture);
2260                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2261                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2262                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2263                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2264                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2265                 {
2266                         m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2267                         m.pointer_texcoord3f[1] = rsurface.vertex3f;
2268                         m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2269                         m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2270                         m.texmatrix[1] = rsurface.entitytolight;
2271                 }
2272                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2273         }
2274         // this final code is shared
2275         R_Mesh_TextureState(&m);
2276         R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
2277 }
2278
2279 static void R_Shadow_RenderLighting_Light_Dot3_DiffusePass(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject, const vec3_t lightcolorbase, rtexture_t *basetexture, rtexture_t *normalmaptexture, float colorscale)
2280 {
2281         rmeshstate_t m;
2282         // colorscale accounts for how much we multiply the brightness
2283         // during combine.
2284         //
2285         // mult is how many times the final pass of the lighting will be
2286         // performed to get more brightness than otherwise possible.
2287         //
2288         // Limit mult to 64 for sanity sake.
2289         GL_Color(1,1,1,1);
2290         // generate normalization cubemap texcoords
2291         R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2292         if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
2293         {
2294                 // 3/2 3D combine path (Geforce3, Radeon 8500)
2295                 memset(&m, 0, sizeof(m));
2296                 m.tex[0] = R_GetTexture(normalmaptexture);
2297                 m.texcombinergb[0] = GL_REPLACE;
2298                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2299                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2300                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2301                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2302                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2303                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2304                 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2305                 m.pointer_texcoord_bufferobject[1] = 0;
2306                 m.pointer_texcoord_bufferoffset[1] = 0;
2307                 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
2308                 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2309                 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2310                 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2311                 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2312                 R_Mesh_TextureState(&m);
2313                 GL_ColorMask(0,0,0,1);
2314                 GL_BlendFunc(GL_ONE, GL_ZERO);
2315                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2316
2317                 // second pass
2318                 memset(&m, 0, sizeof(m));
2319                 m.tex[0] = R_GetTexture(basetexture);
2320                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2321                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2322                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2323                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2324                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2325                 {
2326                         m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2327                         m.pointer_texcoord3f[1] = rsurface.vertex3f;
2328                         m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2329                         m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2330                         m.texmatrix[1] = rsurface.entitytolight;
2331                 }
2332                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2333         }
2334         else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2335         {
2336                 // 1/2/2 3D combine path (original Radeon)
2337                 memset(&m, 0, sizeof(m));
2338                 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2339                 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2340                 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2341                 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2342                 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2343                 R_Mesh_TextureState(&m);
2344                 GL_ColorMask(0,0,0,1);
2345                 GL_BlendFunc(GL_ONE, GL_ZERO);
2346                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2347
2348                 // second pass
2349                 memset(&m, 0, sizeof(m));
2350                 m.tex[0] = R_GetTexture(normalmaptexture);
2351                 m.texcombinergb[0] = GL_REPLACE;
2352                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2353                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2354                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2355                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2356                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2357                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2358                 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2359                 m.pointer_texcoord_bufferobject[1] = 0;
2360                 m.pointer_texcoord_bufferoffset[1] = 0;
2361                 R_Mesh_TextureState(&m);
2362                 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2363                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2364
2365                 // second pass
2366                 memset(&m, 0, sizeof(m));
2367                 m.tex[0] = R_GetTexture(basetexture);
2368                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2369                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2370                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2371                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2372                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2373                 {
2374                         m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2375                         m.pointer_texcoord3f[1] = rsurface.vertex3f;
2376                         m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2377                         m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2378                         m.texmatrix[1] = rsurface.entitytolight;
2379                 }
2380                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2381         }
2382         else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2383         {
2384                 // 2/2 3D combine path (original Radeon)
2385                 memset(&m, 0, sizeof(m));
2386                 m.tex[0] = R_GetTexture(normalmaptexture);
2387                 m.texcombinergb[0] = GL_REPLACE;
2388                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2389                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2390                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2391                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2392                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2393                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2394                 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2395                 m.pointer_texcoord_bufferobject[1] = 0;
2396                 m.pointer_texcoord_bufferoffset[1] = 0;
2397                 R_Mesh_TextureState(&m);
2398                 GL_ColorMask(0,0,0,1);
2399                 GL_BlendFunc(GL_ONE, GL_ZERO);
2400                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2401
2402                 // second pass
2403                 memset(&m, 0, sizeof(m));
2404                 m.tex[0] = R_GetTexture(basetexture);
2405                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2406                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2407                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2408                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2409                 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2410                 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2411                 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2412                 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2413                 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2414                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2415         }
2416         else if (r_textureunits.integer >= 4)
2417         {
2418                 // 4/2 2D combine path (Geforce3, Radeon 8500)
2419                 memset(&m, 0, sizeof(m));
2420                 m.tex[0] = R_GetTexture(normalmaptexture);
2421                 m.texcombinergb[0] = GL_REPLACE;
2422                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2423                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2424                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2425                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2426                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2427                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2428                 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2429                 m.pointer_texcoord_bufferobject[1] = 0;
2430                 m.pointer_texcoord_bufferoffset[1] = 0;
2431                 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2432                 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2433                 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2434                 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2435                 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2436                 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2437                 m.pointer_texcoord3f[3] = rsurface.vertex3f;
2438                 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2439                 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2440                 m.texmatrix[3] = rsurface.entitytoattenuationz;
2441                 R_Mesh_TextureState(&m);
2442                 GL_ColorMask(0,0,0,1);
2443                 GL_BlendFunc(GL_ONE, GL_ZERO);
2444                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2445
2446                 // second pass
2447                 memset(&m, 0, sizeof(m));
2448                 m.tex[0] = R_GetTexture(basetexture);
2449                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2450                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2451                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2452                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2453                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2454                 {
2455                         m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2456                         m.pointer_texcoord3f[1] = rsurface.vertex3f;
2457                         m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2458                         m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2459                         m.texmatrix[1] = rsurface.entitytolight;
2460                 }
2461                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2462         }
2463         else
2464         {
2465                 // 2/2/2 2D combine path (any dot3 card)
2466                 memset(&m, 0, sizeof(m));
2467                 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2468                 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2469                 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2470                 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2471                 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2472                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2473                 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2474                 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2475                 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2476                 m.texmatrix[1] = rsurface.entitytoattenuationz;
2477                 R_Mesh_TextureState(&m);
2478                 GL_ColorMask(0,0,0,1);
2479                 GL_BlendFunc(GL_ONE, GL_ZERO);
2480                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2481
2482                 // second pass
2483                 memset(&m, 0, sizeof(m));
2484                 m.tex[0] = R_GetTexture(normalmaptexture);
2485                 m.texcombinergb[0] = GL_REPLACE;
2486                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2487                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2488                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2489                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2490                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2491                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2492                 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2493                 m.pointer_texcoord_bufferobject[1] = 0;
2494                 m.pointer_texcoord_bufferoffset[1] = 0;
2495                 R_Mesh_TextureState(&m);
2496                 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2497                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2498
2499                 // second pass
2500                 memset(&m, 0, sizeof(m));
2501                 m.tex[0] = R_GetTexture(basetexture);
2502                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2503                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2504                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2505                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2506                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2507                 {
2508                         m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2509                         m.pointer_texcoord3f[1] = rsurface.vertex3f;
2510                         m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2511                         m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2512                         m.texmatrix[1] = rsurface.entitytolight;
2513                 }
2514                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2515         }
2516         // this final code is shared
2517         R_Mesh_TextureState(&m);
2518         R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
2519 }
2520
2521 static void R_Shadow_RenderLighting_Light_Dot3_SpecularPass(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject, const vec3_t lightcolorbase, rtexture_t *glosstexture, rtexture_t *normalmaptexture, float colorscale)
2522 {
2523         float glossexponent;
2524         rmeshstate_t m;
2525         // FIXME: detect blendsquare!
2526         //if (!gl_support_blendsquare)
2527         //      return;
2528         GL_Color(1,1,1,1);
2529         // generate normalization cubemap texcoords
2530         R_Shadow_GenTexCoords_Specular_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2531         if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2532         {
2533                 // 2/0/0/1/2 3D combine blendsquare path
2534                 memset(&m, 0, sizeof(m));
2535                 m.tex[0] = R_GetTexture(normalmaptexture);
2536                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2537                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2538                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2539                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2540                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2541                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2542                 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2543                 m.pointer_texcoord_bufferobject[1] = 0;
2544                 m.pointer_texcoord_bufferoffset[1] = 0;
2545                 R_Mesh_TextureState(&m);
2546                 GL_ColorMask(0,0,0,1);
2547                 // this squares the result
2548                 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2549                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2550
2551                 // second and third pass
2552                 R_Mesh_ResetTextureState();
2553                 // square alpha in framebuffer a few times to make it shiny
2554                 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2555                 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2556                         R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2557
2558                 // fourth pass
2559                 memset(&m, 0, sizeof(m));
2560                 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2561                 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2562                 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2563                 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2564                 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2565                 R_Mesh_TextureState(&m);
2566                 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2567                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2568
2569                 // fifth pass
2570                 memset(&m, 0, sizeof(m));
2571                 m.tex[0] = R_GetTexture(glosstexture);
2572                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2573                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2574                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2575                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2576                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2577                 {
2578                         m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2579                         m.pointer_texcoord3f[1] = rsurface.vertex3f;
2580                         m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2581                         m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2582                         m.texmatrix[1] = rsurface.entitytolight;
2583                 }
2584                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2585         }
2586         else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
2587         {
2588                 // 2/0/0/2 3D combine blendsquare path
2589                 memset(&m, 0, sizeof(m));
2590                 m.tex[0] = R_GetTexture(normalmaptexture);
2591                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2592                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2593                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2594                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2595                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2596                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2597                 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2598                 m.pointer_texcoord_bufferobject[1] = 0;
2599                 m.pointer_texcoord_bufferoffset[1] = 0;
2600                 R_Mesh_TextureState(&m);
2601                 GL_ColorMask(0,0,0,1);
2602                 // this squares the result
2603                 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2604                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2605
2606                 // second and third pass
2607                 R_Mesh_ResetTextureState();
2608                 // square alpha in framebuffer a few times to make it shiny
2609                 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2610                 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2611                         R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2612
2613                 // fourth pass
2614                 memset(&m, 0, sizeof(m));
2615                 m.tex[0] = R_GetTexture(glosstexture);
2616                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2617                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2618                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2619                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2620                 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2621                 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2622                 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2623                 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2624                 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2625                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2626         }
2627         else
2628         {
2629                 // 2/0/0/2/2 2D combine blendsquare path
2630                 memset(&m, 0, sizeof(m));
2631                 m.tex[0] = R_GetTexture(normalmaptexture);
2632                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2633                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2634                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2635                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2636                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2637                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2638                 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2639                 m.pointer_texcoord_bufferobject[1] = 0;
2640                 m.pointer_texcoord_bufferoffset[1] = 0;
2641                 R_Mesh_TextureState(&m);
2642                 GL_ColorMask(0,0,0,1);
2643                 // this squares the result
2644                 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2645                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2646
2647                 // second and third pass
2648                 R_Mesh_ResetTextureState();
2649                 // square alpha in framebuffer a few times to make it shiny
2650                 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2651                 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2652                         R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2653
2654                 // fourth pass
2655                 memset(&m, 0, sizeof(m));
2656                 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2657                 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2658                 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2659                 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2660                 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2661                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2662                 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2663                 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2664                 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2665                 m.texmatrix[1] = rsurface.entitytoattenuationz;
2666                 R_Mesh_TextureState(&m);
2667                 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2668                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2669
2670                 // fifth pass
2671                 memset(&m, 0, sizeof(m));
2672                 m.tex[0] = R_GetTexture(glosstexture);
2673                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2674                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2675                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2676                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2677                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2678                 {
2679                         m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2680                         m.pointer_texcoord3f[1] = rsurface.vertex3f;
2681                         m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2682                         m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2683                         m.texmatrix[1] = rsurface.entitytolight;
2684                 }
2685                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2686         }
2687         // this final code is shared
2688         R_Mesh_TextureState(&m);
2689         R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
2690 }
2691
2692 static void R_Shadow_RenderLighting_Light_Dot3(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject, 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 ambientscale, float diffusescale, float specularscale, qboolean dopants, qboolean doshirt)
2693 {
2694         // ARB path (any Geforce, any Radeon)
2695         qboolean doambient = ambientscale > 0;
2696         qboolean dodiffuse = diffusescale > 0;
2697         qboolean dospecular = specularscale > 0;
2698         if (!doambient && !dodiffuse && !dospecular)
2699                 return;
2700         R_Mesh_ColorPointer(NULL, 0, 0);
2701         if (doambient)
2702                 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, ambientscale * r_refdef.view.colorscale);
2703         if (dodiffuse)
2704                 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2705         if (dopants)
2706         {
2707                 if (doambient)
2708                         R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, ambientscale * r_refdef.view.colorscale);
2709                 if (dodiffuse)
2710                         R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2711         }
2712         if (doshirt)
2713         {
2714                 if (doambient)
2715                         R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, ambientscale * r_refdef.view.colorscale);
2716                 if (dodiffuse)
2717                         R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2718         }
2719         if (dospecular)
2720                 R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_refdef.view.colorscale);
2721 }
2722
2723 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2724 {
2725         int renders;
2726         int i;
2727         int stop;
2728         int newfirstvertex;
2729         int newlastvertex;
2730         int newnumtriangles;
2731         int *newe;
2732         const int *e;
2733         float *c;
2734         int maxtriangles = 4096;
2735         int newelements[4096*3];
2736         R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
2737         for (renders = 0;renders < 64;renders++)
2738         {
2739                 stop = true;
2740                 newfirstvertex = 0;
2741                 newlastvertex = 0;
2742                 newnumtriangles = 0;
2743                 newe = newelements;
2744                 // due to low fillrate on the cards this vertex lighting path is
2745                 // designed for, we manually cull all triangles that do not
2746                 // contain a lit vertex
2747                 // this builds batches of triangles from multiple surfaces and
2748                 // renders them at once
2749                 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2750                 {
2751                         if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
2752                         {
2753                                 if (newnumtriangles)
2754                                 {
2755                                         newfirstvertex = min(newfirstvertex, e[0]);
2756                                         newlastvertex  = max(newlastvertex, e[0]);
2757                                 }
2758                                 else
2759                                 {
2760                                         newfirstvertex = e[0];
2761                                         newlastvertex = e[0];
2762                                 }
2763                                 newfirstvertex = min(newfirstvertex, e[1]);
2764                                 newlastvertex  = max(newlastvertex, e[1]);
2765                                 newfirstvertex = min(newfirstvertex, e[2]);
2766                                 newlastvertex  = max(newlastvertex, e[2]);
2767                                 newe[0] = e[0];
2768                                 newe[1] = e[1];
2769                                 newe[2] = e[2];
2770                                 newnumtriangles++;
2771                                 newe += 3;
2772                                 if (newnumtriangles >= maxtriangles)
2773                                 {
2774                                         R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2775                                         newnumtriangles = 0;
2776                                         newe = newelements;
2777                                         stop = false;
2778                                 }
2779                         }
2780                 }
2781                 if (newnumtriangles >= 1)
2782                 {
2783                         R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2784                         stop = false;
2785                 }
2786                 // if we couldn't find any lit triangles, exit early
2787                 if (stop)
2788                         break;
2789                 // now reduce the intensity for the next overbright pass
2790                 // we have to clamp to 0 here incase the drivers have improper
2791                 // handling of negative colors
2792                 // (some old drivers even have improper handling of >1 color)
2793                 stop = true;
2794                 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2795                 {
2796                         if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2797                         {
2798                                 c[0] = max(0, c[0] - 1);
2799                                 c[1] = max(0, c[1] - 1);
2800                                 c[2] = max(0, c[2] - 1);
2801                                 stop = false;
2802                         }
2803                         else
2804                                 VectorClear(c);
2805                 }
2806                 // another check...
2807                 if (stop)
2808                         break;
2809         }
2810 }
2811
2812 static void R_Shadow_RenderLighting_Light_Vertex(int firstvertex, int numvertices, int numtriangles, const int *element3i, 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 ambientscale, float diffusescale, float specularscale, qboolean dopants, qboolean doshirt)
2813 {
2814         // OpenGL 1.1 path (anything)
2815         float ambientcolorbase[3], diffusecolorbase[3];
2816         float ambientcolorpants[3], diffusecolorpants[3];
2817         float ambientcolorshirt[3], diffusecolorshirt[3];
2818         rmeshstate_t m;
2819         VectorScale(lightcolorbase, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorbase);
2820         VectorScale(lightcolorbase, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorbase);
2821         VectorScale(lightcolorpants, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorpants);
2822         VectorScale(lightcolorpants, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorpants);
2823         VectorScale(lightcolorshirt, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorshirt);
2824         VectorScale(lightcolorshirt, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorshirt);
2825         memset(&m, 0, sizeof(m));
2826         m.tex[0] = R_GetTexture(basetexture);
2827         m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2828         m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2829         m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2830         m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2831         if (r_textureunits.integer >= 2)
2832         {
2833                 // voodoo2 or TNT
2834                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2835                 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2836                 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2837                 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2838                 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2839                 if (r_textureunits.integer >= 3)
2840                 {
2841                         // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
2842                         m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2843                         m.texmatrix[2] = rsurface.entitytoattenuationz;
2844                         m.pointer_texcoord3f[2] = rsurface.vertex3f;
2845                         m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2846                         m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2847                 }
2848         }
2849         R_Mesh_TextureState(&m);
2850         //R_Mesh_TexBind(0, R_GetTexture(basetexture));
2851         R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
2852         if (dopants)
2853         {
2854                 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
2855                 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
2856         }
2857         if (doshirt)
2858         {
2859                 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
2860                 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
2861         }
2862 }
2863
2864 extern cvar_t gl_lightmaps;
2865 void R_Shadow_RenderLighting(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject)
2866 {
2867         float ambientscale, diffusescale, specularscale;
2868         vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
2869         rtexture_t *nmap;
2870         // calculate colors to render this texture with
2871         lightcolorbase[0] = rsurface.rtlight->currentcolor[0] * rsurface.texture->dlightcolor[0];
2872         lightcolorbase[1] = rsurface.rtlight->currentcolor[1] * rsurface.texture->dlightcolor[1];
2873         lightcolorbase[2] = rsurface.rtlight->currentcolor[2] * rsurface.texture->dlightcolor[2];
2874         ambientscale = rsurface.rtlight->ambientscale;
2875         diffusescale = rsurface.rtlight->diffusescale;
2876         specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2877         if (!r_shadow_usenormalmap.integer)
2878         {
2879                 ambientscale += 1.0f * diffusescale;
2880                 diffusescale = 0;
2881                 specularscale = 0;
2882         }
2883         if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
2884                 return;
2885         RSurf_SetupDepthAndCulling();
2886         nmap = rsurface.texture->currentskinframe->nmap;
2887         if (gl_lightmaps.integer)
2888                 nmap = r_texture_blanknormalmap;
2889         if (rsurface.texture->colormapping && !gl_lightmaps.integer)
2890         {
2891                 qboolean dopants = rsurface.texture->currentskinframe->pants != NULL && VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f);
2892                 qboolean doshirt = rsurface.texture->currentskinframe->shirt != NULL && VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f);
2893                 if (dopants)
2894                 {
2895                         lightcolorpants[0] = lightcolorbase[0] * rsurface.colormap_pantscolor[0];
2896                         lightcolorpants[1] = lightcolorbase[1] * rsurface.colormap_pantscolor[1];
2897                         lightcolorpants[2] = lightcolorbase[2] * rsurface.colormap_pantscolor[2];
2898                 }
2899                 else
2900                         VectorClear(lightcolorpants);
2901                 if (doshirt)
2902                 {
2903                         lightcolorshirt[0] = lightcolorbase[0] * rsurface.colormap_shirtcolor[0];
2904                         lightcolorshirt[1] = lightcolorbase[1] * rsurface.colormap_shirtcolor[1];
2905                         lightcolorshirt[2] = lightcolorbase[2] * rsurface.colormap_shirtcolor[2];
2906                 }
2907                 else
2908                         VectorClear(lightcolorshirt);
2909                 switch (r_shadow_rendermode)
2910                 {
2911                 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2912                         GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2913                         R_Shadow_RenderLighting_VisibleLighting(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface.texture->basetexture, rsurface.texture->currentskinframe->pants, rsurface.texture->currentskinframe->shirt, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, dopants, doshirt);
2914                         break;
2915                 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2916                         R_Shadow_RenderLighting_Light_GLSL(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface.texture->basetexture, rsurface.texture->currentskinframe->pants, rsurface.texture->currentskinframe->shirt, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, dopants, doshirt);
2917                         break;
2918                 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2919                         R_Shadow_RenderLighting_Light_Dot3(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface.texture->basetexture, rsurface.texture->currentskinframe->pants, rsurface.texture->currentskinframe->shirt, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, dopants, doshirt);
2920                         break;
2921                 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2922                         R_Shadow_RenderLighting_Light_Vertex(firstvertex, numvertices, numtriangles, element3i + firsttriangle * 3, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface.texture->basetexture, rsurface.texture->currentskinframe->pants, rsurface.texture->currentskinframe->shirt, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, dopants, doshirt);
2923                         break;
2924                 default:
2925                         Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2926                         break;
2927                 }
2928         }
2929         else
2930         {
2931                 switch (r_shadow_rendermode)
2932                 {
2933                 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2934                         GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2935                         R_Shadow_RenderLighting_VisibleLighting(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, vec3_origin, vec3_origin, rsurface.texture->basetexture, r_texture_black, r_texture_black, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, false, false);
2936                         break;
2937                 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2938                         R_Shadow_RenderLighting_Light_GLSL(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, vec3_origin, vec3_origin, rsurface.texture->basetexture, r_texture_black, r_texture_black, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, false, false);
2939                         break;
2940                 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2941                         R_Shadow_RenderLighting_Light_Dot3(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, vec3_origin, vec3_origin, rsurface.texture->basetexture, r_texture_black, r_texture_black, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, false, false);
2942                         break;
2943                 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2944                         R_Shadow_RenderLighting_Light_Vertex(firstvertex, numvertices, numtriangles, element3i + firsttriangle * 3, lightcolorbase, vec3_origin, vec3_origin, rsurface.texture->basetexture, r_texture_black, r_texture_black, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, false, false);
2945                         break;
2946                 default:
2947                         Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2948                         break;
2949                 }
2950         }
2951 }
2952
2953 void R_RTLight_Update(rtlight_t *rtlight, int isstatic, matrix4x4_t *matrix, vec3_t color, int style, const char *cubemapname, int shadow, vec_t corona, vec_t coronasizescale, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int flags)
2954 {
2955         matrix4x4_t tempmatrix = *matrix;
2956         Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2957
2958         // if this light has been compiled before, free the associated data
2959         R_RTLight_Uncompile(rtlight);
2960
2961         // clear it completely to avoid any lingering data
2962         memset(rtlight, 0, sizeof(*rtlight));
2963
2964         // copy the properties
2965         rtlight->matrix_lighttoworld = tempmatrix;
2966         Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2967         Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2968         rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2969         VectorCopy(color, rtlight->color);
2970         rtlight->cubemapname[0] = 0;
2971         if (cubemapname && cubemapname[0])
2972                 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2973         rtlight->shadow = shadow;
2974         rtlight->corona = corona;
2975         rtlight->style = style;
2976         rtlight->isstatic = isstatic;
2977         rtlight->coronasizescale = coronasizescale;
2978         rtlight->ambientscale = ambientscale;
2979         rtlight->diffusescale = diffusescale;
2980         rtlight->specularscale = specularscale;
2981         rtlight->flags = flags;
2982
2983         // compute derived data
2984         //rtlight->cullradius = rtlight->radius;
2985         //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2986         rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2987         rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2988         rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2989         rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2990         rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2991         rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2992 }
2993
2994 // compiles rtlight geometry
2995 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2996 void R_RTLight_Compile(rtlight_t *rtlight)
2997 {
2998         int i;
2999         int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3000         int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
3001         entity_render_t *ent = r_refdef.scene.worldentity;
3002         dp_model_t *model = r_refdef.scene.worldmodel;
3003         unsigned char *data;
3004         shadowmesh_t *mesh;
3005
3006         // compile the light
3007         rtlight->compiled = true;
3008         rtlight->static_numleafs = 0;
3009         rtlight->static_numleafpvsbytes = 0;
3010         rtlight->static_leaflist = NULL;
3011         rtlight->static_leafpvs = NULL;
3012         rtlight->static_numsurfaces = 0;
3013         rtlight->static_surfacelist = NULL;
3014         rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3015         rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3016         rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3017         rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3018         rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3019         rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3020
3021         if (model && model->GetLightInfo)
3022         {
3023                 // this variable must be set for the CompileShadowVolume code
3024                 r_shadow_compilingrtlight = rtlight;
3025                 R_Shadow_EnlargeLeafSurfaceTrisBuffer(model->brush.num_leafs, model->num_surfaces, model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles, model->surfmesh.num_triangles);
3026                 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, r_shadow_buffer_shadowtrispvs, r_shadow_buffer_lighttrispvs, r_shadow_buffer_visitingleafpvs);
3027                 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3028                 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3029                 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3030                 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3031                 rtlight->static_numsurfaces = numsurfaces;
3032                 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3033                 rtlight->static_numleafs = numleafs;
3034                 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3035                 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3036                 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3037                 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3038                 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3039                 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3040                 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3041                 if (rtlight->static_numsurfaces)
3042                         memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3043                 if (rtlight->static_numleafs)
3044                         memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3045                 if (rtlight->static_numleafpvsbytes)
3046                         memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3047                 if (rtlight->static_numshadowtrispvsbytes)
3048                         memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3049                 if (rtlight->static_numlighttrispvsbytes)
3050                         memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3051                 if (model->CompileShadowVolume && rtlight->shadow)
3052                         model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3053                 // now we're done compiling the rtlight
3054                 r_shadow_compilingrtlight = NULL;
3055         }
3056
3057
3058         // use smallest available cullradius - box radius or light radius
3059         //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3060         //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3061
3062         shadowzpasstris = 0;
3063         if (rtlight->static_meshchain_shadow_zpass)
3064                 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3065                         shadowzpasstris += mesh->numtriangles;
3066
3067         shadowzfailtris = 0;
3068         if (rtlight->static_meshchain_shadow_zfail)
3069                 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3070                         shadowzfailtris += mesh->numtriangles;
3071
3072         lighttris = 0;
3073         if (rtlight->static_numlighttrispvsbytes)
3074                 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3075                         if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3076                                 lighttris++;
3077
3078         shadowtris = 0;
3079         if (rtlight->static_numlighttrispvsbytes)
3080                 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3081                         if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3082                                 shadowtris++;
3083
3084         if (developer.integer >= 10)
3085                 Con_Printf("static light built: %f %f %f : %f %f %f box, %i light triangles, %i shadow triangles, %i zpass/%i zfail compiled shadow volume triangles\n", rtlight->cullmins[0], rtlight->cullmins[1], rtlight->cullmins[2], rtlight->cullmaxs[0], rtlight->cullmaxs[1], rtlight->cullmaxs[2], lighttris, shadowtris, shadowzpasstris, shadowzfailtris);
3086 }
3087
3088 void R_RTLight_Uncompile(rtlight_t *rtlight)
3089 {
3090         if (rtlight->compiled)
3091         {
3092                 if (rtlight->static_meshchain_shadow_zpass)
3093                         Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3094                 rtlight->static_meshchain_shadow_zpass = NULL;
3095                 if (rtlight->static_meshchain_shadow_zfail)
3096                         Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3097                 rtlight->static_meshchain_shadow_zfail = NULL;
3098                 // these allocations are grouped
3099                 if (rtlight->static_surfacelist)
3100                         Mem_Free(rtlight->static_surfacelist);
3101                 rtlight->static_numleafs = 0;
3102                 rtlight->static_numleafpvsbytes = 0;
3103                 rtlight->static_leaflist = NULL;
3104                 rtlight->static_leafpvs = NULL;
3105                 rtlight->static_numsurfaces = 0;
3106                 rtlight->static_surfacelist = NULL;
3107                 rtlight->static_numshadowtrispvsbytes = 0;
3108                 rtlight->static_shadowtrispvs = NULL;
3109                 rtlight->static_numlighttrispvsbytes = 0;
3110                 rtlight->static_lighttrispvs = NULL;
3111                 rtlight->compiled = false;
3112         }
3113 }
3114
3115 void R_Shadow_UncompileWorldLights(void)
3116 {
3117         size_t lightindex;
3118         dlight_t *light;
3119         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3120         for (lightindex = 0;lightindex < range;lightindex++)
3121         {
3122                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3123                 if (!light)
3124                         continue;
3125                 R_RTLight_Uncompile(&light->rtlight);
3126         }
3127 }
3128
3129 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3130 {
3131         int i, j;
3132         mplane_t plane;
3133         // reset the count of frustum planes
3134         // see rsurface.rtlight_frustumplanes definition for how much this array
3135         // can hold
3136         rsurface.rtlight_numfrustumplanes = 0;
3137
3138         // haven't implemented a culling path for ortho rendering
3139         if (!r_refdef.view.useperspective)
3140         {
3141                 // check if the light is on screen and copy the 4 planes if it is
3142                 for (i = 0;i < 4;i++)
3143                         if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3144                                 break;
3145                 if (i == 4)
3146                         for (i = 0;i < 4;i++)
3147                                 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3148                 return;
3149         }
3150
3151 #if 1
3152         // generate a deformed frustum that includes the light origin, this is
3153         // used to cull shadow casting surfaces that can not possibly cast a
3154         // shadow onto the visible light-receiving surfaces, which can be a
3155         // performance gain
3156         //
3157         // if the light origin is onscreen the result will be 4 planes exactly
3158         // if the light origin is offscreen on only one axis the result will
3159         // be exactly 5 planes (split-side case)
3160         // if the light origin is offscreen on two axes the result will be
3161         // exactly 4 planes (stretched corner case)
3162         for (i = 0;i < 4;i++)
3163         {
3164                 // quickly reject standard frustum planes that put the light
3165                 // origin outside the frustum
3166                 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3167                         continue;
3168                 // copy the plane
3169                 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3170         }
3171         // if all the standard frustum planes were accepted, the light is onscreen
3172         // otherwise we need to generate some more planes below...
3173         if (rsurface.rtlight_numfrustumplanes < 4)
3174         {
3175                 // at least one of the stock frustum planes failed, so we need to
3176                 // create one or two custom planes to enclose the light origin
3177                 for (i = 0;i < 4;i++)
3178                 {
3179                         // create a plane using the view origin and light origin, and a
3180                         // single point from the frustum corner set
3181                         TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3182                         VectorNormalize(plane.normal);
3183                         plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3184                         // see if this plane is backwards and flip it if so
3185                         for (j = 0;j < 4;j++)
3186                                 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3187                                         break;
3188                         if (j < 4)
3189                         {
3190                                 VectorNegate(plane.normal, plane.normal);
3191                                 plane.dist *= -1;
3192                                 // flipped plane, test again to see if it is now valid
3193                                 for (j = 0;j < 4;j++)
3194                                         if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3195                                                 break;
3196                                 // if the plane is still not valid, then it is dividing the
3197                                 // frustum and has to be rejected
3198                                 if (j < 4)
3199                                         continue;
3200                         }
3201                         // we have created a valid plane, compute extra info
3202                         PlaneClassify(&plane);
3203                         // copy the plane
3204                         rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3205 #if 1
3206                         // if we've found 5 frustum planes then we have constructed a
3207                         // proper split-side case and do not need to keep searching for
3208                         // planes to enclose the light origin
3209                         if (rsurface.rtlight_numfrustumplanes == 5)
3210                                 break;
3211 #endif
3212                 }
3213         }
3214 #endif
3215
3216 #if 0
3217         for (i = 0;i < rsurface.rtlight_numfrustumplanes;i++)
3218         {
3219                 plane = rsurface.rtlight_frustumplanes[i];
3220                 Con_Printf("light %p plane #%i %f %f %f : %f (%f %f %f %f %f)\n", rtlight, i, plane.normal[0], plane.normal[1], plane.normal[2], plane.dist, PlaneDiff(r_refdef.view.frustumcorner[0], &plane), PlaneDiff(r_refdef.view.frustumcorner[1], &plane), PlaneDiff(r_refdef.view.frustumcorner[2], &plane), PlaneDiff(r_refdef.view.frustumcorner[3], &plane), PlaneDiff(rtlight->shadoworigin, &plane));
3221         }
3222 #endif
3223
3224 #if 0
3225         // now add the light-space box planes if the light box is rotated, as any
3226         // caster outside the oriented light box is irrelevant (even if it passed
3227         // the worldspace light box, which is axial)
3228         if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3229         {
3230                 for (i = 0;i < 6;i++)
3231                 {
3232                         vec3_t v;
3233                         VectorClear(v);
3234                         v[i >> 1] = (i & 1) ? -1 : 1;
3235                         Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3236                         VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3237                         plane.dist = VectorNormalizeLength(plane.normal);
3238                         plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3239                         rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3240                 }
3241         }
3242 #endif
3243
3244 #if 0
3245         // add the world-space reduced box planes
3246         for (i = 0;i < 6;i++)
3247         {
3248                 VectorClear(plane.normal);
3249                 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3250                 plane.dist = (i & 1) ? -rsurface.rtlight_cullmaxs[i >> 1] : rsurface.rtlight_cullmins[i >> 1];
3251                 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3252         }
3253 #endif
3254
3255 #if 0
3256         {
3257         int j, oldnum;
3258         vec3_t points[8];
3259         vec_t bestdist;
3260         // reduce all plane distances to tightly fit the rtlight cull box, which
3261         // is in worldspace
3262         VectorSet(points[0], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3263         VectorSet(points[1], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3264         VectorSet(points[2], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3265         VectorSet(points[3], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3266         VectorSet(points[4], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3267         VectorSet(points[5], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3268         VectorSet(points[6], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3269         VectorSet(points[7], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3270         oldnum = rsurface.rtlight_numfrustumplanes;
3271         rsurface.rtlight_numfrustumplanes = 0;
3272         for (j = 0;j < oldnum;j++)
3273         {
3274                 // find the nearest point on the box to this plane
3275                 bestdist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[0]);
3276                 for (i = 1;i < 8;i++)
3277                 {
3278                         dist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[i]);
3279                         if (bestdist > dist)
3280                                 bestdist = dist;
3281                 }
3282                 Con_Printf("light %p %splane #%i %f %f %f : %f < %f\n", rtlight, rsurface.rtlight_frustumplanes[j].dist < bestdist + 0.03125 ? "^2" : "^1", j, rsurface.rtlight_frustumplanes[j].normal[0], rsurface.rtlight_frustumplanes[j].normal[1], rsurface.rtlight_frustumplanes[j].normal[2], rsurface.rtlight_frustumplanes[j].dist, bestdist);
3283                 // if the nearest point is near or behind the plane, we want this
3284                 // plane, otherwise the plane is useless as it won't cull anything
3285                 if (rsurface.rtlight_frustumplanes[j].dist < bestdist + 0.03125)
3286                 {
3287                         PlaneClassify(&rsurface.rtlight_frustumplanes[j]);
3288                         rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = rsurface.rtlight_frustumplanes[j];
3289                 }
3290         }
3291         }
3292 #endif
3293 }
3294
3295 void R_Shadow_DrawWorldShadow(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3296 {
3297         qboolean zpass;
3298         shadowmesh_t *mesh;
3299         int t, tend;
3300         int surfacelistindex;
3301         msurface_t *surface;
3302
3303         RSurf_ActiveWorldEntity();
3304         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
3305         {
3306                 if (r_refdef.scene.worldentity->model)
3307                         r_refdef.scene.worldmodel->DrawShadowMap(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
3308                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3309                 return;
3310         }
3311
3312         if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3313         {
3314                 CHECKGLERROR
3315                 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3316                 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3317                 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3318                 for (;mesh;mesh = mesh->next)
3319                 {
3320                         r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3321                         R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3322                         GL_LockArrays(0, mesh->numverts);
3323                         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3324                         {
3325                                 // increment stencil if frontface is infront of depthbuffer
3326                                 GL_CullFace(r_refdef.view.cullface_back);
3327                                 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
3328                                 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3329                                 // decrement stencil if backface is infront of depthbuffer
3330                                 GL_CullFace(r_refdef.view.cullface_front);
3331                                 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
3332                         }
3333                         else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3334                         {
3335                                 // decrement stencil if backface is behind depthbuffer
3336                                 GL_CullFace(r_refdef.view.cullface_front);
3337                                 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
3338                                 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3339                                 // increment stencil if frontface is behind depthbuffer
3340                                 GL_CullFace(r_refdef.view.cullface_back);
3341                                 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
3342                         }
3343                         R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3344                         GL_LockArrays(0, 0);
3345                 }
3346                 CHECKGLERROR
3347         }
3348         else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
3349         {
3350                 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3351                 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3352                 {
3353                         surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3354                         for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3355                                 if (CHECKPVSBIT(trispvs, t))
3356                                         shadowmarklist[numshadowmark++] = t;
3357                 }
3358                 R_Shadow_VolumeFromList(r_refdef.scene.worldmodel->brush.shadowmesh->numverts, r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles, r_refdef.scene.worldmodel->brush.shadowmesh->vertex3f, r_refdef.scene.worldmodel->brush.shadowmesh->element3i, r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius + r_refdef.scene.worldmodel->radius*2 + r_shadow_projectdistance.value, numshadowmark, shadowmarklist, r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3359         }
3360         else if (numsurfaces)
3361                 r_refdef.scene.worldmodel->DrawShadowVolume(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
3362
3363         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3364 }
3365
3366 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3367 {
3368         vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3369         vec_t relativeshadowradius;
3370         RSurf_ActiveModelEntity(ent, false, false);
3371         Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3372         relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3373         relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3374         relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3375         relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3376         relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3377         relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3378         relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3379         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
3380                 ent->model->DrawShadowMap(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3381         else
3382                 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3383         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3384 }
3385
3386 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3387 {
3388         // set up properties for rendering light onto this entity
3389         RSurf_ActiveModelEntity(ent, true, true);
3390         GL_AlphaTest(false);
3391         Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3392         Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3393         Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3394         Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3395         if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
3396                 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3397 }
3398
3399 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3400 {
3401         if (!r_refdef.scene.worldmodel->DrawLight)
3402                 return;
3403
3404         // set up properties for rendering light onto this entity
3405         RSurf_ActiveWorldEntity();
3406         GL_AlphaTest(false);
3407         rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3408         Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3409         Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3410         VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3411         if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
3412                 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3413
3414         r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, trispvs);
3415
3416         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3417 }
3418
3419 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3420 {
3421         dp_model_t *model = ent->model;
3422         if (!model->DrawLight)
3423                 return;
3424
3425         R_Shadow_SetupEntityLight(ent);
3426
3427         model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3428
3429         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3430 }
3431
3432 /*
3433 {{  0,   0, 0}, "px",  true,  true,  true},
3434 {{  0,  90, 0}, "py", false,  true, false},
3435 {{  0, 180, 0}, "nx", false, false,  true},
3436 {{  0, 270, 0}, "ny",  true, false, false},
3437 {{-90, 180, 0}, "pz", false, false,  true},
3438 {{ 90, 180, 0}, "nz", false, false,  true}
3439 */
3440
3441 static const double shadowviewmat16[6][4][4] =
3442 {
3443         {
3444                 {-1,  0,  0, 0},
3445                 { 0, -1,  0, 0},
3446                 { 0,  0,  1, 0},
3447                 { 0,  0,  0, 1},
3448         },
3449         {
3450                 { 0, -1,  0, 0},
3451                 {-1,  0,  0, 0},
3452                 { 0,  0,  1, 0},
3453                 { 0,  0,  0, 1},
3454         },
3455         {
3456                 {-1,  0,  0, 0},
3457                 { 0, -1,  0, 0},
3458                 { 0,  0,  1, 0},
3459                 { 0,  0,  0, 1},
3460         },
3461         {
3462                 { 0, -1,  0, 0},
3463                 {-1,  0,  0, 0},
3464                 { 0,  0,  1, 0},
3465                 { 0,  0,  0, 1},
3466         },
3467         {
3468                 { 0,  0,  1, 0},
3469                 { 0, -1,  0, 0},
3470                 { 1,  0,  0, 0},
3471                 { 0,  0,  0, 1},
3472         },
3473         {
3474                 { 0,  0, -1, 0},
3475                 { 0, -1,  0, 0},
3476                 {-1,  0,  0, 0},
3477                 { 0,  0,  0, 1},
3478         },
3479 };
3480
3481 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
3482 {
3483         int i;
3484         float f;
3485         int numleafs, numsurfaces;
3486         int *leaflist, *surfacelist;
3487         unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs;
3488         int numlightentities;
3489         int numlightentities_noselfshadow;
3490         int numshadowentities;
3491         int numshadowentities_noselfshadow;
3492         static entity_render_t *lightentities[MAX_EDICTS];
3493         static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3494         static entity_render_t *shadowentities[MAX_EDICTS];
3495         static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3496         vec3_t nearestpoint;
3497         vec_t distance;
3498         qboolean castshadows;
3499         int lodlinear;
3500
3501         // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3502         // skip lights that are basically invisible (color 0 0 0)
3503         if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
3504                 return;
3505
3506         // loading is done before visibility checks because loading should happen
3507         // all at once at the start of a level, not when it stalls gameplay.
3508         // (especially important to benchmarks)
3509         // compile light
3510         if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
3511                 R_RTLight_Compile(rtlight);
3512         // load cubemap
3513         rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
3514
3515         // look up the light style value at this time
3516         f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3517         VectorScale(rtlight->color, f, rtlight->currentcolor);
3518         /*
3519         if (rtlight->selected)
3520         {
3521                 f = 2 + sin(realtime * M_PI * 4.0);
3522                 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3523         }
3524         */
3525
3526         // if lightstyle is currently off, don't draw the light
3527         if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3528                 return;
3529
3530         // if the light box is offscreen, skip it
3531         if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3532                 return;
3533
3534         VectorCopy(rtlight->cullmins, rsurface.rtlight_cullmins);
3535         VectorCopy(rtlight->cullmaxs, rsurface.rtlight_cullmaxs);
3536
3537         if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3538         {
3539                 // compiled light, world available and can receive realtime lighting
3540                 // retrieve leaf information
3541                 numleafs = rtlight->static_numleafs;
3542                 leaflist = rtlight->static_leaflist;
3543                 leafpvs = rtlight->static_leafpvs;
3544                 numsurfaces = rtlight->static_numsurfaces;
3545                 surfacelist = rtlight->static_surfacelist;
3546                 shadowtrispvs = rtlight->static_shadowtrispvs;
3547                 lighttrispvs = rtlight->static_lighttrispvs;
3548         }
3549         else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3550         {
3551                 // dynamic light, world available and can receive realtime lighting
3552                 // calculate lit surfaces and leafs
3553                 R_Shadow_EnlargeLeafSurfaceTrisBuffer(r_refdef.scene.worldmodel->brush.num_leafs, r_refdef.scene.worldmodel->num_surfaces, r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles, r_refdef.scene.worldmodel->surfmesh.num_triangles);
3554                 r_refdef.scene.worldmodel->GetLightInfo(r_refdef.scene.worldentity, rtlight->shadoworigin, rtlight->radius, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs, r_shadow_buffer_leaflist, r_shadow_buffer_leafpvs, &numleafs, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces, r_shadow_buffer_shadowtrispvs, r_shadow_buffer_lighttrispvs, r_shadow_buffer_visitingleafpvs);
3555                 leaflist = r_shadow_buffer_leaflist;
3556                 leafpvs = r_shadow_buffer_leafpvs;
3557                 surfacelist = r_shadow_buffer_surfacelist;
3558                 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3559                 lighttrispvs = r_shadow_buffer_lighttrispvs;
3560                 // if the reduced leaf bounds are offscreen, skip it
3561                 if (R_CullBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3562                         return;
3563         }
3564         else
3565         {
3566                 // no world
3567                 numleafs = 0;
3568                 leaflist = NULL;
3569                 leafpvs = NULL;
3570                 numsurfaces = 0;
3571                 surfacelist = NULL;
3572                 shadowtrispvs = NULL;
3573                 lighttrispvs = NULL;
3574         }
3575         // check if light is illuminating any visible leafs
3576         if (numleafs)
3577         {
3578                 for (i = 0;i < numleafs;i++)
3579                         if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3580                                 break;
3581                 if (i == numleafs)
3582                         return;
3583         }
3584         // set up a scissor rectangle for this light
3585         if (R_Shadow_ScissorForBBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3586                 return;
3587
3588         R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3589
3590         // make a list of lit entities and shadow casting entities
3591         numlightentities = 0;
3592         numlightentities_noselfshadow = 0;
3593         numshadowentities = 0;
3594         numshadowentities_noselfshadow = 0;
3595         // add dynamic entities that are lit by the light
3596         if (r_drawentities.integer)
3597         {
3598                 for (i = 0;i < r_refdef.scene.numentities;i++)
3599                 {
3600                         dp_model_t *model;
3601                         entity_render_t *ent = r_refdef.scene.entities[i];
3602                         vec3_t org;
3603                         if (!BoxesOverlap(ent->mins, ent->maxs, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3604                                 continue;
3605                         // skip the object entirely if it is not within the valid
3606                         // shadow-casting region (which includes the lit region)
3607                         if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rsurface.rtlight_numfrustumplanes, rsurface.rtlight_frustumplanes))
3608                                 continue;
3609                         if (!(model = ent->model))
3610                                 continue;
3611                         if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3612                         {
3613                                 // this entity wants to receive light, is visible, and is
3614                                 // inside the light box
3615                                 // TODO: check if the surfaces in the model can receive light
3616                                 // so now check if it's in a leaf seen by the light
3617                                 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.scene.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.scene.worldmodel, leafpvs, ent->mins, ent->maxs))
3618                                         continue;
3619                                 if (ent->flags & RENDER_NOSELFSHADOW)
3620                                         lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3621                                 else
3622                                         lightentities[numlightentities++] = ent;
3623                                 // since it is lit, it probably also casts a shadow...
3624                                 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3625                                 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3626                                 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3627                                 {
3628                                         // note: exterior models without the RENDER_NOSELFSHADOW
3629                                         // flag still create a RENDER_NOSELFSHADOW shadow but
3630                                         // are lit normally, this means that they are
3631                                         // self-shadowing but do not shadow other
3632                                         // RENDER_NOSELFSHADOW entities such as the gun
3633                                         // (very weird, but keeps the player shadow off the gun)
3634                                         if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3635                                                 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3636                                         else
3637                                                 shadowentities[numshadowentities++] = ent;
3638                                 }
3639                         }
3640                         else if (ent->flags & RENDER_SHADOW)
3641                         {
3642                                 // this entity is not receiving light, but may still need to
3643                                 // cast a shadow...
3644                                 // TODO: check if the surfaces in the model can cast shadow
3645                                 // now check if it is in a leaf seen by the light
3646                                 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.scene.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.scene.worldmodel, leafpvs, ent->mins, ent->maxs))
3647                                         continue;
3648                                 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3649                                 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3650                                 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3651                                 {
3652                                         if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3653                                                 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3654                                         else
3655                                                 shadowentities[numshadowentities++] = ent;
3656                                 }
3657                         }
3658                 }
3659         }
3660
3661         // return if there's nothing at all to light
3662         if (!numlightentities && !numsurfaces)
3663                 return;
3664
3665         // don't let sound skip if going slow
3666         if (r_refdef.scene.extraupdate)
3667                 S_ExtraUpdate ();
3668
3669         // make this the active rtlight for rendering purposes
3670         R_Shadow_RenderMode_ActiveLight(rtlight);
3671         // count this light in the r_speeds
3672         r_refdef.stats.lights++;
3673
3674         if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3675         {
3676                 // optionally draw visible shape of the shadow volumes
3677                 // for performance analysis by level designers
3678                 R_Shadow_RenderMode_VisibleShadowVolumes();
3679                 if (numsurfaces)
3680                         R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3681                 for (i = 0;i < numshadowentities;i++)
3682                         R_Shadow_DrawEntityShadow(shadowentities[i]);
3683                 for (i = 0;i < numshadowentities_noselfshadow;i++)
3684                         R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3685         }
3686
3687         if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3688         {
3689                 // optionally draw the illuminated areas
3690                 // for performance analysis by level designers
3691                 R_Shadow_RenderMode_VisibleLighting(false, false);
3692                 if (numsurfaces)
3693                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3694                 for (i = 0;i < numlightentities;i++)
3695                         R_Shadow_DrawEntityLight(lightentities[i]);
3696                 for (i = 0;i < numlightentities_noselfshadow;i++)
3697                         R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3698         }
3699
3700         castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3701
3702         nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3703         nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3704         nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3705         distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3706         lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3707         lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapping_maxsize.integer);
3708
3709         if (castshadows && r_shadow_shadowmode >= 1 && r_shadow_shadowmode <= 3 && r_glsl.integer && gl_support_fragment_shader)
3710         {
3711                 int side;
3712                 int size;
3713
3714                 r_shadow_shadowmaplod = 0;
3715                 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
3716                         if ((r_shadow_shadowmapping_maxsize.integer >> i) > lodlinear)
3717                                 r_shadow_shadowmaplod = i;
3718
3719                 size = r_shadow_shadowmapvsdct || r_shadow_shadowmode == 3 ? r_shadow_shadowmapping_maxsize.integer >> r_shadow_shadowmaplod : lodlinear;
3720                 size = bound(1, size, 2048);
3721
3722                 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
3723
3724                 // render shadow casters into 6 sided depth texture
3725                 for (side = 0;side < 6;side++)
3726                 {
3727                         R_Shadow_RenderMode_ShadowMap(side, true, size);
3728                         if (numsurfaces)
3729                                 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3730                         for (i = 0;i < numshadowentities;i++)
3731                                 R_Shadow_DrawEntityShadow(shadowentities[i]);
3732                 }
3733
3734                 if (numlightentities_noselfshadow)
3735                 {
3736                         // render lighting using the depth texture as shadowmap
3737                         // draw lighting in the unmasked areas
3738                         R_Shadow_RenderMode_Lighting(false, false, true);
3739                         for (i = 0;i < numlightentities_noselfshadow;i++)
3740                                 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3741                 }
3742
3743                 // render shadow casters into 6 sided depth texture
3744                 for (side = 0;side < 6;side++)
3745                 {
3746                         R_Shadow_RenderMode_ShadowMap(side, false, size);
3747                         for (i = 0;i < numshadowentities_noselfshadow;i++)
3748                                 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3749                 }
3750
3751                 // render lighting using the depth texture as shadowmap
3752                 // draw lighting in the unmasked areas
3753                 R_Shadow_RenderMode_Lighting(false, false, true);
3754                 // draw lighting in the unmasked areas
3755                 if (numsurfaces)
3756                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3757                 for (i = 0;i < numlightentities;i++)
3758                         R_Shadow_DrawEntityLight(lightentities[i]);
3759         }
3760         else if (castshadows && gl_stencil)
3761         {
3762                 // draw stencil shadow volumes to mask off pixels that are in shadow
3763                 // so that they won't receive lighting
3764                 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
3765                 R_Shadow_ClearStencil();
3766                 if (numsurfaces)
3767                         R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3768                 for (i = 0;i < numshadowentities;i++)
3769                         R_Shadow_DrawEntityShadow(shadowentities[i]);
3770                 if (numlightentities_noselfshadow)
3771                 {
3772                         // draw lighting in the unmasked areas
3773                         R_Shadow_RenderMode_Lighting(true, false, false);
3774                         for (i = 0;i < numlightentities_noselfshadow;i++)
3775                                 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3776
3777                         // optionally draw the illuminated areas
3778                         // for performance analysis by level designers
3779                         if (r_showlighting.integer && r_refdef.view.showdebug)
3780                         {
3781                                 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
3782                                 for (i = 0;i < numlightentities_noselfshadow;i++)
3783                                         R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3784                         }
3785                 }
3786                 for (i = 0;i < numshadowentities_noselfshadow;i++)
3787                         R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3788
3789                 if (numsurfaces + numlightentities)
3790                 {
3791                         // draw lighting in the unmasked areas
3792                         R_Shadow_RenderMode_Lighting(true, false, false);
3793                         if (numsurfaces)
3794                                 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3795                         for (i = 0;i < numlightentities;i++)
3796                                 R_Shadow_DrawEntityLight(lightentities[i]);
3797                 }
3798         }
3799         else
3800         {
3801                 if (numsurfaces + numlightentities)
3802                 {
3803                         // draw lighting in the unmasked areas
3804                         R_Shadow_RenderMode_Lighting(false, false, false);
3805                         if (numsurfaces)
3806                                 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3807                         for (i = 0;i < numlightentities;i++)
3808                                 R_Shadow_DrawEntityLight(lightentities[i]);
3809                         for (i = 0;i < numlightentities_noselfshadow;i++)
3810                                 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3811                 }
3812         }
3813 }
3814
3815 void R_Shadow_DrawLightSprites(void);
3816 void R_ShadowVolumeLighting(qboolean visible)
3817 {
3818         int flag;
3819         int lnum;
3820         size_t lightindex;
3821         dlight_t *light;
3822         size_t range;
3823
3824         if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, 2048) || r_shadow_shadowmode != r_shadow_shadowmapping.integer || r_shadow_shadowmapvsdct != r_shadow_shadowmapping_vsdct.integer || r_shadow_shadowmapfilter != r_shadow_shadowmapping_filterquality.integer || r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
3825                 R_Shadow_FreeShadowMaps();
3826
3827         if (r_editlights.integer)
3828                 R_Shadow_DrawLightSprites();
3829
3830         R_Shadow_RenderMode_Begin();
3831
3832         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3833         if (r_shadow_debuglight.integer >= 0)
3834         {
3835                 lightindex = r_shadow_debuglight.integer;
3836                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3837                 if (light && (light->flags & flag))
3838                         R_DrawRTLight(&light->rtlight, visible);
3839         }
3840         else
3841         {
3842                 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3843                 for (lightindex = 0;lightindex < range;lightindex++)
3844                 {
3845                         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3846                         if (light && (light->flags & flag))
3847                                 R_DrawRTLight(&light->rtlight, visible);
3848                 }
3849         }
3850         if (r_refdef.scene.rtdlight)
3851                 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3852                         R_DrawRTLight(r_refdef.scene.lights[lnum], visible);
3853
3854         R_Shadow_RenderMode_End();
3855 }
3856
3857 extern const float r_screenvertex3f[12];
3858 extern void R_SetupView(qboolean allowwaterclippingplane);
3859 extern void R_ResetViewRendering3D(void);
3860 extern void R_ResetViewRendering2D(void);
3861 extern cvar_t r_shadows;
3862 extern cvar_t r_shadows_darken;
3863 extern cvar_t r_shadows_drawafterrtlighting;
3864 extern cvar_t r_shadows_castfrombmodels;
3865 extern cvar_t r_shadows_throwdistance;
3866 extern cvar_t r_shadows_throwdirection;
3867 void R_DrawModelShadows(void)
3868 {
3869         int i;
3870         float relativethrowdistance;
3871         entity_render_t *ent;
3872         vec3_t relativelightorigin;
3873         vec3_t relativelightdirection;
3874         vec3_t relativeshadowmins, relativeshadowmaxs;
3875         vec3_t tmp, shadowdir;
3876
3877         if (!r_drawentities.integer || !gl_stencil)
3878                 return;
3879
3880         CHECKGLERROR
3881         R_ResetViewRendering3D();
3882         //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
3883         //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
3884         R_Shadow_RenderMode_Begin();
3885         R_Shadow_RenderMode_ActiveLight(NULL);
3886         r_shadow_lightscissor[0] = r_refdef.view.x;
3887         r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
3888         r_shadow_lightscissor[2] = r_refdef.view.width;
3889         r_shadow_lightscissor[3] = r_refdef.view.height;
3890         R_Shadow_RenderMode_StencilShadowVolumes(false);
3891
3892         // get shadow dir
3893         if (r_shadows.integer == 2)
3894         {
3895                 Math_atov(r_shadows_throwdirection.string, shadowdir);
3896                 VectorNormalize(shadowdir);
3897         }
3898
3899         R_Shadow_ClearStencil();
3900
3901         for (i = 0;i < r_refdef.scene.numentities;i++)
3902         {
3903                 ent = r_refdef.scene.entities[i];
3904
3905                 // cast shadows from anything of the map (submodels are optional)
3906                 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
3907                 {
3908                         relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
3909                         VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
3910                         VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
3911                         if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
3912                                 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
3913                         else
3914                         {
3915                                 if(ent->entitynumber != 0)
3916                                 {
3917                                         // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
3918                                         int entnum, entnum2, recursion;
3919                                         entnum = entnum2 = ent->entitynumber;
3920                                         for(recursion = 32; recursion > 0; --recursion)
3921                                         {
3922                                                 entnum2 = cl.entities[entnum].state_current.tagentity;
3923                                                 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
3924                                                         entnum = entnum2;
3925                                                 else
3926                                                         break;
3927                                         }
3928                                         if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
3929                                         {
3930                                                 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
3931                                                 // transform into modelspace of OUR entity
3932                                                 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
3933                                                 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
3934                                         }
3935                                         else
3936                                                 VectorNegate(ent->modellight_lightdir, relativelightdirection);
3937                                 }
3938                                 else
3939                                         VectorNegate(ent->modellight_lightdir, relativelightdirection);
3940                         }
3941
3942                         VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
3943                         RSurf_ActiveModelEntity(ent, false, false);
3944                         ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3945                         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3946                 }
3947         }
3948
3949         // not really the right mode, but this will disable any silly stencil features
3950         R_Shadow_RenderMode_End();
3951
3952         // set up ortho view for rendering this pass
3953         //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
3954         //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
3955         //GL_ScissorTest(true);
3956         //R_Mesh_Matrix(&identitymatrix);
3957         //R_Mesh_ResetTextureState();
3958         R_ResetViewRendering2D();
3959         R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
3960         R_Mesh_ColorPointer(NULL, 0, 0);
3961         R_SetupGenericShader(false);
3962
3963         // set up a darkening blend on shadowed areas
3964         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3965         //GL_DepthRange(0, 1);
3966         //GL_DepthTest(false);
3967         //GL_DepthMask(false);
3968         //GL_PolygonOffset(0, 0);CHECKGLERROR
3969         GL_Color(0, 0, 0, r_shadows_darken.value);
3970         //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
3971         //qglDepthFunc(GL_ALWAYS);CHECKGLERROR
3972         qglEnable(GL_STENCIL_TEST);CHECKGLERROR
3973         qglStencilMask(~0);CHECKGLERROR
3974         qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
3975         qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
3976
3977         // apply the blend to the shadowed areas
3978         R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
3979
3980         // restore the viewport
3981         R_SetViewport(&r_refdef.view.viewport);
3982
3983         // restore other state to normal
3984         //R_Shadow_RenderMode_End();
3985 }
3986
3987 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
3988 {
3989         float zdist;
3990         vec3_t centerorigin;
3991         // if it's too close, skip it
3992         if (VectorLength(rtlight->color) < (1.0f / 256.0f))
3993                 return;
3994         zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
3995         if (zdist < 32)
3996                 return;
3997         if (usequery && r_numqueries + 2 <= r_maxqueries)
3998         {
3999                 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4000                 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4001                 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4002
4003                 CHECKGLERROR
4004                 // NOTE: we can't disable depth testing using R_DrawSprite's depthdisable argument, which calls GL_DepthTest, as that's broken in the ATI drivers
4005                 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4006                 qglDepthFunc(GL_ALWAYS);
4007                 R_DrawSprite(GL_ONE, GL_ZERO, r_shadow_lightcorona, NULL, false, false, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale, 1, 1, 1, 1);
4008                 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4009                 qglDepthFunc(GL_LEQUAL);
4010                 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4011                 R_DrawSprite(GL_ONE, GL_ZERO, r_shadow_lightcorona, NULL, false, false, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale, 1, 1, 1, 1);
4012                 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4013                 CHECKGLERROR
4014         }
4015         rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4016 }
4017
4018 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4019 {
4020         vec3_t color;
4021         GLint allpixels = 0, visiblepixels = 0;
4022         // now we have to check the query result
4023         if (rtlight->corona_queryindex_visiblepixels)
4024         {
4025                 CHECKGLERROR
4026                 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4027                 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4028                 CHECKGLERROR
4029                 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4030                 if (visiblepixels < 1 || allpixels < 1)
4031                         return;
4032                 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4033                 cscale *= rtlight->corona_visibility;
4034         }
4035         else
4036         {
4037                 // FIXME: these traces should scan all render entities instead of cl.world
4038                 if (CL_Move(r_refdef.view.origin, vec3_origin, vec3_origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4039                         return;
4040         }
4041         VectorScale(rtlight->color, cscale, color);
4042         if (VectorLength(color) > (1.0f / 256.0f))
4043                 R_DrawSprite(GL_ONE, GL_ONE, r_shadow_lightcorona, NULL, true, false, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale, color[0], color[1], color[2], 1);
4044 }
4045
4046 void R_DrawCoronas(void)
4047 {
4048         int i, flag;
4049         qboolean usequery;
4050         size_t lightindex;
4051         dlight_t *light;
4052         rtlight_t *rtlight;
4053         size_t range;
4054         if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4055                 return;
4056         if (r_waterstate.renderingscene)
4057                 return;
4058         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4059         R_Mesh_Matrix(&identitymatrix);
4060
4061         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4062
4063         // check occlusion of coronas
4064         // use GL_ARB_occlusion_query if available
4065         // otherwise use raytraces
4066         r_numqueries = 0;
4067         usequery = gl_support_arb_occlusion_query && r_coronas_occlusionquery.integer;
4068         if (usequery)
4069         {
4070                 GL_ColorMask(0,0,0,0);
4071                 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4072                 if (r_maxqueries < R_MAX_OCCLUSION_QUERIES)
4073                 {
4074                         i = r_maxqueries;
4075                         r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4076                         r_maxqueries = min(r_maxqueries, R_MAX_OCCLUSION_QUERIES);
4077                         CHECKGLERROR
4078                         qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4079                         CHECKGLERROR
4080                 }
4081         }
4082         for (lightindex = 0;lightindex < range;lightindex++)
4083         {
4084                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4085                 if (!light)
4086                         continue;
4087                 rtlight = &light->rtlight;
4088                 rtlight->corona_visibility = 0;
4089                 rtlight->corona_queryindex_visiblepixels = 0;
4090                 rtlight->corona_queryindex_allpixels = 0;
4091                 if (!(rtlight->flags & flag))
4092                         continue;
4093                 if (rtlight->corona <= 0)
4094                         continue;
4095                 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4096                         continue;
4097                 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4098         }
4099         for (i = 0;i < r_refdef.scene.numlights;i++)
4100         {
4101                 rtlight = r_refdef.scene.lights[i];
4102                 rtlight->corona_visibility = 0;
4103                 rtlight->corona_queryindex_visiblepixels = 0;
4104                 rtlight->corona_queryindex_allpixels = 0;
4105                 if (!(rtlight->flags & flag))
4106                         continue;
4107                 if (rtlight->corona <= 0)
4108                         continue;
4109                 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4110         }
4111         if (usequery)
4112                 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4113
4114         // now draw the coronas using the query data for intensity info
4115         for (lightindex = 0;lightindex < range;lightindex++)
4116         {
4117                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4118                 if (!light)
4119                         continue;
4120                 rtlight = &light->rtlight;
4121                 if (rtlight->corona_visibility <= 0)
4122                         continue;
4123                 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4124         }
4125         for (i = 0;i < r_refdef.scene.numlights;i++)
4126         {
4127                 rtlight = r_refdef.scene.lights[i];
4128                 if (rtlight->corona_visibility <= 0)
4129                         continue;
4130                 if (gl_flashblend.integer)
4131                         R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4132                 else
4133                         R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4134         }
4135 }
4136
4137
4138
4139 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
4140 typedef struct suffixinfo_s
4141 {
4142         char *suffix;
4143         qboolean flipx, flipy, flipdiagonal;
4144 }
4145 suffixinfo_t;
4146 static suffixinfo_t suffix[3][6] =
4147 {
4148         {
4149                 {"px",   false, false, false},
4150                 {"nx",   false, false, false},
4151                 {"py",   false, false, false},
4152                 {"ny",   false, false, false},
4153                 {"pz",   false, false, false},
4154                 {"nz",   false, false, false}
4155         },
4156         {
4157                 {"posx", false, false, false},
4158                 {"negx", false, false, false},
4159                 {"posy", false, false, false},
4160                 {"negy", false, false, false},
4161                 {"posz", false, false, false},
4162                 {"negz", false, false, false}
4163         },
4164         {
4165                 {"rt",    true, false,  true},
4166                 {"lf",   false,  true,  true},
4167                 {"ft",    true,  true, false},
4168                 {"bk",   false, false, false},
4169                 {"up",    true, false,  true},
4170                 {"dn",    true, false,  true}
4171         }
4172 };
4173
4174 static int componentorder[4] = {0, 1, 2, 3};
4175
4176 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
4177 {
4178         int i, j, cubemapsize;
4179         unsigned char *cubemappixels, *image_buffer;
4180         rtexture_t *cubemaptexture;
4181         char name[256];
4182         // must start 0 so the first loadimagepixels has no requested width/height
4183         cubemapsize = 0;
4184         cubemappixels = NULL;
4185         cubemaptexture = NULL;
4186         // keep trying different suffix groups (posx, px, rt) until one loads
4187         for (j = 0;j < 3 && !cubemappixels;j++)
4188         {
4189                 // load the 6 images in the suffix group
4190                 for (i = 0;i < 6;i++)
4191                 {
4192                         // generate an image name based on the base and and suffix
4193                         dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
4194                         // load it
4195                         if ((image_buffer = loadimagepixelsbgra(name, false, false)))
4196                         {
4197                                 // an image loaded, make sure width and height are equal
4198                                 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
4199                                 {
4200                                         // if this is the first image to load successfully, allocate the cubemap memory
4201                                         if (!cubemappixels && image_width >= 1)
4202                                         {
4203                                                 cubemapsize = image_width;
4204                                                 // note this clears to black, so unavailable sides are black
4205                                                 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
4206                                         }
4207                                         // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
4208                                         if (cubemappixels)
4209                                                 Image_CopyMux(cubemappixels+i*cubemapsize*cubemapsize*4, image_buffer, cubemapsize, cubemapsize, suffix[j][i].flipx, suffix[j][i].flipy, suffix[j][i].flipdiagonal, 4, 4, componentorder);
4210                                 }
4211                                 else
4212                                         Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
4213                                 // free the image
4214                                 Mem_Free(image_buffer);
4215                         }
4216                 }
4217         }
4218         // if a cubemap loaded, upload it
4219         if (cubemappixels)
4220         {
4221                 if (developer_loading.integer)
4222                         Con_Printf("loading cubemap \"%s\"\n", basename);
4223
4224                 if (!r_shadow_filters_texturepool)
4225                         r_shadow_filters_texturepool = R_AllocTexturePool();
4226                 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, TEXF_PRECACHE | (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR, NULL);
4227                 Mem_Free(cubemappixels);
4228         }
4229         else
4230         {
4231                 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
4232                 if (developer_loading.integer)
4233                 {
4234                         Con_Printf("(tried tried images ");
4235                         for (j = 0;j < 3;j++)
4236                                 for (i = 0;i < 6;i++)
4237                                         Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
4238                         Con_Print(" and was unable to find any of them).\n");
4239                 }
4240         }
4241         return cubemaptexture;
4242 }
4243
4244 rtexture_t *R_Shadow_Cubemap(const char *basename)
4245 {
4246         int i;
4247         for (i = 0;i < numcubemaps;i++)
4248                 if (!strcasecmp(cubemaps[i].basename, basename))
4249                         return cubemaps[i].texture ? cubemaps[i].texture : r_texture_whitecube;
4250         if (i >= MAX_CUBEMAPS)
4251                 return r_texture_whitecube;
4252         numcubemaps++;
4253         strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
4254         cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
4255         return cubemaps[i].texture;
4256 }
4257
4258 void R_Shadow_FreeCubemaps(void)
4259 {
4260         int i;
4261         for (i = 0;i < numcubemaps;i++)
4262         {
4263                 if (developer_loading.integer)
4264                         Con_Printf("unloading cubemap \"%s\"\n", cubemaps[i].basename);
4265                 if (cubemaps[i].texture)
4266                         R_FreeTexture(cubemaps[i].texture);
4267         }
4268
4269         numcubemaps = 0;
4270         R_FreeTexturePool(&r_shadow_filters_texturepool);
4271 }
4272
4273 dlight_t *R_Shadow_NewWorldLight(void)
4274 {
4275         return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4276 }
4277
4278 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)
4279 {
4280         matrix4x4_t matrix;
4281         // validate parameters
4282         if (style < 0 || style >= MAX_LIGHTSTYLES)
4283         {
4284                 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4285                 style = 0;
4286         }
4287         if (!cubemapname)
4288                 cubemapname = "";
4289
4290         // copy to light properties
4291         VectorCopy(origin, light->origin);
4292         light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4293         light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4294         light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4295         light->color[0] = max(color[0], 0);
4296         light->color[1] = max(color[1], 0);
4297         light->color[2] = max(color[2], 0);
4298         light->radius = max(radius, 0);
4299         light->style = style;
4300         light->shadow = shadowenable;
4301         light->corona = corona;
4302         strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4303         light->coronasizescale = coronasizescale;
4304         light->ambientscale = ambientscale;
4305         light->diffusescale = diffusescale;
4306         light->specularscale = specularscale;
4307         light->flags = flags;
4308
4309         // update renderable light data
4310         Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4311         R_RTLight_Update(&light->rtlight, true, &matrix, light->color, light->style, light->cubemapname[0] ? light->cubemapname : NULL, light->shadow, light->corona, light->coronasizescale, light->ambientscale, light->diffusescale, light->specularscale, light->flags);
4312 }
4313
4314 void R_Shadow_FreeWorldLight(dlight_t *light)
4315 {
4316         if (r_shadow_selectedlight == light)
4317                 r_shadow_selectedlight = NULL;
4318         R_RTLight_Uncompile(&light->rtlight);
4319         Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4320 }
4321
4322 void R_Shadow_ClearWorldLights(void)
4323 {
4324         size_t lightindex;
4325         dlight_t *light;
4326         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4327         for (lightindex = 0;lightindex < range;lightindex++)
4328         {
4329                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4330                 if (light)
4331                         R_Shadow_FreeWorldLight(light);
4332         }
4333         r_shadow_selectedlight = NULL;
4334         R_Shadow_FreeCubemaps();
4335 }
4336
4337 void R_Shadow_SelectLight(dlight_t *light)
4338 {
4339         if (r_shadow_selectedlight)
4340                 r_shadow_selectedlight->selected = false;
4341         r_shadow_selectedlight = light;
4342         if (r_shadow_selectedlight)
4343                 r_shadow_selectedlight->selected = true;
4344 }
4345
4346 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4347 {
4348         // this is never batched (there can be only one)
4349         R_DrawSprite(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, r_editlights_sprcursor->tex, r_editlights_sprcursor->tex, false, false, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE, 1, 1, 1, 1);
4350 }
4351
4352 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4353 {
4354         float intensity;
4355         float s;
4356         vec3_t spritecolor;
4357         cachepic_t *pic;
4358
4359         // this is never batched (due to the ent parameter changing every time)
4360         // so numsurfaces == 1 and surfacelist[0] == lightnumber
4361         const dlight_t *light = (dlight_t *)ent;
4362         s = EDLIGHTSPRSIZE;
4363         intensity = 0.5f;
4364         VectorScale(light->color, intensity, spritecolor);
4365         if (VectorLength(spritecolor) < 0.1732f)
4366                 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4367         if (VectorLength(spritecolor) > 1.0f)
4368                 VectorNormalize(spritecolor);
4369
4370         // draw light sprite
4371         if (light->cubemapname[0] && !light->shadow)
4372                 pic = r_editlights_sprcubemapnoshadowlight;
4373         else if (light->cubemapname[0])
4374                 pic = r_editlights_sprcubemaplight;
4375         else if (!light->shadow)
4376                 pic = r_editlights_sprnoshadowlight;
4377         else
4378                 pic = r_editlights_sprlight;
4379         R_DrawSprite(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, pic->tex, pic->tex, false, false, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s, spritecolor[0], spritecolor[1], spritecolor[2], 1);
4380         // draw selection sprite if light is selected
4381         if (light->selected)
4382                 R_DrawSprite(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, r_editlights_sprselection->tex, r_editlights_sprselection->tex, false, false, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s, 1, 1, 1, 1);
4383         // VorteX todo: add normalmode/realtime mode light overlay sprites?
4384 }
4385
4386 void R_Shadow_DrawLightSprites(void)
4387 {
4388         size_t lightindex;
4389         dlight_t *light;
4390         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4391         for (lightindex = 0;lightindex < range;lightindex++)
4392         {
4393                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4394                 if (light)
4395                         R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4396         }
4397         R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4398 }
4399
4400 void R_Shadow_SelectLightInView(void)
4401 {
4402         float bestrating, rating, temp[3];
4403         dlight_t *best;
4404         size_t lightindex;
4405         dlight_t *light;
4406         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4407         best = NULL;
4408         bestrating = 0;
4409         for (lightindex = 0;lightindex < range;lightindex++)
4410         {
4411                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4412                 if (!light)
4413                         continue;
4414                 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4415                 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4416                 if (rating >= 0.95)
4417                 {
4418                         rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4419                         if (bestrating < rating && CL_Move(light->origin, vec3_origin, vec3_origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
4420                         {
4421                                 bestrating = rating;
4422                                 best = light;
4423                         }
4424                 }
4425         }
4426         R_Shadow_SelectLight(best);
4427 }
4428
4429 void R_Shadow_LoadWorldLights(void)
4430 {
4431         int n, a, style, shadow, flags;
4432         char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4433         float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4434         if (cl.worldmodel == NULL)
4435         {
4436                 Con_Print("No map loaded.\n");
4437                 return;
4438         }
4439         FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4440         strlcat (name, ".rtlights", sizeof (name));
4441         lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4442         if (lightsstring)
4443         {
4444                 s = lightsstring;
4445                 n = 0;
4446                 while (*s)
4447                 {
4448                         t = s;
4449                         /*
4450                         shadow = true;
4451                         for (;COM_Parse(t, true) && strcmp(
4452                         if (COM_Parse(t, true))
4453                         {
4454                                 if (com_token[0] == '!')
4455                                 {
4456                                         shadow = false;
4457                                         origin[0] = atof(com_token+1);
4458                                 }
4459                                 else
4460                                         origin[0] = atof(com_token);
4461                                 if (Com_Parse(t
4462                         }
4463                         */
4464                         t = s;
4465                         while (*s && *s != '\n' && *s != '\r')
4466                                 s++;
4467                         if (!*s)
4468                                 break;
4469                         tempchar = *s;
4470                         shadow = true;
4471                         // check for modifier flags
4472                         if (*t == '!')
4473                         {
4474                                 shadow = false;
4475                                 t++;
4476                         }
4477                         *s = 0;
4478 #if _MSC_VER >= 1400
4479 #define sscanf sscanf_s
4480 #endif
4481                         cubemapname[sizeof(cubemapname)-1] = 0;
4482 #if MAX_QPATH != 128
4483 #error update this code if MAX_QPATH changes
4484 #endif
4485                         a = sscanf(t, "%f %f %f %f %f %f %f %d %127s %f %f %f %f %f %f %f %f %i", &origin[0], &origin[1], &origin[2], &radius, &color[0], &color[1], &color[2], &style, cubemapname
4486 #if _MSC_VER >= 1400
4487 , sizeof(cubemapname)
4488 #endif
4489 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4490                         *s = tempchar;
4491                         if (a < 18)
4492                                 flags = LIGHTFLAG_REALTIMEMODE;
4493                         if (a < 17)
4494                                 specularscale = 1;
4495                         if (a < 16)
4496                                 diffusescale = 1;
4497                         if (a < 15)
4498                                 ambientscale = 0;
4499                         if (a < 14)
4500                                 coronasizescale = 0.25f;
4501                         if (a < 13)
4502                                 VectorClear(angles);
4503                         if (a < 10)
4504                                 corona = 0;
4505                         if (a < 9 || !strcmp(cubemapname, "\"\""))
4506                                 cubemapname[0] = 0;
4507                         // remove quotes on cubemapname
4508                         if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4509                         {
4510                                 size_t namelen;
4511                                 namelen = strlen(cubemapname) - 2;
4512                                 memmove(cubemapname, cubemapname + 1, namelen);
4513                                 cubemapname[namelen] = '\0';
4514                         }
4515                         if (a < 8)
4516                         {
4517                                 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);
4518                                 break;
4519                         }
4520                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4521                         if (*s == '\r')
4522                                 s++;
4523                         if (*s == '\n')
4524                                 s++;
4525                         n++;
4526                 }
4527                 if (*s)
4528                         Con_Printf("invalid rtlights file \"%s\"\n", name);
4529                 Mem_Free(lightsstring);
4530         }
4531 }
4532
4533 void R_Shadow_SaveWorldLights(void)
4534 {
4535         size_t lightindex;
4536         dlight_t *light;
4537         size_t bufchars, bufmaxchars;
4538         char *buf, *oldbuf;
4539         char name[MAX_QPATH];
4540         char line[MAX_INPUTLINE];
4541         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
4542         // I hate lines which are 3 times my screen size :( --blub
4543         if (!range)
4544                 return;
4545         if (cl.worldmodel == NULL)
4546         {
4547                 Con_Print("No map loaded.\n");
4548                 return;
4549         }
4550         FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4551         strlcat (name, ".rtlights", sizeof (name));
4552         bufchars = bufmaxchars = 0;
4553         buf = NULL;
4554         for (lightindex = 0;lightindex < range;lightindex++)
4555         {
4556                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4557                 if (!light)
4558                         continue;
4559                 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
4560                         dpsnprintf(line, sizeof(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);
4561                 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
4562                         dpsnprintf(line, sizeof(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]);
4563                 else
4564                         dpsnprintf(line, sizeof(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);
4565                 if (bufchars + strlen(line) > bufmaxchars)
4566                 {
4567                         bufmaxchars = bufchars + strlen(line) + 2048;
4568                         oldbuf = buf;
4569                         buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
4570                         if (oldbuf)
4571                         {
4572                                 if (bufchars)
4573                                         memcpy(buf, oldbuf, bufchars);
4574                                 Mem_Free(oldbuf);
4575                         }
4576                 }
4577                 if (strlen(line))
4578                 {
4579                         memcpy(buf + bufchars, line, strlen(line));
4580                         bufchars += strlen(line);
4581                 }
4582         }
4583         if (bufchars)
4584                 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
4585         if (buf)
4586                 Mem_Free(buf);
4587 }
4588
4589 void R_Shadow_LoadLightsFile(void)
4590 {
4591         int n, a, style;
4592         char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
4593         float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
4594         if (cl.worldmodel == NULL)
4595         {
4596                 Con_Print("No map loaded.\n");
4597                 return;
4598         }
4599         FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4600         strlcat (name, ".lights", sizeof (name));
4601         lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4602         if (lightsstring)
4603         {
4604                 s = lightsstring;
4605                 n = 0;
4606                 while (*s)
4607                 {
4608                         t = s;
4609                         while (*s && *s != '\n' && *s != '\r')
4610                                 s++;
4611                         if (!*s)
4612                                 break;
4613                         tempchar = *s;
4614                         *s = 0;
4615                         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);
4616                         *s = tempchar;
4617                         if (a < 14)
4618                         {
4619                                 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);
4620                                 break;
4621                         }
4622                         radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
4623                         radius = bound(15, radius, 4096);
4624                         VectorScale(color, (2.0f / (8388608.0f)), color);
4625                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
4626                         if (*s == '\r')
4627                                 s++;
4628                         if (*s == '\n')
4629                                 s++;
4630                         n++;
4631                 }
4632                 if (*s)
4633                         Con_Printf("invalid lights file \"%s\"\n", name);
4634                 Mem_Free(lightsstring);
4635         }
4636 }
4637
4638 // tyrlite/hmap2 light types in the delay field
4639 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
4640
4641 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
4642 {
4643         int entnum, style, islight, skin, pflags, effects, type, n;
4644         char *entfiledata;
4645         const char *data;
4646         float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
4647         char key[256], value[MAX_INPUTLINE];
4648
4649         if (cl.worldmodel == NULL)
4650         {
4651                 Con_Print("No map loaded.\n");
4652                 return;
4653         }
4654         // try to load a .ent file first
4655         FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
4656         strlcat (key, ".ent", sizeof (key));
4657         data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
4658         // and if that is not found, fall back to the bsp file entity string
4659         if (!data)
4660                 data = cl.worldmodel->brush.entities;
4661         if (!data)
4662                 return;
4663         for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
4664         {
4665                 type = LIGHTTYPE_MINUSX;
4666                 origin[0] = origin[1] = origin[2] = 0;
4667                 originhack[0] = originhack[1] = originhack[2] = 0;
4668                 angles[0] = angles[1] = angles[2] = 0;
4669                 color[0] = color[1] = color[2] = 1;
4670                 light[0] = light[1] = light[2] = 1;light[3] = 300;
4671                 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
4672                 fadescale = 1;
4673                 lightscale = 1;
4674                 style = 0;
4675                 skin = 0;
4676                 pflags = 0;
4677                 effects = 0;
4678                 islight = false;
4679                 while (1)
4680                 {
4681                         if (!COM_ParseToken_Simple(&data, false, false))
4682                                 break; // error
4683                         if (com_token[0] == '}')
4684                                 break; // end of entity
4685                         if (com_token[0] == '_')
4686                                 strlcpy(key, com_token + 1, sizeof(key));
4687                         else
4688                                 strlcpy(key, com_token, sizeof(key));
4689                         while (key[strlen(key)-1] == ' ') // remove trailing spaces
4690                                 key[strlen(key)-1] = 0;
4691                         if (!COM_ParseToken_Simple(&data, false, false))
4692                                 break; // error
4693                         strlcpy(value, com_token, sizeof(value));
4694
4695                         // now that we have the key pair worked out...
4696                         if (!strcmp("light", key))
4697                         {
4698                                 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
4699                                 if (n == 1)
4700                                 {
4701                                         // quake
4702                                         light[0] = vec[0] * (1.0f / 256.0f);
4703                                         light[1] = vec[0] * (1.0f / 256.0f);
4704                                         light[2] = vec[0] * (1.0f / 256.0f);
4705                                         light[3] = vec[0];
4706                                 }
4707                                 else if (n == 4)
4708                                 {
4709                                         // halflife
4710                                         light[0] = vec[0] * (1.0f / 255.0f);
4711                                         light[1] = vec[1] * (1.0f / 255.0f);
4712                                         light[2] = vec[2] * (1.0f / 255.0f);
4713                                         light[3] = vec[3];
4714                                 }
4715                         }
4716                         else if (!strcmp("delay", key))
4717                                 type = atoi(value);
4718                         else if (!strcmp("origin", key))
4719                                 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
4720                         else if (!strcmp("angle", key))
4721                                 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
4722                         else if (!strcmp("angles", key))
4723                                 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
4724                         else if (!strcmp("color", key))
4725                                 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
4726                         else if (!strcmp("wait", key))
4727                                 fadescale = atof(value);
4728                         else if (!strcmp("classname", key))
4729                         {
4730                                 if (!strncmp(value, "light", 5))
4731                                 {
4732                                         islight = true;
4733                                         if (!strcmp(value, "light_fluoro"))
4734                                         {
4735                                                 originhack[0] = 0;
4736                                                 originhack[1] = 0;
4737                                                 originhack[2] = 0;
4738                                                 overridecolor[0] = 1;
4739                                                 overridecolor[1] = 1;
4740                                                 overridecolor[2] = 1;
4741                                         }
4742                                         if (!strcmp(value, "light_fluorospark"))
4743                                         {
4744                                                 originhack[0] = 0;
4745                                                 originhack[1] = 0;
4746                                                 originhack[2] = 0;
4747                                                 overridecolor[0] = 1;
4748                                                 overridecolor[1] = 1;
4749                                                 overridecolor[2] = 1;
4750                                         }
4751                                         if (!strcmp(value, "light_globe"))
4752                                         {
4753                                                 originhack[0] = 0;
4754                                                 originhack[1] = 0;
4755                                                 originhack[2] = 0;
4756                                                 overridecolor[0] = 1;
4757                                                 overridecolor[1] = 0.8;
4758                                                 overridecolor[2] = 0.4;
4759                                         }
4760                                         if (!strcmp(value, "light_flame_large_yellow"))
4761                                         {
4762                                                 originhack[0] = 0;
4763                                                 originhack[1] = 0;
4764                                                 originhack[2] = 0;
4765                                                 overridecolor[0] = 1;
4766                                                 overridecolor[1] = 0.5;
4767                                                 overridecolor[2] = 0.1;
4768                                         }
4769                                         if (!strcmp(value, "light_flame_small_yellow"))
4770                                         {
4771                                                 originhack[0] = 0;
4772                                                 originhack[1] = 0;
4773                                                 originhack[2] = 0;
4774                                                 overridecolor[0] = 1;
4775                                                 overridecolor[1] = 0.5;
4776                                                 overridecolor[2] = 0.1;
4777                                         }
4778                                         if (!strcmp(value, "light_torch_small_white"))
4779                                         {
4780                                                 originhack[0] = 0;
4781                                                 originhack[1] = 0;
4782                                                 originhack[2] = 0;
4783                                                 overridecolor[0] = 1;
4784                                                 overridecolor[1] = 0.5;
4785                                                 overridecolor[2] = 0.1;
4786                                         }
4787                                         if (!strcmp(value, "light_torch_small_walltorch"))
4788                                         {
4789                                                 originhack[0] = 0;
4790                                                 originhack[1] = 0;
4791                                                 originhack[2] = 0;
4792                                                 overridecolor[0] = 1;
4793                                                 overridecolor[1] = 0.5;
4794                                                 overridecolor[2] = 0.1;
4795                                         }
4796                                 }
4797                         }
4798                         else if (!strcmp("style", key))
4799                                 style = atoi(value);
4800                         else if (!strcmp("skin", key))
4801                                 skin = (int)atof(value);
4802                         else if (!strcmp("pflags", key))
4803                                 pflags = (int)atof(value);
4804                         else if (!strcmp("effects", key))
4805                                 effects = (int)atof(value);
4806                         else if (cl.worldmodel->type == mod_brushq3)
4807                         {
4808                                 if (!strcmp("scale", key))
4809                                         lightscale = atof(value);
4810                                 if (!strcmp("fade", key))
4811                                         fadescale = atof(value);
4812                         }
4813                 }
4814                 if (!islight)
4815                         continue;
4816                 if (lightscale <= 0)
4817                         lightscale = 1;
4818                 if (fadescale <= 0)
4819                         fadescale = 1;
4820                 if (color[0] == color[1] && color[0] == color[2])
4821                 {
4822                         color[0] *= overridecolor[0];
4823                         color[1] *= overridecolor[1];
4824                         color[2] *= overridecolor[2];
4825                 }
4826                 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
4827                 color[0] = color[0] * light[0];
4828                 color[1] = color[1] * light[1];
4829                 color[2] = color[2] * light[2];
4830                 switch (type)
4831                 {
4832                 case LIGHTTYPE_MINUSX:
4833                         break;
4834                 case LIGHTTYPE_RECIPX:
4835                         radius *= 2;
4836                         VectorScale(color, (1.0f / 16.0f), color);
4837                         break;
4838                 case LIGHTTYPE_RECIPXX:
4839                         radius *= 2;
4840                         VectorScale(color, (1.0f / 16.0f), color);
4841                         break;
4842                 default:
4843                 case LIGHTTYPE_NONE:
4844                         break;
4845                 case LIGHTTYPE_SUN:
4846                         break;
4847                 case LIGHTTYPE_MINUSXX:
4848                         break;
4849                 }
4850                 VectorAdd(origin, originhack, origin);
4851                 if (radius >= 1)
4852                         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);
4853         }
4854         if (entfiledata)
4855                 Mem_Free(entfiledata);
4856 }
4857
4858
4859 void R_Shadow_SetCursorLocationForView(void)
4860 {
4861         vec_t dist, push;
4862         vec3_t dest, endpos;
4863         trace_t trace;
4864         VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
4865         trace = CL_Move(r_refdef.view.origin, vec3_origin, vec3_origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
4866         if (trace.fraction < 1)
4867         {
4868                 dist = trace.fraction * r_editlights_cursordistance.value;
4869                 push = r_editlights_cursorpushback.value;
4870                 if (push > dist)
4871                         push = dist;
4872                 push = -push;
4873                 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
4874                 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
4875         }
4876         else
4877         {
4878                 VectorClear( endpos );
4879         }
4880         r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4881         r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4882         r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4883 }
4884
4885 void R_Shadow_UpdateWorldLightSelection(void)
4886 {
4887         if (r_editlights.integer)
4888         {
4889                 R_Shadow_SetCursorLocationForView();
4890                 R_Shadow_SelectLightInView();
4891         }
4892         else
4893                 R_Shadow_SelectLight(NULL);
4894 }
4895
4896 void R_Shadow_EditLights_Clear_f(void)
4897 {
4898         R_Shadow_ClearWorldLights();
4899 }
4900
4901 void R_Shadow_EditLights_Reload_f(void)
4902 {
4903         if (!cl.worldmodel)
4904                 return;
4905         strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
4906         R_Shadow_ClearWorldLights();
4907         R_Shadow_LoadWorldLights();
4908         if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
4909         {
4910                 R_Shadow_LoadLightsFile();
4911                 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
4912                         R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
4913         }
4914 }
4915
4916 void R_Shadow_EditLights_Save_f(void)
4917 {
4918         if (!cl.worldmodel)
4919                 return;
4920         R_Shadow_SaveWorldLights();
4921 }
4922
4923 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
4924 {
4925         R_Shadow_ClearWorldLights();
4926         R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
4927 }
4928
4929 void R_Shadow_EditLights_ImportLightsFile_f(void)
4930 {
4931         R_Shadow_ClearWorldLights();
4932         R_Shadow_LoadLightsFile();
4933 }
4934
4935 void R_Shadow_EditLights_Spawn_f(void)
4936 {
4937         vec3_t color;
4938         if (!r_editlights.integer)
4939         {
4940                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
4941                 return;
4942         }
4943         if (Cmd_Argc() != 1)
4944         {
4945                 Con_Print("r_editlights_spawn does not take parameters\n");
4946                 return;
4947         }
4948         color[0] = color[1] = color[2] = 1;
4949         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
4950 }
4951
4952 void R_Shadow_EditLights_Edit_f(void)
4953 {
4954         vec3_t origin, angles, color;
4955         vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
4956         int style, shadows, flags, normalmode, realtimemode;
4957         char cubemapname[MAX_INPUTLINE];
4958         if (!r_editlights.integer)
4959         {
4960                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
4961                 return;
4962         }
4963         if (!r_shadow_selectedlight)
4964         {
4965                 Con_Print("No selected light.\n");
4966                 return;
4967         }
4968         VectorCopy(r_shadow_selectedlight->origin, origin);
4969         VectorCopy(r_shadow_selectedlight->angles, angles);
4970         VectorCopy(r_shadow_selectedlight->color, color);
4971         radius = r_shadow_selectedlight->radius;
4972         style = r_shadow_selectedlight->style;
4973         if (r_shadow_selectedlight->cubemapname)
4974                 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
4975         else
4976                 cubemapname[0] = 0;
4977         shadows = r_shadow_selectedlight->shadow;
4978         corona = r_shadow_selectedlight->corona;
4979         coronasizescale = r_shadow_selectedlight->coronasizescale;
4980         ambientscale = r_shadow_selectedlight->ambientscale;
4981         diffusescale = r_shadow_selectedlight->diffusescale;
4982         specularscale = r_shadow_selectedlight->specularscale;
4983         flags = r_shadow_selectedlight->flags;
4984         normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
4985         realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
4986         if (!strcmp(Cmd_Argv(1), "origin"))
4987         {
4988                 if (Cmd_Argc() != 5)
4989                 {
4990                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
4991                         return;
4992                 }
4993                 origin[0] = atof(Cmd_Argv(2));
4994                 origin[1] = atof(Cmd_Argv(3));
4995                 origin[2] = atof(Cmd_Argv(4));
4996         }
4997         else if (!strcmp(Cmd_Argv(1), "originx"))
4998         {
4999                 if (Cmd_Argc() != 3)
5000                 {
5001                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5002                         return;
5003                 }
5004                 origin[0] = atof(Cmd_Argv(2));
5005         }
5006         else if (!strcmp(Cmd_Argv(1), "originy"))
5007         {
5008                 if (Cmd_Argc() != 3)
5009                 {
5010                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5011                         return;
5012                 }
5013                 origin[1] = atof(Cmd_Argv(2));
5014         }
5015         else if (!strcmp(Cmd_Argv(1), "originz"))
5016         {
5017                 if (Cmd_Argc() != 3)
5018                 {
5019                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5020                         return;
5021                 }
5022                 origin[2] = atof(Cmd_Argv(2));
5023         }
5024         else if (!strcmp(Cmd_Argv(1), "move"))
5025         {
5026                 if (Cmd_Argc() != 5)
5027                 {
5028                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5029                         return;
5030                 }
5031                 origin[0] += atof(Cmd_Argv(2));
5032                 origin[1] += atof(Cmd_Argv(3));
5033                 origin[2] += atof(Cmd_Argv(4));
5034         }
5035         else if (!strcmp(Cmd_Argv(1), "movex"))
5036         {
5037                 if (Cmd_Argc() != 3)
5038                 {
5039                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5040                         return;
5041                 }
5042                 origin[0] += atof(Cmd_Argv(2));
5043         }
5044         else if (!strcmp(Cmd_Argv(1), "movey"))
5045         {
5046                 if (Cmd_Argc() != 3)
5047                 {
5048                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5049                         return;
5050                 }
5051                 origin[1] += atof(Cmd_Argv(2));
5052         }
5053         else if (!strcmp(Cmd_Argv(1), "movez"))
5054         {
5055                 if (Cmd_Argc() != 3)
5056                 {
5057                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5058                         return;
5059                 }
5060                 origin[2] += atof(Cmd_Argv(2));
5061         }
5062         else if (!strcmp(Cmd_Argv(1), "angles"))
5063         {
5064                 if (Cmd_Argc() != 5)
5065                 {
5066                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5067                         return;
5068                 }
5069                 angles[0] = atof(Cmd_Argv(2));
5070                 angles[1] = atof(Cmd_Argv(3));
5071                 angles[2] = atof(Cmd_Argv(4));
5072         }
5073         else if (!strcmp(Cmd_Argv(1), "anglesx"))
5074         {
5075                 if (Cmd_Argc() != 3)
5076                 {
5077                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5078                         return;
5079                 }
5080                 angles[0] = atof(Cmd_Argv(2));
5081         }
5082         else if (!strcmp(Cmd_Argv(1), "anglesy"))
5083         {
5084                 if (Cmd_Argc() != 3)
5085                 {
5086                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5087                         return;
5088                 }
5089                 angles[1] = atof(Cmd_Argv(2));
5090         }
5091         else if (!strcmp(Cmd_Argv(1), "anglesz"))
5092         {
5093                 if (Cmd_Argc() != 3)
5094                 {
5095                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5096                         return;
5097                 }
5098                 angles[2] = atof(Cmd_Argv(2));
5099         }
5100         else if (!strcmp(Cmd_Argv(1), "color"))
5101         {
5102                 if (Cmd_Argc() != 5)
5103                 {
5104                         Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5105                         return;
5106                 }
5107                 color[0] = atof(Cmd_Argv(2));
5108                 color[1] = atof(Cmd_Argv(3));
5109                 color[2] = atof(Cmd_Argv(4));
5110         }
5111         else if (!strcmp(Cmd_Argv(1), "radius"))
5112         {
5113                 if (Cmd_Argc() != 3)
5114                 {
5115                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5116                         return;
5117                 }
5118                 radius = atof(Cmd_Argv(2));
5119         }
5120         else if (!strcmp(Cmd_Argv(1), "colorscale"))
5121         {
5122                 if (Cmd_Argc() == 3)
5123                 {
5124                         double scale = atof(Cmd_Argv(2));
5125                         color[0] *= scale;
5126                         color[1] *= scale;
5127                         color[2] *= scale;
5128                 }
5129                 else
5130                 {
5131                         if (Cmd_Argc() != 5)
5132                         {
5133                                 Con_Printf("usage: r_editlights_edit %s red green blue  (OR grey instead of red green blue)\n", Cmd_Argv(1));
5134                                 return;
5135                         }
5136                         color[0] *= atof(Cmd_Argv(2));
5137                         color[1] *= atof(Cmd_Argv(3));
5138                         color[2] *= atof(Cmd_Argv(4));
5139                 }
5140         }
5141         else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5142         {
5143                 if (Cmd_Argc() != 3)
5144                 {
5145                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5146                         return;
5147                 }
5148                 radius *= atof(Cmd_Argv(2));
5149         }
5150         else if (!strcmp(Cmd_Argv(1), "style"))
5151         {
5152                 if (Cmd_Argc() != 3)
5153                 {
5154                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5155                         return;
5156                 }
5157                 style = atoi(Cmd_Argv(2));
5158         }
5159         else if (!strcmp(Cmd_Argv(1), "cubemap"))
5160         {
5161                 if (Cmd_Argc() > 3)
5162                 {
5163                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5164                         return;
5165                 }
5166                 if (Cmd_Argc() == 3)
5167                         strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5168                 else
5169                         cubemapname[0] = 0;
5170         }
5171         else if (!strcmp(Cmd_Argv(1), "shadows"))
5172         {
5173                 if (Cmd_Argc() != 3)
5174                 {
5175                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5176                         return;
5177                 }
5178                 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5179         }
5180         else if (!strcmp(Cmd_Argv(1), "corona"))
5181         {
5182                 if (Cmd_Argc() != 3)
5183                 {
5184                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5185                         return;
5186                 }
5187                 corona = atof(Cmd_Argv(2));
5188         }
5189         else if (!strcmp(Cmd_Argv(1), "coronasize"))
5190         {
5191                 if (Cmd_Argc() != 3)
5192                 {
5193                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5194                         return;
5195                 }
5196                 coronasizescale = atof(Cmd_Argv(2));
5197         }
5198         else if (!strcmp(Cmd_Argv(1), "ambient"))
5199         {
5200                 if (Cmd_Argc() != 3)
5201                 {
5202                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5203                         return;
5204                 }
5205                 ambientscale = atof(Cmd_Argv(2));
5206         }
5207         else if (!strcmp(Cmd_Argv(1), "diffuse"))
5208         {
5209                 if (Cmd_Argc() != 3)
5210                 {
5211                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5212                         return;
5213                 }
5214                 diffusescale = atof(Cmd_Argv(2));
5215         }
5216         else if (!strcmp(Cmd_Argv(1), "specular"))
5217         {
5218                 if (Cmd_Argc() != 3)
5219                 {
5220                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5221                         return;
5222                 }
5223                 specularscale = atof(Cmd_Argv(2));
5224         }
5225         else if (!strcmp(Cmd_Argv(1), "normalmode"))
5226         {
5227                 if (Cmd_Argc() != 3)
5228                 {
5229                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5230                         return;
5231                 }
5232                 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5233         }
5234         else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5235         {
5236                 if (Cmd_Argc() != 3)
5237                 {
5238                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5239                         return;
5240                 }
5241                 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5242         }
5243         else
5244         {
5245                 Con_Print("usage: r_editlights_edit [property] [value]\n");
5246                 Con_Print("Selected light's properties:\n");
5247                 Con_Printf("Origin       : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5248                 Con_Printf("Angles       : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5249                 Con_Printf("Color        : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5250                 Con_Printf("Radius       : %f\n", r_shadow_selectedlight->radius);
5251                 Con_Printf("Corona       : %f\n", r_shadow_selectedlight->corona);
5252                 Con_Printf("Style        : %i\n", r_shadow_selectedlight->style);
5253                 Con_Printf("Shadows      : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5254                 Con_Printf("Cubemap      : %s\n", r_shadow_selectedlight->cubemapname);
5255                 Con_Printf("CoronaSize   : %f\n", r_shadow_selectedlight->coronasizescale);
5256                 Con_Printf("Ambient      : %f\n", r_shadow_selectedlight->ambientscale);
5257                 Con_Printf("Diffuse      : %f\n", r_shadow_selectedlight->diffusescale);
5258                 Con_Printf("Specular     : %f\n", r_shadow_selectedlight->specularscale);
5259                 Con_Printf("NormalMode   : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5260                 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5261                 return;
5262         }
5263         flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5264         R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5265 }
5266
5267 void R_Shadow_EditLights_EditAll_f(void)
5268 {
5269         size_t lightindex;
5270         dlight_t *light;
5271         size_t range;
5272
5273         if (!r_editlights.integer)
5274         {
5275                 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5276                 return;
5277         }
5278
5279         // EditLights doesn't seem to have a "remove" command or something so:
5280         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5281         for (lightindex = 0;lightindex < range;lightindex++)
5282         {
5283                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5284                 if (!light)
5285                         continue;
5286                 R_Shadow_SelectLight(light);
5287                 R_Shadow_EditLights_Edit_f();
5288         }
5289 }
5290
5291 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5292 {
5293         int lightnumber, lightcount;
5294         size_t lightindex, range;
5295         dlight_t *light;
5296         float x, y;
5297         char temp[256];
5298         if (!r_editlights.integer)
5299                 return;
5300         x = vid_conwidth.value - 240;
5301         y = 5;
5302         DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5303         lightnumber = -1;
5304         lightcount = 0;
5305         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5306         for (lightindex = 0;lightindex < range;lightindex++)
5307         {
5308                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5309                 if (!light)
5310                         continue;
5311                 if (light == r_shadow_selectedlight)
5312                         lightnumber = lightindex;
5313                 lightcount++;
5314         }
5315         dpsnprintf(temp, sizeof(temp), "Cursor origin: %.0f %.0f %.0f", r_editlights_cursorlocation[0], r_editlights_cursorlocation[1], r_editlights_cursorlocation[2]); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, false);y += 8;
5316         dpsnprintf(temp, sizeof(temp), "Total lights : %i active (%i total)", lightcount, (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray)); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, false);y += 8;
5317         y += 8;
5318         if (r_shadow_selectedlight == NULL)
5319                 return;
5320         dpsnprintf(temp, sizeof(temp), "Light #%i properties:", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
5321         dpsnprintf(temp, sizeof(temp), "Origin       : %.0f %.0f %.0f\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, NULL, true);y += 8;
5322         dpsnprintf(temp, sizeof(temp), "Angles       : %.0f %.0f %.0f\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, NULL, true);y += 8;
5323         dpsnprintf(temp, sizeof(temp), "Color        : %.2f %.2f %.2f\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, NULL, true);y += 8;
5324         dpsnprintf(temp, sizeof(temp), "Radius       : %.0f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
5325         dpsnprintf(temp, sizeof(temp), "Corona       : %.0f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
5326         dpsnprintf(temp, sizeof(temp), "Style        : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
5327         dpsnprintf(temp, sizeof(temp), "Shadows      : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
5328         dpsnprintf(temp, sizeof(temp), "Cubemap      : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
5329         dpsnprintf(temp, sizeof(temp), "CoronaSize   : %.2f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
5330         dpsnprintf(temp, sizeof(temp), "Ambient      : %.2f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
5331         dpsnprintf(temp, sizeof(temp), "Diffuse      : %.2f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
5332         dpsnprintf(temp, sizeof(temp), "Specular     : %.2f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
5333         dpsnprintf(temp, sizeof(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, NULL, true);y += 8;
5334         dpsnprintf(temp, sizeof(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, NULL, true);y += 8;
5335 }
5336
5337 void R_Shadow_EditLights_ToggleShadow_f(void)
5338 {
5339         if (!r_editlights.integer)
5340         {
5341                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
5342                 return;
5343         }
5344         if (!r_shadow_selectedlight)
5345         {
5346                 Con_Print("No selected light.\n");
5347                 return;
5348         }
5349         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);
5350 }
5351
5352 void R_Shadow_EditLights_ToggleCorona_f(void)
5353 {
5354         if (!r_editlights.integer)
5355         {
5356                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
5357                 return;
5358         }
5359         if (!r_shadow_selectedlight)
5360         {
5361                 Con_Print("No selected light.\n");
5362                 return;
5363         }
5364         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);
5365 }
5366
5367 void R_Shadow_EditLights_Remove_f(void)
5368 {
5369         if (!r_editlights.integer)
5370         {
5371                 Con_Print("Cannot remove light when not in editing mode.  Set r_editlights to 1.\n");
5372                 return;
5373         }
5374         if (!r_shadow_selectedlight)
5375         {
5376                 Con_Print("No selected light.\n");
5377                 return;
5378         }
5379         R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5380         r_shadow_selectedlight = NULL;
5381 }
5382
5383 void R_Shadow_EditLights_Help_f(void)
5384 {
5385         Con_Print(
5386 "Documentation on r_editlights system:\n"
5387 "Settings:\n"
5388 "r_editlights : enable/disable editing mode\n"
5389 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5390 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5391 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5392 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5393 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5394 "Commands:\n"
5395 "r_editlights_help : this help\n"
5396 "r_editlights_clear : remove all lights\n"
5397 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5398 "r_editlights_save : save to .rtlights file\n"
5399 "r_editlights_spawn : create a light with default settings\n"
5400 "r_editlights_edit command : edit selected light - more documentation below\n"
5401 "r_editlights_remove : remove selected light\n"
5402 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5403 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5404 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5405 "Edit commands:\n"
5406 "origin x y z : set light location\n"
5407 "originx x: set x component of light location\n"
5408 "originy y: set y component of light location\n"
5409 "originz z: set z component of light location\n"
5410 "move x y z : adjust light location\n"
5411 "movex x: adjust x component of light location\n"
5412 "movey y: adjust y component of light location\n"
5413 "movez z: adjust z component of light location\n"
5414 "angles x y z : set light angles\n"
5415 "anglesx x: set x component of light angles\n"
5416 "anglesy y: set y component of light angles\n"
5417 "anglesz z: set z component of light angles\n"
5418 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5419 "radius radius : set radius (size) of light\n"
5420 "colorscale grey : multiply color of light (1 does nothing)\n"
5421 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5422 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5423 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5424 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5425 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5426 "shadows 1/0 : turn on/off shadows\n"
5427 "corona n : set corona intensity\n"
5428 "coronasize n : set corona size (0-1)\n"
5429 "ambient n : set ambient intensity (0-1)\n"
5430 "diffuse n : set diffuse intensity (0-1)\n"
5431 "specular n : set specular intensity (0-1)\n"
5432 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5433 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5434 "<nothing> : print light properties to console\n"
5435         );
5436 }
5437
5438 void R_Shadow_EditLights_CopyInfo_f(void)
5439 {
5440         if (!r_editlights.integer)
5441         {
5442                 Con_Print("Cannot copy light info when not in editing mode.  Set r_editlights to 1.\n");
5443                 return;
5444         }
5445         if (!r_shadow_selectedlight)
5446         {
5447                 Con_Print("No selected light.\n");
5448                 return;
5449         }
5450         VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5451         VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5452         r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5453         r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5454         if (r_shadow_selectedlight->cubemapname)
5455                 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5456         else
5457                 r_shadow_bufferlight.cubemapname[0] = 0;
5458         r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5459         r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5460         r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5461         r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5462         r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5463         r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5464         r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5465 }
5466
5467 void R_Shadow_EditLights_PasteInfo_f(void)
5468 {
5469         if (!r_editlights.integer)
5470         {
5471                 Con_Print("Cannot paste light info when not in editing mode.  Set r_editlights to 1.\n");
5472                 return;
5473         }
5474         if (!r_shadow_selectedlight)
5475         {
5476                 Con_Print("No selected light.\n");
5477                 return;
5478         }
5479         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);
5480 }
5481
5482 void R_Shadow_EditLights_Init(void)
5483 {
5484         Cvar_RegisterVariable(&r_editlights);
5485         Cvar_RegisterVariable(&r_editlights_cursordistance);
5486         Cvar_RegisterVariable(&r_editlights_cursorpushback);
5487         Cvar_RegisterVariable(&r_editlights_cursorpushoff);
5488         Cvar_RegisterVariable(&r_editlights_cursorgrid);
5489         Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
5490         Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
5491         Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
5492         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)");
5493         Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
5494         Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
5495         Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
5496         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)");
5497         Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
5498         Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
5499         Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
5500         Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
5501         Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
5502         Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
5503         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)");
5504 }
5505
5506
5507
5508 /*
5509 =============================================================================
5510
5511 LIGHT SAMPLING
5512
5513 =============================================================================
5514 */
5515
5516 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
5517 {
5518         VectorClear(diffusecolor);
5519         VectorClear(diffusenormal);
5520
5521         if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
5522         {
5523                 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient * (2.0f / 128.0f);
5524                 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
5525         }
5526         else
5527                 VectorSet(ambientcolor, 1, 1, 1);
5528
5529         if (dynamic)
5530         {
5531                 int i;
5532                 float f, v[3];
5533                 rtlight_t *light;
5534                 for (i = 0;i < r_refdef.scene.numlights;i++)
5535                 {
5536                         light = r_refdef.scene.lights[i];
5537                         Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
5538                         f = 1 - VectorLength2(v);
5539                         if (f > 0 && CL_Move(p, vec3_origin, vec3_origin, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
5540                                 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);
5541                 }
5542         }
5543 }