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