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