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