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