]> icculus.org git repositories - divverent/darkplaces.git/blob - r_shadow.c
removed DOT3 lighting path (bumpmapped lighting on pre-shader cards)
[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
1293         {
1294                 // decide which type of shadow to generate and set stencil mode
1295                 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1296                 // generate the sides or a solid volume, depending on type
1297                 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1298                         tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1299                 else
1300                         tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1301                 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1302                 r_refdef.stats.lights_shadowtriangles += tris;
1303                 CHECKGLERROR
1304                 R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
1305                 GL_LockArrays(0, outverts);
1306                 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1307                 {
1308                         // increment stencil if frontface is infront of depthbuffer
1309                         GL_CullFace(r_refdef.view.cullface_front);
1310                         qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1311                         R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1312                         // decrement stencil if backface is infront of depthbuffer
1313                         GL_CullFace(r_refdef.view.cullface_back);
1314                         qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1315                 }
1316                 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1317                 {
1318                         // decrement stencil if backface is behind depthbuffer
1319                         GL_CullFace(r_refdef.view.cullface_front);
1320                         qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1321                         R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1322                         // increment stencil if frontface is behind depthbuffer
1323                         GL_CullFace(r_refdef.view.cullface_back);
1324                         qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1325                 }
1326                 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1327                 GL_LockArrays(0, 0);
1328                 CHECKGLERROR
1329         }
1330 }
1331
1332 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1333 {
1334     // p1, p2, p3 are in the cubemap's local coordinate system
1335     // bias = border/(size - border)
1336         int mask = 0x3F;
1337
1338     float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1339           dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1340           dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1341         if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1342         mask &= (3<<4)
1343                         | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1344                         | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1345                         | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1346     if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1347         mask &= (3<<4)
1348             | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1349             | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))            
1350             | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1351
1352     dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1353     dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1354     dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1355     if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1356         mask &= (3<<0)
1357             | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1358             | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))            
1359             | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1360     if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1361         mask &= (3<<0)
1362             | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1363             | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1364             | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1365
1366     dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1367     dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1368     dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1369     if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1370         mask &= (3<<2)
1371             | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1372             | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1373             | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1374     if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1375         mask &= (3<<2)
1376             | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1377             | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1378             | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1379
1380         return mask;
1381 }
1382
1383 int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1384 {
1385         vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1386         float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1387         int mask = 0x3F;
1388
1389         VectorSubtract(maxs, mins, radius);
1390     VectorScale(radius, 0.5f, radius);
1391     VectorAdd(mins, radius, center);
1392     Matrix4x4_Transform(worldtolight, center, lightcenter);
1393         Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1394         VectorSubtract(lightcenter, lightradius, pmin);
1395         VectorAdd(lightcenter, lightradius, pmax);
1396
1397     dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1398     dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1399     if(ap1 > bias*an1 && ap2 > bias*an2)
1400         mask &= (3<<4)
1401             | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1402             | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1403     if(an1 > bias*ap1 && an2 > bias*ap2)
1404         mask &= (3<<4)
1405             | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1406             | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1407
1408     dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1409     dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1410     if(ap1 > bias*an1 && ap2 > bias*an2)
1411         mask &= (3<<0)
1412             | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1413             | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1414     if(an1 > bias*ap1 && an2 > bias*ap2)
1415         mask &= (3<<0)
1416             | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1417             | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1418
1419     dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1420     dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1421     if(ap1 > bias*an1 && ap2 > bias*an2)
1422         mask &= (3<<2)
1423             | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1424             | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1425     if(an1 > bias*ap1 && an2 > bias*ap2)
1426         mask &= (3<<2)
1427             | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1428             | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1429
1430     return mask;
1431 }
1432
1433 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1434
1435 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1436 {
1437     // p is in the cubemap's local coordinate system
1438     // bias = border/(size - border)
1439     float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1440     float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1441     float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1442     int mask = 0x3F;
1443     if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1444     if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1445     if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1446     if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1447     if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1448     if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1449     return mask;
1450 }
1451
1452 int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1453 {
1454         int i;
1455         vec3_t p, n;
1456         int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1457         float scale = (size - 2*border)/size, len;
1458         float bias = border / (float)(size - border), dp, dn, ap, an;
1459         // check if cone enclosing side would cross frustum plane 
1460         scale = 2 / (scale*scale + 2);
1461         for (i = 0;i < 5;i++)
1462         {
1463                 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) > -0.03125)
1464                         continue;
1465                 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1466                 len = scale*VectorLength2(n);
1467                 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1468                 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1469                 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1470         }
1471         if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1472         {
1473         Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1474         len = scale*VectorLength(n);
1475                 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1476                 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1477                 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1478         }
1479         // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1480         // check if frustum corners/origin cross plane sides
1481         for (i = 0;i < 5;i++)
1482         {
1483                 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1484                 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn),
1485                 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1486                 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1487                 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn),
1488                 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1489                 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1490                 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn),
1491                 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1492                 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1493         }
1494         return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1495 }
1496
1497 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)
1498 {
1499         int t, tend;
1500         const int *e;
1501         const float *v[3];
1502         float normal[3];
1503         vec3_t p[3];
1504         float bias;
1505         int mask, surfacemask = 0;
1506         if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1507                 return 0;
1508         bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1509         tend = firsttriangle + numtris;
1510         if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1511         {
1512                 // surface box entirely inside light box, no box cull
1513                 if (projectdirection)
1514                 {
1515                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1516                         {
1517                                 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1518                                 TriangleNormal(v[0], v[1], v[2], normal);
1519                                 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1520                                 {
1521                                         Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1522                                         mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1523                                         surfacemask |= mask;
1524                                         if(totals)
1525                                         {
1526                                                 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;
1527                                                 shadowsides[numshadowsides] = mask;
1528                                                 shadowsideslist[numshadowsides++] = t;
1529                                         }
1530                                 }
1531                         }
1532                 }
1533                 else
1534                 {
1535                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1536                         {
1537                                 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3,     v[2] = invertex3f + e[2] * 3;
1538                                 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1539                                 {
1540                                         Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1541                                         mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1542                                         surfacemask |= mask;
1543                                         if(totals)
1544                                         {
1545                                                 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;
1546                                                 shadowsides[numshadowsides] = mask;
1547                                                 shadowsideslist[numshadowsides++] = t;
1548                                         }
1549                                 }
1550                         }
1551                 }
1552         }
1553         else
1554         {
1555                 // surface box not entirely inside light box, cull each triangle
1556                 if (projectdirection)
1557                 {
1558                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1559                         {
1560                                 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3,     v[2] = invertex3f + e[2] * 3;
1561                                 TriangleNormal(v[0], v[1], v[2], normal);
1562                                 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1563                                  && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1564                                 {
1565                                         Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1566                                         mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1567                                         surfacemask |= mask;
1568                                         if(totals)
1569                                         {
1570                                                 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;
1571                                                 shadowsides[numshadowsides] = mask;
1572                                                 shadowsideslist[numshadowsides++] = t;
1573                                         }
1574                                 }
1575                         }
1576                 }
1577                 else
1578                 {
1579                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1580                         {
1581                                 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1582                                 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1583                                  && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1584                                 {
1585                                         Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1586                                         mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1587                                         surfacemask |= mask;
1588                                         if(totals)
1589                                         {
1590                                                 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;
1591                                                 shadowsides[numshadowsides] = mask;
1592                                                 shadowsideslist[numshadowsides++] = t;
1593                                         }
1594                                 }
1595                         }
1596                 }
1597         }
1598         return surfacemask;
1599 }
1600
1601 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)
1602 {
1603         int i, j, outtriangles = 0;
1604         int *outelement3i[6];
1605         if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1606                 return;
1607         outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1608         // make sure shadowelements is big enough for this mesh
1609         if (maxshadowtriangles < outtriangles)
1610                 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1611
1612         // compute the offset and size of the separate index lists for each cubemap side
1613         outtriangles = 0;
1614         for (i = 0;i < 6;i++)
1615         {
1616                 outelement3i[i] = shadowelements + outtriangles * 3;
1617                 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1618                 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1619                 outtriangles += sidetotals[i];
1620         }
1621
1622         // gather up the (sparse) triangles into separate index lists for each cubemap side
1623         for (i = 0;i < numsidetris;i++)
1624         {
1625                 const int *element = elements + sidetris[i] * 3;
1626                 for (j = 0;j < 6;j++)
1627                 {
1628                         if (sides[i] & (1 << j))
1629                         {
1630                                 outelement3i[j][0] = element[0];
1631                                 outelement3i[j][1] = element[1];
1632                                 outelement3i[j][2] = element[2];
1633                                 outelement3i[j] += 3;
1634                         }
1635                 }
1636         }
1637                         
1638         Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1639 }
1640
1641 static void R_Shadow_MakeTextures_MakeCorona(void)
1642 {
1643         float dx, dy;
1644         int x, y, a;
1645         unsigned char pixels[32][32][4];
1646         for (y = 0;y < 32;y++)
1647         {
1648                 dy = (y - 15.5f) * (1.0f / 16.0f);
1649                 for (x = 0;x < 32;x++)
1650                 {
1651                         dx = (x - 15.5f) * (1.0f / 16.0f);
1652                         a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1653                         a = bound(0, a, 255);
1654                         pixels[y][x][0] = a;
1655                         pixels[y][x][1] = a;
1656                         pixels[y][x][2] = a;
1657                         pixels[y][x][3] = 255;
1658                 }
1659         }
1660         r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_PRECACHE | TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32);
1661 }
1662
1663 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1664 {
1665         float dist = sqrt(x*x+y*y+z*z);
1666         float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1667         // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1668         return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1669 }
1670
1671 static void R_Shadow_MakeTextures(void)
1672 {
1673         int x, y, z;
1674         float intensity, dist;
1675         unsigned int *data;
1676         R_Shadow_FreeShadowMaps();
1677         R_FreeTexturePool(&r_shadow_texturepool);
1678         r_shadow_texturepool = R_AllocTexturePool();
1679         r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1680         r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1681         data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1682         // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1683         for (x = 0;x <= ATTENTABLESIZE;x++)
1684         {
1685                 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1686                 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1687                 r_shadow_attentable[x] = bound(0, intensity, 1);
1688         }
1689         // 1D gradient texture
1690         for (x = 0;x < ATTEN1DSIZE;x++)
1691                 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1692         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);
1693         // 2D circle texture
1694         for (y = 0;y < ATTEN2DSIZE;y++)
1695                 for (x = 0;x < ATTEN2DSIZE;x++)
1696                         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);
1697         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);
1698         // 3D sphere texture
1699         if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1700         {
1701                 for (z = 0;z < ATTEN3DSIZE;z++)
1702                         for (y = 0;y < ATTEN3DSIZE;y++)
1703                                 for (x = 0;x < ATTEN3DSIZE;x++)
1704                                         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));
1705                 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);
1706         }
1707         else
1708                 r_shadow_attenuation3dtexture = NULL;
1709         Mem_Free(data);
1710
1711         R_Shadow_MakeTextures_MakeCorona();
1712
1713         // Editor light sprites
1714         r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_PRECACHE | TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1715         "................"
1716         ".3............3."
1717         "..5...2332...5.."
1718         "...7.3....3.7..."
1719         "....7......7...."
1720         "...3.7....7.3..."
1721         "..2...7..7...2.."
1722         "..3..........3.."
1723         "..3..........3.."
1724         "..2...7..7...2.."
1725         "...3.7....7.3..."
1726         "....7......7...."
1727         "...7.3....3.7..."
1728         "..5...2332...5.."
1729         ".3............3."
1730         "................"
1731         , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1732         r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_PRECACHE | TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1733         "................"
1734         "................"
1735         "......1111......"
1736         "....11233211...."
1737         "...1234554321..."
1738         "...1356776531..."
1739         "..124677776421.."
1740         "..135777777531.."
1741         "..135777777531.."
1742         "..124677776421.."
1743         "...1356776531..."
1744         "...1234554321..."
1745         "....11233211...."
1746         "......1111......"
1747         "................"
1748         "................"
1749         , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1750         r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_PRECACHE | TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1751         "................"
1752         "................"
1753         "......1111......"
1754         "....11233211...."
1755         "...1234554321..."
1756         "...1356226531..."
1757         "..12462..26421.."
1758         "..1352....2531.."
1759         "..1352....2531.."
1760         "..12462..26421.."
1761         "...1356226531..."
1762         "...1234554321..."
1763         "....11233211...."
1764         "......1111......"
1765         "................"
1766         "................"
1767         , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1768         r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_PRECACHE | TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1769         "................"
1770         "................"
1771         "......2772......"
1772         "....27755772...."
1773         "..277533335772.."
1774         "..753333333357.."
1775         "..777533335777.."
1776         "..735775577537.."
1777         "..733357753337.."
1778         "..733337733337.."
1779         "..753337733357.."
1780         "..277537735772.."
1781         "....27777772...."
1782         "......2772......"
1783         "................"
1784         "................"
1785         , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1786         r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_PRECACHE | TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1787         "................"
1788         "................"
1789         "......2772......"
1790         "....27722772...."
1791         "..2772....2772.."
1792         "..72........27.."
1793         "..7772....2777.."
1794         "..7.27722772.7.."
1795         "..7...2772...7.."
1796         "..7....77....7.."
1797         "..72...77...27.."
1798         "..2772.77.2772.."
1799         "....27777772...."
1800         "......2772......"
1801         "................"
1802         "................"
1803         , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1804         r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_PRECACHE | TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1805         "................"
1806         ".777752..257777."
1807         ".742........247."
1808         ".72..........27."
1809         ".7............7."
1810         ".5............5."
1811         ".2............2."
1812         "................"
1813         "................"
1814         ".2............2."
1815         ".5............5."
1816         ".7............7."
1817         ".72..........27."
1818         ".742........247."
1819         ".777752..257777."
1820         "................"
1821         , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1822 }
1823
1824 void R_Shadow_ValidateCvars(void)
1825 {
1826         if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
1827                 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1828         if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
1829                 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1830         if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
1831                 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1832 }
1833
1834 void R_Shadow_RenderMode_Begin(void)
1835 {
1836 #if 0
1837         GLint drawbuffer;
1838         GLint readbuffer;
1839 #endif
1840         R_Shadow_ValidateCvars();
1841
1842         if (!r_shadow_attenuation2dtexture
1843          || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1844          || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1845          || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1846                 R_Shadow_MakeTextures();
1847
1848         CHECKGLERROR
1849         R_Mesh_ColorPointer(NULL, 0, 0);
1850         R_Mesh_ResetTextureState();
1851         GL_BlendFunc(GL_ONE, GL_ZERO);
1852         GL_DepthRange(0, 1);
1853         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1854         GL_DepthTest(true);
1855         GL_DepthMask(false);
1856         GL_Color(0, 0, 0, 1);
1857         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1858
1859         r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1860
1861         if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
1862         {
1863                 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1864                 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1865         }
1866         else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
1867         {
1868                 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1869                 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1870         }
1871         else
1872         {
1873                 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1874                 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1875         }
1876
1877         switch(vid.renderpath)
1878         {
1879         case RENDERPATH_GL20:
1880                 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1881                 break;
1882         case RENDERPATH_GL13:
1883         case RENDERPATH_GL11:
1884                 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
1885                         r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
1886                 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
1887                         r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
1888                 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
1889                         r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
1890                 else
1891                         r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1892                 break;
1893         }
1894
1895         CHECKGLERROR
1896 #if 0
1897         qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1898         qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1899         r_shadow_drawbuffer = drawbuffer;
1900         r_shadow_readbuffer = readbuffer;
1901 #endif
1902         r_shadow_cullface_front = r_refdef.view.cullface_front;
1903         r_shadow_cullface_back = r_refdef.view.cullface_back;
1904 }
1905
1906 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1907 {
1908         rsurface.rtlight = rtlight;
1909 }
1910
1911 void R_Shadow_RenderMode_Reset(void)
1912 {
1913         CHECKGLERROR
1914         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE)
1915         {
1916                 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1917         }
1918         if (vid.support.ext_framebuffer_object)
1919         {
1920                 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
1921         }
1922 #if 0
1923         qglDrawBuffer(r_shadow_drawbuffer);CHECKGLERROR
1924         qglReadBuffer(r_shadow_readbuffer);CHECKGLERROR
1925 #endif
1926         R_SetViewport(&r_refdef.view.viewport);
1927         GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1928         R_Mesh_ColorPointer(NULL, 0, 0);
1929         R_Mesh_ResetTextureState();
1930         GL_DepthRange(0, 1);
1931         GL_DepthTest(true);
1932         GL_DepthMask(false);
1933         qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1934         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1935         qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1936         qglStencilMask(~0);CHECKGLERROR
1937         qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1938         qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1939         r_refdef.view.cullface_front = r_shadow_cullface_front;
1940         r_refdef.view.cullface_back = r_shadow_cullface_back;
1941         GL_CullFace(r_refdef.view.cullface_back);
1942         GL_Color(1, 1, 1, 1);
1943         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1944         GL_BlendFunc(GL_ONE, GL_ZERO);
1945         R_SetupGenericShader(false);
1946         r_shadow_usingshadowmaprect = false;
1947         r_shadow_usingshadowmapcube = false;
1948         r_shadow_usingshadowmap2d = false;
1949         CHECKGLERROR
1950 }
1951
1952 void R_Shadow_ClearStencil(void)
1953 {
1954         CHECKGLERROR
1955         GL_Clear(GL_STENCIL_BUFFER_BIT);
1956         r_refdef.stats.lights_clears++;
1957 }
1958
1959 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
1960 {
1961         r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
1962         if (r_shadow_rendermode == mode)
1963                 return;
1964         CHECKGLERROR
1965         R_Shadow_RenderMode_Reset();
1966         GL_ColorMask(0, 0, 0, 0);
1967         GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1968         R_SetupDepthOrShadowShader();
1969         qglDepthFunc(GL_LESS);CHECKGLERROR
1970         qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1971         r_shadow_rendermode = mode;
1972         switch(mode)
1973         {
1974         default:
1975                 break;
1976         case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
1977                 GL_CullFace(GL_NONE);
1978                 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1979                 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1980                 break;
1981         case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
1982                 GL_CullFace(GL_NONE);
1983                 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1984                 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1985                 break;
1986         case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
1987                 GL_CullFace(GL_NONE);
1988                 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1989                 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1990                 qglStencilMask(~0);CHECKGLERROR
1991                 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1992                 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1993                 qglStencilMask(~0);CHECKGLERROR
1994                 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1995                 break;
1996         case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
1997                 GL_CullFace(GL_NONE);
1998                 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1999                 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
2000                 qglStencilMask(~0);CHECKGLERROR
2001                 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2002                 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
2003                 qglStencilMask(~0);CHECKGLERROR
2004                 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2005                 break;
2006         }
2007 }
2008
2009 static void R_Shadow_MakeVSDCT(void)
2010 {
2011         // maps to a 2x3 texture rectangle with normalized coordinates
2012         // +-
2013         // XX
2014         // YY
2015         // ZZ
2016         // stores abs(dir.xy), offset.xy/2.5
2017         unsigned char data[4*6] =
2018         {
2019                 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2020                 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2021                 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2022                 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2023                 0,   0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2024                 0,   0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2025         };
2026         r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_ALWAYSPRECACHE | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, NULL); 
2027 }
2028
2029 void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size)
2030 {
2031         int status;
2032         int maxsize;
2033         float nearclip, farclip, bias;
2034         r_viewport_t viewport;
2035         GLuint fbo = 0;
2036         CHECKGLERROR
2037         maxsize = r_shadow_shadowmapmaxsize;
2038         nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2039         farclip = 1.0f;
2040         bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2041         r_shadow_shadowmap_parameters[2] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2042         r_shadow_shadowmap_parameters[3] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2043         r_shadow_shadowmapside = side;
2044         r_shadow_shadowmapsize = size;
2045         if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
2046         {
2047                 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2048                 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2049                 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2050                 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
2051
2052                 // complex unrolled cube approach (more flexible)
2053                 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2054                         R_Shadow_MakeVSDCT();
2055                 if (!r_shadow_shadowmap2dtexture)
2056                 {
2057 #if 1
2058                         int w = maxsize*2, h = vid.support.arb_texture_non_power_of_two ? maxsize*3 : maxsize*4;
2059                         r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", w, h, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2060                         qglGenFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
2061                         qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
2062                         qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_shadowmap2dtexture), 0);CHECKGLERROR
2063             // render depth into the fbo, do not render color at all
2064                         qglDrawBuffer(GL_NONE);CHECKGLERROR
2065                         qglReadBuffer(GL_NONE);CHECKGLERROR
2066                         status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2067                         if (status != GL_FRAMEBUFFER_COMPLETE_EXT && r_shadow_shadowmapping.integer)
2068                         {
2069                                 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2070                                 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2071                         }
2072 #endif
2073                 }
2074                 CHECKGLERROR
2075                 if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d;
2076                 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
2077                 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
2078                 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2079         }
2080         else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
2081         {
2082                 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2083                 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2084                 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2085                 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE) goto init_done;
2086
2087                 // complex unrolled cube approach (more flexible)
2088                 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2089                         R_Shadow_MakeVSDCT();
2090                 if (!r_shadow_shadowmaprectangletexture)
2091                 {
2092 #if 1
2093                         r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", maxsize*2, maxsize*3, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2094                         qglGenFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
2095                         qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
2096                         qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_shadowmaprectangletexture), 0);CHECKGLERROR
2097                         // render depth into the fbo, do not render color at all
2098                         qglDrawBuffer(GL_NONE);CHECKGLERROR
2099                         qglReadBuffer(GL_NONE);CHECKGLERROR
2100                         status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2101                         if (status != GL_FRAMEBUFFER_COMPLETE_EXT && r_shadow_shadowmapping.integer)
2102                         {
2103                                 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2104                                 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2105                         }
2106 #endif
2107                 }
2108                 CHECKGLERROR
2109                 if(r_shadow_shadowmaprectangletexture) fbo = r_shadow_fborectangle;
2110                 r_shadow_shadowmap_texturescale[0] = 1.0f;
2111                 r_shadow_shadowmap_texturescale[1] = 1.0f;
2112                 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
2113         }
2114         else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
2115         {
2116                 r_shadow_shadowmap_parameters[0] = 1.0f;
2117                 r_shadow_shadowmap_parameters[1] = 1.0f;
2118                 R_Viewport_InitCubeSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, nearclip, farclip, NULL);
2119                 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE) goto init_done;
2120
2121                 // simple cube approach
2122                 if (!r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
2123                 {
2124  #if 1
2125                         r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", size, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2126                         qglGenFramebuffersEXT(1, &r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2127                         qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2128                         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
2129                         // render depth into the fbo, do not render color at all
2130                         qglDrawBuffer(GL_NONE);CHECKGLERROR
2131                         qglReadBuffer(GL_NONE);CHECKGLERROR
2132                         status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2133                         if (status != GL_FRAMEBUFFER_COMPLETE_EXT && r_shadow_shadowmapping.integer)
2134                         {
2135                                 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2136                                 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2137                         }
2138  #endif
2139                 }
2140                 CHECKGLERROR
2141                 if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]) fbo = r_shadow_fbocubeside[r_shadow_shadowmaplod];
2142                 r_shadow_shadowmap_texturescale[0] = 0.0f;
2143                 r_shadow_shadowmap_texturescale[1] = 0.0f;
2144                 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE;
2145         }
2146
2147         R_Shadow_RenderMode_Reset();
2148         if (fbo)
2149         {
2150                 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);CHECKGLERROR
2151                 R_SetupDepthOrShadowShader();
2152         }
2153         else
2154         {
2155                 R_SetupShowDepthShader();
2156                 qglClearColor(1,1,1,1);CHECKGLERROR
2157         }
2158         CHECKGLERROR
2159         GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2160         GL_DepthMask(true);
2161         GL_DepthTest(true);
2162         qglClearDepth(1);
2163         CHECKGLERROR
2164
2165 init_done:
2166         R_SetViewport(&viewport);
2167         GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2168         if(r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE)
2169         {
2170                 int flipped = (side&1)^(side>>2);
2171                 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2172                 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2173                 GL_CullFace(r_refdef.view.cullface_back);
2174         }
2175         else if(r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE)
2176         {
2177                 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
2178         }
2179         if (clear)
2180                 qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |  GL_STENCIL_BUFFER_BIT);
2181         CHECKGLERROR
2182 }
2183
2184 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2185 {
2186         if (transparent)
2187         {
2188                 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2189                 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2190                 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2191                 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2192         }
2193         CHECKGLERROR
2194         R_Shadow_RenderMode_Reset();
2195         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2196         if (!transparent)
2197         {
2198                 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2199         }
2200         if (stenciltest)
2201         {
2202                 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2203                 // only draw light where this geometry was already rendered AND the
2204                 // stencil is 128 (values other than this mean shadow)
2205                 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
2206         }
2207         r_shadow_rendermode = r_shadow_lightingrendermode;
2208         // do global setup needed for the chosen lighting mode
2209         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2210         {
2211                 R_Mesh_TexBindAll(GL20TU_CUBE, 0, 0, R_GetTexture(rsurface.rtlight->currentcubemap), 0); // light filter
2212                 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2213                 CHECKGLERROR
2214                 if (shadowmapping)
2215                 {
2216                         if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
2217                         {
2218                                 r_shadow_usingshadowmap2d = true;
2219                                 R_Mesh_TexBind(GL20TU_SHADOWMAP2D, R_GetTexture(r_shadow_shadowmap2dtexture));
2220                                 CHECKGLERROR
2221                         }
2222                         else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
2223                         {
2224                                 r_shadow_usingshadowmaprect = true;
2225                                 R_Mesh_TexBindAll(GL20TU_SHADOWMAPRECT, 0, 0, 0, R_GetTexture(r_shadow_shadowmaprectangletexture));
2226                                 CHECKGLERROR
2227                         }
2228                         else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
2229                         {
2230                                 r_shadow_usingshadowmapcube = true;
2231                                 R_Mesh_TexBindAll(GL20TU_SHADOWMAPCUBE, 0, 0, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]), 0);
2232                                 CHECKGLERROR
2233                         }
2234
2235                         if (r_shadow_shadowmapvsdct && (r_shadow_usingshadowmap2d || r_shadow_usingshadowmaprect))
2236                         {
2237                                 R_Mesh_TexBindAll(GL20TU_CUBEPROJECTION, 0, 0, R_GetTexture(r_shadow_shadowmapvsdcttexture), 0);
2238                                 CHECKGLERROR
2239                         }
2240                 }
2241         }
2242         R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
2243         //GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2244         CHECKGLERROR
2245 }
2246
2247 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2248 {
2249         CHECKGLERROR
2250         R_Shadow_RenderMode_Reset();
2251         GL_BlendFunc(GL_ONE, GL_ONE);
2252         GL_DepthRange(0, 1);
2253         GL_DepthTest(r_showshadowvolumes.integer < 2);
2254         GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2255         GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2256         GL_CullFace(GL_NONE);
2257         r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2258 }
2259
2260 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2261 {
2262         CHECKGLERROR
2263         R_Shadow_RenderMode_Reset();
2264         GL_BlendFunc(GL_ONE, GL_ONE);
2265         GL_DepthRange(0, 1);
2266         GL_DepthTest(r_showlighting.integer < 2);
2267         GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2268         if (!transparent)
2269         {
2270                 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2271         }
2272         if (stenciltest)
2273         {
2274                 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2275                 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
2276         }
2277         r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2278 }
2279
2280 void R_Shadow_RenderMode_End(void)
2281 {
2282         CHECKGLERROR
2283         R_Shadow_RenderMode_Reset();
2284         R_Shadow_RenderMode_ActiveLight(NULL);
2285         GL_DepthMask(true);
2286         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2287         r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2288 }
2289
2290 int bboxedges[12][2] =
2291 {
2292         // top
2293         {0, 1}, // +X
2294         {0, 2}, // +Y
2295         {1, 3}, // Y, +X
2296         {2, 3}, // X, +Y
2297         // bottom
2298         {4, 5}, // +X
2299         {4, 6}, // +Y
2300         {5, 7}, // Y, +X
2301         {6, 7}, // X, +Y
2302         // verticals
2303         {0, 4}, // +Z
2304         {1, 5}, // X, +Z
2305         {2, 6}, // Y, +Z
2306         {3, 7}, // XY, +Z
2307 };
2308
2309 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2310 {
2311         int i, ix1, iy1, ix2, iy2;
2312         float x1, y1, x2, y2;
2313         vec4_t v, v2;
2314         float vertex[20][3];
2315         int j, k;
2316         vec4_t plane4f;
2317         int numvertices;
2318         float corner[8][4];
2319         float dist[8];
2320         int sign[8];
2321         float f;
2322
2323         r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2324         r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2325         r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2326         r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2327
2328         if (!r_shadow_scissor.integer)
2329                 return false;
2330
2331         // if view is inside the light box, just say yes it's visible
2332         if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
2333                 return false;
2334
2335         x1 = y1 = x2 = y2 = 0;
2336
2337         // transform all corners that are infront of the nearclip plane
2338         VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
2339         plane4f[3] = r_refdef.view.frustum[4].dist;
2340         numvertices = 0;
2341         for (i = 0;i < 8;i++)
2342         {
2343                 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
2344                 dist[i] = DotProduct4(corner[i], plane4f);
2345                 sign[i] = dist[i] > 0;
2346                 if (!sign[i])
2347                 {
2348                         VectorCopy(corner[i], vertex[numvertices]);
2349                         numvertices++;
2350                 }
2351         }
2352         // if some points are behind the nearclip, add clipped edge points to make
2353         // sure that the scissor boundary is complete
2354         if (numvertices > 0 && numvertices < 8)
2355         {
2356                 // add clipped edge points
2357                 for (i = 0;i < 12;i++)
2358                 {
2359                         j = bboxedges[i][0];
2360                         k = bboxedges[i][1];
2361                         if (sign[j] != sign[k])
2362                         {
2363                                 f = dist[j] / (dist[j] - dist[k]);
2364                                 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
2365                                 numvertices++;
2366                         }
2367                 }
2368         }
2369
2370         // if we have no points to check, the light is behind the view plane
2371         if (!numvertices)
2372                 return true;
2373
2374         // if we have some points to transform, check what screen area is covered
2375         x1 = y1 = x2 = y2 = 0;
2376         v[3] = 1.0f;
2377         //Con_Printf("%i vertices to transform...\n", numvertices);
2378         for (i = 0;i < numvertices;i++)
2379         {
2380                 VectorCopy(vertex[i], v);
2381                 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
2382                 //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]);
2383                 if (i)
2384                 {
2385                         if (x1 > v2[0]) x1 = v2[0];
2386                         if (x2 < v2[0]) x2 = v2[0];
2387                         if (y1 > v2[1]) y1 = v2[1];
2388                         if (y2 < v2[1]) y2 = v2[1];
2389                 }
2390                 else
2391                 {
2392                         x1 = x2 = v2[0];
2393                         y1 = y2 = v2[1];
2394                 }
2395         }
2396
2397         // now convert the scissor rectangle to integer screen coordinates
2398         ix1 = (int)(x1 - 1.0f);
2399         iy1 = vid.height - (int)(y2 - 1.0f);
2400         ix2 = (int)(x2 + 1.0f);
2401         iy2 = vid.height - (int)(y1 + 1.0f);
2402         //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
2403
2404         // clamp it to the screen
2405         if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
2406         if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
2407         if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
2408         if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
2409
2410         // if it is inside out, it's not visible
2411         if (ix2 <= ix1 || iy2 <= iy1)
2412                 return true;
2413
2414         // the light area is visible, set up the scissor rectangle
2415         r_shadow_lightscissor[0] = ix1;
2416         r_shadow_lightscissor[1] = iy1;
2417         r_shadow_lightscissor[2] = ix2 - ix1;
2418         r_shadow_lightscissor[3] = iy2 - iy1;
2419
2420         r_refdef.stats.lights_scissored++;
2421         return false;
2422 }
2423
2424 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
2425 {
2426         const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2427         const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2428         float *color4f = rsurface.array_color4f + 4 * firstvertex;
2429         float dist, dot, distintensity, shadeintensity, v[3], n[3];
2430         switch (r_shadow_rendermode)
2431         {
2432         case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2433         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2434                 if (VectorLength2(diffusecolor) > 0)
2435                 {
2436                         for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2437                         {
2438                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2439                                 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2440                                 if ((dot = DotProduct(n, v)) < 0)
2441                                 {
2442                                         shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2443                                         VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2444                                 }
2445                                 else
2446                                         VectorCopy(ambientcolor, color4f);
2447                                 if (r_refdef.fogenabled)
2448                                 {
2449                                         float f;
2450                                         f = RSurf_FogVertex(vertex3f);
2451                                         VectorScale(color4f, f, color4f);
2452                                 }
2453                                 color4f[3] = 1;
2454                         }
2455                 }
2456                 else
2457                 {
2458                         for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2459                         {
2460                                 VectorCopy(ambientcolor, color4f);
2461                                 if (r_refdef.fogenabled)
2462                                 {
2463                                         float f;
2464                                         Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2465                                         f = RSurf_FogVertex(vertex3f);
2466                                         VectorScale(color4f, f, color4f);
2467                                 }
2468                                 color4f[3] = 1;
2469                         }
2470                 }
2471                 break;
2472         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2473                 if (VectorLength2(diffusecolor) > 0)
2474                 {
2475                         for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2476                         {
2477                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2478                                 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2479                                 {
2480                                         Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2481                                         if ((dot = DotProduct(n, v)) < 0)
2482                                         {
2483                                                 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2484                                                 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2485                                                 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2486                                                 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2487                                         }
2488                                         else
2489                                         {
2490                                                 color4f[0] = ambientcolor[0] * distintensity;
2491                                                 color4f[1] = ambientcolor[1] * distintensity;
2492                                                 color4f[2] = ambientcolor[2] * distintensity;
2493                                         }
2494                                         if (r_refdef.fogenabled)
2495                                         {
2496                                                 float f;
2497                                                 f = RSurf_FogVertex(vertex3f);
2498                                                 VectorScale(color4f, f, color4f);
2499                                         }
2500                                 }
2501                                 else
2502                                         VectorClear(color4f);
2503                                 color4f[3] = 1;
2504                         }
2505                 }
2506                 else
2507                 {
2508                         for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2509                         {
2510                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2511                                 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2512                                 {
2513                                         color4f[0] = ambientcolor[0] * distintensity;
2514                                         color4f[1] = ambientcolor[1] * distintensity;
2515                                         color4f[2] = ambientcolor[2] * distintensity;
2516                                         if (r_refdef.fogenabled)
2517                                         {
2518                                                 float f;
2519                                                 f = RSurf_FogVertex(vertex3f);
2520                                                 VectorScale(color4f, f, color4f);
2521                                         }
2522                                 }
2523                                 else
2524                                         VectorClear(color4f);
2525                                 color4f[3] = 1;
2526                         }
2527                 }
2528                 break;
2529         case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2530                 if (VectorLength2(diffusecolor) > 0)
2531                 {
2532                         for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2533                         {
2534                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2535                                 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2536                                 {
2537                                         distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2538                                         Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2539                                         if ((dot = DotProduct(n, v)) < 0)
2540                                         {
2541                                                 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2542                                                 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2543                                                 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2544                                                 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2545                                         }
2546                                         else
2547                                         {
2548                                                 color4f[0] = ambientcolor[0] * distintensity;
2549                                                 color4f[1] = ambientcolor[1] * distintensity;
2550                                                 color4f[2] = ambientcolor[2] * distintensity;
2551                                         }
2552                                         if (r_refdef.fogenabled)
2553                                         {
2554                                                 float f;
2555                                                 f = RSurf_FogVertex(vertex3f);
2556                                                 VectorScale(color4f, f, color4f);
2557                                         }
2558                                 }
2559                                 else
2560                                         VectorClear(color4f);
2561                                 color4f[3] = 1;
2562                         }
2563                 }
2564                 else
2565                 {
2566                         for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2567                         {
2568                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2569                                 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2570                                 {
2571                                         distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2572                                         color4f[0] = ambientcolor[0] * distintensity;
2573                                         color4f[1] = ambientcolor[1] * distintensity;
2574                                         color4f[2] = ambientcolor[2] * distintensity;
2575                                         if (r_refdef.fogenabled)
2576                                         {
2577                                                 float f;
2578                                                 f = RSurf_FogVertex(vertex3f);
2579                                                 VectorScale(color4f, f, color4f);
2580                                         }
2581                                 }
2582                                 else
2583                                         VectorClear(color4f);
2584                                 color4f[3] = 1;
2585                         }
2586                 }
2587                 break;
2588         default:
2589                 break;
2590         }
2591 }
2592
2593 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)
2594 {
2595         // used to display how many times a surface is lit for level design purposes
2596         R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2597 }
2598
2599 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)
2600 {
2601         // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2602         R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
2603         if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND))
2604                 R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
2605         else
2606                 R_Mesh_ColorPointer(NULL, 0, 0);
2607         R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2608         R_Mesh_TexMatrix(1, &rsurface.texture->currentbackgroundtexmatrix);
2609         R_Mesh_TexBind(GL20TU_NORMAL, R_GetTexture(rsurface.texture->currentskinframe->nmap));
2610         R_Mesh_TexBind(GL20TU_COLOR, R_GetTexture(rsurface.texture->basetexture));
2611         R_Mesh_TexBind(GL20TU_GLOSS, R_GetTexture(rsurface.texture->glosstexture));
2612         if (rsurface.texture->backgroundcurrentskinframe)
2613         {
2614                 R_Mesh_TexBind(GL20TU_SECONDARY_NORMAL, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->nmap));
2615                 R_Mesh_TexBind(GL20TU_SECONDARY_COLOR, R_GetTexture(rsurface.texture->backgroundbasetexture));
2616                 R_Mesh_TexBind(GL20TU_SECONDARY_GLOSS, R_GetTexture(rsurface.texture->backgroundglosstexture));
2617                 R_Mesh_TexBind(GL20TU_SECONDARY_GLOW, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->glow));
2618         }
2619         //R_Mesh_TexBindAll(GL20TU_CUBE, 0, 0, R_GetTexture(rsurface.rtlight->currentcubemap), 0);
2620         R_Mesh_TexBind(GL20TU_FOGMASK, R_GetTexture(r_texture_fogattenuation));
2621         if(rsurface.texture->colormapping)
2622         {
2623                 R_Mesh_TexBind(GL20TU_PANTS, R_GetTexture(rsurface.texture->currentskinframe->pants));
2624                 R_Mesh_TexBind(GL20TU_SHIRT, R_GetTexture(rsurface.texture->currentskinframe->shirt));
2625         }
2626         R_Mesh_TexBind(GL20TU_ATTENUATION, R_GetTexture(r_shadow_attenuationgradienttexture));
2627         R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
2628         R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
2629         R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
2630         R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
2631         if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2632         {
2633                 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2634         }
2635         R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2636         if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2637         {
2638                 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2639         }
2640 }
2641
2642 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2643 {
2644         int renders;
2645         int i;
2646         int stop;
2647         int newfirstvertex;
2648         int newlastvertex;
2649         int newnumtriangles;
2650         int *newe;
2651         const int *e;
2652         float *c;
2653         int maxtriangles = 4096;
2654         int newelements[4096*3];
2655         R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
2656         for (renders = 0;renders < 64;renders++)
2657         {
2658                 stop = true;
2659                 newfirstvertex = 0;
2660                 newlastvertex = 0;
2661                 newnumtriangles = 0;
2662                 newe = newelements;
2663                 // due to low fillrate on the cards this vertex lighting path is
2664                 // designed for, we manually cull all triangles that do not
2665                 // contain a lit vertex
2666                 // this builds batches of triangles from multiple surfaces and
2667                 // renders them at once
2668                 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2669                 {
2670                         if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
2671                         {
2672                                 if (newnumtriangles)
2673                                 {
2674                                         newfirstvertex = min(newfirstvertex, e[0]);
2675                                         newlastvertex  = max(newlastvertex, e[0]);
2676                                 }
2677                                 else
2678                                 {
2679                                         newfirstvertex = e[0];
2680                                         newlastvertex = e[0];
2681                                 }
2682                                 newfirstvertex = min(newfirstvertex, e[1]);
2683                                 newlastvertex  = max(newlastvertex, e[1]);
2684                                 newfirstvertex = min(newfirstvertex, e[2]);
2685                                 newlastvertex  = max(newlastvertex, e[2]);
2686                                 newe[0] = e[0];
2687                                 newe[1] = e[1];
2688                                 newe[2] = e[2];
2689                                 newnumtriangles++;
2690                                 newe += 3;
2691                                 if (newnumtriangles >= maxtriangles)
2692                                 {
2693                                         R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2694                                         newnumtriangles = 0;
2695                                         newe = newelements;
2696                                         stop = false;
2697                                 }
2698                         }
2699                 }
2700                 if (newnumtriangles >= 1)
2701                 {
2702                         R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2703                         stop = false;
2704                 }
2705                 // if we couldn't find any lit triangles, exit early
2706                 if (stop)
2707                         break;
2708                 // now reduce the intensity for the next overbright pass
2709                 // we have to clamp to 0 here incase the drivers have improper
2710                 // handling of negative colors
2711                 // (some old drivers even have improper handling of >1 color)
2712                 stop = true;
2713                 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2714                 {
2715                         if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2716                         {
2717                                 c[0] = max(0, c[0] - 1);
2718                                 c[1] = max(0, c[1] - 1);
2719                                 c[2] = max(0, c[2] - 1);
2720                                 stop = false;
2721                         }
2722                         else
2723                                 VectorClear(c);
2724                 }
2725                 // another check...
2726                 if (stop)
2727                         break;
2728         }
2729 }
2730
2731 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)
2732 {
2733         // OpenGL 1.1 path (anything)
2734         float ambientcolorbase[3], diffusecolorbase[3];
2735         float ambientcolorpants[3], diffusecolorpants[3];
2736         float ambientcolorshirt[3], diffusecolorshirt[3];
2737         rmeshstate_t m;
2738         VectorScale(lightcolorbase, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorbase);
2739         VectorScale(lightcolorbase, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorbase);
2740         VectorScale(lightcolorpants, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorpants);
2741         VectorScale(lightcolorpants, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorpants);
2742         VectorScale(lightcolorshirt, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorshirt);
2743         VectorScale(lightcolorshirt, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorshirt);
2744         switch(r_shadow_rendermode)
2745         {
2746         case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2747                 memset(&m, 0, sizeof(m));
2748                 m.tex[0] = R_GetTexture(basetexture);
2749                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2750                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2751                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2752                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2753                 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2754                 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2755                 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2756                 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2757                 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2758                 R_Mesh_TextureState(&m);
2759                 break;
2760         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2761                 memset(&m, 0, sizeof(m));
2762                 m.tex[0] = R_GetTexture(basetexture);
2763                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2764                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2765                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2766                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2767                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2768                 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2769                 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2770                 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2771                 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2772                 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2773                 m.texmatrix[2] = rsurface.entitytoattenuationz;
2774                 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2775                 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2776                 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2777                 R_Mesh_TextureState(&m);
2778                 break;
2779         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2780                 memset(&m, 0, sizeof(m));
2781                 m.tex[0] = R_GetTexture(basetexture);
2782                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2783                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2784                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2785                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2786                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2787                 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2788                 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2789                 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2790                 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2791                 R_Mesh_TextureState(&m);
2792                 break;
2793         case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2794                 memset(&m, 0, sizeof(m));
2795                 m.tex[0] = R_GetTexture(basetexture);
2796                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2797                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2798                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2799                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2800                 R_Mesh_TextureState(&m);
2801                 break;
2802         default:
2803                 break;
2804         }
2805         //R_Mesh_TexBind(0, R_GetTexture(basetexture));
2806         R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
2807         if (dopants)
2808         {
2809                 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
2810                 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
2811         }
2812         if (doshirt)
2813         {
2814                 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
2815                 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
2816         }
2817 }
2818
2819 extern cvar_t gl_lightmaps;
2820 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)
2821 {
2822         float ambientscale, diffusescale, specularscale;
2823         qboolean negated;
2824         vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
2825         rtexture_t *nmap;
2826         // calculate colors to render this texture with
2827         lightcolorbase[0] = rsurface.rtlight->currentcolor[0] * rsurface.texture->dlightcolor[0];
2828         lightcolorbase[1] = rsurface.rtlight->currentcolor[1] * rsurface.texture->dlightcolor[1];
2829         lightcolorbase[2] = rsurface.rtlight->currentcolor[2] * rsurface.texture->dlightcolor[2];
2830         ambientscale = rsurface.rtlight->ambientscale;
2831         diffusescale = rsurface.rtlight->diffusescale;
2832         specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2833         if (!r_shadow_usenormalmap.integer)
2834         {
2835                 ambientscale += 1.0f * diffusescale;
2836                 diffusescale = 0;
2837                 specularscale = 0;
2838         }
2839         if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
2840                 return;
2841         negated = (lightcolorbase[0] + lightcolorbase[1] + lightcolorbase[2] < 0) && vid.support.ext_blend_subtract;
2842         if(negated)
2843         {
2844                 VectorNegate(lightcolorbase, lightcolorbase);
2845                 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
2846         }
2847         RSurf_SetupDepthAndCulling();
2848         nmap = rsurface.texture->currentskinframe->nmap;
2849         if (gl_lightmaps.integer)
2850                 nmap = r_texture_blanknormalmap;
2851         if (rsurface.texture->colormapping && !gl_lightmaps.integer)
2852         {
2853                 qboolean dopants = rsurface.texture->currentskinframe->pants != NULL && VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f);
2854                 qboolean doshirt = rsurface.texture->currentskinframe->shirt != NULL && VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f);
2855                 if (dopants)
2856                 {
2857                         lightcolorpants[0] = lightcolorbase[0] * rsurface.colormap_pantscolor[0];
2858                         lightcolorpants[1] = lightcolorbase[1] * rsurface.colormap_pantscolor[1];
2859                         lightcolorpants[2] = lightcolorbase[2] * rsurface.colormap_pantscolor[2];
2860                 }
2861                 else
2862                         VectorClear(lightcolorpants);
2863                 if (doshirt)
2864                 {
2865                         lightcolorshirt[0] = lightcolorbase[0] * rsurface.colormap_shirtcolor[0];
2866                         lightcolorshirt[1] = lightcolorbase[1] * rsurface.colormap_shirtcolor[1];
2867                         lightcolorshirt[2] = lightcolorbase[2] * rsurface.colormap_shirtcolor[2];
2868                 }
2869                 else
2870                         VectorClear(lightcolorshirt);
2871                 switch (r_shadow_rendermode)
2872                 {
2873                 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2874                         GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2875                         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);
2876                         break;
2877                 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2878                         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);
2879                         break;
2880                 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2881                 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2882                 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2883                 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2884                         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);
2885                         break;
2886                 default:
2887                         Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2888                         break;
2889                 }
2890         }
2891         else
2892         {
2893                 switch (r_shadow_rendermode)
2894                 {
2895                 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2896                         GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2897                         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);
2898                         break;
2899                 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2900                         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);
2901                         break;
2902                 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2903                 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2904                 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2905                 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2906                         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);
2907                         break;
2908                 default:
2909                         Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2910                         break;
2911                 }
2912         }
2913         if(negated)
2914                 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
2915 }
2916
2917 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)
2918 {
2919         matrix4x4_t tempmatrix = *matrix;
2920         Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2921
2922         // if this light has been compiled before, free the associated data
2923         R_RTLight_Uncompile(rtlight);
2924
2925         // clear it completely to avoid any lingering data
2926         memset(rtlight, 0, sizeof(*rtlight));
2927
2928         // copy the properties
2929         rtlight->matrix_lighttoworld = tempmatrix;
2930         Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2931         Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2932         rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2933         VectorCopy(color, rtlight->color);
2934         rtlight->cubemapname[0] = 0;
2935         if (cubemapname && cubemapname[0])
2936                 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2937         rtlight->shadow = shadow;
2938         rtlight->corona = corona;
2939         rtlight->style = style;
2940         rtlight->isstatic = isstatic;
2941         rtlight->coronasizescale = coronasizescale;
2942         rtlight->ambientscale = ambientscale;
2943         rtlight->diffusescale = diffusescale;
2944         rtlight->specularscale = specularscale;
2945         rtlight->flags = flags;
2946
2947         // compute derived data
2948         //rtlight->cullradius = rtlight->radius;
2949         //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2950         rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2951         rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2952         rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2953         rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2954         rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2955         rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2956 }
2957
2958 // compiles rtlight geometry
2959 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2960 void R_RTLight_Compile(rtlight_t *rtlight)
2961 {
2962         int i;
2963         int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2964         int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
2965         entity_render_t *ent = r_refdef.scene.worldentity;
2966         dp_model_t *model = r_refdef.scene.worldmodel;
2967         unsigned char *data;
2968         shadowmesh_t *mesh;
2969
2970         // compile the light
2971         rtlight->compiled = true;
2972         rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
2973         rtlight->static_numleafs = 0;
2974         rtlight->static_numleafpvsbytes = 0;
2975         rtlight->static_leaflist = NULL;
2976         rtlight->static_leafpvs = NULL;
2977         rtlight->static_numsurfaces = 0;
2978         rtlight->static_surfacelist = NULL;
2979         rtlight->static_shadowmap_receivers = 0x3F;
2980         rtlight->static_shadowmap_casters = 0x3F;
2981         rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2982         rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2983         rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2984         rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2985         rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2986         rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2987
2988         if (model && model->GetLightInfo)
2989         {
2990                 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
2991                 r_shadow_compilingrtlight = rtlight;
2992                 R_Shadow_EnlargeLeafSurfaceTrisBuffer(model->brush.num_leafs, model->num_surfaces, model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles, model->surfmesh.num_triangles);
2993                 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);
2994                 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2995                 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
2996                 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
2997                 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
2998                 rtlight->static_numsurfaces = numsurfaces;
2999                 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3000                 rtlight->static_numleafs = numleafs;
3001                 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3002                 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3003                 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3004                 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3005                 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3006                 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3007                 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3008                 if (rtlight->static_numsurfaces)
3009                         memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3010                 if (rtlight->static_numleafs)
3011                         memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3012                 if (rtlight->static_numleafpvsbytes)
3013                         memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3014                 if (rtlight->static_numshadowtrispvsbytes)
3015                         memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3016                 if (rtlight->static_numlighttrispvsbytes)
3017                         memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3018                 switch (rtlight->shadowmode)
3019                 {
3020                 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
3021                 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
3022                 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
3023                         if (model->CompileShadowMap && rtlight->shadow)
3024                                 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3025                         break;
3026                 default:
3027                         if (model->CompileShadowVolume && rtlight->shadow)
3028                                 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3029                         break;
3030                 }
3031                 // now we're done compiling the rtlight
3032                 r_shadow_compilingrtlight = NULL;
3033         }
3034
3035
3036         // use smallest available cullradius - box radius or light radius
3037         //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3038         //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3039
3040         shadowzpasstris = 0;
3041         if (rtlight->static_meshchain_shadow_zpass)
3042                 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3043                         shadowzpasstris += mesh->numtriangles;
3044
3045         shadowzfailtris = 0;
3046         if (rtlight->static_meshchain_shadow_zfail)
3047                 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3048                         shadowzfailtris += mesh->numtriangles;
3049
3050         lighttris = 0;
3051         if (rtlight->static_numlighttrispvsbytes)
3052                 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3053                         if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3054                                 lighttris++;
3055
3056         shadowtris = 0;
3057         if (rtlight->static_numlighttrispvsbytes)
3058                 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3059                         if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3060                                 shadowtris++;
3061
3062         if (developer.integer >= 10)
3063                 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);
3064 }
3065
3066 void R_RTLight_Uncompile(rtlight_t *rtlight)
3067 {
3068         if (rtlight->compiled)
3069         {
3070                 if (rtlight->static_meshchain_shadow_zpass)
3071                         Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3072                 rtlight->static_meshchain_shadow_zpass = NULL;
3073                 if (rtlight->static_meshchain_shadow_zfail)
3074                         Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3075                 rtlight->static_meshchain_shadow_zfail = NULL;
3076                 if (rtlight->static_meshchain_shadow_shadowmap)
3077                         Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3078                 rtlight->static_meshchain_shadow_shadowmap = NULL;
3079                 // these allocations are grouped
3080                 if (rtlight->static_surfacelist)
3081                         Mem_Free(rtlight->static_surfacelist);
3082                 rtlight->static_numleafs = 0;
3083                 rtlight->static_numleafpvsbytes = 0;
3084                 rtlight->static_leaflist = NULL;
3085                 rtlight->static_leafpvs = NULL;
3086                 rtlight->static_numsurfaces = 0;
3087                 rtlight->static_surfacelist = NULL;
3088                 rtlight->static_numshadowtrispvsbytes = 0;
3089                 rtlight->static_shadowtrispvs = NULL;
3090                 rtlight->static_numlighttrispvsbytes = 0;
3091                 rtlight->static_lighttrispvs = NULL;
3092                 rtlight->compiled = false;
3093         }
3094 }
3095
3096 void R_Shadow_UncompileWorldLights(void)
3097 {
3098         size_t lightindex;
3099         dlight_t *light;
3100         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3101         for (lightindex = 0;lightindex < range;lightindex++)
3102         {
3103                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3104                 if (!light)
3105                         continue;
3106                 R_RTLight_Uncompile(&light->rtlight);
3107         }
3108 }
3109
3110 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3111 {
3112         int i, j;
3113         mplane_t plane;
3114         // reset the count of frustum planes
3115         // see rsurface.rtlight_frustumplanes definition for how much this array
3116         // can hold
3117         rsurface.rtlight_numfrustumplanes = 0;
3118
3119         // haven't implemented a culling path for ortho rendering
3120         if (!r_refdef.view.useperspective)
3121         {
3122                 // check if the light is on screen and copy the 4 planes if it is
3123                 for (i = 0;i < 4;i++)
3124                         if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3125                                 break;
3126                 if (i == 4)
3127                         for (i = 0;i < 4;i++)
3128                                 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3129                 return;
3130         }
3131
3132 #if 1
3133         // generate a deformed frustum that includes the light origin, this is
3134         // used to cull shadow casting surfaces that can not possibly cast a
3135         // shadow onto the visible light-receiving surfaces, which can be a
3136         // performance gain
3137         //
3138         // if the light origin is onscreen the result will be 4 planes exactly
3139         // if the light origin is offscreen on only one axis the result will
3140         // be exactly 5 planes (split-side case)
3141         // if the light origin is offscreen on two axes the result will be
3142         // exactly 4 planes (stretched corner case)
3143         for (i = 0;i < 4;i++)
3144         {
3145                 // quickly reject standard frustum planes that put the light
3146                 // origin outside the frustum
3147                 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3148                         continue;
3149                 // copy the plane
3150                 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3151         }
3152         // if all the standard frustum planes were accepted, the light is onscreen
3153         // otherwise we need to generate some more planes below...
3154         if (rsurface.rtlight_numfrustumplanes < 4)
3155         {
3156                 // at least one of the stock frustum planes failed, so we need to
3157                 // create one or two custom planes to enclose the light origin
3158                 for (i = 0;i < 4;i++)
3159                 {
3160                         // create a plane using the view origin and light origin, and a
3161                         // single point from the frustum corner set
3162                         TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3163                         VectorNormalize(plane.normal);
3164                         plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3165                         // see if this plane is backwards and flip it if so
3166                         for (j = 0;j < 4;j++)
3167                                 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3168                                         break;
3169                         if (j < 4)
3170                         {
3171                                 VectorNegate(plane.normal, plane.normal);
3172                                 plane.dist *= -1;
3173                                 // flipped plane, test again to see if it is now valid
3174                                 for (j = 0;j < 4;j++)
3175                                         if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3176                                                 break;
3177                                 // if the plane is still not valid, then it is dividing the
3178                                 // frustum and has to be rejected
3179                                 if (j < 4)
3180                                         continue;
3181                         }
3182                         // we have created a valid plane, compute extra info
3183                         PlaneClassify(&plane);
3184                         // copy the plane
3185                         rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3186 #if 1
3187                         // if we've found 5 frustum planes then we have constructed a
3188                         // proper split-side case and do not need to keep searching for
3189                         // planes to enclose the light origin
3190                         if (rsurface.rtlight_numfrustumplanes == 5)
3191                                 break;
3192 #endif
3193                 }
3194         }
3195 #endif
3196
3197 #if 0
3198         for (i = 0;i < rsurface.rtlight_numfrustumplanes;i++)
3199         {
3200                 plane = rsurface.rtlight_frustumplanes[i];
3201                 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));
3202         }
3203 #endif
3204
3205 #if 0
3206         // now add the light-space box planes if the light box is rotated, as any
3207         // caster outside the oriented light box is irrelevant (even if it passed
3208         // the worldspace light box, which is axial)
3209         if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3210         {
3211                 for (i = 0;i < 6;i++)
3212                 {
3213                         vec3_t v;
3214                         VectorClear(v);
3215                         v[i >> 1] = (i & 1) ? -1 : 1;
3216                         Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3217                         VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3218                         plane.dist = VectorNormalizeLength(plane.normal);
3219                         plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3220                         rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3221                 }
3222         }
3223 #endif
3224
3225 #if 0
3226         // add the world-space reduced box planes
3227         for (i = 0;i < 6;i++)
3228         {
3229                 VectorClear(plane.normal);
3230                 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3231                 plane.dist = (i & 1) ? -rsurface.rtlight_cullmaxs[i >> 1] : rsurface.rtlight_cullmins[i >> 1];
3232                 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3233         }
3234 #endif
3235
3236 #if 0
3237         {
3238         int j, oldnum;
3239         vec3_t points[8];
3240         vec_t bestdist;
3241         // reduce all plane distances to tightly fit the rtlight cull box, which
3242         // is in worldspace
3243         VectorSet(points[0], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3244         VectorSet(points[1], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3245         VectorSet(points[2], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3246         VectorSet(points[3], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3247         VectorSet(points[4], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3248         VectorSet(points[5], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3249         VectorSet(points[6], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3250         VectorSet(points[7], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3251         oldnum = rsurface.rtlight_numfrustumplanes;
3252         rsurface.rtlight_numfrustumplanes = 0;
3253         for (j = 0;j < oldnum;j++)
3254         {
3255                 // find the nearest point on the box to this plane
3256                 bestdist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[0]);
3257                 for (i = 1;i < 8;i++)
3258                 {
3259                         dist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[i]);
3260                         if (bestdist > dist)
3261                                 bestdist = dist;
3262                 }
3263                 Con_Printf("light %p %splane #%i %f %f %f : %f < %f\n", rtlight, rsurface.rtlight_frustumplanes[j].dist < bestdist + 0.03125 ? "^2" : "^1", j, rsurface.rtlight_frustumplanes[j].normal[0], rsurface.rtlight_frustumplanes[j].normal[1], rsurface.rtlight_frustumplanes[j].normal[2], rsurface.rtlight_frustumplanes[j].dist, bestdist);
3264                 // if the nearest point is near or behind the plane, we want this
3265                 // plane, otherwise the plane is useless as it won't cull anything
3266                 if (rsurface.rtlight_frustumplanes[j].dist < bestdist + 0.03125)
3267                 {
3268                         PlaneClassify(&rsurface.rtlight_frustumplanes[j]);
3269                         rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = rsurface.rtlight_frustumplanes[j];
3270                 }
3271         }
3272         }
3273 #endif
3274 }
3275
3276 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3277 {
3278         shadowmesh_t *mesh;
3279
3280         RSurf_ActiveWorldEntity();
3281
3282         if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3283         {
3284                 CHECKGLERROR
3285                 GL_CullFace(GL_NONE);
3286         mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3287         for (;mesh;mesh = mesh->next)
3288         {
3289                         if (!mesh->sidetotals[r_shadow_shadowmapside])
3290                                 continue;
3291             r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3292             R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3293             R_Mesh_Draw(0, mesh->numverts, mesh->sideoffsets[r_shadow_shadowmapside], mesh->sidetotals[r_shadow_shadowmapside], mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3294         }
3295         CHECKGLERROR
3296     }
3297         else if (r_refdef.scene.worldentity->model)
3298                 r_refdef.scene.worldmodel->DrawShadowMap(r_shadow_shadowmapside, r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, surfacesides, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
3299
3300         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3301 }
3302
3303 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3304 {
3305         qboolean zpass;
3306         shadowmesh_t *mesh;
3307         int t, tend;
3308         int surfacelistindex;
3309         msurface_t *surface;
3310
3311         RSurf_ActiveWorldEntity();
3312
3313         if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3314         {
3315                 CHECKGLERROR
3316                 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3317                 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3318                 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3319                 for (;mesh;mesh = mesh->next)
3320                 {
3321                         r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3322                         R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3323                         GL_LockArrays(0, mesh->numverts);
3324                         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3325                         {
3326                                 // increment stencil if frontface is infront of depthbuffer
3327                                 GL_CullFace(r_refdef.view.cullface_back);
3328                                 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
3329                                 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3330                                 // decrement stencil if backface is infront of depthbuffer
3331                                 GL_CullFace(r_refdef.view.cullface_front);
3332                                 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
3333                         }
3334                         else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3335                         {
3336                                 // decrement stencil if backface is behind depthbuffer
3337                                 GL_CullFace(r_refdef.view.cullface_front);
3338                                 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
3339                                 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3340                                 // increment stencil if frontface is behind depthbuffer
3341                                 GL_CullFace(r_refdef.view.cullface_back);
3342                                 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
3343                         }
3344                         R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3345                         GL_LockArrays(0, 0);
3346                 }
3347                 CHECKGLERROR
3348         }
3349         else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
3350         {
3351                 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3352                 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3353                 {
3354                         surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3355                         for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3356                                 if (CHECKPVSBIT(trispvs, t))
3357                                         shadowmarklist[numshadowmark++] = t;
3358                 }
3359                 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);
3360         }
3361         else if (numsurfaces)
3362                 r_refdef.scene.worldmodel->DrawShadowVolume(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
3363
3364         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3365 }
3366
3367 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3368 {
3369         vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3370         vec_t relativeshadowradius;
3371         RSurf_ActiveModelEntity(ent, false, false);
3372         Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3373         relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3374         relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3375         relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3376         relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3377         relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3378         relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3379         relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3380         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
3381         {
3382                 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3383         }
3384         else
3385                 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3386         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3387 }
3388
3389 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3390 {
3391         // set up properties for rendering light onto this entity
3392         RSurf_ActiveModelEntity(ent, true, true);
3393         GL_AlphaTest(false);
3394         Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3395         Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3396         Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3397         Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3398         switch(r_shadow_lightingrendermode)
3399         {
3400         case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3401                 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3402                 break;
3403         default:
3404                 break;
3405         }
3406 }
3407
3408 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3409 {
3410         if (!r_refdef.scene.worldmodel->DrawLight)
3411                 return;
3412
3413         // set up properties for rendering light onto this entity
3414         RSurf_ActiveWorldEntity();
3415         GL_AlphaTest(false);
3416         rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3417         Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3418         Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3419         VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3420         switch(r_shadow_lightingrendermode)
3421         {
3422         case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3423                 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3424                 break;
3425         default:
3426                 break;
3427         }
3428
3429         r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, trispvs);
3430
3431         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3432 }
3433
3434 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3435 {
3436         dp_model_t *model = ent->model;
3437         if (!model->DrawLight)
3438                 return;
3439
3440         R_Shadow_SetupEntityLight(ent);
3441
3442         model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3443
3444         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3445 }
3446
3447 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
3448 {
3449         int i;
3450         float f;
3451         int numleafs, numsurfaces;
3452         int *leaflist, *surfacelist;
3453         unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs, *surfacesides;
3454         int numlightentities;
3455         int numlightentities_noselfshadow;
3456         int numshadowentities;
3457         int numshadowentities_noselfshadow;
3458         static entity_render_t *lightentities[MAX_EDICTS];
3459         static entity_render_t *shadowentities[MAX_EDICTS];
3460         static unsigned char entitysides[MAX_EDICTS];
3461         int lightentities_noselfshadow;
3462         int shadowentities_noselfshadow;
3463         vec3_t nearestpoint;
3464         vec_t distance;
3465         qboolean castshadows;
3466         int lodlinear;
3467
3468         // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3469         // skip lights that are basically invisible (color 0 0 0)
3470         if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
3471                 return;
3472
3473         // loading is done before visibility checks because loading should happen
3474         // all at once at the start of a level, not when it stalls gameplay.
3475         // (especially important to benchmarks)
3476         // compile light
3477         if (rtlight->isstatic && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3478         {
3479                 if (rtlight->compiled)
3480                         R_RTLight_Uncompile(rtlight);
3481                 R_RTLight_Compile(rtlight);
3482         }
3483
3484         // load cubemap
3485         rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
3486
3487         // look up the light style value at this time
3488         f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3489         VectorScale(rtlight->color, f, rtlight->currentcolor);
3490         /*
3491         if (rtlight->selected)
3492         {
3493                 f = 2 + sin(realtime * M_PI * 4.0);
3494                 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3495         }
3496         */
3497
3498         // if lightstyle is currently off, don't draw the light
3499         if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3500                 return;
3501
3502         // if the light box is offscreen, skip it
3503         if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3504                 return;
3505
3506         VectorCopy(rtlight->cullmins, rsurface.rtlight_cullmins);
3507         VectorCopy(rtlight->cullmaxs, rsurface.rtlight_cullmaxs);
3508
3509         if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3510         {
3511                 // compiled light, world available and can receive realtime lighting
3512                 // retrieve leaf information
3513                 numleafs = rtlight->static_numleafs;
3514                 leaflist = rtlight->static_leaflist;
3515                 leafpvs = rtlight->static_leafpvs;
3516                 numsurfaces = rtlight->static_numsurfaces;
3517                 surfacelist = rtlight->static_surfacelist;
3518                 surfacesides = NULL;
3519                 shadowtrispvs = rtlight->static_shadowtrispvs;
3520                 lighttrispvs = rtlight->static_lighttrispvs;
3521         }
3522         else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3523         {
3524                 // dynamic light, world available and can receive realtime lighting
3525                 // calculate lit surfaces and leafs
3526                 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);
3527                 r_refdef.scene.worldmodel->GetLightInfo(r_refdef.scene.worldentity, rtlight->shadoworigin, rtlight->radius, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs, r_shadow_buffer_leaflist, r_shadow_buffer_leafpvs, &numleafs, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces, r_shadow_buffer_shadowtrispvs, r_shadow_buffer_lighttrispvs, r_shadow_buffer_visitingleafpvs);
3528                 leaflist = r_shadow_buffer_leaflist;
3529                 leafpvs = r_shadow_buffer_leafpvs;
3530                 surfacelist = r_shadow_buffer_surfacelist;
3531                 surfacesides = r_shadow_buffer_surfacesides;
3532                 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3533                 lighttrispvs = r_shadow_buffer_lighttrispvs;
3534                 // if the reduced leaf bounds are offscreen, skip it
3535                 if (R_CullBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3536                         return;
3537         }
3538         else
3539         {
3540                 // no world
3541                 numleafs = 0;
3542                 leaflist = NULL;
3543                 leafpvs = NULL;
3544                 numsurfaces = 0;
3545                 surfacelist = NULL;
3546                 surfacesides = NULL;
3547                 shadowtrispvs = NULL;
3548                 lighttrispvs = NULL;
3549         }
3550         // check if light is illuminating any visible leafs
3551         if (numleafs)
3552         {
3553                 for (i = 0;i < numleafs;i++)
3554                         if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3555                                 break;
3556                 if (i == numleafs)
3557                         return;
3558         }
3559         // set up a scissor rectangle for this light
3560         if (R_Shadow_ScissorForBBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3561                 return;
3562
3563         R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3564
3565         // make a list of lit entities and shadow casting entities
3566         numlightentities = 0;
3567         numlightentities_noselfshadow = 0;
3568         lightentities_noselfshadow = sizeof(lightentities)/sizeof(lightentities[0]) - 1;
3569         numshadowentities = 0;
3570         numshadowentities_noselfshadow = 0;
3571         shadowentities_noselfshadow = sizeof(shadowentities)/sizeof(shadowentities[0]) - 1;
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, rsurface.rtlight_cullmins, rsurface.rtlight_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, rsurface.rtlight_numfrustumplanes, rsurface.rtlight_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[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[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[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         // don't let sound skip if going slow
3644         if (r_refdef.scene.extraupdate)
3645                 S_ExtraUpdate ();
3646
3647         // make this the active rtlight for rendering purposes
3648         R_Shadow_RenderMode_ActiveLight(rtlight);
3649         // count this light in the r_speeds
3650         r_refdef.stats.lights++;
3651
3652         if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3653         {
3654                 // optionally draw visible shape of the shadow volumes
3655                 // for performance analysis by level designers
3656                 R_Shadow_RenderMode_VisibleShadowVolumes();
3657                 if (numsurfaces)
3658                         R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3659                 for (i = 0;i < numshadowentities;i++)
3660                         R_Shadow_DrawEntityShadow(shadowentities[i]);
3661                 for (i = 0;i < numshadowentities_noselfshadow;i++)
3662                         R_Shadow_DrawEntityShadow(shadowentities[shadowentities_noselfshadow - i]);
3663         }
3664
3665         if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3666         {
3667                 // optionally draw the illuminated areas
3668                 // for performance analysis by level designers
3669                 R_Shadow_RenderMode_VisibleLighting(false, false);
3670                 if (numsurfaces)
3671                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3672                 for (i = 0;i < numlightentities;i++)
3673                         R_Shadow_DrawEntityLight(lightentities[i]);
3674                 for (i = 0;i < numlightentities_noselfshadow;i++)
3675                         R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
3676         }
3677
3678         castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3679
3680         nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3681         nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3682         nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3683         distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3684
3685         lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
3686         //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3687         lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3688
3689         if (castshadows && (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE))
3690         {
3691                 float borderbias;
3692                 int side;
3693                 int size;
3694                 int castermask = 0;
3695                 int receivermask = 0;
3696                 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3697                 Matrix4x4_Abs(&radiustolight);
3698
3699                 r_shadow_shadowmaplod = 0;
3700                 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
3701                         if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
3702                                 r_shadow_shadowmaplod = i;
3703
3704                 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
3705                         size = max(1, r_shadow_shadowmapmaxsize >> r_shadow_shadowmaplod);
3706                 else
3707                         size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3708                         
3709                 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3710
3711                 if (numsurfaces)
3712                 {
3713                         if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3714                         {
3715                                 castermask = rtlight->static_shadowmap_casters;
3716                                 receivermask = rtlight->static_shadowmap_receivers;
3717                         }
3718                         else
3719                         {
3720                                 for(i = 0;i < numsurfaces;i++)
3721                                 {
3722                                         msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3723                                         surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);           
3724                                         castermask |= surfacesides[i];
3725                                         receivermask |= surfacesides[i];
3726                                 }
3727                         }
3728                 }
3729                 if (receivermask < 0x3F) 
3730                 {
3731                         for (i = 0;i < numlightentities;i++)
3732                                 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3733                         if (receivermask < 0x3F)
3734                                 for(i = 0; i < numlightentities_noselfshadow;i++)
3735                                         receivermask |= R_Shadow_CalcEntitySideMask(lightentities[lightentities_noselfshadow - i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3736                 }
3737
3738                 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3739
3740                 if (receivermask)
3741                 {
3742                         for (i = 0;i < numshadowentities;i++)
3743                                 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3744                         for (i = 0;i < numshadowentities_noselfshadow;i++)
3745                                 castermask |= (entitysides[shadowentities_noselfshadow - i] = R_Shadow_CalcEntitySideMask(shadowentities[shadowentities_noselfshadow - i], &rtlight->matrix_worldtolight, &radiustolight, borderbias)); 
3746                 }
3747
3748                 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
3749
3750                 // render shadow casters into 6 sided depth texture
3751                 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
3752                 {
3753                         R_Shadow_RenderMode_ShadowMap(side, true, size);
3754                         if (! (castermask & (1 << side))) continue;
3755                         if (numsurfaces)
3756                                 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3757                         for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
3758                                 R_Shadow_DrawEntityShadow(shadowentities[i]);
3759                 }
3760
3761                 if (numlightentities_noselfshadow)
3762                 {
3763                         // render lighting using the depth texture as shadowmap
3764                         // draw lighting in the unmasked areas
3765                         R_Shadow_RenderMode_Lighting(false, false, true);
3766                         for (i = 0;i < numlightentities_noselfshadow;i++)
3767                                 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
3768                 }
3769
3770                 // render shadow casters into 6 sided depth texture
3771                 if (numshadowentities_noselfshadow) 
3772                 {
3773                         for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
3774                         {
3775                                 R_Shadow_RenderMode_ShadowMap(side, false, size);
3776                                 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides[shadowentities_noselfshadow - i] & (1 << side))
3777                                         R_Shadow_DrawEntityShadow(shadowentities[shadowentities_noselfshadow - i]);
3778                         }
3779                 }
3780
3781                 // render lighting using the depth texture as shadowmap
3782                 // draw lighting in the unmasked areas
3783                 R_Shadow_RenderMode_Lighting(false, false, true);
3784                 // draw lighting in the unmasked areas
3785                 if (numsurfaces)
3786                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3787                 for (i = 0;i < numlightentities;i++)
3788                         R_Shadow_DrawEntityLight(lightentities[i]);
3789         }
3790         else if (castshadows && vid.stencil)
3791         {
3792                 // draw stencil shadow volumes to mask off pixels that are in shadow
3793                 // so that they won't receive lighting
3794                 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
3795                 R_Shadow_ClearStencil();
3796
3797                 if (numsurfaces + numshadowentities)
3798                 {
3799                         if (numsurfaces)
3800                                 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3801                         for (i = 0;i < numshadowentities;i++)
3802                                 R_Shadow_DrawEntityShadow(shadowentities[i]);
3803                 }
3804
3805                 if (numlightentities_noselfshadow)
3806                 {
3807                         // draw lighting in the unmasked areas
3808                         R_Shadow_RenderMode_Lighting(true, false, false);
3809                         for (i = 0;i < numlightentities_noselfshadow;i++)
3810                                 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
3811
3812                         // optionally draw the illuminated areas
3813                         // for performance analysis by level designers
3814                         if (r_showlighting.integer && r_refdef.view.showdebug)
3815                         {
3816                                 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
3817                                 for (i = 0;i < numlightentities_noselfshadow;i++)
3818                                         R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
3819                         }
3820                         for (i = 0;i < numshadowentities_noselfshadow;i++)
3821                                 R_Shadow_DrawEntityShadow(shadowentities[shadowentities_noselfshadow - i]);
3822                 }
3823
3824                 if (numsurfaces + numlightentities)
3825                 {
3826                         // draw lighting in the unmasked areas
3827                         R_Shadow_RenderMode_Lighting(true, false, false);
3828                         if (numsurfaces)
3829                                 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3830                         for (i = 0;i < numlightentities;i++)
3831                                 R_Shadow_DrawEntityLight(lightentities[i]);
3832                 }
3833         }
3834         else
3835         {
3836                 // draw lighting in the unmasked areas
3837                 R_Shadow_RenderMode_Lighting(false, false, false);
3838                 if (numsurfaces)
3839                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3840                 for (i = 0;i < numlightentities;i++)
3841                         R_Shadow_DrawEntityLight(lightentities[i]);
3842                 for (i = 0;i < numlightentities_noselfshadow;i++)
3843                         R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
3844         }
3845 }
3846
3847 void R_Shadow_DrawLightSprites(void);
3848 void R_ShadowVolumeLighting(qboolean visible)
3849 {
3850         int flag;
3851         int lnum;
3852         size_t lightindex;
3853         dlight_t *light;
3854         size_t range;
3855         float f;
3856
3857         if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
3858                 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != r_shadow_shadowmapping.integer ||
3859                 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0) || 
3860                 r_shadow_shadowmaptexturetype != r_shadow_shadowmapping_texturetype.integer ||
3861                 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer || 
3862                 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer || 
3863                 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
3864                 R_Shadow_FreeShadowMaps();
3865
3866         if (r_editlights.integer)
3867                 R_Shadow_DrawLightSprites();
3868
3869         R_Shadow_RenderMode_Begin();
3870
3871         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3872         if (r_shadow_debuglight.integer >= 0)
3873         {
3874                 lightindex = r_shadow_debuglight.integer;
3875                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3876                 if (light && (light->flags & flag))
3877                         R_DrawRTLight(&light->rtlight, visible);
3878         }
3879         else
3880         {
3881                 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3882                 for (lightindex = 0;lightindex < range;lightindex++)
3883                 {
3884                         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3885                         if (light && (light->flags & flag))
3886                                 R_DrawRTLight(&light->rtlight, visible);
3887                 }
3888         }
3889         if (r_refdef.scene.rtdlight)
3890         {
3891                 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3892                         R_DrawRTLight(r_refdef.scene.lights[lnum], visible);
3893         }
3894         else if(gl_flashblend.integer)
3895         {
3896                 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3897                 {
3898                         rtlight_t *rtlight = r_refdef.scene.lights[lnum];
3899                         f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3900                         VectorScale(rtlight->color, f, rtlight->currentcolor);
3901                 }
3902         }
3903
3904         R_Shadow_RenderMode_End();
3905 }
3906
3907 extern const float r_screenvertex3f[12];
3908 extern void R_SetupView(qboolean allowwaterclippingplane);
3909 extern void R_ResetViewRendering3D(void);
3910 extern void R_ResetViewRendering2D(void);
3911 extern cvar_t r_shadows;
3912 extern cvar_t r_shadows_darken;
3913 extern cvar_t r_shadows_drawafterrtlighting;
3914 extern cvar_t r_shadows_castfrombmodels;
3915 extern cvar_t r_shadows_throwdistance;
3916 extern cvar_t r_shadows_throwdirection;
3917 void R_DrawModelShadows(void)
3918 {
3919         int i;
3920         float relativethrowdistance;
3921         entity_render_t *ent;
3922         vec3_t relativelightorigin;
3923         vec3_t relativelightdirection;
3924         vec3_t relativeshadowmins, relativeshadowmaxs;
3925         vec3_t tmp, shadowdir;
3926
3927         if (!r_drawentities.integer || !vid.stencil)
3928                 return;
3929
3930         CHECKGLERROR
3931         R_ResetViewRendering3D();
3932         //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
3933         //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
3934         R_Shadow_RenderMode_Begin();
3935         R_Shadow_RenderMode_ActiveLight(NULL);
3936         r_shadow_lightscissor[0] = r_refdef.view.x;
3937         r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
3938         r_shadow_lightscissor[2] = r_refdef.view.width;
3939         r_shadow_lightscissor[3] = r_refdef.view.height;
3940         R_Shadow_RenderMode_StencilShadowVolumes(false);
3941
3942         // get shadow dir
3943         if (r_shadows.integer == 2)
3944         {
3945                 Math_atov(r_shadows_throwdirection.string, shadowdir);
3946                 VectorNormalize(shadowdir);
3947         }
3948
3949         R_Shadow_ClearStencil();
3950
3951         for (i = 0;i < r_refdef.scene.numentities;i++)
3952         {
3953                 ent = r_refdef.scene.entities[i];
3954
3955                 // cast shadows from anything of the map (submodels are optional)
3956                 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
3957                 {
3958                         relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
3959                         VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
3960                         VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
3961                         if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
3962                                 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
3963                         else
3964                         {
3965                                 if(ent->entitynumber != 0)
3966                                 {
3967                                         // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
3968                                         int entnum, entnum2, recursion;
3969                                         entnum = entnum2 = ent->entitynumber;
3970                                         for(recursion = 32; recursion > 0; --recursion)
3971                                         {
3972                                                 entnum2 = cl.entities[entnum].state_current.tagentity;
3973                                                 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
3974                                                         entnum = entnum2;
3975                                                 else
3976                                                         break;
3977                                         }
3978                                         if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
3979                                         {
3980                                                 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
3981                                                 // transform into modelspace of OUR entity
3982                                                 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
3983                                                 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
3984                                         }
3985                                         else
3986                                                 VectorNegate(ent->modellight_lightdir, relativelightdirection);
3987                                 }
3988                                 else
3989                                         VectorNegate(ent->modellight_lightdir, relativelightdirection);
3990                         }
3991
3992                         VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
3993                         RSurf_ActiveModelEntity(ent, false, false);
3994                         ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3995                         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3996                 }
3997         }
3998
3999         // not really the right mode, but this will disable any silly stencil features
4000         R_Shadow_RenderMode_End();
4001
4002         // set up ortho view for rendering this pass
4003         //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4004         //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4005         //GL_ScissorTest(true);
4006         //R_Mesh_Matrix(&identitymatrix);
4007         //R_Mesh_ResetTextureState();
4008         R_ResetViewRendering2D();
4009         R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
4010         R_Mesh_ColorPointer(NULL, 0, 0);
4011         R_SetupGenericShader(false);
4012
4013         // set up a darkening blend on shadowed areas
4014         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4015         //GL_DepthRange(0, 1);
4016         //GL_DepthTest(false);
4017         //GL_DepthMask(false);
4018         //GL_PolygonOffset(0, 0);CHECKGLERROR
4019         GL_Color(0, 0, 0, r_shadows_darken.value);
4020         //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4021         //qglDepthFunc(GL_ALWAYS);CHECKGLERROR
4022         qglEnable(GL_STENCIL_TEST);CHECKGLERROR
4023         qglStencilMask(~0);CHECKGLERROR
4024         qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
4025         qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
4026
4027         // apply the blend to the shadowed areas
4028         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4029
4030         // restore the viewport
4031         R_SetViewport(&r_refdef.view.viewport);
4032
4033         // restore other state to normal
4034         //R_Shadow_RenderMode_End();
4035 }
4036
4037 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4038 {
4039         float zdist;
4040         vec3_t centerorigin;
4041         float vertex3f[12];
4042         // if it's too close, skip it
4043         if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4044                 return;
4045         zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4046         if (zdist < 32)
4047                 return;
4048         if (usequery && r_numqueries + 2 <= r_maxqueries)
4049         {
4050                 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4051                 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4052                 // 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
4053                 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4054
4055                 CHECKGLERROR
4056                 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use qglDepthFunc instead
4057                 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4058                 qglDepthFunc(GL_ALWAYS);
4059                 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4060                 R_Mesh_VertexPointer(vertex3f, 0, 0);
4061                 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4062                 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4063                 qglDepthFunc(GL_LEQUAL);
4064                 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4065                 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4066                 R_Mesh_VertexPointer(vertex3f, 0, 0);
4067                 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4068                 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4069                 CHECKGLERROR
4070         }
4071         rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4072 }
4073
4074 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4075
4076 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4077 {
4078         vec3_t color;
4079         GLint allpixels = 0, visiblepixels = 0;
4080         // now we have to check the query result
4081         if (rtlight->corona_queryindex_visiblepixels)
4082         {
4083                 CHECKGLERROR
4084                 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4085                 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4086                 CHECKGLERROR
4087                 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4088                 if (visiblepixels < 1 || allpixels < 1)
4089                         return;
4090                 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4091                 cscale *= rtlight->corona_visibility;
4092         }
4093         else
4094         {
4095                 // FIXME: these traces should scan all render entities instead of cl.world
4096                 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4097                         return;
4098         }
4099         VectorScale(rtlight->currentcolor, cscale, color);
4100         if (VectorLength(color) > (1.0f / 256.0f))
4101         {
4102                 float vertex3f[12];
4103                 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
4104                 if(negated)
4105                 {
4106                         VectorNegate(color, color);
4107                         qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
4108                 }
4109                 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4110                 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);
4111                 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false);
4112                 if(negated)
4113                         qglBlendEquationEXT(GL_FUNC_ADD_EXT);
4114         }
4115 }
4116
4117 void R_DrawCoronas(void)
4118 {
4119         int i, flag;
4120         qboolean usequery;
4121         size_t lightindex;
4122         dlight_t *light;
4123         rtlight_t *rtlight;
4124         size_t range;
4125         if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4126                 return;
4127         if (r_waterstate.renderingscene)
4128                 return;
4129         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4130         R_Mesh_Matrix(&identitymatrix);
4131
4132         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4133
4134         // check occlusion of coronas
4135         // use GL_ARB_occlusion_query if available
4136         // otherwise use raytraces
4137         r_numqueries = 0;
4138         usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
4139         if (usequery)
4140         {
4141                 GL_ColorMask(0,0,0,0);
4142                 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4143                 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4144                 {
4145                         i = r_maxqueries;
4146                         r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4147                         r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4148                         CHECKGLERROR
4149                         qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4150                         CHECKGLERROR
4151                 }
4152                 RSurf_ActiveWorldEntity();
4153                 GL_BlendFunc(GL_ONE, GL_ZERO);
4154                 GL_CullFace(GL_NONE);
4155                 GL_DepthMask(false);
4156                 GL_DepthRange(0, 1);
4157                 GL_PolygonOffset(0, 0);
4158                 GL_DepthTest(true);
4159                 R_Mesh_ColorPointer(NULL, 0, 0);
4160                 R_Mesh_ResetTextureState();
4161                 R_SetupGenericShader(false);
4162         }
4163         for (lightindex = 0;lightindex < range;lightindex++)
4164         {
4165                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4166                 if (!light)
4167                         continue;
4168                 rtlight = &light->rtlight;
4169                 rtlight->corona_visibility = 0;
4170                 rtlight->corona_queryindex_visiblepixels = 0;
4171                 rtlight->corona_queryindex_allpixels = 0;
4172                 if (!(rtlight->flags & flag))
4173                         continue;
4174                 if (rtlight->corona <= 0)
4175                         continue;
4176                 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4177                         continue;
4178                 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4179         }
4180         for (i = 0;i < r_refdef.scene.numlights;i++)
4181         {
4182                 rtlight = r_refdef.scene.lights[i];
4183                 rtlight->corona_visibility = 0;
4184                 rtlight->corona_queryindex_visiblepixels = 0;
4185                 rtlight->corona_queryindex_allpixels = 0;
4186                 if (!(rtlight->flags & flag))
4187                         continue;
4188                 if (rtlight->corona <= 0)
4189                         continue;
4190                 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4191         }
4192         if (usequery)
4193                 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4194
4195         // now draw the coronas using the query data for intensity info
4196         for (lightindex = 0;lightindex < range;lightindex++)
4197         {
4198                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4199                 if (!light)
4200                         continue;
4201                 rtlight = &light->rtlight;
4202                 if (rtlight->corona_visibility <= 0)
4203                         continue;
4204                 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4205         }
4206         for (i = 0;i < r_refdef.scene.numlights;i++)
4207         {
4208                 rtlight = r_refdef.scene.lights[i];
4209                 if (rtlight->corona_visibility <= 0)
4210                         continue;
4211                 if (gl_flashblend.integer)
4212                         R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4213                 else
4214                         R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4215         }
4216 }
4217
4218
4219
4220 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
4221 typedef struct suffixinfo_s
4222 {
4223         char *suffix;
4224         qboolean flipx, flipy, flipdiagonal;
4225 }
4226 suffixinfo_t;
4227 static suffixinfo_t suffix[3][6] =
4228 {
4229         {
4230                 {"px",   false, false, false},
4231                 {"nx",   false, false, false},
4232                 {"py",   false, false, false},
4233                 {"ny",   false, false, false},
4234                 {"pz",   false, false, false},
4235                 {"nz",   false, false, false}
4236         },
4237         {
4238                 {"posx", false, false, false},
4239                 {"negx", false, false, false},
4240                 {"posy", false, false, false},
4241                 {"negy", false, false, false},
4242                 {"posz", false, false, false},
4243                 {"negz", false, false, false}
4244         },
4245         {
4246                 {"rt",    true, false,  true},
4247                 {"lf",   false,  true,  true},
4248                 {"ft",    true,  true, false},
4249                 {"bk",   false, false, false},
4250                 {"up",    true, false,  true},
4251                 {"dn",    true, false,  true}
4252         }
4253 };
4254
4255 static int componentorder[4] = {0, 1, 2, 3};
4256
4257 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
4258 {
4259         int i, j, cubemapsize;
4260         unsigned char *cubemappixels, *image_buffer;
4261         rtexture_t *cubemaptexture;
4262         char name[256];
4263         // must start 0 so the first loadimagepixels has no requested width/height
4264         cubemapsize = 0;
4265         cubemappixels = NULL;
4266         cubemaptexture = NULL;
4267         // keep trying different suffix groups (posx, px, rt) until one loads
4268         for (j = 0;j < 3 && !cubemappixels;j++)
4269         {
4270                 // load the 6 images in the suffix group
4271                 for (i = 0;i < 6;i++)
4272                 {
4273                         // generate an image name based on the base and and suffix
4274                         dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
4275                         // load it
4276                         if ((image_buffer = loadimagepixelsbgra(name, false, false)))
4277                         {
4278                                 // an image loaded, make sure width and height are equal
4279                                 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
4280                                 {
4281                                         // if this is the first image to load successfully, allocate the cubemap memory
4282                                         if (!cubemappixels && image_width >= 1)
4283                                         {
4284                                                 cubemapsize = image_width;
4285                                                 // note this clears to black, so unavailable sides are black
4286                                                 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
4287                                         }
4288                                         // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
4289                                         if (cubemappixels)
4290                                                 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);
4291                                 }
4292                                 else
4293                                         Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
4294                                 // free the image
4295                                 Mem_Free(image_buffer);
4296                         }
4297                 }
4298         }
4299         // if a cubemap loaded, upload it
4300         if (cubemappixels)
4301         {
4302                 if (developer_loading.integer)
4303                         Con_Printf("loading cubemap \"%s\"\n", basename);
4304
4305                 if (!r_shadow_filters_texturepool)
4306                         r_shadow_filters_texturepool = R_AllocTexturePool();
4307                 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, TEXF_PRECACHE | (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR, NULL);
4308                 Mem_Free(cubemappixels);
4309         }
4310         else
4311         {
4312                 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
4313                 if (developer_loading.integer)
4314                 {
4315                         Con_Printf("(tried tried images ");
4316                         for (j = 0;j < 3;j++)
4317                                 for (i = 0;i < 6;i++)
4318                                         Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
4319                         Con_Print(" and was unable to find any of them).\n");
4320                 }
4321         }
4322         return cubemaptexture;
4323 }
4324
4325 rtexture_t *R_Shadow_Cubemap(const char *basename)
4326 {
4327         int i;
4328         for (i = 0;i < numcubemaps;i++)
4329                 if (!strcasecmp(cubemaps[i].basename, basename))
4330                         return cubemaps[i].texture ? cubemaps[i].texture : r_texture_whitecube;
4331         if (i >= MAX_CUBEMAPS)
4332                 return r_texture_whitecube;
4333         numcubemaps++;
4334         strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
4335         cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
4336         return cubemaps[i].texture;
4337 }
4338
4339 void R_Shadow_FreeCubemaps(void)
4340 {
4341         int i;
4342         for (i = 0;i < numcubemaps;i++)
4343         {
4344                 if (developer_loading.integer)
4345                         Con_Printf("unloading cubemap \"%s\"\n", cubemaps[i].basename);
4346                 if (cubemaps[i].texture)
4347                         R_FreeTexture(cubemaps[i].texture);
4348         }
4349
4350         numcubemaps = 0;
4351         R_FreeTexturePool(&r_shadow_filters_texturepool);
4352 }
4353
4354 dlight_t *R_Shadow_NewWorldLight(void)
4355 {
4356         return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4357 }
4358
4359 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)
4360 {
4361         matrix4x4_t matrix;
4362         // validate parameters
4363         if (style < 0 || style >= MAX_LIGHTSTYLES)
4364         {
4365                 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4366                 style = 0;
4367         }
4368         if (!cubemapname)
4369                 cubemapname = "";
4370
4371         // copy to light properties
4372         VectorCopy(origin, light->origin);
4373         light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4374         light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4375         light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4376         /*
4377         light->color[0] = max(color[0], 0);
4378         light->color[1] = max(color[1], 0);
4379         light->color[2] = max(color[2], 0);
4380         */
4381         light->color[0] = color[0];
4382         light->color[1] = color[1];
4383         light->color[2] = color[2];
4384         light->radius = max(radius, 0);
4385         light->style = style;
4386         light->shadow = shadowenable;
4387         light->corona = corona;
4388         strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4389         light->coronasizescale = coronasizescale;
4390         light->ambientscale = ambientscale;
4391         light->diffusescale = diffusescale;
4392         light->specularscale = specularscale;
4393         light->flags = flags;
4394
4395         // update renderable light data
4396         Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4397         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);
4398 }
4399
4400 void R_Shadow_FreeWorldLight(dlight_t *light)
4401 {
4402         if (r_shadow_selectedlight == light)
4403                 r_shadow_selectedlight = NULL;
4404         R_RTLight_Uncompile(&light->rtlight);
4405         Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4406 }
4407
4408 void R_Shadow_ClearWorldLights(void)
4409 {
4410         size_t lightindex;
4411         dlight_t *light;
4412         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4413         for (lightindex = 0;lightindex < range;lightindex++)
4414         {
4415                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4416                 if (light)
4417                         R_Shadow_FreeWorldLight(light);
4418         }
4419         r_shadow_selectedlight = NULL;
4420         R_Shadow_FreeCubemaps();
4421 }
4422
4423 void R_Shadow_SelectLight(dlight_t *light)
4424 {
4425         if (r_shadow_selectedlight)
4426                 r_shadow_selectedlight->selected = false;
4427         r_shadow_selectedlight = light;
4428         if (r_shadow_selectedlight)
4429                 r_shadow_selectedlight->selected = true;
4430 }
4431
4432 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4433 {
4434         // this is never batched (there can be only one)
4435         float vertex3f[12];
4436         R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4437         RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4438         R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false);
4439 }
4440
4441 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4442 {
4443         float intensity;
4444         float s;
4445         vec3_t spritecolor;
4446         skinframe_t *skinframe;
4447         float vertex3f[12];
4448
4449         // this is never batched (due to the ent parameter changing every time)
4450         // so numsurfaces == 1 and surfacelist[0] == lightnumber
4451         const dlight_t *light = (dlight_t *)ent;
4452         s = EDLIGHTSPRSIZE;
4453
4454         R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4455
4456         intensity = 0.5f;
4457         VectorScale(light->color, intensity, spritecolor);
4458         if (VectorLength(spritecolor) < 0.1732f)
4459                 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4460         if (VectorLength(spritecolor) > 1.0f)
4461                 VectorNormalize(spritecolor);
4462
4463         // draw light sprite
4464         if (light->cubemapname[0] && !light->shadow)
4465                 skinframe = r_editlights_sprcubemapnoshadowlight;
4466         else if (light->cubemapname[0])
4467                 skinframe = r_editlights_sprcubemaplight;
4468         else if (!light->shadow)
4469                 skinframe = r_editlights_sprnoshadowlight;
4470         else
4471                 skinframe = r_editlights_sprlight;
4472
4473         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);
4474         R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false);
4475
4476         // draw selection sprite if light is selected
4477         if (light->selected)
4478         {
4479                 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4480                 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false);
4481                 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4482         }
4483 }
4484
4485 void R_Shadow_DrawLightSprites(void)
4486 {
4487         size_t lightindex;
4488         dlight_t *light;
4489         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4490         for (lightindex = 0;lightindex < range;lightindex++)
4491         {
4492                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4493                 if (light)
4494                         R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4495         }
4496         R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4497 }
4498
4499 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4500 {
4501         unsigned int range;
4502         dlight_t *light;
4503         rtlight_t *rtlight;
4504         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4505         if (lightindex >= range)
4506                 return -1;
4507         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4508         if (!light)
4509                 return 0;
4510         rtlight = &light->rtlight;
4511         //if (!(rtlight->flags & flag))
4512         //      return 0;
4513         VectorCopy(rtlight->shadoworigin, origin);
4514         *radius = rtlight->radius;
4515         VectorCopy(rtlight->color, color);
4516         return 1;
4517 }
4518
4519 void R_Shadow_SelectLightInView(void)
4520 {
4521         float bestrating, rating, temp[3];
4522         dlight_t *best;
4523         size_t lightindex;
4524         dlight_t *light;
4525         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4526         best = NULL;
4527         bestrating = 0;
4528         for (lightindex = 0;lightindex < range;lightindex++)
4529         {
4530                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4531                 if (!light)
4532                         continue;
4533                 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4534                 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4535                 if (rating >= 0.95)
4536                 {
4537                         rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4538                         if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
4539                         {
4540                                 bestrating = rating;
4541                                 best = light;
4542                         }
4543                 }
4544         }
4545         R_Shadow_SelectLight(best);
4546 }
4547
4548 void R_Shadow_LoadWorldLights(void)
4549 {
4550         int n, a, style, shadow, flags;
4551         char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4552         float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4553         if (cl.worldmodel == NULL)
4554         {
4555                 Con_Print("No map loaded.\n");
4556                 return;
4557         }
4558         FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4559         strlcat (name, ".rtlights", sizeof (name));
4560         lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4561         if (lightsstring)
4562         {
4563                 s = lightsstring;
4564                 n = 0;
4565                 while (*s)
4566                 {
4567                         t = s;
4568                         /*
4569                         shadow = true;
4570                         for (;COM_Parse(t, true) && strcmp(
4571                         if (COM_Parse(t, true))
4572                         {
4573                                 if (com_token[0] == '!')
4574                                 {
4575                                         shadow = false;
4576                                         origin[0] = atof(com_token+1);
4577                                 }
4578                                 else
4579                                         origin[0] = atof(com_token);
4580                                 if (Com_Parse(t
4581                         }
4582                         */
4583                         t = s;
4584                         while (*s && *s != '\n' && *s != '\r')
4585                                 s++;
4586                         if (!*s)
4587                                 break;
4588                         tempchar = *s;
4589                         shadow = true;
4590                         // check for modifier flags
4591                         if (*t == '!')
4592                         {
4593                                 shadow = false;
4594                                 t++;
4595                         }
4596                         *s = 0;
4597 #if _MSC_VER >= 1400
4598 #define sscanf sscanf_s
4599 #endif
4600                         cubemapname[sizeof(cubemapname)-1] = 0;
4601 #if MAX_QPATH != 128
4602 #error update this code if MAX_QPATH changes
4603 #endif
4604                         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
4605 #if _MSC_VER >= 1400
4606 , sizeof(cubemapname)
4607 #endif
4608 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4609                         *s = tempchar;
4610                         if (a < 18)
4611                                 flags = LIGHTFLAG_REALTIMEMODE;
4612                         if (a < 17)
4613                                 specularscale = 1;
4614                         if (a < 16)
4615                                 diffusescale = 1;
4616                         if (a < 15)
4617                                 ambientscale = 0;
4618                         if (a < 14)
4619                                 coronasizescale = 0.25f;
4620                         if (a < 13)
4621                                 VectorClear(angles);
4622                         if (a < 10)
4623                                 corona = 0;
4624                         if (a < 9 || !strcmp(cubemapname, "\"\""))
4625                                 cubemapname[0] = 0;
4626                         // remove quotes on cubemapname
4627                         if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4628                         {
4629                                 size_t namelen;
4630                                 namelen = strlen(cubemapname) - 2;
4631                                 memmove(cubemapname, cubemapname + 1, namelen);
4632                                 cubemapname[namelen] = '\0';
4633                         }
4634                         if (a < 8)
4635                         {
4636                                 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);
4637                                 break;
4638                         }
4639                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4640                         if (*s == '\r')
4641                                 s++;
4642                         if (*s == '\n')
4643                                 s++;
4644                         n++;
4645                 }
4646                 if (*s)
4647                         Con_Printf("invalid rtlights file \"%s\"\n", name);
4648                 Mem_Free(lightsstring);
4649         }
4650 }
4651
4652 void R_Shadow_SaveWorldLights(void)
4653 {
4654         size_t lightindex;
4655         dlight_t *light;
4656         size_t bufchars, bufmaxchars;
4657         char *buf, *oldbuf;
4658         char name[MAX_QPATH];
4659         char line[MAX_INPUTLINE];
4660         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
4661         // I hate lines which are 3 times my screen size :( --blub
4662         if (!range)
4663                 return;
4664         if (cl.worldmodel == NULL)
4665         {
4666                 Con_Print("No map loaded.\n");
4667                 return;
4668         }
4669         FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4670         strlcat (name, ".rtlights", sizeof (name));
4671         bufchars = bufmaxchars = 0;
4672         buf = NULL;
4673         for (lightindex = 0;lightindex < range;lightindex++)
4674         {
4675                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4676                 if (!light)
4677                         continue;
4678                 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
4679                         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);
4680                 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
4681                         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]);
4682                 else
4683                         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);
4684                 if (bufchars + strlen(line) > bufmaxchars)
4685                 {
4686                         bufmaxchars = bufchars + strlen(line) + 2048;
4687                         oldbuf = buf;
4688                         buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
4689                         if (oldbuf)
4690                         {
4691                                 if (bufchars)
4692                                         memcpy(buf, oldbuf, bufchars);
4693                                 Mem_Free(oldbuf);
4694                         }
4695                 }
4696                 if (strlen(line))
4697                 {
4698                         memcpy(buf + bufchars, line, strlen(line));
4699                         bufchars += strlen(line);
4700                 }
4701         }
4702         if (bufchars)
4703                 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
4704         if (buf)
4705                 Mem_Free(buf);
4706 }
4707
4708 void R_Shadow_LoadLightsFile(void)
4709 {
4710         int n, a, style;
4711         char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
4712         float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
4713         if (cl.worldmodel == NULL)
4714         {
4715                 Con_Print("No map loaded.\n");
4716                 return;
4717         }
4718         FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4719         strlcat (name, ".lights", sizeof (name));
4720         lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4721         if (lightsstring)
4722         {
4723                 s = lightsstring;
4724                 n = 0;
4725                 while (*s)
4726                 {
4727                         t = s;
4728                         while (*s && *s != '\n' && *s != '\r')
4729                                 s++;
4730                         if (!*s)
4731                                 break;
4732                         tempchar = *s;
4733                         *s = 0;
4734                         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);
4735                         *s = tempchar;
4736                         if (a < 14)
4737                         {
4738                                 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);
4739                                 break;
4740                         }
4741                         radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
4742                         radius = bound(15, radius, 4096);
4743                         VectorScale(color, (2.0f / (8388608.0f)), color);
4744                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
4745                         if (*s == '\r')
4746                                 s++;
4747                         if (*s == '\n')
4748                                 s++;
4749                         n++;
4750                 }
4751                 if (*s)
4752                         Con_Printf("invalid lights file \"%s\"\n", name);
4753                 Mem_Free(lightsstring);
4754         }
4755 }
4756
4757 // tyrlite/hmap2 light types in the delay field
4758 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
4759
4760 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
4761 {
4762         int entnum, style, islight, skin, pflags, effects, type, n;
4763         char *entfiledata;
4764         const char *data;
4765         float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
4766         char key[256], value[MAX_INPUTLINE];
4767
4768         if (cl.worldmodel == NULL)
4769         {
4770                 Con_Print("No map loaded.\n");
4771                 return;
4772         }
4773         // try to load a .ent file first
4774         FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
4775         strlcat (key, ".ent", sizeof (key));
4776         data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
4777         // and if that is not found, fall back to the bsp file entity string
4778         if (!data)
4779                 data = cl.worldmodel->brush.entities;
4780         if (!data)
4781                 return;
4782         for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
4783         {
4784                 type = LIGHTTYPE_MINUSX;
4785                 origin[0] = origin[1] = origin[2] = 0;
4786                 originhack[0] = originhack[1] = originhack[2] = 0;
4787                 angles[0] = angles[1] = angles[2] = 0;
4788                 color[0] = color[1] = color[2] = 1;
4789                 light[0] = light[1] = light[2] = 1;light[3] = 300;
4790                 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
4791                 fadescale = 1;
4792                 lightscale = 1;
4793                 style = 0;
4794                 skin = 0;
4795                 pflags = 0;
4796                 effects = 0;
4797                 islight = false;
4798                 while (1)
4799                 {
4800                         if (!COM_ParseToken_Simple(&data, false, false))
4801                                 break; // error
4802                         if (com_token[0] == '}')
4803                                 break; // end of entity
4804                         if (com_token[0] == '_')
4805                                 strlcpy(key, com_token + 1, sizeof(key));
4806                         else
4807                                 strlcpy(key, com_token, sizeof(key));
4808                         while (key[strlen(key)-1] == ' ') // remove trailing spaces
4809                                 key[strlen(key)-1] = 0;
4810                         if (!COM_ParseToken_Simple(&data, false, false))
4811                                 break; // error
4812                         strlcpy(value, com_token, sizeof(value));
4813
4814                         // now that we have the key pair worked out...
4815                         if (!strcmp("light", key))
4816                         {
4817                                 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
4818                                 if (n == 1)
4819                                 {
4820                                         // quake
4821                                         light[0] = vec[0] * (1.0f / 256.0f);
4822                                         light[1] = vec[0] * (1.0f / 256.0f);
4823                                         light[2] = vec[0] * (1.0f / 256.0f);
4824                                         light[3] = vec[0];
4825                                 }
4826                                 else if (n == 4)
4827                                 {
4828                                         // halflife
4829                                         light[0] = vec[0] * (1.0f / 255.0f);
4830                                         light[1] = vec[1] * (1.0f / 255.0f);
4831                                         light[2] = vec[2] * (1.0f / 255.0f);
4832                                         light[3] = vec[3];
4833                                 }
4834                         }
4835                         else if (!strcmp("delay", key))
4836                                 type = atoi(value);
4837                         else if (!strcmp("origin", key))
4838                                 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
4839                         else if (!strcmp("angle", key))
4840                                 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
4841                         else if (!strcmp("angles", key))
4842                                 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
4843                         else if (!strcmp("color", key))
4844                                 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
4845                         else if (!strcmp("wait", key))
4846                                 fadescale = atof(value);
4847                         else if (!strcmp("classname", key))
4848                         {
4849                                 if (!strncmp(value, "light", 5))
4850                                 {
4851                                         islight = true;
4852                                         if (!strcmp(value, "light_fluoro"))
4853                                         {
4854                                                 originhack[0] = 0;
4855                                                 originhack[1] = 0;
4856                                                 originhack[2] = 0;
4857                                                 overridecolor[0] = 1;
4858                                                 overridecolor[1] = 1;
4859                                                 overridecolor[2] = 1;
4860                                         }
4861                                         if (!strcmp(value, "light_fluorospark"))
4862                                         {
4863                                                 originhack[0] = 0;
4864                                                 originhack[1] = 0;
4865                                                 originhack[2] = 0;
4866                                                 overridecolor[0] = 1;
4867                                                 overridecolor[1] = 1;
4868                                                 overridecolor[2] = 1;
4869                                         }
4870                                         if (!strcmp(value, "light_globe"))
4871                                         {
4872                                                 originhack[0] = 0;
4873                                                 originhack[1] = 0;
4874                                                 originhack[2] = 0;
4875                                                 overridecolor[0] = 1;
4876                                                 overridecolor[1] = 0.8;
4877                                                 overridecolor[2] = 0.4;
4878                                         }
4879                                         if (!strcmp(value, "light_flame_large_yellow"))
4880                                         {
4881                                                 originhack[0] = 0;
4882                                                 originhack[1] = 0;
4883                                                 originhack[2] = 0;
4884                                                 overridecolor[0] = 1;
4885                                                 overridecolor[1] = 0.5;
4886                                                 overridecolor[2] = 0.1;
4887                                         }
4888                                         if (!strcmp(value, "light_flame_small_yellow"))
4889                                         {
4890                                                 originhack[0] = 0;
4891                                                 originhack[1] = 0;
4892                                                 originhack[2] = 0;
4893                                                 overridecolor[0] = 1;
4894                                                 overridecolor[1] = 0.5;
4895                                                 overridecolor[2] = 0.1;
4896                                         }
4897                                         if (!strcmp(value, "light_torch_small_white"))
4898                                         {
4899                                                 originhack[0] = 0;
4900                                                 originhack[1] = 0;
4901                                                 originhack[2] = 0;
4902                                                 overridecolor[0] = 1;
4903                                                 overridecolor[1] = 0.5;
4904                                                 overridecolor[2] = 0.1;
4905                                         }
4906                                         if (!strcmp(value, "light_torch_small_walltorch"))
4907                                         {
4908                                                 originhack[0] = 0;
4909                                                 originhack[1] = 0;
4910                                                 originhack[2] = 0;
4911                                                 overridecolor[0] = 1;
4912                                                 overridecolor[1] = 0.5;
4913                                                 overridecolor[2] = 0.1;
4914                                         }
4915                                 }
4916                         }
4917                         else if (!strcmp("style", key))
4918                                 style = atoi(value);
4919                         else if (!strcmp("skin", key))
4920                                 skin = (int)atof(value);
4921                         else if (!strcmp("pflags", key))
4922                                 pflags = (int)atof(value);
4923                         else if (!strcmp("effects", key))
4924                                 effects = (int)atof(value);
4925                         else if (cl.worldmodel->type == mod_brushq3)
4926                         {
4927                                 if (!strcmp("scale", key))
4928                                         lightscale = atof(value);
4929                                 if (!strcmp("fade", key))
4930                                         fadescale = atof(value);
4931                         }
4932                 }
4933                 if (!islight)
4934                         continue;
4935                 if (lightscale <= 0)
4936                         lightscale = 1;
4937                 if (fadescale <= 0)
4938                         fadescale = 1;
4939                 if (color[0] == color[1] && color[0] == color[2])
4940                 {
4941                         color[0] *= overridecolor[0];
4942                         color[1] *= overridecolor[1];
4943                         color[2] *= overridecolor[2];
4944                 }
4945                 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
4946                 color[0] = color[0] * light[0];
4947                 color[1] = color[1] * light[1];
4948                 color[2] = color[2] * light[2];
4949                 switch (type)
4950                 {
4951                 case LIGHTTYPE_MINUSX:
4952                         break;
4953                 case LIGHTTYPE_RECIPX:
4954                         radius *= 2;
4955                         VectorScale(color, (1.0f / 16.0f), color);
4956                         break;
4957                 case LIGHTTYPE_RECIPXX:
4958                         radius *= 2;
4959                         VectorScale(color, (1.0f / 16.0f), color);
4960                         break;
4961                 default:
4962                 case LIGHTTYPE_NONE:
4963                         break;
4964                 case LIGHTTYPE_SUN:
4965                         break;
4966                 case LIGHTTYPE_MINUSXX:
4967                         break;
4968                 }
4969                 VectorAdd(origin, originhack, origin);
4970                 if (radius >= 1)
4971                         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);
4972         }
4973         if (entfiledata)
4974                 Mem_Free(entfiledata);
4975 }
4976
4977
4978 void R_Shadow_SetCursorLocationForView(void)
4979 {
4980         vec_t dist, push;
4981         vec3_t dest, endpos;
4982         trace_t trace;
4983         VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
4984         trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
4985         if (trace.fraction < 1)
4986         {
4987                 dist = trace.fraction * r_editlights_cursordistance.value;
4988                 push = r_editlights_cursorpushback.value;
4989                 if (push > dist)
4990                         push = dist;
4991                 push = -push;
4992                 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
4993                 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
4994         }
4995         else
4996         {
4997                 VectorClear( endpos );
4998         }
4999         r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5000         r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5001         r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5002 }
5003
5004 void R_Shadow_UpdateWorldLightSelection(void)
5005 {
5006         if (r_editlights.integer)
5007         {
5008                 R_Shadow_SetCursorLocationForView();
5009                 R_Shadow_SelectLightInView();
5010         }
5011         else
5012                 R_Shadow_SelectLight(NULL);
5013 }
5014
5015 void R_Shadow_EditLights_Clear_f(void)
5016 {
5017         R_Shadow_ClearWorldLights();
5018 }
5019
5020 void R_Shadow_EditLights_Reload_f(void)
5021 {
5022         if (!cl.worldmodel)
5023                 return;
5024         strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
5025         R_Shadow_ClearWorldLights();
5026         R_Shadow_LoadWorldLights();
5027         if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5028         {
5029                 R_Shadow_LoadLightsFile();
5030                 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5031                         R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5032         }
5033 }
5034
5035 void R_Shadow_EditLights_Save_f(void)
5036 {
5037         if (!cl.worldmodel)
5038                 return;
5039         R_Shadow_SaveWorldLights();
5040 }
5041
5042 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5043 {
5044         R_Shadow_ClearWorldLights();
5045         R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5046 }
5047
5048 void R_Shadow_EditLights_ImportLightsFile_f(void)
5049 {
5050         R_Shadow_ClearWorldLights();
5051         R_Shadow_LoadLightsFile();
5052 }
5053
5054 void R_Shadow_EditLights_Spawn_f(void)
5055 {
5056         vec3_t color;
5057         if (!r_editlights.integer)
5058         {
5059                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
5060                 return;
5061         }
5062         if (Cmd_Argc() != 1)
5063         {
5064                 Con_Print("r_editlights_spawn does not take parameters\n");
5065                 return;
5066         }
5067         color[0] = color[1] = color[2] = 1;
5068         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5069 }
5070
5071 void R_Shadow_EditLights_Edit_f(void)
5072 {
5073         vec3_t origin, angles, color;
5074         vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5075         int style, shadows, flags, normalmode, realtimemode;
5076         char cubemapname[MAX_INPUTLINE];
5077         if (!r_editlights.integer)
5078         {
5079                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
5080                 return;
5081         }
5082         if (!r_shadow_selectedlight)
5083         {
5084                 Con_Print("No selected light.\n");
5085                 return;
5086         }
5087         VectorCopy(r_shadow_selectedlight->origin, origin);
5088         VectorCopy(r_shadow_selectedlight->angles, angles);
5089         VectorCopy(r_shadow_selectedlight->color, color);
5090         radius = r_shadow_selectedlight->radius;
5091         style = r_shadow_selectedlight->style;
5092         if (r_shadow_selectedlight->cubemapname)
5093                 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5094         else
5095                 cubemapname[0] = 0;
5096         shadows = r_shadow_selectedlight->shadow;
5097         corona = r_shadow_selectedlight->corona;
5098         coronasizescale = r_shadow_selectedlight->coronasizescale;
5099         ambientscale = r_shadow_selectedlight->ambientscale;
5100         diffusescale = r_shadow_selectedlight->diffusescale;
5101         specularscale = r_shadow_selectedlight->specularscale;
5102         flags = r_shadow_selectedlight->flags;
5103         normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5104         realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5105         if (!strcmp(Cmd_Argv(1), "origin"))
5106         {
5107                 if (Cmd_Argc() != 5)
5108                 {
5109                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5110                         return;
5111                 }
5112                 origin[0] = atof(Cmd_Argv(2));
5113                 origin[1] = atof(Cmd_Argv(3));
5114                 origin[2] = atof(Cmd_Argv(4));
5115         }
5116         else if (!strcmp(Cmd_Argv(1), "originx"))
5117         {
5118                 if (Cmd_Argc() != 3)
5119                 {
5120                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5121                         return;
5122                 }
5123                 origin[0] = atof(Cmd_Argv(2));
5124         }
5125         else if (!strcmp(Cmd_Argv(1), "originy"))
5126         {
5127                 if (Cmd_Argc() != 3)
5128                 {
5129                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5130                         return;
5131                 }
5132                 origin[1] = atof(Cmd_Argv(2));
5133         }
5134         else if (!strcmp(Cmd_Argv(1), "originz"))
5135         {
5136                 if (Cmd_Argc() != 3)
5137                 {
5138                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5139                         return;
5140                 }
5141                 origin[2] = atof(Cmd_Argv(2));
5142         }
5143         else if (!strcmp(Cmd_Argv(1), "move"))
5144         {
5145                 if (Cmd_Argc() != 5)
5146                 {
5147                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5148                         return;
5149                 }
5150                 origin[0] += atof(Cmd_Argv(2));
5151                 origin[1] += atof(Cmd_Argv(3));
5152                 origin[2] += atof(Cmd_Argv(4));
5153         }
5154         else if (!strcmp(Cmd_Argv(1), "movex"))
5155         {
5156                 if (Cmd_Argc() != 3)
5157                 {
5158                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5159                         return;
5160                 }
5161                 origin[0] += atof(Cmd_Argv(2));
5162         }
5163         else if (!strcmp(Cmd_Argv(1), "movey"))
5164         {
5165                 if (Cmd_Argc() != 3)
5166                 {
5167                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5168                         return;
5169                 }
5170                 origin[1] += atof(Cmd_Argv(2));
5171         }
5172         else if (!strcmp(Cmd_Argv(1), "movez"))
5173         {
5174                 if (Cmd_Argc() != 3)
5175                 {
5176                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5177                         return;
5178                 }
5179                 origin[2] += atof(Cmd_Argv(2));
5180         }
5181         else if (!strcmp(Cmd_Argv(1), "angles"))
5182         {
5183                 if (Cmd_Argc() != 5)
5184                 {
5185                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5186                         return;
5187                 }
5188                 angles[0] = atof(Cmd_Argv(2));
5189                 angles[1] = atof(Cmd_Argv(3));
5190                 angles[2] = atof(Cmd_Argv(4));
5191         }
5192         else if (!strcmp(Cmd_Argv(1), "anglesx"))
5193         {
5194                 if (Cmd_Argc() != 3)
5195                 {
5196                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5197                         return;
5198                 }
5199                 angles[0] = atof(Cmd_Argv(2));
5200         }
5201         else if (!strcmp(Cmd_Argv(1), "anglesy"))
5202         {
5203                 if (Cmd_Argc() != 3)
5204                 {
5205                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5206                         return;
5207                 }
5208                 angles[1] = atof(Cmd_Argv(2));
5209         }
5210         else if (!strcmp(Cmd_Argv(1), "anglesz"))
5211         {
5212                 if (Cmd_Argc() != 3)
5213                 {
5214                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5215                         return;
5216                 }
5217                 angles[2] = atof(Cmd_Argv(2));
5218         }
5219         else if (!strcmp(Cmd_Argv(1), "color"))
5220         {
5221                 if (Cmd_Argc() != 5)
5222                 {
5223                         Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5224                         return;
5225                 }
5226                 color[0] = atof(Cmd_Argv(2));
5227                 color[1] = atof(Cmd_Argv(3));
5228                 color[2] = atof(Cmd_Argv(4));
5229         }
5230         else if (!strcmp(Cmd_Argv(1), "radius"))
5231         {
5232                 if (Cmd_Argc() != 3)
5233                 {
5234                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5235                         return;
5236                 }
5237                 radius = atof(Cmd_Argv(2));
5238         }
5239         else if (!strcmp(Cmd_Argv(1), "colorscale"))
5240         {
5241                 if (Cmd_Argc() == 3)
5242                 {
5243                         double scale = atof(Cmd_Argv(2));
5244                         color[0] *= scale;
5245                         color[1] *= scale;
5246                         color[2] *= scale;
5247                 }
5248                 else
5249                 {
5250                         if (Cmd_Argc() != 5)
5251                         {
5252                                 Con_Printf("usage: r_editlights_edit %s red green blue  (OR grey instead of red green blue)\n", Cmd_Argv(1));
5253                                 return;
5254                         }
5255                         color[0] *= atof(Cmd_Argv(2));
5256                         color[1] *= atof(Cmd_Argv(3));
5257                         color[2] *= atof(Cmd_Argv(4));
5258                 }
5259         }
5260         else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5261         {
5262                 if (Cmd_Argc() != 3)
5263                 {
5264                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5265                         return;
5266                 }
5267                 radius *= atof(Cmd_Argv(2));
5268         }
5269         else if (!strcmp(Cmd_Argv(1), "style"))
5270         {
5271                 if (Cmd_Argc() != 3)
5272                 {
5273                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5274                         return;
5275                 }
5276                 style = atoi(Cmd_Argv(2));
5277         }
5278         else if (!strcmp(Cmd_Argv(1), "cubemap"))
5279         {
5280                 if (Cmd_Argc() > 3)
5281                 {
5282                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5283                         return;
5284                 }
5285                 if (Cmd_Argc() == 3)
5286                         strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5287                 else
5288                         cubemapname[0] = 0;
5289         }
5290         else if (!strcmp(Cmd_Argv(1), "shadows"))
5291         {
5292                 if (Cmd_Argc() != 3)
5293                 {
5294                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5295                         return;
5296                 }
5297                 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5298         }
5299         else if (!strcmp(Cmd_Argv(1), "corona"))
5300         {
5301                 if (Cmd_Argc() != 3)
5302                 {
5303                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5304                         return;
5305                 }
5306                 corona = atof(Cmd_Argv(2));
5307         }
5308         else if (!strcmp(Cmd_Argv(1), "coronasize"))
5309         {
5310                 if (Cmd_Argc() != 3)
5311                 {
5312                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5313                         return;
5314                 }
5315                 coronasizescale = atof(Cmd_Argv(2));
5316         }
5317         else if (!strcmp(Cmd_Argv(1), "ambient"))
5318         {
5319                 if (Cmd_Argc() != 3)
5320                 {
5321                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5322                         return;
5323                 }
5324                 ambientscale = atof(Cmd_Argv(2));
5325         }
5326         else if (!strcmp(Cmd_Argv(1), "diffuse"))
5327         {
5328                 if (Cmd_Argc() != 3)
5329                 {
5330                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5331                         return;
5332                 }
5333                 diffusescale = atof(Cmd_Argv(2));
5334         }
5335         else if (!strcmp(Cmd_Argv(1), "specular"))
5336         {
5337                 if (Cmd_Argc() != 3)
5338                 {
5339                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5340                         return;
5341                 }
5342                 specularscale = atof(Cmd_Argv(2));
5343         }
5344         else if (!strcmp(Cmd_Argv(1), "normalmode"))
5345         {
5346                 if (Cmd_Argc() != 3)
5347                 {
5348                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5349                         return;
5350                 }
5351                 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5352         }
5353         else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5354         {
5355                 if (Cmd_Argc() != 3)
5356                 {
5357                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5358                         return;
5359                 }
5360                 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5361         }
5362         else
5363         {
5364                 Con_Print("usage: r_editlights_edit [property] [value]\n");
5365                 Con_Print("Selected light's properties:\n");
5366                 Con_Printf("Origin       : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5367                 Con_Printf("Angles       : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5368                 Con_Printf("Color        : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5369                 Con_Printf("Radius       : %f\n", r_shadow_selectedlight->radius);
5370                 Con_Printf("Corona       : %f\n", r_shadow_selectedlight->corona);
5371                 Con_Printf("Style        : %i\n", r_shadow_selectedlight->style);
5372                 Con_Printf("Shadows      : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5373                 Con_Printf("Cubemap      : %s\n", r_shadow_selectedlight->cubemapname);
5374                 Con_Printf("CoronaSize   : %f\n", r_shadow_selectedlight->coronasizescale);
5375                 Con_Printf("Ambient      : %f\n", r_shadow_selectedlight->ambientscale);
5376                 Con_Printf("Diffuse      : %f\n", r_shadow_selectedlight->diffusescale);
5377                 Con_Printf("Specular     : %f\n", r_shadow_selectedlight->specularscale);
5378                 Con_Printf("NormalMode   : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5379                 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5380                 return;
5381         }
5382         flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5383         R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5384 }
5385
5386 void R_Shadow_EditLights_EditAll_f(void)
5387 {
5388         size_t lightindex;
5389         dlight_t *light;
5390         size_t range;
5391
5392         if (!r_editlights.integer)
5393         {
5394                 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5395                 return;
5396         }
5397
5398         // EditLights doesn't seem to have a "remove" command or something so:
5399         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5400         for (lightindex = 0;lightindex < range;lightindex++)
5401         {
5402                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5403                 if (!light)
5404                         continue;
5405                 R_Shadow_SelectLight(light);
5406                 R_Shadow_EditLights_Edit_f();
5407         }
5408 }
5409
5410 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5411 {
5412         int lightnumber, lightcount;
5413         size_t lightindex, range;
5414         dlight_t *light;
5415         float x, y;
5416         char temp[256];
5417         if (!r_editlights.integer)
5418                 return;
5419         x = vid_conwidth.value - 240;
5420         y = 5;
5421         DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5422         lightnumber = -1;
5423         lightcount = 0;
5424         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5425         for (lightindex = 0;lightindex < range;lightindex++)
5426         {
5427                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5428                 if (!light)
5429                         continue;
5430                 if (light == r_shadow_selectedlight)
5431                         lightnumber = lightindex;
5432                 lightcount++;
5433         }
5434         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;
5435         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;
5436         y += 8;
5437         if (r_shadow_selectedlight == NULL)
5438                 return;
5439         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;
5440         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;
5441         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;
5442         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;
5443         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;
5444         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;
5445         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;
5446         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;
5447         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;
5448         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;
5449         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;
5450         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;
5451         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;
5452         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;
5453         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;
5454 }
5455
5456 void R_Shadow_EditLights_ToggleShadow_f(void)
5457 {
5458         if (!r_editlights.integer)
5459         {
5460                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
5461                 return;
5462         }
5463         if (!r_shadow_selectedlight)
5464         {
5465                 Con_Print("No selected light.\n");
5466                 return;
5467         }
5468         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);
5469 }
5470
5471 void R_Shadow_EditLights_ToggleCorona_f(void)
5472 {
5473         if (!r_editlights.integer)
5474         {
5475                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
5476                 return;
5477         }
5478         if (!r_shadow_selectedlight)
5479         {
5480                 Con_Print("No selected light.\n");
5481                 return;
5482         }
5483         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);
5484 }
5485
5486 void R_Shadow_EditLights_Remove_f(void)
5487 {
5488         if (!r_editlights.integer)
5489         {
5490                 Con_Print("Cannot remove light when not in editing mode.  Set r_editlights to 1.\n");
5491                 return;
5492         }
5493         if (!r_shadow_selectedlight)
5494         {
5495                 Con_Print("No selected light.\n");
5496                 return;
5497         }
5498         R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5499         r_shadow_selectedlight = NULL;
5500 }
5501
5502 void R_Shadow_EditLights_Help_f(void)
5503 {
5504         Con_Print(
5505 "Documentation on r_editlights system:\n"
5506 "Settings:\n"
5507 "r_editlights : enable/disable editing mode\n"
5508 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5509 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5510 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5511 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5512 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5513 "Commands:\n"
5514 "r_editlights_help : this help\n"
5515 "r_editlights_clear : remove all lights\n"
5516 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5517 "r_editlights_save : save to .rtlights file\n"
5518 "r_editlights_spawn : create a light with default settings\n"
5519 "r_editlights_edit command : edit selected light - more documentation below\n"
5520 "r_editlights_remove : remove selected light\n"
5521 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5522 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5523 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5524 "Edit commands:\n"
5525 "origin x y z : set light location\n"
5526 "originx x: set x component of light location\n"
5527 "originy y: set y component of light location\n"
5528 "originz z: set z component of light location\n"
5529 "move x y z : adjust light location\n"
5530 "movex x: adjust x component of light location\n"
5531 "movey y: adjust y component of light location\n"
5532 "movez z: adjust z component of light location\n"
5533 "angles x y z : set light angles\n"
5534 "anglesx x: set x component of light angles\n"
5535 "anglesy y: set y component of light angles\n"
5536 "anglesz z: set z component of light angles\n"
5537 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5538 "radius radius : set radius (size) of light\n"
5539 "colorscale grey : multiply color of light (1 does nothing)\n"
5540 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5541 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5542 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5543 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5544 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5545 "shadows 1/0 : turn on/off shadows\n"
5546 "corona n : set corona intensity\n"
5547 "coronasize n : set corona size (0-1)\n"
5548 "ambient n : set ambient intensity (0-1)\n"
5549 "diffuse n : set diffuse intensity (0-1)\n"
5550 "specular n : set specular intensity (0-1)\n"
5551 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5552 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5553 "<nothing> : print light properties to console\n"
5554         );
5555 }
5556
5557 void R_Shadow_EditLights_CopyInfo_f(void)
5558 {
5559         if (!r_editlights.integer)
5560         {
5561                 Con_Print("Cannot copy light info when not in editing mode.  Set r_editlights to 1.\n");
5562                 return;
5563         }
5564         if (!r_shadow_selectedlight)
5565         {
5566                 Con_Print("No selected light.\n");
5567                 return;
5568         }
5569         VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5570         VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5571         r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5572         r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5573         if (r_shadow_selectedlight->cubemapname)
5574                 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5575         else
5576                 r_shadow_bufferlight.cubemapname[0] = 0;
5577         r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5578         r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5579         r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5580         r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5581         r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5582         r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5583         r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5584 }
5585
5586 void R_Shadow_EditLights_PasteInfo_f(void)
5587 {
5588         if (!r_editlights.integer)
5589         {
5590                 Con_Print("Cannot paste light info 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_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);
5599 }
5600
5601 void R_Shadow_EditLights_Init(void)
5602 {
5603         Cvar_RegisterVariable(&r_editlights);
5604         Cvar_RegisterVariable(&r_editlights_cursordistance);
5605         Cvar_RegisterVariable(&r_editlights_cursorpushback);
5606         Cvar_RegisterVariable(&r_editlights_cursorpushoff);
5607         Cvar_RegisterVariable(&r_editlights_cursorgrid);
5608         Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
5609         Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
5610         Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
5611         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)");
5612         Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
5613         Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
5614         Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
5615         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)");
5616         Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
5617         Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
5618         Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
5619         Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
5620         Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
5621         Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
5622         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)");
5623 }
5624
5625
5626
5627 /*
5628 =============================================================================
5629
5630 LIGHT SAMPLING
5631
5632 =============================================================================
5633 */
5634
5635 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
5636 {
5637         VectorClear(diffusecolor);
5638         VectorClear(diffusenormal);
5639
5640         if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
5641         {
5642                 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient * (2.0f / 128.0f);
5643                 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
5644         }
5645         else
5646                 VectorSet(ambientcolor, 1, 1, 1);
5647
5648         if (dynamic)
5649         {
5650                 int i;
5651                 float f, v[3];
5652                 rtlight_t *light;
5653                 for (i = 0;i < r_refdef.scene.numlights;i++)
5654                 {
5655                         light = r_refdef.scene.lights[i];
5656                         Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
5657                         f = 1 - VectorLength2(v);
5658                         if (f > 0 && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
5659                                 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);
5660                 }
5661         }
5662 }