]> icculus.org git repositories - divverent/darkplaces.git/blob - r_shadow.c
limit shadowmap maxsize to a value based on gl_max_size
[divverent/darkplaces.git] / r_shadow.c
1
2 /*
3 Terminology: Stencil Shadow Volume (sometimes called Stencil Shadows)
4 An extrusion of the lit faces, beginning at the original geometry and ending
5 further from the light source than the original geometry (presumably at least
6 as far as the light's radius, if the light has a radius at all), capped at
7 both front and back to avoid any problems (extrusion from dark faces also
8 works but has a different set of problems)
9
10 This is normally rendered using Carmack's Reverse technique, in which
11 backfaces behind zbuffer (zfail) increment the stencil, and frontfaces behind
12 zbuffer (zfail) decrement the stencil, the result is a stencil value of zero
13 where shadows did not intersect the visible geometry, suitable as a stencil
14 mask for rendering lighting everywhere but shadow.
15
16 In our case to hopefully avoid the Creative Labs patent, we draw the backfaces
17 as decrement and the frontfaces as increment, and we redefine the DepthFunc to
18 GL_LESS (the patent uses GL_GEQUAL) which causes zfail when behind surfaces
19 and zpass when infront (the patent draws where zpass with a GL_GEQUAL test),
20 additionally we clear stencil to 128 to avoid the need for the unclamped
21 incr/decr extension (not related to patent).
22
23 Patent warning:
24 This algorithm may be covered by Creative's patent (US Patent #6384822),
25 however that patent is quite specific about increment on backfaces and
26 decrement on frontfaces where zpass with GL_GEQUAL depth test, which is
27 opposite this implementation and partially opposite Carmack's Reverse paper
28 (which uses GL_LESS, but increments on backfaces and decrements on frontfaces).
29
30
31
32 Terminology: Stencil Light Volume (sometimes called Light Volumes)
33 Similar to a Stencil Shadow Volume, but inverted; rather than containing the
34 areas in shadow it contains the areas in light, this can only be built
35 quickly for certain limited cases (such as portal visibility from a point),
36 but is quite useful for some effects (sunlight coming from sky polygons is
37 one possible example, translucent occluders is another example).
38
39
40
41 Terminology: Optimized Stencil Shadow Volume
42 A Stencil Shadow Volume that has been processed sufficiently to ensure it has
43 no duplicate coverage of areas (no need to shadow an area twice), often this
44 greatly improves performance but is an operation too costly to use on moving
45 lights (however completely optimal Stencil Light Volumes can be constructed
46 in some ideal cases).
47
48
49
50 Terminology: Per Pixel Lighting (sometimes abbreviated PPL)
51 Per pixel evaluation of lighting equations, at a bare minimum this involves
52 DOT3 shading of diffuse lighting (per pixel dotproduct of negated incidence
53 vector and surface normal, using a texture of the surface bumps, called a
54 NormalMap) if supported by hardware; in our case there is support for cards
55 which are incapable of DOT3, the quality is quite poor however.  Additionally
56 it is desirable to have specular evaluation per pixel, per vertex
57 normalization of specular halfangle vectors causes noticable distortion but
58 is unavoidable on hardware without GL_ARB_fragment_program or
59 GL_ARB_fragment_shader.
60
61
62
63 Terminology: Normalization CubeMap
64 A cubemap containing normalized dot3-encoded (vectors of length 1 or less
65 encoded as RGB colors) for any possible direction, this technique allows per
66 pixel calculation of incidence vector for per pixel lighting purposes, which
67 would not otherwise be possible per pixel without GL_ARB_fragment_program or
68 GL_ARB_fragment_shader.
69
70
71
72 Terminology: 2D+1D Attenuation Texturing
73 A very crude approximation of light attenuation with distance which results
74 in cylindrical light shapes which fade vertically as a streak (some games
75 such as Doom3 allow this to be rotated to be less noticable in specific
76 cases), the technique is simply modulating lighting by two 2D textures (which
77 can be the same) on different axes of projection (XY and Z, typically), this
78 is the second best technique available without 3D Attenuation Texturing,
79 GL_ARB_fragment_program or GL_ARB_fragment_shader technology.
80
81
82
83 Terminology: 2D+1D Inverse Attenuation Texturing
84 A clever method described in papers on the Abducted engine, this has a squared
85 distance texture (bright on the outside, black in the middle), which is used
86 twice using GL_ADD blending, the result of this is used in an inverse modulate
87 (GL_ONE_MINUS_DST_ALPHA, GL_ZERO) to implement the equation
88 lighting*=(1-((X*X+Y*Y)+(Z*Z))) which is spherical (unlike 2D+1D attenuation
89 texturing).
90
91
92
93 Terminology: 3D Attenuation Texturing
94 A slightly crude approximation of light attenuation with distance, its flaws
95 are limited radius and resolution (performance tradeoffs).
96
97
98
99 Terminology: 3D Attenuation-Normalization Texturing
100 A 3D Attenuation Texture merged with a Normalization CubeMap, by making the
101 vectors shorter the lighting becomes darker, a very effective optimization of
102 diffuse lighting if 3D Attenuation Textures are already used.
103
104
105
106 Terminology: Light Cubemap Filtering
107 A technique for modeling non-uniform light distribution according to
108 direction, for example a lantern may use a cubemap to describe the light
109 emission pattern of the cage around the lantern (as well as soot buildup
110 discoloring the light in certain areas), often also used for softened grate
111 shadows and light shining through a stained glass window (done crudely by
112 texturing the lighting with a cubemap), another good example would be a disco
113 light.  This technique is used heavily in many games (Doom3 does not support
114 this however).
115
116
117
118 Terminology: Light Projection Filtering
119 A technique for modeling shadowing of light passing through translucent
120 surfaces, allowing stained glass windows and other effects to be done more
121 elegantly than possible with Light Cubemap Filtering by applying an occluder
122 texture to the lighting combined with a stencil light volume to limit the lit
123 area, this technique is used by Doom3 for spotlights and flashlights, among
124 other things, this can also be used more generally to render light passing
125 through multiple translucent occluders in a scene (using a light volume to
126 describe the area beyond the occluder, and thus mask off rendering of all
127 other areas).
128
129
130
131 Terminology: Doom3 Lighting
132 A combination of Stencil Shadow Volume, Per Pixel Lighting, Normalization
133 CubeMap, 2D+1D Attenuation Texturing, and Light Projection Filtering, as
134 demonstrated by the game Doom3.
135 */
136
137 #include "quakedef.h"
138 #include "r_shadow.h"
139 #include "cl_collision.h"
140 #include "portals.h"
141 #include "image.h"
142
143 #define R_SHADOW_SHADOWMAP_NUMCUBEMAPS 8
144
145 extern void R_Shadow_EditLights_Init(void);
146
147 typedef enum r_shadow_rendermode_e
148 {
149         R_SHADOW_RENDERMODE_NONE,
150         R_SHADOW_RENDERMODE_ZPASS_STENCIL,
151         R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL,
152         R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE,
153         R_SHADOW_RENDERMODE_ZFAIL_STENCIL,
154         R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL,
155         R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE,
156         R_SHADOW_RENDERMODE_LIGHT_VERTEX,
157         R_SHADOW_RENDERMODE_LIGHT_DOT3,
158         R_SHADOW_RENDERMODE_LIGHT_GLSL,
159         R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
160         R_SHADOW_RENDERMODE_VISIBLELIGHTING,
161         R_SHADOW_RENDERMODE_SHADOWMAP2D,
162         R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE,
163         R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE,
164 }
165 r_shadow_rendermode_t;
166
167 typedef enum r_shadow_shadowmode_e
168 {
169     R_SHADOW_SHADOWMODE_STENCIL,
170     R_SHADOW_SHADOWMODE_SHADOWMAP2D,
171     R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE,
172     R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE
173 }
174 r_shadow_shadowmode_t;
175
176 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
177 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
178 r_shadow_rendermode_t r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_NONE;
179 r_shadow_rendermode_t r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_NONE;
180 qboolean r_shadow_usingshadowmaprect;
181 qboolean r_shadow_usingshadowmap2d;
182 qboolean r_shadow_usingshadowmapcube;
183 int r_shadow_shadowmapside;
184 float r_shadow_shadowmap_texturescale[2];
185 float r_shadow_shadowmap_parameters[4];
186 #if 0
187 int r_shadow_drawbuffer;
188 int r_shadow_readbuffer;
189 #endif
190 int r_shadow_cullface_front, r_shadow_cullface_back;
191 GLuint r_shadow_fborectangle;
192 GLuint r_shadow_fbocubeside[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
193 GLuint r_shadow_fbo2d;
194 r_shadow_shadowmode_t r_shadow_shadowmode;
195 int r_shadow_shadowmapfilterquality;
196 int r_shadow_shadowmaptexturetype;
197 int r_shadow_shadowmapdepthbits;
198 int r_shadow_shadowmapmaxsize;
199 qboolean r_shadow_shadowmapvsdct;
200 qboolean r_shadow_shadowmapsampler;
201 int r_shadow_shadowmappcf;
202 int r_shadow_shadowmapborder;
203 int r_shadow_lightscissor[4];
204
205 int maxshadowtriangles;
206 int *shadowelements;
207
208 int maxshadowvertices;
209 float *shadowvertex3f;
210
211 int maxshadowmark;
212 int numshadowmark;
213 int *shadowmark;
214 int *shadowmarklist;
215 int shadowmarkcount;
216
217 int maxshadowsides;
218 int numshadowsides;
219 unsigned char *shadowsides;
220 int *shadowsideslist;
221
222 int maxvertexupdate;
223 int *vertexupdate;
224 int *vertexremap;
225 int vertexupdatenum;
226
227 int r_shadow_buffer_numleafpvsbytes;
228 unsigned char *r_shadow_buffer_visitingleafpvs;
229 unsigned char *r_shadow_buffer_leafpvs;
230 int *r_shadow_buffer_leaflist;
231
232 int r_shadow_buffer_numsurfacepvsbytes;
233 unsigned char *r_shadow_buffer_surfacepvs;
234 int *r_shadow_buffer_surfacelist;
235 unsigned char *r_shadow_buffer_surfacesides;
236
237 int r_shadow_buffer_numshadowtrispvsbytes;
238 unsigned char *r_shadow_buffer_shadowtrispvs;
239 int r_shadow_buffer_numlighttrispvsbytes;
240 unsigned char *r_shadow_buffer_lighttrispvs;
241
242 rtexturepool_t *r_shadow_texturepool;
243 rtexture_t *r_shadow_attenuationgradienttexture;
244 rtexture_t *r_shadow_attenuation2dtexture;
245 rtexture_t *r_shadow_attenuation3dtexture;
246 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_FreeTexturePool(&r_shadow_texturepool);
1698         r_shadow_texturepool = R_AllocTexturePool();
1699         r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1700         r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1701         data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1702         // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1703         for (x = 0;x <= ATTENTABLESIZE;x++)
1704         {
1705                 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1706                 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1707                 r_shadow_attentable[x] = bound(0, intensity, 1);
1708         }
1709         // 1D gradient texture
1710         for (x = 0;x < ATTEN1DSIZE;x++)
1711                 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1712         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);
1713         // 2D circle texture
1714         for (y = 0;y < ATTEN2DSIZE;y++)
1715                 for (x = 0;x < ATTEN2DSIZE;x++)
1716                         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);
1717         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);
1718         // 3D sphere texture
1719         if (r_shadow_texture3d.integer && gl_texture3d)
1720         {
1721                 for (z = 0;z < ATTEN3DSIZE;z++)
1722                         for (y = 0;y < ATTEN3DSIZE;y++)
1723                                 for (x = 0;x < ATTEN3DSIZE;x++)
1724                                         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));
1725                 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);
1726         }
1727         else
1728                 r_shadow_attenuation3dtexture = NULL;
1729         Mem_Free(data);
1730
1731         R_Shadow_MakeTextures_MakeCorona();
1732
1733         // Editor light sprites
1734         r_editlights_sprcursor = Draw_CachePic ("gfx/editlights/cursor");
1735         r_editlights_sprlight = Draw_CachePic ("gfx/editlights/light");
1736         r_editlights_sprnoshadowlight = Draw_CachePic ("gfx/editlights/noshadow");
1737         r_editlights_sprcubemaplight = Draw_CachePic ("gfx/editlights/cubemaplight");
1738         r_editlights_sprcubemapnoshadowlight = Draw_CachePic ("gfx/editlights/cubemapnoshadowlight");
1739         r_editlights_sprselection = Draw_CachePic ("gfx/editlights/selection");
1740 }
1741
1742 void R_Shadow_ValidateCvars(void)
1743 {
1744         if (r_shadow_texture3d.integer && !gl_texture3d)
1745                 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1746         if (gl_ext_separatestencil.integer && !gl_support_separatestencil)
1747                 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1748         if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1749                 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1750 }
1751
1752 void R_Shadow_RenderMode_Begin(void)
1753 {
1754 #if 0
1755         GLint drawbuffer;
1756         GLint readbuffer;
1757 #endif
1758         R_Shadow_ValidateCvars();
1759
1760         if (!r_shadow_attenuation2dtexture
1761          || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1762          || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1763          || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1764                 R_Shadow_MakeTextures();
1765
1766         CHECKGLERROR
1767         R_Mesh_ColorPointer(NULL, 0, 0);
1768         R_Mesh_ResetTextureState();
1769         GL_BlendFunc(GL_ONE, GL_ZERO);
1770         GL_DepthRange(0, 1);
1771         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1772         GL_DepthTest(true);
1773         GL_DepthMask(false);
1774         GL_Color(0, 0, 0, 1);
1775         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1776
1777         r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1778
1779         if (gl_ext_separatestencil.integer)
1780         {
1781                 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1782                 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1783         }
1784         else if (gl_ext_stenciltwoside.integer)
1785         {
1786                 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1787                 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1788         }
1789         else
1790         {
1791                 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1792                 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1793         }
1794
1795         if (r_glsl.integer && gl_support_fragment_shader)
1796                 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1797         else if (gl_dot3arb && gl_texturecubemap && r_shadow_dot3.integer && gl_stencil)
1798                 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
1799         else
1800                 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1801
1802         CHECKGLERROR
1803 #if 0
1804         qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1805         qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1806         r_shadow_drawbuffer = drawbuffer;
1807         r_shadow_readbuffer = readbuffer;
1808 #endif
1809         r_shadow_cullface_front = r_refdef.view.cullface_front;
1810         r_shadow_cullface_back = r_refdef.view.cullface_back;
1811 }
1812
1813 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1814 {
1815         rsurface.rtlight = rtlight;
1816 }
1817
1818 void R_Shadow_RenderMode_Reset(void)
1819 {
1820         CHECKGLERROR
1821         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE)
1822         {
1823                 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1824         }
1825         if (gl_support_ext_framebuffer_object)
1826         {
1827                 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
1828         }
1829 #if 0
1830         qglDrawBuffer(r_shadow_drawbuffer);CHECKGLERROR
1831         qglReadBuffer(r_shadow_readbuffer);CHECKGLERROR
1832 #endif
1833         R_SetViewport(&r_refdef.view.viewport);
1834         GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1835         R_Mesh_ColorPointer(NULL, 0, 0);
1836         R_Mesh_ResetTextureState();
1837         GL_DepthRange(0, 1);
1838         GL_DepthTest(true);
1839         GL_DepthMask(false);
1840         qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1841         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1842         qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1843         qglStencilMask(~0);CHECKGLERROR
1844         qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1845         qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1846         r_refdef.view.cullface_front = r_shadow_cullface_front;
1847         r_refdef.view.cullface_back = r_shadow_cullface_back;
1848         GL_CullFace(r_refdef.view.cullface_back);
1849         GL_Color(1, 1, 1, 1);
1850         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1851         GL_BlendFunc(GL_ONE, GL_ZERO);
1852         R_SetupGenericShader(false);
1853         r_shadow_usingshadowmaprect = false;
1854         r_shadow_usingshadowmapcube = false;
1855         r_shadow_usingshadowmap2d = false;
1856         CHECKGLERROR
1857 }
1858
1859 void R_Shadow_ClearStencil(void)
1860 {
1861         CHECKGLERROR
1862         GL_Clear(GL_STENCIL_BUFFER_BIT);
1863         r_refdef.stats.lights_clears++;
1864 }
1865
1866 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
1867 {
1868         r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
1869         if (r_shadow_rendermode == mode)
1870                 return;
1871         CHECKGLERROR
1872         R_Shadow_RenderMode_Reset();
1873         GL_ColorMask(0, 0, 0, 0);
1874         GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1875         R_SetupDepthOrShadowShader();
1876         qglDepthFunc(GL_LESS);CHECKGLERROR
1877         qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1878         r_shadow_rendermode = mode;
1879         switch(mode)
1880         {
1881         default:
1882                 break;
1883         case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
1884                 GL_CullFace(GL_NONE);
1885                 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1886                 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1887                 break;
1888         case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
1889                 GL_CullFace(GL_NONE);
1890                 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1891                 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1892                 break;
1893         case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
1894                 GL_CullFace(GL_NONE);
1895                 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1896                 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1897                 qglStencilMask(~0);CHECKGLERROR
1898                 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1899                 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1900                 qglStencilMask(~0);CHECKGLERROR
1901                 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1902                 break;
1903         case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
1904                 GL_CullFace(GL_NONE);
1905                 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1906                 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1907                 qglStencilMask(~0);CHECKGLERROR
1908                 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1909                 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1910                 qglStencilMask(~0);CHECKGLERROR
1911                 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1912                 break;
1913         }
1914 }
1915
1916 static void R_Shadow_MakeVSDCT(void)
1917 {
1918         // maps to a 2x3 texture rectangle with normalized coordinates
1919         // +-
1920         // XX
1921         // YY
1922         // ZZ
1923         // stores abs(dir.xy), offset.xy/2.5
1924         unsigned char data[4*6] =
1925         {
1926                 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
1927                 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
1928                 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
1929                 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
1930                 0,   0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
1931                 0,   0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
1932         };
1933         r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_ALWAYSPRECACHE | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, NULL); 
1934 }
1935
1936 void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size)
1937 {
1938         int status;
1939         int maxsize;
1940         float nearclip, farclip, bias;
1941         r_viewport_t viewport;
1942         GLuint fbo = 0;
1943         CHECKGLERROR
1944         maxsize = r_shadow_shadowmapmaxsize;
1945         nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
1946         farclip = 1.0f;
1947         bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
1948         r_shadow_shadowmap_parameters[2] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
1949         r_shadow_shadowmap_parameters[3] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
1950         r_shadow_shadowmapside = side;
1951         r_shadow_shadowmapsize = size;
1952         if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
1953         {
1954                 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
1955                 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
1956                 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
1957                 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
1958
1959                 // complex unrolled cube approach (more flexible)
1960                 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
1961                         R_Shadow_MakeVSDCT();
1962                 if (!r_shadow_shadowmap2dtexture)
1963                 {
1964 #if 1
1965                         int w = maxsize*2, h = gl_support_arb_texture_non_power_of_two ? maxsize*3 : maxsize*4;
1966                         r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", w, h, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
1967                         qglGenFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
1968                         qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
1969                         qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_shadowmap2dtexture), 0);CHECKGLERROR
1970             // render depth into the fbo, do not render color at all
1971                         qglDrawBuffer(GL_NONE);CHECKGLERROR
1972                         qglReadBuffer(GL_NONE);CHECKGLERROR
1973                         status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1974                         if (status != GL_FRAMEBUFFER_COMPLETE_EXT && r_shadow_shadowmapping.integer)
1975                         {
1976                                 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1977                                 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1978                         }
1979 #endif
1980                 }
1981                 CHECKGLERROR
1982                 if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d;
1983                 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
1984                 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
1985                 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
1986         }
1987         else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
1988         {
1989                 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
1990                 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
1991                 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
1992                 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE) goto init_done;
1993
1994                 // complex unrolled cube approach (more flexible)
1995                 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
1996                         R_Shadow_MakeVSDCT();
1997                 if (!r_shadow_shadowmaprectangletexture)
1998                 {
1999 #if 1
2000                         r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", maxsize*2, maxsize*3, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2001                         qglGenFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
2002                         qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
2003                         qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_shadowmaprectangletexture), 0);CHECKGLERROR
2004                         // render depth into the fbo, do not render color at all
2005                         qglDrawBuffer(GL_NONE);CHECKGLERROR
2006                         qglReadBuffer(GL_NONE);CHECKGLERROR
2007                         status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2008                         if (status != GL_FRAMEBUFFER_COMPLETE_EXT && r_shadow_shadowmapping.integer)
2009                         {
2010                                 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2011                                 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2012                         }
2013 #endif
2014                 }
2015                 CHECKGLERROR
2016                 if(r_shadow_shadowmaprectangletexture) fbo = r_shadow_fborectangle;
2017                 r_shadow_shadowmap_texturescale[0] = 1.0f;
2018                 r_shadow_shadowmap_texturescale[1] = 1.0f;
2019                 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
2020         }
2021         else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
2022         {
2023                 r_shadow_shadowmap_parameters[0] = 1.0f;
2024                 r_shadow_shadowmap_parameters[1] = 1.0f;
2025                 R_Viewport_InitCubeSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, nearclip, farclip, NULL);
2026                 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE) goto init_done;
2027
2028                 // simple cube approach
2029                 if (!r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
2030                 {
2031  #if 1
2032                         r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", size, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2033                         qglGenFramebuffersEXT(1, &r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2034                         qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2035                         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
2036                         // render depth into the fbo, do not render color at all
2037                         qglDrawBuffer(GL_NONE);CHECKGLERROR
2038                         qglReadBuffer(GL_NONE);CHECKGLERROR
2039                         status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2040                         if (status != GL_FRAMEBUFFER_COMPLETE_EXT && r_shadow_shadowmapping.integer)
2041                         {
2042                                 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2043                                 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2044                         }
2045  #endif
2046                 }
2047                 CHECKGLERROR
2048                 if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]) fbo = r_shadow_fbocubeside[r_shadow_shadowmaplod];
2049                 r_shadow_shadowmap_texturescale[0] = 0.0f;
2050                 r_shadow_shadowmap_texturescale[1] = 0.0f;
2051                 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE;
2052         }
2053
2054         R_Shadow_RenderMode_Reset();
2055         if (fbo)
2056         {
2057                 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);CHECKGLERROR
2058                 R_SetupDepthOrShadowShader();
2059         }
2060         else
2061         {
2062                 R_SetupShowDepthShader();
2063                 qglClearColor(1,1,1,1);CHECKGLERROR
2064         }
2065         CHECKGLERROR
2066         GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2067         GL_DepthMask(true);
2068         GL_DepthTest(true);
2069         qglClearDepth(1);
2070         CHECKGLERROR
2071
2072 init_done:
2073         R_SetViewport(&viewport);
2074         GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2075         if(r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE)
2076         {
2077                 int flipped = (side&1)^(side>>2);
2078                 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2079                 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2080                 GL_CullFace(r_refdef.view.cullface_back);
2081         }
2082         else if(r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE)
2083         {
2084                 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
2085         }
2086         if (clear)
2087                 qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |  GL_STENCIL_BUFFER_BIT);
2088         CHECKGLERROR
2089 }
2090
2091 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2092 {
2093         if (transparent)
2094         {
2095                 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2096                 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2097                 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2098                 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2099         }
2100         CHECKGLERROR
2101         R_Shadow_RenderMode_Reset();
2102         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2103         if (!transparent)
2104         {
2105                 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2106         }
2107         if (stenciltest)
2108         {
2109                 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2110                 // only draw light where this geometry was already rendered AND the
2111                 // stencil is 128 (values other than this mean shadow)
2112                 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
2113         }
2114         r_shadow_rendermode = r_shadow_lightingrendermode;
2115         // do global setup needed for the chosen lighting mode
2116         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2117         {
2118                 R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap)); // light filter
2119                 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2120                 CHECKGLERROR
2121                 if (shadowmapping)
2122                 {
2123                         if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
2124                         {
2125                                 r_shadow_usingshadowmap2d = true;
2126                                 R_Mesh_TexBind(GL20TU_SHADOWMAP2D, R_GetTexture(r_shadow_shadowmap2dtexture));
2127                                 CHECKGLERROR
2128                         }
2129                         else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
2130                         {
2131                                 r_shadow_usingshadowmaprect = true;
2132                                 R_Mesh_TexBindRectangle(GL20TU_SHADOWMAPRECT, R_GetTexture(r_shadow_shadowmaprectangletexture));
2133                                 CHECKGLERROR
2134                         }
2135                         else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
2136                         {
2137                                 r_shadow_usingshadowmapcube = true;
2138                                 R_Mesh_TexBindCubeMap(GL20TU_SHADOWMAPCUBE, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]));
2139                                 CHECKGLERROR
2140                         }
2141
2142                         if (r_shadow_shadowmapvsdct && (r_shadow_usingshadowmap2d || r_shadow_usingshadowmaprect))
2143                         {
2144                                 R_Mesh_TexBindCubeMap(GL20TU_CUBEPROJECTION, R_GetTexture(r_shadow_shadowmapvsdcttexture));
2145                                 CHECKGLERROR
2146                         }
2147                 }
2148         }
2149         else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_VERTEX)
2150                 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
2151         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2152         CHECKGLERROR
2153 }
2154
2155 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2156 {
2157         CHECKGLERROR
2158         R_Shadow_RenderMode_Reset();
2159         GL_BlendFunc(GL_ONE, GL_ONE);
2160         GL_DepthRange(0, 1);
2161         GL_DepthTest(r_showshadowvolumes.integer < 2);
2162         GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2163         GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2164         GL_CullFace(GL_NONE);
2165         r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2166 }
2167
2168 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2169 {
2170         CHECKGLERROR
2171         R_Shadow_RenderMode_Reset();
2172         GL_BlendFunc(GL_ONE, GL_ONE);
2173         GL_DepthRange(0, 1);
2174         GL_DepthTest(r_showlighting.integer < 2);
2175         GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2176         if (!transparent)
2177         {
2178                 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2179         }
2180         if (stenciltest)
2181         {
2182                 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2183                 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
2184         }
2185         r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2186 }
2187
2188 void R_Shadow_RenderMode_End(void)
2189 {
2190         CHECKGLERROR
2191         R_Shadow_RenderMode_Reset();
2192         R_Shadow_RenderMode_ActiveLight(NULL);
2193         GL_DepthMask(true);
2194         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2195         r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2196 }
2197
2198 int bboxedges[12][2] =
2199 {
2200         // top
2201         {0, 1}, // +X
2202         {0, 2}, // +Y
2203         {1, 3}, // Y, +X
2204         {2, 3}, // X, +Y
2205         // bottom
2206         {4, 5}, // +X
2207         {4, 6}, // +Y
2208         {5, 7}, // Y, +X
2209         {6, 7}, // X, +Y
2210         // verticals
2211         {0, 4}, // +Z
2212         {1, 5}, // X, +Z
2213         {2, 6}, // Y, +Z
2214         {3, 7}, // XY, +Z
2215 };
2216
2217 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2218 {
2219         int i, ix1, iy1, ix2, iy2;
2220         float x1, y1, x2, y2;
2221         vec4_t v, v2;
2222         float vertex[20][3];
2223         int j, k;
2224         vec4_t plane4f;
2225         int numvertices;
2226         float corner[8][4];
2227         float dist[8];
2228         int sign[8];
2229         float f;
2230
2231         r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2232         r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2233         r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2234         r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2235
2236         if (!r_shadow_scissor.integer)
2237                 return false;
2238
2239         // if view is inside the light box, just say yes it's visible
2240         if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
2241                 return false;
2242
2243         x1 = y1 = x2 = y2 = 0;
2244
2245         // transform all corners that are infront of the nearclip plane
2246         VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
2247         plane4f[3] = r_refdef.view.frustum[4].dist;
2248         numvertices = 0;
2249         for (i = 0;i < 8;i++)
2250         {
2251                 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
2252                 dist[i] = DotProduct4(corner[i], plane4f);
2253                 sign[i] = dist[i] > 0;
2254                 if (!sign[i])
2255                 {
2256                         VectorCopy(corner[i], vertex[numvertices]);
2257                         numvertices++;
2258                 }
2259         }
2260         // if some points are behind the nearclip, add clipped edge points to make
2261         // sure that the scissor boundary is complete
2262         if (numvertices > 0 && numvertices < 8)
2263         {
2264                 // add clipped edge points
2265                 for (i = 0;i < 12;i++)
2266                 {
2267                         j = bboxedges[i][0];
2268                         k = bboxedges[i][1];
2269                         if (sign[j] != sign[k])
2270                         {
2271                                 f = dist[j] / (dist[j] - dist[k]);
2272                                 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
2273                                 numvertices++;
2274                         }
2275                 }
2276         }
2277
2278         // if we have no points to check, the light is behind the view plane
2279         if (!numvertices)
2280                 return true;
2281
2282         // if we have some points to transform, check what screen area is covered
2283         x1 = y1 = x2 = y2 = 0;
2284         v[3] = 1.0f;
2285         //Con_Printf("%i vertices to transform...\n", numvertices);
2286         for (i = 0;i < numvertices;i++)
2287         {
2288                 VectorCopy(vertex[i], v);
2289                 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
2290                 //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]);
2291                 if (i)
2292                 {
2293                         if (x1 > v2[0]) x1 = v2[0];
2294                         if (x2 < v2[0]) x2 = v2[0];
2295                         if (y1 > v2[1]) y1 = v2[1];
2296                         if (y2 < v2[1]) y2 = v2[1];
2297                 }
2298                 else
2299                 {
2300                         x1 = x2 = v2[0];
2301                         y1 = y2 = v2[1];
2302                 }
2303         }
2304
2305         // now convert the scissor rectangle to integer screen coordinates
2306         ix1 = (int)(x1 - 1.0f);
2307         iy1 = vid.height - (int)(y2 - 1.0f);
2308         ix2 = (int)(x2 + 1.0f);
2309         iy2 = vid.height - (int)(y1 + 1.0f);
2310         //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
2311
2312         // clamp it to the screen
2313         if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
2314         if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
2315         if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
2316         if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
2317
2318         // if it is inside out, it's not visible
2319         if (ix2 <= ix1 || iy2 <= iy1)
2320                 return true;
2321
2322         // the light area is visible, set up the scissor rectangle
2323         r_shadow_lightscissor[0] = ix1;
2324         r_shadow_lightscissor[1] = iy1;
2325         r_shadow_lightscissor[2] = ix2 - ix1;
2326         r_shadow_lightscissor[3] = iy2 - iy1;
2327
2328         r_refdef.stats.lights_scissored++;
2329         return false;
2330 }
2331
2332 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
2333 {
2334         float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2335         float *normal3f = rsurface.normal3f + 3 * firstvertex;
2336         float *color4f = rsurface.array_color4f + 4 * firstvertex;
2337         float dist, dot, distintensity, shadeintensity, v[3], n[3];
2338         if (r_textureunits.integer >= 3)
2339         {
2340                 if (VectorLength2(diffusecolor) > 0)
2341                 {
2342                         for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2343                         {
2344                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2345                                 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2346                                 if ((dot = DotProduct(n, v)) < 0)
2347                                 {
2348                                         shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2349                                         VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2350                                 }
2351                                 else
2352                                         VectorCopy(ambientcolor, color4f);
2353                                 if (r_refdef.fogenabled)
2354                                 {
2355                                         float f;
2356                                         f = FogPoint_Model(vertex3f);
2357                                         VectorScale(color4f, f, color4f);
2358                                 }
2359                                 color4f[3] = 1;
2360                         }
2361                 }
2362                 else
2363                 {
2364                         for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2365                         {
2366                                 VectorCopy(ambientcolor, color4f);
2367                                 if (r_refdef.fogenabled)
2368                                 {
2369                                         float f;
2370                                         Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2371                                         f = FogPoint_Model(vertex3f);
2372                                         VectorScale(color4f, f, color4f);
2373                                 }
2374                                 color4f[3] = 1;
2375                         }
2376                 }
2377         }
2378         else if (r_textureunits.integer >= 2)
2379         {
2380                 if (VectorLength2(diffusecolor) > 0)
2381                 {
2382                         for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2383                         {
2384                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2385                                 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2386                                 {
2387                                         Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2388                                         if ((dot = DotProduct(n, v)) < 0)
2389                                         {
2390                                                 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2391                                                 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2392                                                 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2393                                                 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2394                                         }
2395                                         else
2396                                         {
2397                                                 color4f[0] = ambientcolor[0] * distintensity;
2398                                                 color4f[1] = ambientcolor[1] * distintensity;
2399                                                 color4f[2] = ambientcolor[2] * distintensity;
2400                                         }
2401                                         if (r_refdef.fogenabled)
2402                                         {
2403                                                 float f;
2404                                                 f = FogPoint_Model(vertex3f);
2405                                                 VectorScale(color4f, f, color4f);
2406                                         }
2407                                 }
2408                                 else
2409                                         VectorClear(color4f);
2410                                 color4f[3] = 1;
2411                         }
2412                 }
2413                 else
2414                 {
2415                         for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2416                         {
2417                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2418                                 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2419                                 {
2420                                         color4f[0] = ambientcolor[0] * distintensity;
2421                                         color4f[1] = ambientcolor[1] * distintensity;
2422                                         color4f[2] = ambientcolor[2] * distintensity;
2423                                         if (r_refdef.fogenabled)
2424                                         {
2425                                                 float f;
2426                                                 f = FogPoint_Model(vertex3f);
2427                                                 VectorScale(color4f, f, color4f);
2428                                         }
2429                                 }
2430                                 else
2431                                         VectorClear(color4f);
2432                                 color4f[3] = 1;
2433                         }
2434                 }
2435         }
2436         else
2437         {
2438                 if (VectorLength2(diffusecolor) > 0)
2439                 {
2440                         for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2441                         {
2442                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2443                                 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2444                                 {
2445                                         distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2446                                         Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2447                                         if ((dot = DotProduct(n, v)) < 0)
2448                                         {
2449                                                 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2450                                                 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2451                                                 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2452                                                 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2453                                         }
2454                                         else
2455                                         {
2456                                                 color4f[0] = ambientcolor[0] * distintensity;
2457                                                 color4f[1] = ambientcolor[1] * distintensity;
2458                                                 color4f[2] = ambientcolor[2] * distintensity;
2459                                         }
2460                                         if (r_refdef.fogenabled)
2461                                         {
2462                                                 float f;
2463                                                 f = FogPoint_Model(vertex3f);
2464                                                 VectorScale(color4f, f, color4f);
2465                                         }
2466                                 }
2467                                 else
2468                                         VectorClear(color4f);
2469                                 color4f[3] = 1;
2470                         }
2471                 }
2472                 else
2473                 {
2474                         for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2475                         {
2476                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2477                                 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2478                                 {
2479                                         distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2480                                         color4f[0] = ambientcolor[0] * distintensity;
2481                                         color4f[1] = ambientcolor[1] * distintensity;
2482                                         color4f[2] = ambientcolor[2] * distintensity;
2483                                         if (r_refdef.fogenabled)
2484                                         {
2485                                                 float f;
2486                                                 f = FogPoint_Model(vertex3f);
2487                                                 VectorScale(color4f, f, color4f);
2488                                         }
2489                                 }
2490                                 else
2491                                         VectorClear(color4f);
2492                                 color4f[3] = 1;
2493                         }
2494                 }
2495         }
2496 }
2497
2498 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
2499
2500 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2501 {
2502         int i;
2503         float       *out3f     = rsurface.array_texcoord3f + 3 * firstvertex;
2504         const float *vertex3f  = rsurface.vertex3f         + 3 * firstvertex;
2505         const float *svector3f = rsurface.svector3f        + 3 * firstvertex;
2506         const float *tvector3f = rsurface.tvector3f        + 3 * firstvertex;
2507         const float *normal3f  = rsurface.normal3f         + 3 * firstvertex;
2508         float lightdir[3];
2509         for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2510         {
2511                 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2512                 // the cubemap normalizes this for us
2513                 out3f[0] = DotProduct(svector3f, lightdir);
2514                 out3f[1] = DotProduct(tvector3f, lightdir);
2515                 out3f[2] = DotProduct(normal3f, lightdir);
2516         }
2517 }
2518
2519 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2520 {
2521         int i;
2522         float       *out3f     = rsurface.array_texcoord3f + 3 * firstvertex;
2523         const float *vertex3f  = rsurface.vertex3f         + 3 * firstvertex;
2524         const float *svector3f = rsurface.svector3f        + 3 * firstvertex;
2525         const float *tvector3f = rsurface.tvector3f        + 3 * firstvertex;
2526         const float *normal3f  = rsurface.normal3f         + 3 * firstvertex;
2527         float lightdir[3], eyedir[3], halfdir[3];
2528         for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2529         {
2530                 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2531                 VectorNormalize(lightdir);
2532                 VectorSubtract(rsurface.modelorg, vertex3f, eyedir);
2533                 VectorNormalize(eyedir);
2534                 VectorAdd(lightdir, eyedir, halfdir);
2535                 // the cubemap normalizes this for us
2536                 out3f[0] = DotProduct(svector3f, halfdir);
2537                 out3f[1] = DotProduct(tvector3f, halfdir);
2538                 out3f[2] = DotProduct(normal3f, halfdir);
2539         }
2540 }
2541
2542 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)
2543 {
2544         // used to display how many times a surface is lit for level design purposes
2545         R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2546 }
2547
2548 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)
2549 {
2550         // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2551         R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
2552         if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND))
2553                 R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
2554         else
2555                 R_Mesh_ColorPointer(NULL, 0, 0);
2556         R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2557         R_Mesh_TexMatrix(1, &rsurface.texture->currentbackgroundtexmatrix);
2558         R_Mesh_TexBind(GL20TU_NORMAL, R_GetTexture(rsurface.texture->currentskinframe->nmap));
2559         R_Mesh_TexBind(GL20TU_COLOR, R_GetTexture(rsurface.texture->basetexture));
2560         R_Mesh_TexBind(GL20TU_GLOSS, R_GetTexture(rsurface.texture->glosstexture));
2561         if (rsurface.texture->backgroundcurrentskinframe)
2562         {
2563                 R_Mesh_TexBind(GL20TU_SECONDARY_NORMAL, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->nmap));
2564                 R_Mesh_TexBind(GL20TU_SECONDARY_COLOR, R_GetTexture(rsurface.texture->backgroundbasetexture));
2565                 R_Mesh_TexBind(GL20TU_SECONDARY_GLOSS, R_GetTexture(rsurface.texture->backgroundglosstexture));
2566                 R_Mesh_TexBind(GL20TU_SECONDARY_GLOW, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->glow));
2567         }
2568         //R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap));
2569         R_Mesh_TexBind(GL20TU_FOGMASK, R_GetTexture(r_texture_fogattenuation));
2570         if(rsurface.texture->colormapping)
2571         {
2572                 R_Mesh_TexBind(GL20TU_PANTS, R_GetTexture(rsurface.texture->currentskinframe->pants));
2573                 R_Mesh_TexBind(GL20TU_SHIRT, R_GetTexture(rsurface.texture->currentskinframe->shirt));
2574         }
2575         R_Mesh_TexBind(GL20TU_ATTENUATION, R_GetTexture(r_shadow_attenuationgradienttexture));
2576         R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
2577         R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
2578         R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
2579         R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
2580         if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2581         {
2582                 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2583         }
2584         R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2585         if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2586         {
2587                 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2588         }
2589 }
2590
2591 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)
2592 {
2593         // shared final code for all the dot3 layers
2594         int renders;
2595         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2596         for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
2597         {
2598                 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
2599                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2600         }
2601 }
2602
2603 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)
2604 {
2605         rmeshstate_t m;
2606         // colorscale accounts for how much we multiply the brightness
2607         // during combine.
2608         //
2609         // mult is how many times the final pass of the lighting will be
2610         // performed to get more brightness than otherwise possible.
2611         //
2612         // Limit mult to 64 for sanity sake.
2613         GL_Color(1,1,1,1);
2614         if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
2615         {
2616                 // 3 3D combine path (Geforce3, Radeon 8500)
2617                 memset(&m, 0, sizeof(m));
2618                 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2619                 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2620                 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2621                 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2622                 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2623                 m.tex[1] = R_GetTexture(basetexture);
2624                 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2625                 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2626                 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2627                 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2628                 m.texcubemap[2] = R_GetTexture(rsurface.rtlight->currentcubemap);
2629                 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2630                 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2631                 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2632                 m.texmatrix[2] = rsurface.entitytolight;
2633                 GL_BlendFunc(GL_ONE, GL_ONE);
2634         }
2635         else if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
2636         {
2637                 // 2 3D combine path (Geforce3, original Radeon)
2638                 memset(&m, 0, sizeof(m));
2639                 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2640                 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2641                 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2642                 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2643                 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2644                 m.tex[1] = R_GetTexture(basetexture);
2645                 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2646                 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2647                 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2648                 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2649                 GL_BlendFunc(GL_ONE, GL_ONE);
2650         }
2651         else if (r_textureunits.integer >= 4 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2652         {
2653                 // 4 2D combine path (Geforce3, Radeon 8500)
2654                 memset(&m, 0, sizeof(m));
2655                 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2656                 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2657                 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2658                 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2659                 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2660                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2661                 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2662                 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2663                 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2664                 m.texmatrix[1] = rsurface.entitytoattenuationz;
2665                 m.tex[2] = R_GetTexture(basetexture);
2666                 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2667                 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2668                 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2669                 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2670                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2671                 {
2672                         m.texcubemap[3] = R_GetTexture(rsurface.rtlight->currentcubemap);
2673                         m.pointer_texcoord3f[3] = rsurface.vertex3f;
2674                         m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2675                         m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2676                         m.texmatrix[3] = rsurface.entitytolight;
2677                 }
2678                 GL_BlendFunc(GL_ONE, GL_ONE);
2679         }
2680         else if (r_textureunits.integer >= 3 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2681         {
2682                 // 3 2D combine path (Geforce3, original Radeon)
2683                 memset(&m, 0, sizeof(m));
2684                 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2685                 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2686                 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2687                 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2688                 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2689                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2690                 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2691                 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2692                 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2693                 m.texmatrix[1] = rsurface.entitytoattenuationz;
2694                 m.tex[2] = R_GetTexture(basetexture);
2695                 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2696                 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2697                 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2698                 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2699                 GL_BlendFunc(GL_ONE, GL_ONE);
2700         }
2701         else
2702         {
2703                 // 2/2/2 2D combine path (any dot3 card)
2704                 memset(&m, 0, sizeof(m));
2705                 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2706                 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2707                 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2708                 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2709                 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2710                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2711                 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2712                 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2713                 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2714                 m.texmatrix[1] = rsurface.entitytoattenuationz;
2715                 R_Mesh_TextureState(&m);
2716                 GL_ColorMask(0,0,0,1);
2717                 GL_BlendFunc(GL_ONE, GL_ZERO);
2718                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2719
2720                 // second pass
2721                 memset(&m, 0, sizeof(m));
2722                 m.tex[0] = R_GetTexture(basetexture);
2723                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2724                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2725                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2726                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2727                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2728                 {
2729                         m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2730                         m.pointer_texcoord3f[1] = rsurface.vertex3f;
2731                         m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2732                         m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2733                         m.texmatrix[1] = rsurface.entitytolight;
2734                 }
2735                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2736         }
2737         // this final code is shared
2738         R_Mesh_TextureState(&m);
2739         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);
2740 }
2741
2742 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)
2743 {
2744         rmeshstate_t m;
2745         // colorscale accounts for how much we multiply the brightness
2746         // during combine.
2747         //
2748         // mult is how many times the final pass of the lighting will be
2749         // performed to get more brightness than otherwise possible.
2750         //
2751         // Limit mult to 64 for sanity sake.
2752         GL_Color(1,1,1,1);
2753         // generate normalization cubemap texcoords
2754         R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2755         if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
2756         {
2757                 // 3/2 3D combine path (Geforce3, Radeon 8500)
2758                 memset(&m, 0, sizeof(m));
2759                 m.tex[0] = R_GetTexture(normalmaptexture);
2760                 m.texcombinergb[0] = GL_REPLACE;
2761                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2762                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2763                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2764                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2765                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2766                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2767                 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2768                 m.pointer_texcoord_bufferobject[1] = 0;
2769                 m.pointer_texcoord_bufferoffset[1] = 0;
2770                 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
2771                 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2772                 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2773                 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2774                 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2775                 R_Mesh_TextureState(&m);
2776                 GL_ColorMask(0,0,0,1);
2777                 GL_BlendFunc(GL_ONE, GL_ZERO);
2778                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2779
2780                 // second pass
2781                 memset(&m, 0, sizeof(m));
2782                 m.tex[0] = R_GetTexture(basetexture);
2783                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2784                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2785                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2786                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2787                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2788                 {
2789                         m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2790                         m.pointer_texcoord3f[1] = rsurface.vertex3f;
2791                         m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2792                         m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2793                         m.texmatrix[1] = rsurface.entitytolight;
2794                 }
2795                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2796         }
2797         else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2798         {
2799                 // 1/2/2 3D combine path (original Radeon)
2800                 memset(&m, 0, sizeof(m));
2801                 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2802                 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2803                 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2804                 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2805                 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2806                 R_Mesh_TextureState(&m);
2807                 GL_ColorMask(0,0,0,1);
2808                 GL_BlendFunc(GL_ONE, GL_ZERO);
2809                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2810
2811                 // second pass
2812                 memset(&m, 0, sizeof(m));
2813                 m.tex[0] = R_GetTexture(normalmaptexture);
2814                 m.texcombinergb[0] = GL_REPLACE;
2815                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2816                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2817                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2818                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2819                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2820                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2821                 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2822                 m.pointer_texcoord_bufferobject[1] = 0;
2823                 m.pointer_texcoord_bufferoffset[1] = 0;
2824                 R_Mesh_TextureState(&m);
2825                 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2826                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2827
2828                 // second pass
2829                 memset(&m, 0, sizeof(m));
2830                 m.tex[0] = R_GetTexture(basetexture);
2831                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2832                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2833                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2834                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2835                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2836                 {
2837                         m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2838                         m.pointer_texcoord3f[1] = rsurface.vertex3f;
2839                         m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2840                         m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2841                         m.texmatrix[1] = rsurface.entitytolight;
2842                 }
2843                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2844         }
2845         else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2846         {
2847                 // 2/2 3D combine path (original Radeon)
2848                 memset(&m, 0, sizeof(m));
2849                 m.tex[0] = R_GetTexture(normalmaptexture);
2850                 m.texcombinergb[0] = GL_REPLACE;
2851                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2852                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2853                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2854                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2855                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2856                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2857                 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2858                 m.pointer_texcoord_bufferobject[1] = 0;
2859                 m.pointer_texcoord_bufferoffset[1] = 0;
2860                 R_Mesh_TextureState(&m);
2861                 GL_ColorMask(0,0,0,1);
2862                 GL_BlendFunc(GL_ONE, GL_ZERO);
2863                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2864
2865                 // second pass
2866                 memset(&m, 0, sizeof(m));
2867                 m.tex[0] = R_GetTexture(basetexture);
2868                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2869                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2870                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2871                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2872                 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2873                 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2874                 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2875                 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2876                 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2877                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2878         }
2879         else if (r_textureunits.integer >= 4)
2880         {
2881                 // 4/2 2D combine path (Geforce3, Radeon 8500)
2882                 memset(&m, 0, sizeof(m));
2883                 m.tex[0] = R_GetTexture(normalmaptexture);
2884                 m.texcombinergb[0] = GL_REPLACE;
2885                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2886                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2887                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2888                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2889                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2890                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2891                 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2892                 m.pointer_texcoord_bufferobject[1] = 0;
2893                 m.pointer_texcoord_bufferoffset[1] = 0;
2894                 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2895                 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2896                 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2897                 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2898                 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2899                 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2900                 m.pointer_texcoord3f[3] = rsurface.vertex3f;
2901                 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2902                 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2903                 m.texmatrix[3] = rsurface.entitytoattenuationz;
2904                 R_Mesh_TextureState(&m);
2905                 GL_ColorMask(0,0,0,1);
2906                 GL_BlendFunc(GL_ONE, GL_ZERO);
2907                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2908
2909                 // second pass
2910                 memset(&m, 0, sizeof(m));
2911                 m.tex[0] = R_GetTexture(basetexture);
2912                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2913                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2914                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2915                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2916                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2917                 {
2918                         m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2919                         m.pointer_texcoord3f[1] = rsurface.vertex3f;
2920                         m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2921                         m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2922                         m.texmatrix[1] = rsurface.entitytolight;
2923                 }
2924                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2925         }
2926         else
2927         {
2928                 // 2/2/2 2D combine path (any dot3 card)
2929                 memset(&m, 0, sizeof(m));
2930                 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2931                 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2932                 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2933                 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2934                 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2935                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2936                 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2937                 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2938                 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2939                 m.texmatrix[1] = rsurface.entitytoattenuationz;
2940                 R_Mesh_TextureState(&m);
2941                 GL_ColorMask(0,0,0,1);
2942                 GL_BlendFunc(GL_ONE, GL_ZERO);
2943                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2944
2945                 // second pass
2946                 memset(&m, 0, sizeof(m));
2947                 m.tex[0] = R_GetTexture(normalmaptexture);
2948                 m.texcombinergb[0] = GL_REPLACE;
2949                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2950                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2951                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2952                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2953                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2954                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2955                 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2956                 m.pointer_texcoord_bufferobject[1] = 0;
2957                 m.pointer_texcoord_bufferoffset[1] = 0;
2958                 R_Mesh_TextureState(&m);
2959                 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2960                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2961
2962                 // second pass
2963                 memset(&m, 0, sizeof(m));
2964                 m.tex[0] = R_GetTexture(basetexture);
2965                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2966                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2967                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2968                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2969                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2970                 {
2971                         m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2972                         m.pointer_texcoord3f[1] = rsurface.vertex3f;
2973                         m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2974                         m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2975                         m.texmatrix[1] = rsurface.entitytolight;
2976                 }
2977                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2978         }
2979         // this final code is shared
2980         R_Mesh_TextureState(&m);
2981         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);
2982 }
2983
2984 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)
2985 {
2986         float glossexponent;
2987         rmeshstate_t m;
2988         // FIXME: detect blendsquare!
2989         //if (!gl_support_blendsquare)
2990         //      return;
2991         GL_Color(1,1,1,1);
2992         // generate normalization cubemap texcoords
2993         R_Shadow_GenTexCoords_Specular_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2994         if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2995         {
2996                 // 2/0/0/1/2 3D combine blendsquare path
2997                 memset(&m, 0, sizeof(m));
2998                 m.tex[0] = R_GetTexture(normalmaptexture);
2999                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3000                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3001                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3002                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3003                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
3004                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
3005                 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
3006                 m.pointer_texcoord_bufferobject[1] = 0;
3007                 m.pointer_texcoord_bufferoffset[1] = 0;
3008                 R_Mesh_TextureState(&m);
3009                 GL_ColorMask(0,0,0,1);
3010                 // this squares the result
3011                 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
3012                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3013
3014                 // second and third pass
3015                 R_Mesh_ResetTextureState();
3016                 // square alpha in framebuffer a few times to make it shiny
3017                 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
3018                 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
3019                         R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3020
3021                 // fourth pass
3022                 memset(&m, 0, sizeof(m));
3023                 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
3024                 m.pointer_texcoord3f[0] = rsurface.vertex3f;
3025                 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
3026                 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
3027                 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
3028                 R_Mesh_TextureState(&m);
3029                 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
3030                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3031
3032                 // fifth pass
3033                 memset(&m, 0, sizeof(m));
3034                 m.tex[0] = R_GetTexture(glosstexture);
3035                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3036                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3037                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3038                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3039                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
3040                 {
3041                         m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
3042                         m.pointer_texcoord3f[1] = rsurface.vertex3f;
3043                         m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3044                         m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3045                         m.texmatrix[1] = rsurface.entitytolight;
3046                 }
3047                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
3048         }
3049         else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
3050         {
3051                 // 2/0/0/2 3D combine blendsquare path
3052                 memset(&m, 0, sizeof(m));
3053                 m.tex[0] = R_GetTexture(normalmaptexture);
3054                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3055                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3056                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3057                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3058                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
3059                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
3060                 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
3061                 m.pointer_texcoord_bufferobject[1] = 0;
3062                 m.pointer_texcoord_bufferoffset[1] = 0;
3063                 R_Mesh_TextureState(&m);
3064                 GL_ColorMask(0,0,0,1);
3065                 // this squares the result
3066                 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
3067                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3068
3069                 // second and third pass
3070                 R_Mesh_ResetTextureState();
3071                 // square alpha in framebuffer a few times to make it shiny
3072                 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
3073                 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
3074                         R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3075
3076                 // fourth pass
3077                 memset(&m, 0, sizeof(m));
3078                 m.tex[0] = R_GetTexture(glosstexture);
3079                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3080                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3081                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3082                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3083                 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
3084                 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3085                 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3086                 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3087                 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
3088                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
3089         }
3090         else
3091         {
3092                 // 2/0/0/2/2 2D combine blendsquare path
3093                 memset(&m, 0, sizeof(m));
3094                 m.tex[0] = R_GetTexture(normalmaptexture);
3095                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3096                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3097                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3098                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3099                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
3100                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
3101                 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
3102                 m.pointer_texcoord_bufferobject[1] = 0;
3103                 m.pointer_texcoord_bufferoffset[1] = 0;
3104                 R_Mesh_TextureState(&m);
3105                 GL_ColorMask(0,0,0,1);
3106                 // this squares the result
3107                 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
3108                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3109
3110                 // second and third pass
3111                 R_Mesh_ResetTextureState();
3112                 // square alpha in framebuffer a few times to make it shiny
3113                 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
3114                 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
3115                         R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3116
3117                 // fourth pass
3118                 memset(&m, 0, sizeof(m));
3119                 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
3120                 m.pointer_texcoord3f[0] = rsurface.vertex3f;
3121                 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
3122                 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
3123                 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
3124                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
3125                 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3126                 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3127                 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3128                 m.texmatrix[1] = rsurface.entitytoattenuationz;
3129                 R_Mesh_TextureState(&m);
3130                 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
3131                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3132
3133                 // fifth pass
3134                 memset(&m, 0, sizeof(m));
3135                 m.tex[0] = R_GetTexture(glosstexture);
3136                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3137                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3138                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3139                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3140                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
3141                 {
3142                         m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
3143                         m.pointer_texcoord3f[1] = rsurface.vertex3f;
3144                         m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3145                         m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3146                         m.texmatrix[1] = rsurface.entitytolight;
3147                 }
3148                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
3149         }
3150         // this final code is shared
3151         R_Mesh_TextureState(&m);
3152         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);
3153 }
3154
3155 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)
3156 {
3157         // ARB path (any Geforce, any Radeon)
3158         qboolean doambient = ambientscale > 0;
3159         qboolean dodiffuse = diffusescale > 0;
3160         qboolean dospecular = specularscale > 0;
3161         if (!doambient && !dodiffuse && !dospecular)
3162                 return;
3163         R_Mesh_ColorPointer(NULL, 0, 0);
3164         if (doambient)
3165                 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, ambientscale * r_refdef.view.colorscale);
3166         if (dodiffuse)
3167                 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
3168         if (dopants)
3169         {
3170                 if (doambient)
3171                         R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, ambientscale * r_refdef.view.colorscale);
3172                 if (dodiffuse)
3173                         R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
3174         }
3175         if (doshirt)
3176         {
3177                 if (doambient)
3178                         R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, ambientscale * r_refdef.view.colorscale);
3179                 if (dodiffuse)
3180                         R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
3181         }
3182         if (dospecular)
3183                 R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_refdef.view.colorscale);
3184 }
3185
3186 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
3187 {
3188         int renders;
3189         int i;
3190         int stop;
3191         int newfirstvertex;
3192         int newlastvertex;
3193         int newnumtriangles;
3194         int *newe;
3195         const int *e;
3196         float *c;
3197         int maxtriangles = 4096;
3198         int newelements[4096*3];
3199         R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
3200         for (renders = 0;renders < 64;renders++)
3201         {
3202                 stop = true;
3203                 newfirstvertex = 0;
3204                 newlastvertex = 0;
3205                 newnumtriangles = 0;
3206                 newe = newelements;
3207                 // due to low fillrate on the cards this vertex lighting path is
3208                 // designed for, we manually cull all triangles that do not
3209                 // contain a lit vertex
3210                 // this builds batches of triangles from multiple surfaces and
3211                 // renders them at once
3212                 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
3213                 {
3214                         if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
3215                         {
3216                                 if (newnumtriangles)
3217                                 {
3218                                         newfirstvertex = min(newfirstvertex, e[0]);
3219                                         newlastvertex  = max(newlastvertex, e[0]);
3220                                 }
3221                                 else
3222                                 {
3223                                         newfirstvertex = e[0];
3224                                         newlastvertex = e[0];
3225                                 }
3226                                 newfirstvertex = min(newfirstvertex, e[1]);
3227                                 newlastvertex  = max(newlastvertex, e[1]);
3228                                 newfirstvertex = min(newfirstvertex, e[2]);
3229                                 newlastvertex  = max(newlastvertex, e[2]);
3230                                 newe[0] = e[0];
3231                                 newe[1] = e[1];
3232                                 newe[2] = e[2];
3233                                 newnumtriangles++;
3234                                 newe += 3;
3235                                 if (newnumtriangles >= maxtriangles)
3236                                 {
3237                                         R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
3238                                         newnumtriangles = 0;
3239                                         newe = newelements;
3240                                         stop = false;
3241                                 }
3242                         }
3243                 }
3244                 if (newnumtriangles >= 1)
3245                 {
3246                         R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
3247                         stop = false;
3248                 }
3249                 // if we couldn't find any lit triangles, exit early
3250                 if (stop)
3251                         break;
3252                 // now reduce the intensity for the next overbright pass
3253                 // we have to clamp to 0 here incase the drivers have improper
3254                 // handling of negative colors
3255                 // (some old drivers even have improper handling of >1 color)
3256                 stop = true;
3257                 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
3258                 {
3259                         if (c[0] > 1 || c[1] > 1 || c[2] > 1)
3260                         {
3261                                 c[0] = max(0, c[0] - 1);
3262                                 c[1] = max(0, c[1] - 1);
3263                                 c[2] = max(0, c[2] - 1);
3264                                 stop = false;
3265                         }
3266                         else
3267                                 VectorClear(c);
3268                 }
3269                 // another check...
3270                 if (stop)
3271                         break;
3272         }
3273 }
3274
3275 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)
3276 {
3277         // OpenGL 1.1 path (anything)
3278         float ambientcolorbase[3], diffusecolorbase[3];
3279         float ambientcolorpants[3], diffusecolorpants[3];
3280         float ambientcolorshirt[3], diffusecolorshirt[3];
3281         rmeshstate_t m;
3282         VectorScale(lightcolorbase, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorbase);
3283         VectorScale(lightcolorbase, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorbase);
3284         VectorScale(lightcolorpants, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorpants);
3285         VectorScale(lightcolorpants, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorpants);
3286         VectorScale(lightcolorshirt, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorshirt);
3287         VectorScale(lightcolorshirt, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorshirt);
3288         memset(&m, 0, sizeof(m));
3289         m.tex[0] = R_GetTexture(basetexture);
3290         m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3291         m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3292         m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3293         m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3294         if (r_textureunits.integer >= 2)
3295         {
3296                 // voodoo2 or TNT
3297                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
3298                 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
3299                 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3300                 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3301                 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3302                 if (r_textureunits.integer >= 3)
3303                 {
3304                         // Voodoo4 or Kyro (or Geforce3/Radeon with r_shadow_dot3 off)
3305                         m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
3306                         m.texmatrix[2] = rsurface.entitytoattenuationz;
3307                         m.pointer_texcoord3f[2] = rsurface.vertex3f;
3308                         m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
3309                         m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
3310                 }
3311         }
3312         R_Mesh_TextureState(&m);
3313         //R_Mesh_TexBind(0, R_GetTexture(basetexture));
3314         R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
3315         if (dopants)
3316         {
3317                 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
3318                 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
3319         }
3320         if (doshirt)
3321         {
3322                 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
3323                 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
3324         }
3325 }
3326
3327 extern cvar_t gl_lightmaps;
3328 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)
3329 {
3330         float ambientscale, diffusescale, specularscale;
3331         vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
3332         rtexture_t *nmap;
3333         // calculate colors to render this texture with
3334         lightcolorbase[0] = rsurface.rtlight->currentcolor[0] * rsurface.texture->dlightcolor[0];
3335         lightcolorbase[1] = rsurface.rtlight->currentcolor[1] * rsurface.texture->dlightcolor[1];
3336         lightcolorbase[2] = rsurface.rtlight->currentcolor[2] * rsurface.texture->dlightcolor[2];
3337         ambientscale = rsurface.rtlight->ambientscale;
3338         diffusescale = rsurface.rtlight->diffusescale;
3339         specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
3340         if (!r_shadow_usenormalmap.integer)
3341         {
3342                 ambientscale += 1.0f * diffusescale;
3343                 diffusescale = 0;
3344                 specularscale = 0;
3345         }
3346         if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
3347                 return;
3348         RSurf_SetupDepthAndCulling();
3349         nmap = rsurface.texture->currentskinframe->nmap;
3350         if (gl_lightmaps.integer)
3351                 nmap = r_texture_blanknormalmap;
3352         if (rsurface.texture->colormapping && !gl_lightmaps.integer)
3353         {
3354                 qboolean dopants = rsurface.texture->currentskinframe->pants != NULL && VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f);
3355                 qboolean doshirt = rsurface.texture->currentskinframe->shirt != NULL && VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f);
3356                 if (dopants)
3357                 {
3358                         lightcolorpants[0] = lightcolorbase[0] * rsurface.colormap_pantscolor[0];
3359                         lightcolorpants[1] = lightcolorbase[1] * rsurface.colormap_pantscolor[1];
3360                         lightcolorpants[2] = lightcolorbase[2] * rsurface.colormap_pantscolor[2];
3361                 }
3362                 else
3363                         VectorClear(lightcolorpants);
3364                 if (doshirt)
3365                 {
3366                         lightcolorshirt[0] = lightcolorbase[0] * rsurface.colormap_shirtcolor[0];
3367                         lightcolorshirt[1] = lightcolorbase[1] * rsurface.colormap_shirtcolor[1];
3368                         lightcolorshirt[2] = lightcolorbase[2] * rsurface.colormap_shirtcolor[2];
3369                 }
3370                 else
3371                         VectorClear(lightcolorshirt);
3372                 switch (r_shadow_rendermode)
3373                 {
3374                 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3375                         GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3376                         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);
3377                         break;
3378                 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3379                         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);
3380                         break;
3381                 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
3382                         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);
3383                         break;
3384                 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3385                         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);
3386                         break;
3387                 default:
3388                         Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3389                         break;
3390                 }
3391         }
3392         else
3393         {
3394                 switch (r_shadow_rendermode)
3395                 {
3396                 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3397                         GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3398                         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);
3399                         break;
3400                 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3401                         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);
3402                         break;
3403                 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
3404                         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);
3405                         break;
3406                 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3407                         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);
3408                         break;
3409                 default:
3410                         Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3411                         break;
3412                 }
3413         }
3414 }
3415
3416 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)
3417 {
3418         matrix4x4_t tempmatrix = *matrix;
3419         Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
3420
3421         // if this light has been compiled before, free the associated data
3422         R_RTLight_Uncompile(rtlight);
3423
3424         // clear it completely to avoid any lingering data
3425         memset(rtlight, 0, sizeof(*rtlight));
3426
3427         // copy the properties
3428         rtlight->matrix_lighttoworld = tempmatrix;
3429         Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3430         Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3431         rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3432         VectorCopy(color, rtlight->color);
3433         rtlight->cubemapname[0] = 0;
3434         if (cubemapname && cubemapname[0])
3435                 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3436         rtlight->shadow = shadow;
3437         rtlight->corona = corona;
3438         rtlight->style = style;
3439         rtlight->isstatic = isstatic;
3440         rtlight->coronasizescale = coronasizescale;
3441         rtlight->ambientscale = ambientscale;
3442         rtlight->diffusescale = diffusescale;
3443         rtlight->specularscale = specularscale;
3444         rtlight->flags = flags;
3445
3446         // compute derived data
3447         //rtlight->cullradius = rtlight->radius;
3448         //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3449         rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3450         rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3451         rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3452         rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3453         rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3454         rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3455 }
3456
3457 // compiles rtlight geometry
3458 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3459 void R_RTLight_Compile(rtlight_t *rtlight)
3460 {
3461         int i;
3462         int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3463         int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
3464         entity_render_t *ent = r_refdef.scene.worldentity;
3465         dp_model_t *model = r_refdef.scene.worldmodel;
3466         unsigned char *data;
3467         shadowmesh_t *mesh;
3468
3469         // compile the light
3470         rtlight->compiled = true;
3471         rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
3472         rtlight->static_numleafs = 0;
3473         rtlight->static_numleafpvsbytes = 0;
3474         rtlight->static_leaflist = NULL;
3475         rtlight->static_leafpvs = NULL;
3476         rtlight->static_numsurfaces = 0;
3477         rtlight->static_surfacelist = NULL;
3478         rtlight->static_shadowmap_receivers = 0x3F;
3479         rtlight->static_shadowmap_casters = 0x3F;
3480         rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3481         rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3482         rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3483         rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3484         rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3485         rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3486
3487         if (model && model->GetLightInfo)
3488         {
3489                 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
3490                 r_shadow_compilingrtlight = rtlight;
3491                 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);
3492                 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);
3493                 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3494                 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3495                 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3496                 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3497                 rtlight->static_numsurfaces = numsurfaces;
3498                 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3499                 rtlight->static_numleafs = numleafs;
3500                 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3501                 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3502                 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3503                 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3504                 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3505                 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3506                 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3507                 if (rtlight->static_numsurfaces)
3508                         memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3509                 if (rtlight->static_numleafs)
3510                         memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3511                 if (rtlight->static_numleafpvsbytes)
3512                         memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3513                 if (rtlight->static_numshadowtrispvsbytes)
3514                         memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3515                 if (rtlight->static_numlighttrispvsbytes)
3516                         memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3517                 switch (rtlight->shadowmode)
3518                 {
3519                 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
3520                 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
3521                 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
3522                         if (model->CompileShadowMap && rtlight->shadow)
3523                                 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3524                         break;
3525                 default:
3526                         if (model->CompileShadowVolume && rtlight->shadow)
3527                                 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3528                         break;
3529                 }
3530                 // now we're done compiling the rtlight
3531                 r_shadow_compilingrtlight = NULL;
3532         }
3533
3534
3535         // use smallest available cullradius - box radius or light radius
3536         //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3537         //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3538
3539         shadowzpasstris = 0;
3540         if (rtlight->static_meshchain_shadow_zpass)
3541                 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3542                         shadowzpasstris += mesh->numtriangles;
3543
3544         shadowzfailtris = 0;
3545         if (rtlight->static_meshchain_shadow_zfail)
3546                 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3547                         shadowzfailtris += mesh->numtriangles;
3548
3549         lighttris = 0;
3550         if (rtlight->static_numlighttrispvsbytes)
3551                 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3552                         if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3553                                 lighttris++;
3554
3555         shadowtris = 0;
3556         if (rtlight->static_numlighttrispvsbytes)
3557                 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3558                         if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3559                                 shadowtris++;
3560
3561         if (developer.integer >= 10)
3562                 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);
3563 }
3564
3565 void R_RTLight_Uncompile(rtlight_t *rtlight)
3566 {
3567         if (rtlight->compiled)
3568         {
3569                 if (rtlight->static_meshchain_shadow_zpass)
3570                         Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3571                 rtlight->static_meshchain_shadow_zpass = NULL;
3572                 if (rtlight->static_meshchain_shadow_zfail)
3573                         Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3574                 rtlight->static_meshchain_shadow_zfail = NULL;
3575                 if (rtlight->static_meshchain_shadow_shadowmap)
3576                         Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3577                 rtlight->static_meshchain_shadow_shadowmap = NULL;
3578                 // these allocations are grouped
3579                 if (rtlight->static_surfacelist)
3580                         Mem_Free(rtlight->static_surfacelist);
3581                 rtlight->static_numleafs = 0;
3582                 rtlight->static_numleafpvsbytes = 0;
3583                 rtlight->static_leaflist = NULL;
3584                 rtlight->static_leafpvs = NULL;
3585                 rtlight->static_numsurfaces = 0;
3586                 rtlight->static_surfacelist = NULL;
3587                 rtlight->static_numshadowtrispvsbytes = 0;
3588                 rtlight->static_shadowtrispvs = NULL;
3589                 rtlight->static_numlighttrispvsbytes = 0;
3590                 rtlight->static_lighttrispvs = NULL;
3591                 rtlight->compiled = false;
3592         }
3593 }
3594
3595 void R_Shadow_UncompileWorldLights(void)
3596 {
3597         size_t lightindex;
3598         dlight_t *light;
3599         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3600         for (lightindex = 0;lightindex < range;lightindex++)
3601         {
3602                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3603                 if (!light)
3604                         continue;
3605                 R_RTLight_Uncompile(&light->rtlight);
3606         }
3607 }
3608
3609 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3610 {
3611         int i, j;
3612         mplane_t plane;
3613         // reset the count of frustum planes
3614         // see rsurface.rtlight_frustumplanes definition for how much this array
3615         // can hold
3616         rsurface.rtlight_numfrustumplanes = 0;
3617
3618         // haven't implemented a culling path for ortho rendering
3619         if (!r_refdef.view.useperspective)
3620         {
3621                 // check if the light is on screen and copy the 4 planes if it is
3622                 for (i = 0;i < 4;i++)
3623                         if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3624                                 break;
3625                 if (i == 4)
3626                         for (i = 0;i < 4;i++)
3627                                 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3628                 return;
3629         }
3630
3631 #if 1
3632         // generate a deformed frustum that includes the light origin, this is
3633         // used to cull shadow casting surfaces that can not possibly cast a
3634         // shadow onto the visible light-receiving surfaces, which can be a
3635         // performance gain
3636         //
3637         // if the light origin is onscreen the result will be 4 planes exactly
3638         // if the light origin is offscreen on only one axis the result will
3639         // be exactly 5 planes (split-side case)
3640         // if the light origin is offscreen on two axes the result will be
3641         // exactly 4 planes (stretched corner case)
3642         for (i = 0;i < 4;i++)
3643         {
3644                 // quickly reject standard frustum planes that put the light
3645                 // origin outside the frustum
3646                 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3647                         continue;
3648                 // copy the plane
3649                 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3650         }
3651         // if all the standard frustum planes were accepted, the light is onscreen
3652         // otherwise we need to generate some more planes below...
3653         if (rsurface.rtlight_numfrustumplanes < 4)
3654         {
3655                 // at least one of the stock frustum planes failed, so we need to
3656                 // create one or two custom planes to enclose the light origin
3657                 for (i = 0;i < 4;i++)
3658                 {
3659                         // create a plane using the view origin and light origin, and a
3660                         // single point from the frustum corner set
3661                         TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3662                         VectorNormalize(plane.normal);
3663                         plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3664                         // see if this plane is backwards and flip it if so
3665                         for (j = 0;j < 4;j++)
3666                                 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3667                                         break;
3668                         if (j < 4)
3669                         {
3670                                 VectorNegate(plane.normal, plane.normal);
3671                                 plane.dist *= -1;
3672                                 // flipped plane, test again to see if it is now valid
3673                                 for (j = 0;j < 4;j++)
3674                                         if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3675                                                 break;
3676                                 // if the plane is still not valid, then it is dividing the
3677                                 // frustum and has to be rejected
3678                                 if (j < 4)
3679                                         continue;
3680                         }
3681                         // we have created a valid plane, compute extra info
3682                         PlaneClassify(&plane);
3683                         // copy the plane
3684                         rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3685 #if 1
3686                         // if we've found 5 frustum planes then we have constructed a
3687                         // proper split-side case and do not need to keep searching for
3688                         // planes to enclose the light origin
3689                         if (rsurface.rtlight_numfrustumplanes == 5)
3690                                 break;
3691 #endif
3692                 }
3693         }
3694 #endif
3695
3696 #if 0
3697         for (i = 0;i < rsurface.rtlight_numfrustumplanes;i++)
3698         {
3699                 plane = rsurface.rtlight_frustumplanes[i];
3700                 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));
3701         }
3702 #endif
3703
3704 #if 0
3705         // now add the light-space box planes if the light box is rotated, as any
3706         // caster outside the oriented light box is irrelevant (even if it passed
3707         // the worldspace light box, which is axial)
3708         if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3709         {
3710                 for (i = 0;i < 6;i++)
3711                 {
3712                         vec3_t v;
3713                         VectorClear(v);
3714                         v[i >> 1] = (i & 1) ? -1 : 1;
3715                         Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3716                         VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3717                         plane.dist = VectorNormalizeLength(plane.normal);
3718                         plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3719                         rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3720                 }
3721         }
3722 #endif
3723
3724 #if 0
3725         // add the world-space reduced box planes
3726         for (i = 0;i < 6;i++)
3727         {
3728                 VectorClear(plane.normal);
3729                 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3730                 plane.dist = (i & 1) ? -rsurface.rtlight_cullmaxs[i >> 1] : rsurface.rtlight_cullmins[i >> 1];
3731                 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3732         }
3733 #endif
3734
3735 #if 0
3736         {
3737         int j, oldnum;
3738         vec3_t points[8];
3739         vec_t bestdist;
3740         // reduce all plane distances to tightly fit the rtlight cull box, which
3741         // is in worldspace
3742         VectorSet(points[0], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3743         VectorSet(points[1], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3744         VectorSet(points[2], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3745         VectorSet(points[3], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3746         VectorSet(points[4], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3747         VectorSet(points[5], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3748         VectorSet(points[6], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3749         VectorSet(points[7], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3750         oldnum = rsurface.rtlight_numfrustumplanes;
3751         rsurface.rtlight_numfrustumplanes = 0;
3752         for (j = 0;j < oldnum;j++)
3753         {
3754                 // find the nearest point on the box to this plane
3755                 bestdist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[0]);
3756                 for (i = 1;i < 8;i++)
3757                 {
3758                         dist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[i]);
3759                         if (bestdist > dist)
3760                                 bestdist = dist;
3761                 }
3762                 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);
3763                 // if the nearest point is near or behind the plane, we want this
3764                 // plane, otherwise the plane is useless as it won't cull anything
3765                 if (rsurface.rtlight_frustumplanes[j].dist < bestdist + 0.03125)
3766                 {
3767                         PlaneClassify(&rsurface.rtlight_frustumplanes[j]);
3768                         rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = rsurface.rtlight_frustumplanes[j];
3769                 }
3770         }
3771         }
3772 #endif
3773 }
3774
3775 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3776 {
3777         shadowmesh_t *mesh;
3778
3779         RSurf_ActiveWorldEntity();
3780
3781         if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3782         {
3783                 CHECKGLERROR
3784                 GL_CullFace(GL_NONE);
3785         mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3786         for (;mesh;mesh = mesh->next)
3787         {
3788                         if (!mesh->sidetotals[r_shadow_shadowmapside])
3789                                 continue;
3790             r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3791             R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3792             R_Mesh_Draw(0, mesh->numverts, mesh->sideoffsets[r_shadow_shadowmapside], mesh->sidetotals[r_shadow_shadowmapside], mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3793         }
3794         CHECKGLERROR
3795     }
3796         else if (r_refdef.scene.worldentity->model)
3797                 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);
3798
3799         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3800 }
3801
3802 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3803 {
3804         qboolean zpass;
3805         shadowmesh_t *mesh;
3806         int t, tend;
3807         int surfacelistindex;
3808         msurface_t *surface;
3809
3810         RSurf_ActiveWorldEntity();
3811
3812         if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3813         {
3814                 CHECKGLERROR
3815                 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3816                 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3817                 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3818                 for (;mesh;mesh = mesh->next)
3819                 {
3820                         r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3821                         R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3822                         GL_LockArrays(0, mesh->numverts);
3823                         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3824                         {
3825                                 // increment stencil if frontface is infront of depthbuffer
3826                                 GL_CullFace(r_refdef.view.cullface_back);
3827                                 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
3828                                 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3829                                 // decrement stencil if backface is infront of depthbuffer
3830                                 GL_CullFace(r_refdef.view.cullface_front);
3831                                 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
3832                         }
3833                         else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3834                         {
3835                                 // decrement stencil if backface is behind depthbuffer
3836                                 GL_CullFace(r_refdef.view.cullface_front);
3837                                 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
3838                                 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3839                                 // increment stencil if frontface is behind depthbuffer
3840                                 GL_CullFace(r_refdef.view.cullface_back);
3841                                 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
3842                         }
3843                         R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3844                         GL_LockArrays(0, 0);
3845                 }
3846                 CHECKGLERROR
3847         }
3848         else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
3849         {
3850                 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3851                 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3852                 {
3853                         surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3854                         for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3855                                 if (CHECKPVSBIT(trispvs, t))
3856                                         shadowmarklist[numshadowmark++] = t;
3857                 }
3858                 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);
3859         }
3860         else if (numsurfaces)
3861                 r_refdef.scene.worldmodel->DrawShadowVolume(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
3862
3863         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3864 }
3865
3866 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3867 {
3868         vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3869         vec_t relativeshadowradius;
3870         RSurf_ActiveModelEntity(ent, false, false);
3871         Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3872         relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3873         relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3874         relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3875         relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3876         relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3877         relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3878         relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3879         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
3880         {
3881                 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3882         }
3883         else
3884                 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3885         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3886 }
3887
3888 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3889 {
3890         // set up properties for rendering light onto this entity
3891         RSurf_ActiveModelEntity(ent, true, true);
3892         GL_AlphaTest(false);
3893         Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3894         Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3895         Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3896         Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3897         if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
3898                 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3899 }
3900
3901 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3902 {
3903         if (!r_refdef.scene.worldmodel->DrawLight)
3904                 return;
3905
3906         // set up properties for rendering light onto this entity
3907         RSurf_ActiveWorldEntity();
3908         GL_AlphaTest(false);
3909         rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3910         Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3911         Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3912         VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3913         if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
3914                 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3915
3916         r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, trispvs);
3917
3918         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3919 }
3920
3921 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3922 {
3923         dp_model_t *model = ent->model;
3924         if (!model->DrawLight)
3925                 return;
3926
3927         R_Shadow_SetupEntityLight(ent);
3928
3929         model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3930
3931         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3932 }
3933
3934 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
3935 {
3936         int i;
3937         float f;
3938         int numleafs, numsurfaces;
3939         int *leaflist, *surfacelist;
3940         unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs, *surfacesides;
3941         int numlightentities;
3942         int numlightentities_noselfshadow;
3943         int numshadowentities;
3944         int numshadowentities_noselfshadow;
3945         static entity_render_t *lightentities[MAX_EDICTS];
3946         static entity_render_t *shadowentities[MAX_EDICTS];
3947         static unsigned char entitysides[MAX_EDICTS];
3948         int lightentities_noselfshadow;
3949         int shadowentities_noselfshadow;
3950         vec3_t nearestpoint;
3951         vec_t distance;
3952         qboolean castshadows;
3953         int lodlinear;
3954
3955         // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3956         // skip lights that are basically invisible (color 0 0 0)
3957         if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
3958                 return;
3959
3960         // loading is done before visibility checks because loading should happen
3961         // all at once at the start of a level, not when it stalls gameplay.
3962         // (especially important to benchmarks)
3963         // compile light
3964         if (rtlight->isstatic && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3965         {
3966                 if (rtlight->compiled)
3967                         R_RTLight_Uncompile(rtlight);
3968                 R_RTLight_Compile(rtlight);
3969         }
3970
3971         // load cubemap
3972         rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
3973
3974         // look up the light style value at this time
3975         f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3976         VectorScale(rtlight->color, f, rtlight->currentcolor);
3977         /*
3978         if (rtlight->selected)
3979         {
3980                 f = 2 + sin(realtime * M_PI * 4.0);
3981                 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3982         }
3983         */
3984
3985         // if lightstyle is currently off, don't draw the light
3986         if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3987                 return;
3988
3989         // if the light box is offscreen, skip it
3990         if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3991                 return;
3992
3993         VectorCopy(rtlight->cullmins, rsurface.rtlight_cullmins);
3994         VectorCopy(rtlight->cullmaxs, rsurface.rtlight_cullmaxs);
3995
3996         if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3997         {
3998                 // compiled light, world available and can receive realtime lighting
3999                 // retrieve leaf information
4000                 numleafs = rtlight->static_numleafs;
4001                 leaflist = rtlight->static_leaflist;
4002                 leafpvs = rtlight->static_leafpvs;
4003                 numsurfaces = rtlight->static_numsurfaces;
4004                 surfacelist = rtlight->static_surfacelist;
4005                 surfacesides = NULL;
4006                 shadowtrispvs = rtlight->static_shadowtrispvs;
4007                 lighttrispvs = rtlight->static_lighttrispvs;
4008         }
4009         else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
4010         {
4011                 // dynamic light, world available and can receive realtime lighting
4012                 // calculate lit surfaces and leafs
4013                 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);
4014                 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);
4015                 leaflist = r_shadow_buffer_leaflist;
4016                 leafpvs = r_shadow_buffer_leafpvs;
4017                 surfacelist = r_shadow_buffer_surfacelist;
4018                 surfacesides = r_shadow_buffer_surfacesides;
4019                 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
4020                 lighttrispvs = r_shadow_buffer_lighttrispvs;
4021                 // if the reduced leaf bounds are offscreen, skip it
4022                 if (R_CullBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
4023                         return;
4024         }
4025         else
4026         {
4027                 // no world
4028                 numleafs = 0;
4029                 leaflist = NULL;
4030                 leafpvs = NULL;
4031                 numsurfaces = 0;
4032                 surfacelist = NULL;
4033                 surfacesides = NULL;
4034                 shadowtrispvs = NULL;
4035                 lighttrispvs = NULL;
4036         }
4037         // check if light is illuminating any visible leafs
4038         if (numleafs)
4039         {
4040                 for (i = 0;i < numleafs;i++)
4041                         if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
4042                                 break;
4043                 if (i == numleafs)
4044                         return;
4045         }
4046         // set up a scissor rectangle for this light
4047         if (R_Shadow_ScissorForBBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
4048                 return;
4049
4050         R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4051
4052         // make a list of lit entities and shadow casting entities
4053         numlightentities = 0;
4054         numlightentities_noselfshadow = 0;
4055         lightentities_noselfshadow = sizeof(lightentities)/sizeof(lightentities[0]) - 1;
4056         numshadowentities = 0;
4057         numshadowentities_noselfshadow = 0;
4058         shadowentities_noselfshadow = sizeof(shadowentities)/sizeof(shadowentities[0]) - 1;
4059
4060         // add dynamic entities that are lit by the light
4061         if (r_drawentities.integer)
4062         {
4063                 for (i = 0;i < r_refdef.scene.numentities;i++)
4064                 {
4065                         dp_model_t *model;
4066                         entity_render_t *ent = r_refdef.scene.entities[i];
4067                         vec3_t org;
4068                         if (!BoxesOverlap(ent->mins, ent->maxs, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
4069                                 continue;
4070                         // skip the object entirely if it is not within the valid
4071                         // shadow-casting region (which includes the lit region)
4072                         if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rsurface.rtlight_numfrustumplanes, rsurface.rtlight_frustumplanes))
4073                                 continue;
4074                         if (!(model = ent->model))
4075                                 continue;
4076                         if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
4077                         {
4078                                 // this entity wants to receive light, is visible, and is
4079                                 // inside the light box
4080                                 // TODO: check if the surfaces in the model can receive light
4081                                 // so now check if it's in a leaf seen by the light
4082                                 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))
4083                                         continue;
4084                                 if (ent->flags & RENDER_NOSELFSHADOW)
4085                                         lightentities[lightentities_noselfshadow - numlightentities_noselfshadow++] = ent;
4086                                 else
4087                                         lightentities[numlightentities++] = ent;
4088                                 // since it is lit, it probably also casts a shadow...
4089                                 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4090                                 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4091                                 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4092                                 {
4093                                         // note: exterior models without the RENDER_NOSELFSHADOW
4094                                         // flag still create a RENDER_NOSELFSHADOW shadow but
4095                                         // are lit normally, this means that they are
4096                                         // self-shadowing but do not shadow other
4097                                         // RENDER_NOSELFSHADOW entities such as the gun
4098                                         // (very weird, but keeps the player shadow off the gun)
4099                                         if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4100                                                 shadowentities[shadowentities_noselfshadow - numshadowentities_noselfshadow++] = ent;
4101                                         else
4102                                                 shadowentities[numshadowentities++] = ent;
4103                                 }
4104                         }
4105                         else if (ent->flags & RENDER_SHADOW)
4106                         {
4107                                 // this entity is not receiving light, but may still need to
4108                                 // cast a shadow...
4109                                 // TODO: check if the surfaces in the model can cast shadow
4110                                 // now check if it is in a leaf seen by the light
4111                                 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))
4112                                         continue;
4113                                 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4114                                 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4115                                 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4116                                 {
4117                                         if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4118                                                 shadowentities[shadowentities_noselfshadow - numshadowentities_noselfshadow++] = ent;
4119                                         else
4120                                                 shadowentities[numshadowentities++] = ent;
4121                                 }
4122                         }
4123                 }
4124         }
4125
4126         // return if there's nothing at all to light
4127         if (!numlightentities && !numsurfaces)
4128                 return;
4129
4130         // don't let sound skip if going slow
4131         if (r_refdef.scene.extraupdate)
4132                 S_ExtraUpdate ();
4133
4134         // make this the active rtlight for rendering purposes
4135         R_Shadow_RenderMode_ActiveLight(rtlight);
4136         // count this light in the r_speeds
4137         r_refdef.stats.lights++;
4138
4139         if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
4140         {
4141                 // optionally draw visible shape of the shadow volumes
4142                 // for performance analysis by level designers
4143                 R_Shadow_RenderMode_VisibleShadowVolumes();
4144                 if (numsurfaces)
4145                         R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4146                 for (i = 0;i < numshadowentities;i++)
4147                         R_Shadow_DrawEntityShadow(shadowentities[i]);
4148                 for (i = 0;i < numshadowentities_noselfshadow;i++)
4149                         R_Shadow_DrawEntityShadow(shadowentities[shadowentities_noselfshadow - i]);
4150         }
4151
4152         if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
4153         {
4154                 // optionally draw the illuminated areas
4155                 // for performance analysis by level designers
4156                 R_Shadow_RenderMode_VisibleLighting(false, false);
4157                 if (numsurfaces)
4158                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4159                 for (i = 0;i < numlightentities;i++)
4160                         R_Shadow_DrawEntityLight(lightentities[i]);
4161                 for (i = 0;i < numlightentities_noselfshadow;i++)
4162                         R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4163         }
4164
4165         castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
4166
4167         nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
4168         nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
4169         nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
4170         distance = VectorDistance(nearestpoint, r_refdef.view.origin);
4171
4172         lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
4173         //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
4174         lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapping_maxsize.integer);
4175
4176         if (castshadows && (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE))
4177         {
4178                 float borderbias;
4179                 int side;
4180                 int size;
4181                 int castermask = 0;
4182                 int receivermask = 0;
4183                 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
4184                 Matrix4x4_Abs(&radiustolight);
4185
4186                 r_shadow_shadowmaplod = 0;
4187                 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
4188                         if ((r_shadow_shadowmapping_maxsize.integer >> i) > lodlinear)
4189                                 r_shadow_shadowmaplod = i;
4190
4191                 size = r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE ? r_shadow_shadowmapping_maxsize.integer >> r_shadow_shadowmaplod : lodlinear;
4192                 size = bound(1, size, r_shadow_shadowmapping_maxsize.integer);
4193                 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
4194
4195                 if (numsurfaces)
4196                 {
4197                         if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4198                         {
4199                                 castermask = rtlight->static_shadowmap_casters;
4200                                 receivermask = rtlight->static_shadowmap_receivers;
4201                         }
4202                         else
4203                         {
4204                                 for(i = 0;i < numsurfaces;i++)
4205                                 {
4206                                         msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
4207                                         surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);           
4208                                         castermask |= surfacesides[i];
4209                                         receivermask |= surfacesides[i];
4210                                 }
4211                         }
4212                 }
4213                 if (receivermask < 0x3F) 
4214                 {
4215                         for (i = 0;i < numlightentities;i++)
4216                                 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4217                         if (receivermask < 0x3F)
4218                                 for(i = 0; i < numlightentities_noselfshadow;i++)
4219                                         receivermask |= R_Shadow_CalcEntitySideMask(lightentities[lightentities_noselfshadow - i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4220                 }
4221
4222                 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
4223
4224                 if (receivermask)
4225                 {
4226                         for (i = 0;i < numshadowentities;i++)
4227                                 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4228                         for (i = 0;i < numshadowentities_noselfshadow;i++)
4229                                 castermask |= (entitysides[shadowentities_noselfshadow - i] = R_Shadow_CalcEntitySideMask(shadowentities[shadowentities_noselfshadow - i], &rtlight->matrix_worldtolight, &radiustolight, borderbias)); 
4230                 }
4231
4232                 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
4233
4234                 // render shadow casters into 6 sided depth texture
4235                 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
4236                 {
4237                         R_Shadow_RenderMode_ShadowMap(side, true, size);
4238                         if (! (castermask & (1 << side))) continue;
4239                         if (numsurfaces)
4240                                 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
4241                         for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
4242                                 R_Shadow_DrawEntityShadow(shadowentities[i]);
4243                 }
4244
4245                 if (numlightentities_noselfshadow)
4246                 {
4247                         // render lighting using the depth texture as shadowmap
4248                         // draw lighting in the unmasked areas
4249                         R_Shadow_RenderMode_Lighting(false, false, true);
4250                         for (i = 0;i < numlightentities_noselfshadow;i++)
4251                                 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4252                 }
4253
4254                 // render shadow casters into 6 sided depth texture
4255                 if (numshadowentities_noselfshadow) 
4256                 {
4257                         for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
4258                         {
4259                                 R_Shadow_RenderMode_ShadowMap(side, false, size);
4260                                 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides[shadowentities_noselfshadow - i] & (1 << side))
4261                                         R_Shadow_DrawEntityShadow(shadowentities[shadowentities_noselfshadow - i]);
4262                         }
4263                 }
4264
4265                 // render lighting using the depth texture as shadowmap
4266                 // draw lighting in the unmasked areas
4267                 R_Shadow_RenderMode_Lighting(false, false, true);
4268                 // draw lighting in the unmasked areas
4269                 if (numsurfaces)
4270                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4271                 for (i = 0;i < numlightentities;i++)
4272                         R_Shadow_DrawEntityLight(lightentities[i]);
4273         }
4274         else if (castshadows && gl_stencil)
4275         {
4276                 // draw stencil shadow volumes to mask off pixels that are in shadow
4277                 // so that they won't receive lighting
4278                 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
4279                 R_Shadow_ClearStencil();
4280                 if (numsurfaces)
4281                         R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4282                 for (i = 0;i < numshadowentities;i++)
4283                         R_Shadow_DrawEntityShadow(shadowentities[i]);
4284                 if (numlightentities_noselfshadow)
4285                 {
4286                         // draw lighting in the unmasked areas
4287                         R_Shadow_RenderMode_Lighting(true, false, false);
4288                         for (i = 0;i < numlightentities_noselfshadow;i++)
4289                                 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4290
4291                         // optionally draw the illuminated areas
4292                         // for performance analysis by level designers
4293                         if (r_showlighting.integer && r_refdef.view.showdebug)
4294                         {
4295                                 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
4296                                 for (i = 0;i < numlightentities_noselfshadow;i++)
4297                                         R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4298                         }
4299                 }
4300                 for (i = 0;i < numshadowentities_noselfshadow;i++)
4301                         R_Shadow_DrawEntityShadow(shadowentities[shadowentities_noselfshadow - i]);
4302
4303                 if (numsurfaces + numlightentities)
4304                 {
4305                         // draw lighting in the unmasked areas
4306                         R_Shadow_RenderMode_Lighting(true, false, false);
4307                         if (numsurfaces)
4308                                 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4309                         for (i = 0;i < numlightentities;i++)
4310                                 R_Shadow_DrawEntityLight(lightentities[i]);
4311                 }
4312         }
4313         else
4314         {
4315                 if (numsurfaces + numlightentities)
4316                 {
4317                         // draw lighting in the unmasked areas
4318                         R_Shadow_RenderMode_Lighting(false, false, false);
4319                         if (numsurfaces)
4320                                 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4321                         for (i = 0;i < numlightentities;i++)
4322                                 R_Shadow_DrawEntityLight(lightentities[i]);
4323                         for (i = 0;i < numlightentities_noselfshadow;i++)
4324                                 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4325                 }
4326         }
4327 }
4328
4329 void R_Shadow_DrawLightSprites(void);
4330 void R_ShadowVolumeLighting(qboolean visible)
4331 {
4332         int flag;
4333         int lnum;
4334         size_t lightindex;
4335         dlight_t *light;
4336         size_t range;
4337
4338         if (r_shadow_shadowmapmaxsize != r_shadow_shadowmapping_maxsize.integer || 
4339                 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer && r_glsl.integer && gl_support_fragment_shader && gl_support_ext_framebuffer_object) || 
4340                 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0) || 
4341                 r_shadow_shadowmaptexturetype != r_shadow_shadowmapping_texturetype.integer ||
4342                 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer || 
4343                 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer || 
4344                 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
4345                 R_Shadow_FreeShadowMaps();
4346
4347         if (r_editlights.integer)
4348                 R_Shadow_DrawLightSprites();
4349
4350         R_Shadow_RenderMode_Begin();
4351
4352         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4353         if (r_shadow_debuglight.integer >= 0)
4354         {
4355                 lightindex = r_shadow_debuglight.integer;
4356                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4357                 if (light && (light->flags & flag))
4358                         R_DrawRTLight(&light->rtlight, visible);
4359         }
4360         else
4361         {
4362                 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4363                 for (lightindex = 0;lightindex < range;lightindex++)
4364                 {
4365                         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4366                         if (light && (light->flags & flag))
4367                                 R_DrawRTLight(&light->rtlight, visible);
4368                 }
4369         }
4370         if (r_refdef.scene.rtdlight)
4371                 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4372                         R_DrawRTLight(r_refdef.scene.lights[lnum], visible);
4373
4374         R_Shadow_RenderMode_End();
4375 }
4376
4377 extern const float r_screenvertex3f[12];
4378 extern void R_SetupView(qboolean allowwaterclippingplane);
4379 extern void R_ResetViewRendering3D(void);
4380 extern void R_ResetViewRendering2D(void);
4381 extern cvar_t r_shadows;
4382 extern cvar_t r_shadows_darken;
4383 extern cvar_t r_shadows_drawafterrtlighting;
4384 extern cvar_t r_shadows_castfrombmodels;
4385 extern cvar_t r_shadows_throwdistance;
4386 extern cvar_t r_shadows_throwdirection;
4387 void R_DrawModelShadows(void)
4388 {
4389         int i;
4390         float relativethrowdistance;
4391         entity_render_t *ent;
4392         vec3_t relativelightorigin;
4393         vec3_t relativelightdirection;
4394         vec3_t relativeshadowmins, relativeshadowmaxs;
4395         vec3_t tmp, shadowdir;
4396
4397         if (!r_drawentities.integer || !gl_stencil)
4398                 return;
4399
4400         CHECKGLERROR
4401         R_ResetViewRendering3D();
4402         //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4403         //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4404         R_Shadow_RenderMode_Begin();
4405         R_Shadow_RenderMode_ActiveLight(NULL);
4406         r_shadow_lightscissor[0] = r_refdef.view.x;
4407         r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4408         r_shadow_lightscissor[2] = r_refdef.view.width;
4409         r_shadow_lightscissor[3] = r_refdef.view.height;
4410         R_Shadow_RenderMode_StencilShadowVolumes(false);
4411
4412         // get shadow dir
4413         if (r_shadows.integer == 2)
4414         {
4415                 Math_atov(r_shadows_throwdirection.string, shadowdir);
4416                 VectorNormalize(shadowdir);
4417         }
4418
4419         R_Shadow_ClearStencil();
4420
4421         for (i = 0;i < r_refdef.scene.numentities;i++)
4422         {
4423                 ent = r_refdef.scene.entities[i];
4424
4425                 // cast shadows from anything of the map (submodels are optional)
4426                 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4427                 {
4428                         relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4429                         VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4430                         VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4431                         if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4432                                 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4433                         else
4434                         {
4435                                 if(ent->entitynumber != 0)
4436                                 {
4437                                         // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4438                                         int entnum, entnum2, recursion;
4439                                         entnum = entnum2 = ent->entitynumber;
4440                                         for(recursion = 32; recursion > 0; --recursion)
4441                                         {
4442                                                 entnum2 = cl.entities[entnum].state_current.tagentity;
4443                                                 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4444                                                         entnum = entnum2;
4445                                                 else
4446                                                         break;
4447                                         }
4448                                         if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4449                                         {
4450                                                 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4451                                                 // transform into modelspace of OUR entity
4452                                                 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4453                                                 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4454                                         }
4455                                         else
4456                                                 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4457                                 }
4458                                 else
4459                                         VectorNegate(ent->modellight_lightdir, relativelightdirection);
4460                         }
4461
4462                         VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4463                         RSurf_ActiveModelEntity(ent, false, false);
4464                         ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4465                         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4466                 }
4467         }
4468
4469         // not really the right mode, but this will disable any silly stencil features
4470         R_Shadow_RenderMode_End();
4471
4472         // set up ortho view for rendering this pass
4473         //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4474         //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4475         //GL_ScissorTest(true);
4476         //R_Mesh_Matrix(&identitymatrix);
4477         //R_Mesh_ResetTextureState();
4478         R_ResetViewRendering2D();
4479         R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
4480         R_Mesh_ColorPointer(NULL, 0, 0);
4481         R_SetupGenericShader(false);
4482
4483         // set up a darkening blend on shadowed areas
4484         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4485         //GL_DepthRange(0, 1);
4486         //GL_DepthTest(false);
4487         //GL_DepthMask(false);
4488         //GL_PolygonOffset(0, 0);CHECKGLERROR
4489         GL_Color(0, 0, 0, r_shadows_darken.value);
4490         //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4491         //qglDepthFunc(GL_ALWAYS);CHECKGLERROR
4492         qglEnable(GL_STENCIL_TEST);CHECKGLERROR
4493         qglStencilMask(~0);CHECKGLERROR
4494         qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
4495         qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
4496
4497         // apply the blend to the shadowed areas
4498         R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
4499
4500         // restore the viewport
4501         R_SetViewport(&r_refdef.view.viewport);
4502
4503         // restore other state to normal
4504         //R_Shadow_RenderMode_End();
4505 }
4506
4507 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4508 {
4509         float zdist;
4510         vec3_t centerorigin;
4511         // if it's too close, skip it
4512         if (VectorLength(rtlight->color) < (1.0f / 256.0f))
4513                 return;
4514         zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4515         if (zdist < 32)
4516                 return;
4517         if (usequery && r_numqueries + 2 <= r_maxqueries)
4518         {
4519                 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4520                 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4521                 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4522
4523                 CHECKGLERROR
4524                 // 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
4525                 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4526                 qglDepthFunc(GL_ALWAYS);
4527                 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);
4528                 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4529                 qglDepthFunc(GL_LEQUAL);
4530                 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4531                 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);
4532                 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4533                 CHECKGLERROR
4534         }
4535         rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4536 }
4537
4538 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4539 {
4540         vec3_t color;
4541         GLint allpixels = 0, visiblepixels = 0;
4542         // now we have to check the query result
4543         if (rtlight->corona_queryindex_visiblepixels)
4544         {
4545                 CHECKGLERROR
4546                 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4547                 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4548                 CHECKGLERROR
4549                 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4550                 if (visiblepixels < 1 || allpixels < 1)
4551                         return;
4552                 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4553                 cscale *= rtlight->corona_visibility;
4554         }
4555         else
4556         {
4557                 // FIXME: these traces should scan all render entities instead of cl.world
4558                 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4559                         return;
4560         }
4561         VectorScale(rtlight->color, cscale, color);
4562         if (VectorLength(color) > (1.0f / 256.0f))
4563                 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);
4564 }
4565
4566 void R_DrawCoronas(void)
4567 {
4568         int i, flag;
4569         qboolean usequery;
4570         size_t lightindex;
4571         dlight_t *light;
4572         rtlight_t *rtlight;
4573         size_t range;
4574         if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4575                 return;
4576         if (r_waterstate.renderingscene)
4577                 return;
4578         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4579         R_Mesh_Matrix(&identitymatrix);
4580
4581         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4582
4583         // check occlusion of coronas
4584         // use GL_ARB_occlusion_query if available
4585         // otherwise use raytraces
4586         r_numqueries = 0;
4587         usequery = gl_support_arb_occlusion_query && r_coronas_occlusionquery.integer;
4588         if (usequery)
4589         {
4590                 GL_ColorMask(0,0,0,0);
4591                 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4592                 if (r_maxqueries < R_MAX_OCCLUSION_QUERIES)
4593                 {
4594                         i = r_maxqueries;
4595                         r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4596                         r_maxqueries = min(r_maxqueries, R_MAX_OCCLUSION_QUERIES);
4597                         CHECKGLERROR
4598                         qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4599                         CHECKGLERROR
4600                 }
4601         }
4602         for (lightindex = 0;lightindex < range;lightindex++)
4603         {
4604                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4605                 if (!light)
4606                         continue;
4607                 rtlight = &light->rtlight;
4608                 rtlight->corona_visibility = 0;
4609                 rtlight->corona_queryindex_visiblepixels = 0;
4610                 rtlight->corona_queryindex_allpixels = 0;
4611                 if (!(rtlight->flags & flag))
4612                         continue;
4613                 if (rtlight->corona <= 0)
4614                         continue;
4615                 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4616                         continue;
4617                 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4618         }
4619         for (i = 0;i < r_refdef.scene.numlights;i++)
4620         {
4621                 rtlight = r_refdef.scene.lights[i];
4622                 rtlight->corona_visibility = 0;
4623                 rtlight->corona_queryindex_visiblepixels = 0;
4624                 rtlight->corona_queryindex_allpixels = 0;
4625                 if (!(rtlight->flags & flag))
4626                         continue;
4627                 if (rtlight->corona <= 0)
4628                         continue;
4629                 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4630         }
4631         if (usequery)
4632                 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4633
4634         // now draw the coronas using the query data for intensity info
4635         for (lightindex = 0;lightindex < range;lightindex++)
4636         {
4637                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4638                 if (!light)
4639                         continue;
4640                 rtlight = &light->rtlight;
4641                 if (rtlight->corona_visibility <= 0)
4642                         continue;
4643                 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4644         }
4645         for (i = 0;i < r_refdef.scene.numlights;i++)
4646         {
4647                 rtlight = r_refdef.scene.lights[i];
4648                 if (rtlight->corona_visibility <= 0)
4649                         continue;
4650                 if (gl_flashblend.integer)
4651                         R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4652                 else
4653                         R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4654         }
4655 }
4656
4657
4658
4659 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
4660 typedef struct suffixinfo_s
4661 {
4662         char *suffix;
4663         qboolean flipx, flipy, flipdiagonal;
4664 }
4665 suffixinfo_t;
4666 static suffixinfo_t suffix[3][6] =
4667 {
4668         {
4669                 {"px",   false, false, false},
4670                 {"nx",   false, false, false},
4671                 {"py",   false, false, false},
4672                 {"ny",   false, false, false},
4673                 {"pz",   false, false, false},
4674                 {"nz",   false, false, false}
4675         },
4676         {
4677                 {"posx", false, false, false},
4678                 {"negx", false, false, false},
4679                 {"posy", false, false, false},
4680                 {"negy", false, false, false},
4681                 {"posz", false, false, false},
4682                 {"negz", false, false, false}
4683         },
4684         {
4685                 {"rt",    true, false,  true},
4686                 {"lf",   false,  true,  true},
4687                 {"ft",    true,  true, false},
4688                 {"bk",   false, false, false},
4689                 {"up",    true, false,  true},
4690                 {"dn",    true, false,  true}
4691         }
4692 };
4693
4694 static int componentorder[4] = {0, 1, 2, 3};
4695
4696 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
4697 {
4698         int i, j, cubemapsize;
4699         unsigned char *cubemappixels, *image_buffer;
4700         rtexture_t *cubemaptexture;
4701         char name[256];
4702         // must start 0 so the first loadimagepixels has no requested width/height
4703         cubemapsize = 0;
4704         cubemappixels = NULL;
4705         cubemaptexture = NULL;
4706         // keep trying different suffix groups (posx, px, rt) until one loads
4707         for (j = 0;j < 3 && !cubemappixels;j++)
4708         {
4709                 // load the 6 images in the suffix group
4710                 for (i = 0;i < 6;i++)
4711                 {
4712                         // generate an image name based on the base and and suffix
4713                         dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
4714                         // load it
4715                         if ((image_buffer = loadimagepixelsbgra(name, false, false)))
4716                         {
4717                                 // an image loaded, make sure width and height are equal
4718                                 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
4719                                 {
4720                                         // if this is the first image to load successfully, allocate the cubemap memory
4721                                         if (!cubemappixels && image_width >= 1)
4722                                         {
4723                                                 cubemapsize = image_width;
4724                                                 // note this clears to black, so unavailable sides are black
4725                                                 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
4726                                         }
4727                                         // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
4728                                         if (cubemappixels)
4729                                                 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);
4730                                 }
4731                                 else
4732                                         Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
4733                                 // free the image
4734                                 Mem_Free(image_buffer);
4735                         }
4736                 }
4737         }
4738         // if a cubemap loaded, upload it
4739         if (cubemappixels)
4740         {
4741                 if (developer_loading.integer)
4742                         Con_Printf("loading cubemap \"%s\"\n", basename);
4743
4744                 if (!r_shadow_filters_texturepool)
4745                         r_shadow_filters_texturepool = R_AllocTexturePool();
4746                 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, TEXF_PRECACHE | (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR, NULL);
4747                 Mem_Free(cubemappixels);
4748         }
4749         else
4750         {
4751                 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
4752                 if (developer_loading.integer)
4753                 {
4754                         Con_Printf("(tried tried images ");
4755                         for (j = 0;j < 3;j++)
4756                                 for (i = 0;i < 6;i++)
4757                                         Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
4758                         Con_Print(" and was unable to find any of them).\n");
4759                 }
4760         }
4761         return cubemaptexture;
4762 }
4763
4764 rtexture_t *R_Shadow_Cubemap(const char *basename)
4765 {
4766         int i;
4767         for (i = 0;i < numcubemaps;i++)
4768                 if (!strcasecmp(cubemaps[i].basename, basename))
4769                         return cubemaps[i].texture ? cubemaps[i].texture : r_texture_whitecube;
4770         if (i >= MAX_CUBEMAPS)
4771                 return r_texture_whitecube;
4772         numcubemaps++;
4773         strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
4774         cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
4775         return cubemaps[i].texture;
4776 }
4777
4778 void R_Shadow_FreeCubemaps(void)
4779 {
4780         int i;
4781         for (i = 0;i < numcubemaps;i++)
4782         {
4783                 if (developer_loading.integer)
4784                         Con_Printf("unloading cubemap \"%s\"\n", cubemaps[i].basename);
4785                 if (cubemaps[i].texture)
4786                         R_FreeTexture(cubemaps[i].texture);
4787         }
4788
4789         numcubemaps = 0;
4790         R_FreeTexturePool(&r_shadow_filters_texturepool);
4791 }
4792
4793 dlight_t *R_Shadow_NewWorldLight(void)
4794 {
4795         return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4796 }
4797
4798 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)
4799 {
4800         matrix4x4_t matrix;
4801         // validate parameters
4802         if (style < 0 || style >= MAX_LIGHTSTYLES)
4803         {
4804                 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4805                 style = 0;
4806         }
4807         if (!cubemapname)
4808                 cubemapname = "";
4809
4810         // copy to light properties
4811         VectorCopy(origin, light->origin);
4812         light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4813         light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4814         light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4815         light->color[0] = max(color[0], 0);
4816         light->color[1] = max(color[1], 0);
4817         light->color[2] = max(color[2], 0);
4818         light->radius = max(radius, 0);
4819         light->style = style;
4820         light->shadow = shadowenable;
4821         light->corona = corona;
4822         strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4823         light->coronasizescale = coronasizescale;
4824         light->ambientscale = ambientscale;
4825         light->diffusescale = diffusescale;
4826         light->specularscale = specularscale;
4827         light->flags = flags;
4828
4829         // update renderable light data
4830         Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4831         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);
4832 }
4833
4834 void R_Shadow_FreeWorldLight(dlight_t *light)
4835 {
4836         if (r_shadow_selectedlight == light)
4837                 r_shadow_selectedlight = NULL;
4838         R_RTLight_Uncompile(&light->rtlight);
4839         Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4840 }
4841
4842 void R_Shadow_ClearWorldLights(void)
4843 {
4844         size_t lightindex;
4845         dlight_t *light;
4846         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4847         for (lightindex = 0;lightindex < range;lightindex++)
4848         {
4849                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4850                 if (light)
4851                         R_Shadow_FreeWorldLight(light);
4852         }
4853         r_shadow_selectedlight = NULL;
4854         R_Shadow_FreeCubemaps();
4855 }
4856
4857 void R_Shadow_SelectLight(dlight_t *light)
4858 {
4859         if (r_shadow_selectedlight)
4860                 r_shadow_selectedlight->selected = false;
4861         r_shadow_selectedlight = light;
4862         if (r_shadow_selectedlight)
4863                 r_shadow_selectedlight->selected = true;
4864 }
4865
4866 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4867 {
4868         // this is never batched (there can be only one)
4869         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);
4870 }
4871
4872 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4873 {
4874         float intensity;
4875         float s;
4876         vec3_t spritecolor;
4877         cachepic_t *pic;
4878
4879         // this is never batched (due to the ent parameter changing every time)
4880         // so numsurfaces == 1 and surfacelist[0] == lightnumber
4881         const dlight_t *light = (dlight_t *)ent;
4882         s = EDLIGHTSPRSIZE;
4883         intensity = 0.5f;
4884         VectorScale(light->color, intensity, spritecolor);
4885         if (VectorLength(spritecolor) < 0.1732f)
4886                 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4887         if (VectorLength(spritecolor) > 1.0f)
4888                 VectorNormalize(spritecolor);
4889
4890         // draw light sprite
4891         if (light->cubemapname[0] && !light->shadow)
4892                 pic = r_editlights_sprcubemapnoshadowlight;
4893         else if (light->cubemapname[0])
4894                 pic = r_editlights_sprcubemaplight;
4895         else if (!light->shadow)
4896                 pic = r_editlights_sprnoshadowlight;
4897         else
4898                 pic = r_editlights_sprlight;
4899         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);
4900         // draw selection sprite if light is selected
4901         if (light->selected)
4902                 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);
4903         // VorteX todo: add normalmode/realtime mode light overlay sprites?
4904 }
4905
4906 void R_Shadow_DrawLightSprites(void)
4907 {
4908         size_t lightindex;
4909         dlight_t *light;
4910         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4911         for (lightindex = 0;lightindex < range;lightindex++)
4912         {
4913                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4914                 if (light)
4915                         R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4916         }
4917         R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4918 }
4919
4920 void R_Shadow_SelectLightInView(void)
4921 {
4922         float bestrating, rating, temp[3];
4923         dlight_t *best;
4924         size_t lightindex;
4925         dlight_t *light;
4926         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4927         best = NULL;
4928         bestrating = 0;
4929         for (lightindex = 0;lightindex < range;lightindex++)
4930         {
4931                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4932                 if (!light)
4933                         continue;
4934                 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4935                 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4936                 if (rating >= 0.95)
4937                 {
4938                         rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4939                         if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
4940                         {
4941                                 bestrating = rating;
4942                                 best = light;
4943                         }
4944                 }
4945         }
4946         R_Shadow_SelectLight(best);
4947 }
4948
4949 void R_Shadow_LoadWorldLights(void)
4950 {
4951         int n, a, style, shadow, flags;
4952         char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4953         float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4954         if (cl.worldmodel == NULL)
4955         {
4956                 Con_Print("No map loaded.\n");
4957                 return;
4958         }
4959         FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4960         strlcat (name, ".rtlights", sizeof (name));
4961         lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4962         if (lightsstring)
4963         {
4964                 s = lightsstring;
4965                 n = 0;
4966                 while (*s)
4967                 {
4968                         t = s;
4969                         /*
4970                         shadow = true;
4971                         for (;COM_Parse(t, true) && strcmp(
4972                         if (COM_Parse(t, true))
4973                         {
4974                                 if (com_token[0] == '!')
4975                                 {
4976                                         shadow = false;
4977                                         origin[0] = atof(com_token+1);
4978                                 }
4979                                 else
4980                                         origin[0] = atof(com_token);
4981                                 if (Com_Parse(t
4982                         }
4983                         */
4984                         t = s;
4985                         while (*s && *s != '\n' && *s != '\r')
4986                                 s++;
4987                         if (!*s)
4988                                 break;
4989                         tempchar = *s;
4990                         shadow = true;
4991                         // check for modifier flags
4992                         if (*t == '!')
4993                         {
4994                                 shadow = false;
4995                                 t++;
4996                         }
4997                         *s = 0;
4998 #if _MSC_VER >= 1400
4999 #define sscanf sscanf_s
5000 #endif
5001                         cubemapname[sizeof(cubemapname)-1] = 0;
5002 #if MAX_QPATH != 128
5003 #error update this code if MAX_QPATH changes
5004 #endif
5005                         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
5006 #if _MSC_VER >= 1400
5007 , sizeof(cubemapname)
5008 #endif
5009 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
5010                         *s = tempchar;
5011                         if (a < 18)
5012                                 flags = LIGHTFLAG_REALTIMEMODE;
5013                         if (a < 17)
5014                                 specularscale = 1;
5015                         if (a < 16)
5016                                 diffusescale = 1;
5017                         if (a < 15)
5018                                 ambientscale = 0;
5019                         if (a < 14)
5020                                 coronasizescale = 0.25f;
5021                         if (a < 13)
5022                                 VectorClear(angles);
5023                         if (a < 10)
5024                                 corona = 0;
5025                         if (a < 9 || !strcmp(cubemapname, "\"\""))
5026                                 cubemapname[0] = 0;
5027                         // remove quotes on cubemapname
5028                         if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
5029                         {
5030                                 size_t namelen;
5031                                 namelen = strlen(cubemapname) - 2;
5032                                 memmove(cubemapname, cubemapname + 1, namelen);
5033                                 cubemapname[namelen] = '\0';
5034                         }
5035                         if (a < 8)
5036                         {
5037                                 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);
5038                                 break;
5039                         }
5040                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5041                         if (*s == '\r')
5042                                 s++;
5043                         if (*s == '\n')
5044                                 s++;
5045                         n++;
5046                 }
5047                 if (*s)
5048                         Con_Printf("invalid rtlights file \"%s\"\n", name);
5049                 Mem_Free(lightsstring);
5050         }
5051 }
5052
5053 void R_Shadow_SaveWorldLights(void)
5054 {
5055         size_t lightindex;
5056         dlight_t *light;
5057         size_t bufchars, bufmaxchars;
5058         char *buf, *oldbuf;
5059         char name[MAX_QPATH];
5060         char line[MAX_INPUTLINE];
5061         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5062         // I hate lines which are 3 times my screen size :( --blub
5063         if (!range)
5064                 return;
5065         if (cl.worldmodel == NULL)
5066         {
5067                 Con_Print("No map loaded.\n");
5068                 return;
5069         }
5070         FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
5071         strlcat (name, ".rtlights", sizeof (name));
5072         bufchars = bufmaxchars = 0;
5073         buf = NULL;
5074         for (lightindex = 0;lightindex < range;lightindex++)
5075         {
5076                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5077                 if (!light)
5078                         continue;
5079                 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5080                         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);
5081                 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5082                         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]);
5083                 else
5084                         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);
5085                 if (bufchars + strlen(line) > bufmaxchars)
5086                 {
5087                         bufmaxchars = bufchars + strlen(line) + 2048;
5088                         oldbuf = buf;
5089                         buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5090                         if (oldbuf)
5091                         {
5092                                 if (bufchars)
5093                                         memcpy(buf, oldbuf, bufchars);
5094                                 Mem_Free(oldbuf);
5095                         }
5096                 }
5097                 if (strlen(line))
5098                 {
5099                         memcpy(buf + bufchars, line, strlen(line));
5100                         bufchars += strlen(line);
5101                 }
5102         }
5103         if (bufchars)
5104                 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5105         if (buf)
5106                 Mem_Free(buf);
5107 }
5108
5109 void R_Shadow_LoadLightsFile(void)
5110 {
5111         int n, a, style;
5112         char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5113         float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5114         if (cl.worldmodel == NULL)
5115         {
5116                 Con_Print("No map loaded.\n");
5117                 return;
5118         }
5119         FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
5120         strlcat (name, ".lights", sizeof (name));
5121         lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5122         if (lightsstring)
5123         {
5124                 s = lightsstring;
5125                 n = 0;
5126                 while (*s)
5127                 {
5128                         t = s;
5129                         while (*s && *s != '\n' && *s != '\r')
5130                                 s++;
5131                         if (!*s)
5132                                 break;
5133                         tempchar = *s;
5134                         *s = 0;
5135                         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);
5136                         *s = tempchar;
5137                         if (a < 14)
5138                         {
5139                                 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);
5140                                 break;
5141                         }
5142                         radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5143                         radius = bound(15, radius, 4096);
5144                         VectorScale(color, (2.0f / (8388608.0f)), color);
5145                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5146                         if (*s == '\r')
5147                                 s++;
5148                         if (*s == '\n')
5149                                 s++;
5150                         n++;
5151                 }
5152                 if (*s)
5153                         Con_Printf("invalid lights file \"%s\"\n", name);
5154                 Mem_Free(lightsstring);
5155         }
5156 }
5157
5158 // tyrlite/hmap2 light types in the delay field
5159 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5160
5161 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5162 {
5163         int entnum, style, islight, skin, pflags, effects, type, n;
5164         char *entfiledata;
5165         const char *data;
5166         float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5167         char key[256], value[MAX_INPUTLINE];
5168
5169         if (cl.worldmodel == NULL)
5170         {
5171                 Con_Print("No map loaded.\n");
5172                 return;
5173         }
5174         // try to load a .ent file first
5175         FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
5176         strlcat (key, ".ent", sizeof (key));
5177         data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5178         // and if that is not found, fall back to the bsp file entity string
5179         if (!data)
5180                 data = cl.worldmodel->brush.entities;
5181         if (!data)
5182                 return;
5183         for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5184         {
5185                 type = LIGHTTYPE_MINUSX;
5186                 origin[0] = origin[1] = origin[2] = 0;
5187                 originhack[0] = originhack[1] = originhack[2] = 0;
5188                 angles[0] = angles[1] = angles[2] = 0;
5189                 color[0] = color[1] = color[2] = 1;
5190                 light[0] = light[1] = light[2] = 1;light[3] = 300;
5191                 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5192                 fadescale = 1;
5193                 lightscale = 1;
5194                 style = 0;
5195                 skin = 0;
5196                 pflags = 0;
5197                 effects = 0;
5198                 islight = false;
5199                 while (1)
5200                 {
5201                         if (!COM_ParseToken_Simple(&data, false, false))
5202                                 break; // error
5203                         if (com_token[0] == '}')
5204                                 break; // end of entity
5205                         if (com_token[0] == '_')
5206                                 strlcpy(key, com_token + 1, sizeof(key));
5207                         else
5208                                 strlcpy(key, com_token, sizeof(key));
5209                         while (key[strlen(key)-1] == ' ') // remove trailing spaces
5210                                 key[strlen(key)-1] = 0;
5211                         if (!COM_ParseToken_Simple(&data, false, false))
5212                                 break; // error
5213                         strlcpy(value, com_token, sizeof(value));
5214
5215                         // now that we have the key pair worked out...
5216                         if (!strcmp("light", key))
5217                         {
5218                                 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5219                                 if (n == 1)
5220                                 {
5221                                         // quake
5222                                         light[0] = vec[0] * (1.0f / 256.0f);
5223                                         light[1] = vec[0] * (1.0f / 256.0f);
5224                                         light[2] = vec[0] * (1.0f / 256.0f);
5225                                         light[3] = vec[0];
5226                                 }
5227                                 else if (n == 4)
5228                                 {
5229                                         // halflife
5230                                         light[0] = vec[0] * (1.0f / 255.0f);
5231                                         light[1] = vec[1] * (1.0f / 255.0f);
5232                                         light[2] = vec[2] * (1.0f / 255.0f);
5233                                         light[3] = vec[3];
5234                                 }
5235                         }
5236                         else if (!strcmp("delay", key))
5237                                 type = atoi(value);
5238                         else if (!strcmp("origin", key))
5239                                 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5240                         else if (!strcmp("angle", key))
5241                                 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5242                         else if (!strcmp("angles", key))
5243                                 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5244                         else if (!strcmp("color", key))
5245                                 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5246                         else if (!strcmp("wait", key))
5247                                 fadescale = atof(value);
5248                         else if (!strcmp("classname", key))
5249                         {
5250                                 if (!strncmp(value, "light", 5))
5251                                 {
5252                                         islight = true;
5253                                         if (!strcmp(value, "light_fluoro"))
5254                                         {
5255                                                 originhack[0] = 0;
5256                                                 originhack[1] = 0;
5257                                                 originhack[2] = 0;
5258                                                 overridecolor[0] = 1;
5259                                                 overridecolor[1] = 1;
5260                                                 overridecolor[2] = 1;
5261                                         }
5262                                         if (!strcmp(value, "light_fluorospark"))
5263                                         {
5264                                                 originhack[0] = 0;
5265                                                 originhack[1] = 0;
5266                                                 originhack[2] = 0;
5267                                                 overridecolor[0] = 1;
5268                                                 overridecolor[1] = 1;
5269                                                 overridecolor[2] = 1;
5270                                         }
5271                                         if (!strcmp(value, "light_globe"))
5272                                         {
5273                                                 originhack[0] = 0;
5274                                                 originhack[1] = 0;
5275                                                 originhack[2] = 0;
5276                                                 overridecolor[0] = 1;
5277                                                 overridecolor[1] = 0.8;
5278                                                 overridecolor[2] = 0.4;
5279                                         }
5280                                         if (!strcmp(value, "light_flame_large_yellow"))
5281                                         {
5282                                                 originhack[0] = 0;
5283                                                 originhack[1] = 0;
5284                                                 originhack[2] = 0;
5285                                                 overridecolor[0] = 1;
5286                                                 overridecolor[1] = 0.5;
5287                                                 overridecolor[2] = 0.1;
5288                                         }
5289                                         if (!strcmp(value, "light_flame_small_yellow"))
5290                                         {
5291                                                 originhack[0] = 0;
5292                                                 originhack[1] = 0;
5293                                                 originhack[2] = 0;
5294                                                 overridecolor[0] = 1;
5295                                                 overridecolor[1] = 0.5;
5296                                                 overridecolor[2] = 0.1;
5297                                         }
5298                                         if (!strcmp(value, "light_torch_small_white"))
5299                                         {
5300                                                 originhack[0] = 0;
5301                                                 originhack[1] = 0;
5302                                                 originhack[2] = 0;
5303                                                 overridecolor[0] = 1;
5304                                                 overridecolor[1] = 0.5;
5305                                                 overridecolor[2] = 0.1;
5306                                         }
5307                                         if (!strcmp(value, "light_torch_small_walltorch"))
5308                                         {
5309                                                 originhack[0] = 0;
5310                                                 originhack[1] = 0;
5311                                                 originhack[2] = 0;
5312                                                 overridecolor[0] = 1;
5313                                                 overridecolor[1] = 0.5;
5314                                                 overridecolor[2] = 0.1;
5315                                         }
5316                                 }
5317                         }
5318                         else if (!strcmp("style", key))
5319                                 style = atoi(value);
5320                         else if (!strcmp("skin", key))
5321                                 skin = (int)atof(value);
5322                         else if (!strcmp("pflags", key))
5323                                 pflags = (int)atof(value);
5324                         else if (!strcmp("effects", key))
5325                                 effects = (int)atof(value);
5326                         else if (cl.worldmodel->type == mod_brushq3)
5327                         {
5328                                 if (!strcmp("scale", key))
5329                                         lightscale = atof(value);
5330                                 if (!strcmp("fade", key))
5331                                         fadescale = atof(value);
5332                         }
5333                 }
5334                 if (!islight)
5335                         continue;
5336                 if (lightscale <= 0)
5337                         lightscale = 1;
5338                 if (fadescale <= 0)
5339                         fadescale = 1;
5340                 if (color[0] == color[1] && color[0] == color[2])
5341                 {
5342                         color[0] *= overridecolor[0];
5343                         color[1] *= overridecolor[1];
5344                         color[2] *= overridecolor[2];
5345                 }
5346                 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5347                 color[0] = color[0] * light[0];
5348                 color[1] = color[1] * light[1];
5349                 color[2] = color[2] * light[2];
5350                 switch (type)
5351                 {
5352                 case LIGHTTYPE_MINUSX:
5353                         break;
5354                 case LIGHTTYPE_RECIPX:
5355                         radius *= 2;
5356                         VectorScale(color, (1.0f / 16.0f), color);
5357                         break;
5358                 case LIGHTTYPE_RECIPXX:
5359                         radius *= 2;
5360                         VectorScale(color, (1.0f / 16.0f), color);
5361                         break;
5362                 default:
5363                 case LIGHTTYPE_NONE:
5364                         break;
5365                 case LIGHTTYPE_SUN:
5366                         break;
5367                 case LIGHTTYPE_MINUSXX:
5368                         break;
5369                 }
5370                 VectorAdd(origin, originhack, origin);
5371                 if (radius >= 1)
5372                         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);
5373         }
5374         if (entfiledata)
5375                 Mem_Free(entfiledata);
5376 }
5377
5378
5379 void R_Shadow_SetCursorLocationForView(void)
5380 {
5381         vec_t dist, push;
5382         vec3_t dest, endpos;
5383         trace_t trace;
5384         VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5385         trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5386         if (trace.fraction < 1)
5387         {
5388                 dist = trace.fraction * r_editlights_cursordistance.value;
5389                 push = r_editlights_cursorpushback.value;
5390                 if (push > dist)
5391                         push = dist;
5392                 push = -push;
5393                 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5394                 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5395         }
5396         else
5397         {
5398                 VectorClear( endpos );
5399         }
5400         r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5401         r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5402         r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5403 }
5404
5405 void R_Shadow_UpdateWorldLightSelection(void)
5406 {
5407         if (r_editlights.integer)
5408         {
5409                 R_Shadow_SetCursorLocationForView();
5410                 R_Shadow_SelectLightInView();
5411         }
5412         else
5413                 R_Shadow_SelectLight(NULL);
5414 }
5415
5416 void R_Shadow_EditLights_Clear_f(void)
5417 {
5418         R_Shadow_ClearWorldLights();
5419 }
5420
5421 void R_Shadow_EditLights_Reload_f(void)
5422 {
5423         if (!cl.worldmodel)
5424                 return;
5425         strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
5426         R_Shadow_ClearWorldLights();
5427         R_Shadow_LoadWorldLights();
5428         if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5429         {
5430                 R_Shadow_LoadLightsFile();
5431                 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5432                         R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5433         }
5434 }
5435
5436 void R_Shadow_EditLights_Save_f(void)
5437 {
5438         if (!cl.worldmodel)
5439                 return;
5440         R_Shadow_SaveWorldLights();
5441 }
5442
5443 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5444 {
5445         R_Shadow_ClearWorldLights();
5446         R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5447 }
5448
5449 void R_Shadow_EditLights_ImportLightsFile_f(void)
5450 {
5451         R_Shadow_ClearWorldLights();
5452         R_Shadow_LoadLightsFile();
5453 }
5454
5455 void R_Shadow_EditLights_Spawn_f(void)
5456 {
5457         vec3_t color;
5458         if (!r_editlights.integer)
5459         {
5460                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
5461                 return;
5462         }
5463         if (Cmd_Argc() != 1)
5464         {
5465                 Con_Print("r_editlights_spawn does not take parameters\n");
5466                 return;
5467         }
5468         color[0] = color[1] = color[2] = 1;
5469         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5470 }
5471
5472 void R_Shadow_EditLights_Edit_f(void)
5473 {
5474         vec3_t origin, angles, color;
5475         vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5476         int style, shadows, flags, normalmode, realtimemode;
5477         char cubemapname[MAX_INPUTLINE];
5478         if (!r_editlights.integer)
5479         {
5480                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
5481                 return;
5482         }
5483         if (!r_shadow_selectedlight)
5484         {
5485                 Con_Print("No selected light.\n");
5486                 return;
5487         }
5488         VectorCopy(r_shadow_selectedlight->origin, origin);
5489         VectorCopy(r_shadow_selectedlight->angles, angles);
5490         VectorCopy(r_shadow_selectedlight->color, color);
5491         radius = r_shadow_selectedlight->radius;
5492         style = r_shadow_selectedlight->style;
5493         if (r_shadow_selectedlight->cubemapname)
5494                 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5495         else
5496                 cubemapname[0] = 0;
5497         shadows = r_shadow_selectedlight->shadow;
5498         corona = r_shadow_selectedlight->corona;
5499         coronasizescale = r_shadow_selectedlight->coronasizescale;
5500         ambientscale = r_shadow_selectedlight->ambientscale;
5501         diffusescale = r_shadow_selectedlight->diffusescale;
5502         specularscale = r_shadow_selectedlight->specularscale;
5503         flags = r_shadow_selectedlight->flags;
5504         normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5505         realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5506         if (!strcmp(Cmd_Argv(1), "origin"))
5507         {
5508                 if (Cmd_Argc() != 5)
5509                 {
5510                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5511                         return;
5512                 }
5513                 origin[0] = atof(Cmd_Argv(2));
5514                 origin[1] = atof(Cmd_Argv(3));
5515                 origin[2] = atof(Cmd_Argv(4));
5516         }
5517         else if (!strcmp(Cmd_Argv(1), "originx"))
5518         {
5519                 if (Cmd_Argc() != 3)
5520                 {
5521                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5522                         return;
5523                 }
5524                 origin[0] = atof(Cmd_Argv(2));
5525         }
5526         else if (!strcmp(Cmd_Argv(1), "originy"))
5527         {
5528                 if (Cmd_Argc() != 3)
5529                 {
5530                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5531                         return;
5532                 }
5533                 origin[1] = atof(Cmd_Argv(2));
5534         }
5535         else if (!strcmp(Cmd_Argv(1), "originz"))
5536         {
5537                 if (Cmd_Argc() != 3)
5538                 {
5539                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5540                         return;
5541                 }
5542                 origin[2] = atof(Cmd_Argv(2));
5543         }
5544         else if (!strcmp(Cmd_Argv(1), "move"))
5545         {
5546                 if (Cmd_Argc() != 5)
5547                 {
5548                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5549                         return;
5550                 }
5551                 origin[0] += atof(Cmd_Argv(2));
5552                 origin[1] += atof(Cmd_Argv(3));
5553                 origin[2] += atof(Cmd_Argv(4));
5554         }
5555         else if (!strcmp(Cmd_Argv(1), "movex"))
5556         {
5557                 if (Cmd_Argc() != 3)
5558                 {
5559                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5560                         return;
5561                 }
5562                 origin[0] += atof(Cmd_Argv(2));
5563         }
5564         else if (!strcmp(Cmd_Argv(1), "movey"))
5565         {
5566                 if (Cmd_Argc() != 3)
5567                 {
5568                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5569                         return;
5570                 }
5571                 origin[1] += atof(Cmd_Argv(2));
5572         }
5573         else if (!strcmp(Cmd_Argv(1), "movez"))
5574         {
5575                 if (Cmd_Argc() != 3)
5576                 {
5577                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5578                         return;
5579                 }
5580                 origin[2] += atof(Cmd_Argv(2));
5581         }
5582         else if (!strcmp(Cmd_Argv(1), "angles"))
5583         {
5584                 if (Cmd_Argc() != 5)
5585                 {
5586                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5587                         return;
5588                 }
5589                 angles[0] = atof(Cmd_Argv(2));
5590                 angles[1] = atof(Cmd_Argv(3));
5591                 angles[2] = atof(Cmd_Argv(4));
5592         }
5593         else if (!strcmp(Cmd_Argv(1), "anglesx"))
5594         {
5595                 if (Cmd_Argc() != 3)
5596                 {
5597                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5598                         return;
5599                 }
5600                 angles[0] = atof(Cmd_Argv(2));
5601         }
5602         else if (!strcmp(Cmd_Argv(1), "anglesy"))
5603         {
5604                 if (Cmd_Argc() != 3)
5605                 {
5606                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5607                         return;
5608                 }
5609                 angles[1] = atof(Cmd_Argv(2));
5610         }
5611         else if (!strcmp(Cmd_Argv(1), "anglesz"))
5612         {
5613                 if (Cmd_Argc() != 3)
5614                 {
5615                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5616                         return;
5617                 }
5618                 angles[2] = atof(Cmd_Argv(2));
5619         }
5620         else if (!strcmp(Cmd_Argv(1), "color"))
5621         {
5622                 if (Cmd_Argc() != 5)
5623                 {
5624                         Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5625                         return;
5626                 }
5627                 color[0] = atof(Cmd_Argv(2));
5628                 color[1] = atof(Cmd_Argv(3));
5629                 color[2] = atof(Cmd_Argv(4));
5630         }
5631         else if (!strcmp(Cmd_Argv(1), "radius"))
5632         {
5633                 if (Cmd_Argc() != 3)
5634                 {
5635                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5636                         return;
5637                 }
5638                 radius = atof(Cmd_Argv(2));
5639         }
5640         else if (!strcmp(Cmd_Argv(1), "colorscale"))
5641         {
5642                 if (Cmd_Argc() == 3)
5643                 {
5644                         double scale = atof(Cmd_Argv(2));
5645                         color[0] *= scale;
5646                         color[1] *= scale;
5647                         color[2] *= scale;
5648                 }
5649                 else
5650                 {
5651                         if (Cmd_Argc() != 5)
5652                         {
5653                                 Con_Printf("usage: r_editlights_edit %s red green blue  (OR grey instead of red green blue)\n", Cmd_Argv(1));
5654                                 return;
5655                         }
5656                         color[0] *= atof(Cmd_Argv(2));
5657                         color[1] *= atof(Cmd_Argv(3));
5658                         color[2] *= atof(Cmd_Argv(4));
5659                 }
5660         }
5661         else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5662         {
5663                 if (Cmd_Argc() != 3)
5664                 {
5665                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5666                         return;
5667                 }
5668                 radius *= atof(Cmd_Argv(2));
5669         }
5670         else if (!strcmp(Cmd_Argv(1), "style"))
5671         {
5672                 if (Cmd_Argc() != 3)
5673                 {
5674                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5675                         return;
5676                 }
5677                 style = atoi(Cmd_Argv(2));
5678         }
5679         else if (!strcmp(Cmd_Argv(1), "cubemap"))
5680         {
5681                 if (Cmd_Argc() > 3)
5682                 {
5683                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5684                         return;
5685                 }
5686                 if (Cmd_Argc() == 3)
5687                         strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5688                 else
5689                         cubemapname[0] = 0;
5690         }
5691         else if (!strcmp(Cmd_Argv(1), "shadows"))
5692         {
5693                 if (Cmd_Argc() != 3)
5694                 {
5695                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5696                         return;
5697                 }
5698                 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5699         }
5700         else if (!strcmp(Cmd_Argv(1), "corona"))
5701         {
5702                 if (Cmd_Argc() != 3)
5703                 {
5704                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5705                         return;
5706                 }
5707                 corona = atof(Cmd_Argv(2));
5708         }
5709         else if (!strcmp(Cmd_Argv(1), "coronasize"))
5710         {
5711                 if (Cmd_Argc() != 3)
5712                 {
5713                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5714                         return;
5715                 }
5716                 coronasizescale = atof(Cmd_Argv(2));
5717         }
5718         else if (!strcmp(Cmd_Argv(1), "ambient"))
5719         {
5720                 if (Cmd_Argc() != 3)
5721                 {
5722                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5723                         return;
5724                 }
5725                 ambientscale = atof(Cmd_Argv(2));
5726         }
5727         else if (!strcmp(Cmd_Argv(1), "diffuse"))
5728         {
5729                 if (Cmd_Argc() != 3)
5730                 {
5731                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5732                         return;
5733                 }
5734                 diffusescale = atof(Cmd_Argv(2));
5735         }
5736         else if (!strcmp(Cmd_Argv(1), "specular"))
5737         {
5738                 if (Cmd_Argc() != 3)
5739                 {
5740                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5741                         return;
5742                 }
5743                 specularscale = atof(Cmd_Argv(2));
5744         }
5745         else if (!strcmp(Cmd_Argv(1), "normalmode"))
5746         {
5747                 if (Cmd_Argc() != 3)
5748                 {
5749                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5750                         return;
5751                 }
5752                 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5753         }
5754         else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5755         {
5756                 if (Cmd_Argc() != 3)
5757                 {
5758                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5759                         return;
5760                 }
5761                 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5762         }
5763         else
5764         {
5765                 Con_Print("usage: r_editlights_edit [property] [value]\n");
5766                 Con_Print("Selected light's properties:\n");
5767                 Con_Printf("Origin       : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5768                 Con_Printf("Angles       : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5769                 Con_Printf("Color        : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5770                 Con_Printf("Radius       : %f\n", r_shadow_selectedlight->radius);
5771                 Con_Printf("Corona       : %f\n", r_shadow_selectedlight->corona);
5772                 Con_Printf("Style        : %i\n", r_shadow_selectedlight->style);
5773                 Con_Printf("Shadows      : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5774                 Con_Printf("Cubemap      : %s\n", r_shadow_selectedlight->cubemapname);
5775                 Con_Printf("CoronaSize   : %f\n", r_shadow_selectedlight->coronasizescale);
5776                 Con_Printf("Ambient      : %f\n", r_shadow_selectedlight->ambientscale);
5777                 Con_Printf("Diffuse      : %f\n", r_shadow_selectedlight->diffusescale);
5778                 Con_Printf("Specular     : %f\n", r_shadow_selectedlight->specularscale);
5779                 Con_Printf("NormalMode   : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5780                 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5781                 return;
5782         }
5783         flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5784         R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5785 }
5786
5787 void R_Shadow_EditLights_EditAll_f(void)
5788 {
5789         size_t lightindex;
5790         dlight_t *light;
5791         size_t range;
5792
5793         if (!r_editlights.integer)
5794         {
5795                 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5796                 return;
5797         }
5798
5799         // EditLights doesn't seem to have a "remove" command or something so:
5800         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5801         for (lightindex = 0;lightindex < range;lightindex++)
5802         {
5803                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5804                 if (!light)
5805                         continue;
5806                 R_Shadow_SelectLight(light);
5807                 R_Shadow_EditLights_Edit_f();
5808         }
5809 }
5810
5811 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5812 {
5813         int lightnumber, lightcount;
5814         size_t lightindex, range;
5815         dlight_t *light;
5816         float x, y;
5817         char temp[256];
5818         if (!r_editlights.integer)
5819                 return;
5820         x = vid_conwidth.value - 240;
5821         y = 5;
5822         DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5823         lightnumber = -1;
5824         lightcount = 0;
5825         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5826         for (lightindex = 0;lightindex < range;lightindex++)
5827         {
5828                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5829                 if (!light)
5830                         continue;
5831                 if (light == r_shadow_selectedlight)
5832                         lightnumber = lightindex;
5833                 lightcount++;
5834         }
5835         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;
5836         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;
5837         y += 8;
5838         if (r_shadow_selectedlight == NULL)
5839                 return;
5840         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;
5841         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;
5842         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;
5843         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;
5844         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;
5845         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;
5846         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;
5847         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;
5848         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;
5849         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;
5850         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;
5851         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;
5852         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;
5853         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;
5854         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;
5855 }
5856
5857 void R_Shadow_EditLights_ToggleShadow_f(void)
5858 {
5859         if (!r_editlights.integer)
5860         {
5861                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
5862                 return;
5863         }
5864         if (!r_shadow_selectedlight)
5865         {
5866                 Con_Print("No selected light.\n");
5867                 return;
5868         }
5869         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);
5870 }
5871
5872 void R_Shadow_EditLights_ToggleCorona_f(void)
5873 {
5874         if (!r_editlights.integer)
5875         {
5876                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
5877                 return;
5878         }
5879         if (!r_shadow_selectedlight)
5880         {
5881                 Con_Print("No selected light.\n");
5882                 return;
5883         }
5884         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);
5885 }
5886
5887 void R_Shadow_EditLights_Remove_f(void)
5888 {
5889         if (!r_editlights.integer)
5890         {
5891                 Con_Print("Cannot remove light when not in editing mode.  Set r_editlights to 1.\n");
5892                 return;
5893         }
5894         if (!r_shadow_selectedlight)
5895         {
5896                 Con_Print("No selected light.\n");
5897                 return;
5898         }
5899         R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5900         r_shadow_selectedlight = NULL;
5901 }
5902
5903 void R_Shadow_EditLights_Help_f(void)
5904 {
5905         Con_Print(
5906 "Documentation on r_editlights system:\n"
5907 "Settings:\n"
5908 "r_editlights : enable/disable editing mode\n"
5909 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5910 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5911 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5912 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5913 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5914 "Commands:\n"
5915 "r_editlights_help : this help\n"
5916 "r_editlights_clear : remove all lights\n"
5917 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5918 "r_editlights_save : save to .rtlights file\n"
5919 "r_editlights_spawn : create a light with default settings\n"
5920 "r_editlights_edit command : edit selected light - more documentation below\n"
5921 "r_editlights_remove : remove selected light\n"
5922 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5923 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5924 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5925 "Edit commands:\n"
5926 "origin x y z : set light location\n"
5927 "originx x: set x component of light location\n"
5928 "originy y: set y component of light location\n"
5929 "originz z: set z component of light location\n"
5930 "move x y z : adjust light location\n"
5931 "movex x: adjust x component of light location\n"
5932 "movey y: adjust y component of light location\n"
5933 "movez z: adjust z component of light location\n"
5934 "angles x y z : set light angles\n"
5935 "anglesx x: set x component of light angles\n"
5936 "anglesy y: set y component of light angles\n"
5937 "anglesz z: set z component of light angles\n"
5938 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5939 "radius radius : set radius (size) of light\n"
5940 "colorscale grey : multiply color of light (1 does nothing)\n"
5941 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5942 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5943 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5944 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5945 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5946 "shadows 1/0 : turn on/off shadows\n"
5947 "corona n : set corona intensity\n"
5948 "coronasize n : set corona size (0-1)\n"
5949 "ambient n : set ambient intensity (0-1)\n"
5950 "diffuse n : set diffuse intensity (0-1)\n"
5951 "specular n : set specular intensity (0-1)\n"
5952 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5953 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5954 "<nothing> : print light properties to console\n"
5955         );
5956 }
5957
5958 void R_Shadow_EditLights_CopyInfo_f(void)
5959 {
5960         if (!r_editlights.integer)
5961         {
5962                 Con_Print("Cannot copy light info when not in editing mode.  Set r_editlights to 1.\n");
5963                 return;
5964         }
5965         if (!r_shadow_selectedlight)
5966         {
5967                 Con_Print("No selected light.\n");
5968                 return;
5969         }
5970         VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5971         VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5972         r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5973         r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5974         if (r_shadow_selectedlight->cubemapname)
5975                 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5976         else
5977                 r_shadow_bufferlight.cubemapname[0] = 0;
5978         r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5979         r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5980         r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5981         r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5982         r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5983         r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5984         r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5985 }
5986
5987 void R_Shadow_EditLights_PasteInfo_f(void)
5988 {
5989         if (!r_editlights.integer)
5990         {
5991                 Con_Print("Cannot paste light info when not in editing mode.  Set r_editlights to 1.\n");
5992                 return;
5993         }
5994         if (!r_shadow_selectedlight)
5995         {
5996                 Con_Print("No selected light.\n");
5997                 return;
5998         }
5999         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);
6000 }
6001
6002 void R_Shadow_EditLights_Init(void)
6003 {
6004         Cvar_RegisterVariable(&r_editlights);
6005         Cvar_RegisterVariable(&r_editlights_cursordistance);
6006         Cvar_RegisterVariable(&r_editlights_cursorpushback);
6007         Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6008         Cvar_RegisterVariable(&r_editlights_cursorgrid);
6009         Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6010         Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6011         Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6012         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)");
6013         Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6014         Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6015         Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6016         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)");
6017         Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6018         Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6019         Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6020         Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6021         Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6022         Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6023         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)");
6024 }
6025
6026
6027
6028 /*
6029 =============================================================================
6030
6031 LIGHT SAMPLING
6032
6033 =============================================================================
6034 */
6035
6036 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
6037 {
6038         VectorClear(diffusecolor);
6039         VectorClear(diffusenormal);
6040
6041         if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6042         {
6043                 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient * (2.0f / 128.0f);
6044                 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
6045         }
6046         else
6047                 VectorSet(ambientcolor, 1, 1, 1);
6048
6049         if (dynamic)
6050         {
6051                 int i;
6052                 float f, v[3];
6053                 rtlight_t *light;
6054                 for (i = 0;i < r_refdef.scene.numlights;i++)
6055                 {
6056                         light = r_refdef.scene.lights[i];
6057                         Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
6058                         f = 1 - VectorLength2(v);
6059                         if (f > 0 && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
6060                                 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);
6061                 }
6062         }
6063 }