]> icculus.org git repositories - divverent/darkplaces.git/blob - r_shadow.c
Fixed the x axis flipped shadows, 1 step closer to getting all this to work perfecty...
[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 static float testcolor[4] = {0,1,0,1};
2050 void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
2051 {
2052         float nearclip, farclip, bias;
2053         r_viewport_t viewport;
2054         int flipped;
2055         GLuint fbo = 0;
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                 // completely different meaning than in OpenGL path
2120                 r_shadow_shadowmap_parameters[1] = 0;
2121                 r_shadow_shadowmap_parameters[3] = -bias;
2122                 // we invert the cull mode because we flip the projection matrix
2123                 // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
2124                 GL_CullFace(r_refdef.view.cullface_front);
2125                 // D3D considers it an error to use a scissor larger than the viewport...  clear just this view
2126                 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2127                 if (r_shadow_shadowmapsampler)
2128                 {
2129                         GL_ColorMask(0,0,0,0);
2130                         if (clear)
2131                                 GL_Clear(GL_DEPTH_BUFFER_BIT, testcolor, 1.0f, 0);
2132                 }
2133                 else
2134                 {
2135                         GL_ColorMask(1,1,1,1);
2136                         if (clear)
2137                                 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, testcolor, 1.0f, 0);
2138                 }
2139                 break;
2140         case RENDERPATH_D3D10:
2141         case RENDERPATH_D3D11:
2142                 // D3D considers it an error to use a scissor larger than the viewport...  clear just this view
2143                 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2144                 GL_ColorMask(0,0,0,0);
2145                 if (clear)
2146                         GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
2147                 break;
2148         }
2149 }
2150
2151 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2152 {
2153         R_Mesh_ResetTextureState();
2154         R_Mesh_ResetRenderTargets();
2155         if (transparent)
2156         {
2157                 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2158                 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2159                 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2160                 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2161         }
2162         R_Shadow_RenderMode_Reset();
2163         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2164         if (!transparent)
2165                 GL_DepthFunc(GL_EQUAL);
2166         // do global setup needed for the chosen lighting mode
2167         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2168                 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2169         r_shadow_usingshadowmap2d = shadowmapping;
2170         r_shadow_rendermode = r_shadow_lightingrendermode;
2171         // only draw light where this geometry was already rendered AND the
2172         // stencil is 128 (values other than this mean shadow)
2173         if (stenciltest)
2174                 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2175         else
2176                 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2177 }
2178
2179 static const unsigned short bboxelements[36] =
2180 {
2181         5, 1, 3, 5, 3, 7,
2182         6, 2, 0, 6, 0, 4,
2183         7, 3, 2, 7, 2, 6,
2184         4, 0, 1, 4, 1, 5,
2185         4, 5, 7, 4, 7, 6,
2186         1, 0, 2, 1, 2, 3,
2187 };
2188
2189 static const float bboxpoints[8][3] =
2190 {
2191         {-1,-1,-1},
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 };
2200
2201 void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadowmapping)
2202 {
2203         int i;
2204         float vertex3f[8*3];
2205         const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2206 // do global setup needed for the chosen lighting mode
2207         R_Shadow_RenderMode_Reset();
2208         r_shadow_rendermode = r_shadow_lightingrendermode;
2209         R_EntityMatrix(&identitymatrix);
2210         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2211         // only draw light where this geometry was already rendered AND the
2212         // stencil is 128 (values other than this mean shadow)
2213         R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2214         R_Mesh_SetRenderTargets(r_shadow_prepasslightingfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
2215
2216         r_shadow_usingshadowmap2d = shadowmapping;
2217
2218         // render the lighting
2219         R_SetupShader_DeferredLight(rsurface.rtlight);
2220         for (i = 0;i < 8;i++)
2221                 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2222         GL_ColorMask(1,1,1,1);
2223         GL_DepthMask(false);
2224         GL_DepthRange(0, 1);
2225         GL_PolygonOffset(0, 0);
2226         GL_DepthTest(true);
2227         GL_DepthFunc(GL_GREATER);
2228         GL_CullFace(r_refdef.view.cullface_back);
2229         R_Mesh_PrepareVertices_Position_Arrays(8, vertex3f);
2230         R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
2231 }
2232
2233 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2234 {
2235         R_Shadow_RenderMode_Reset();
2236         GL_BlendFunc(GL_ONE, GL_ONE);
2237         GL_DepthRange(0, 1);
2238         GL_DepthTest(r_showshadowvolumes.integer < 2);
2239         GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2240         GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2241         GL_CullFace(GL_NONE);
2242         r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2243 }
2244
2245 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2246 {
2247         R_Shadow_RenderMode_Reset();
2248         GL_BlendFunc(GL_ONE, GL_ONE);
2249         GL_DepthRange(0, 1);
2250         GL_DepthTest(r_showlighting.integer < 2);
2251         GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2252         if (!transparent)
2253                 GL_DepthFunc(GL_EQUAL);
2254         R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2255         r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2256 }
2257
2258 void R_Shadow_RenderMode_End(void)
2259 {
2260         R_Shadow_RenderMode_Reset();
2261         R_Shadow_RenderMode_ActiveLight(NULL);
2262         GL_DepthMask(true);
2263         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2264         r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2265 }
2266
2267 int bboxedges[12][2] =
2268 {
2269         // top
2270         {0, 1}, // +X
2271         {0, 2}, // +Y
2272         {1, 3}, // Y, +X
2273         {2, 3}, // X, +Y
2274         // bottom
2275         {4, 5}, // +X
2276         {4, 6}, // +Y
2277         {5, 7}, // Y, +X
2278         {6, 7}, // X, +Y
2279         // verticals
2280         {0, 4}, // +Z
2281         {1, 5}, // X, +Z
2282         {2, 6}, // Y, +Z
2283         {3, 7}, // XY, +Z
2284 };
2285
2286 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2287 {
2288         int i, ix1, iy1, ix2, iy2;
2289         float x1, y1, x2, y2;
2290         vec4_t v, v2;
2291         float vertex[20][3];
2292         int j, k;
2293         vec4_t plane4f;
2294         int numvertices;
2295         float corner[8][4];
2296         float dist[8];
2297         int sign[8];
2298         float f;
2299
2300         r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2301         r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2302         r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2303         r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2304
2305         if (!r_shadow_scissor.integer)
2306                 return false;
2307
2308         // if view is inside the light box, just say yes it's visible
2309         if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
2310                 return false;
2311
2312         x1 = y1 = x2 = y2 = 0;
2313
2314         // transform all corners that are infront of the nearclip plane
2315         VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
2316         plane4f[3] = r_refdef.view.frustum[4].dist;
2317         numvertices = 0;
2318         for (i = 0;i < 8;i++)
2319         {
2320                 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
2321                 dist[i] = DotProduct4(corner[i], plane4f);
2322                 sign[i] = dist[i] > 0;
2323                 if (!sign[i])
2324                 {
2325                         VectorCopy(corner[i], vertex[numvertices]);
2326                         numvertices++;
2327                 }
2328         }
2329         // if some points are behind the nearclip, add clipped edge points to make
2330         // sure that the scissor boundary is complete
2331         if (numvertices > 0 && numvertices < 8)
2332         {
2333                 // add clipped edge points
2334                 for (i = 0;i < 12;i++)
2335                 {
2336                         j = bboxedges[i][0];
2337                         k = bboxedges[i][1];
2338                         if (sign[j] != sign[k])
2339                         {
2340                                 f = dist[j] / (dist[j] - dist[k]);
2341                                 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
2342                                 numvertices++;
2343                         }
2344                 }
2345         }
2346
2347         // if we have no points to check, the light is behind the view plane
2348         if (!numvertices)
2349                 return true;
2350
2351         // if we have some points to transform, check what screen area is covered
2352         x1 = y1 = x2 = y2 = 0;
2353         v[3] = 1.0f;
2354         //Con_Printf("%i vertices to transform...\n", numvertices);
2355         for (i = 0;i < numvertices;i++)
2356         {
2357                 VectorCopy(vertex[i], v);
2358                 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
2359                 //Con_Printf("%.3f %.3f %.3f %.3f transformed to %.3f %.3f %.3f %.3f\n", v[0], v[1], v[2], v[3], v2[0], v2[1], v2[2], v2[3]);
2360                 if (i)
2361                 {
2362                         if (x1 > v2[0]) x1 = v2[0];
2363                         if (x2 < v2[0]) x2 = v2[0];
2364                         if (y1 > v2[1]) y1 = v2[1];
2365                         if (y2 < v2[1]) y2 = v2[1];
2366                 }
2367                 else
2368                 {
2369                         x1 = x2 = v2[0];
2370                         y1 = y2 = v2[1];
2371                 }
2372         }
2373
2374         // now convert the scissor rectangle to integer screen coordinates
2375         ix1 = (int)(x1 - 1.0f);
2376         iy1 = vid.height - (int)(y2 - 1.0f);
2377         ix2 = (int)(x2 + 1.0f);
2378         iy2 = vid.height - (int)(y1 + 1.0f);
2379         //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
2380
2381         // clamp it to the screen
2382         if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
2383         if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
2384         if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
2385         if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
2386
2387         // if it is inside out, it's not visible
2388         if (ix2 <= ix1 || iy2 <= iy1)
2389                 return true;
2390
2391         // the light area is visible, set up the scissor rectangle
2392         r_shadow_lightscissor[0] = ix1;
2393         r_shadow_lightscissor[1] = iy1;
2394         r_shadow_lightscissor[2] = ix2 - ix1;
2395         r_shadow_lightscissor[3] = iy2 - iy1;
2396
2397         // D3D Y coordinate is top to bottom, OpenGL is bottom to top, fix the D3D one
2398         switch(vid.renderpath)
2399         {
2400         case RENDERPATH_D3D9:
2401         case RENDERPATH_D3D10:
2402         case RENDERPATH_D3D11:
2403                 r_shadow_lightscissor[1] = vid.height - r_shadow_lightscissor[1] - r_shadow_lightscissor[3];
2404                 break;
2405         case RENDERPATH_GL11:
2406         case RENDERPATH_GL13:
2407         case RENDERPATH_GL20:
2408         case RENDERPATH_CGGL:
2409                 break;
2410         }
2411
2412         r_refdef.stats.lights_scissored++;
2413         return false;
2414 }
2415
2416 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor)
2417 {
2418         int i;
2419         const float *vertex3f;
2420         const float *normal3f;
2421         float *color4f;
2422         float dist, dot, distintensity, shadeintensity, v[3], n[3];
2423         switch (r_shadow_rendermode)
2424         {
2425         case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2426         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2427                 if (VectorLength2(diffusecolor) > 0)
2428                 {
2429                         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)
2430                         {
2431                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2432                                 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2433                                 if ((dot = DotProduct(n, v)) < 0)
2434                                 {
2435                                         shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2436                                         VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2437                                 }
2438                                 else
2439                                         VectorCopy(ambientcolor, color4f);
2440                                 if (r_refdef.fogenabled)
2441                                 {
2442                                         float f;
2443                                         f = RSurf_FogVertex(vertex3f);
2444                                         VectorScale(color4f, f, color4f);
2445                                 }
2446                                 color4f[3] = 1;
2447                         }
2448                 }
2449                 else
2450                 {
2451                         for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2452                         {
2453                                 VectorCopy(ambientcolor, color4f);
2454                                 if (r_refdef.fogenabled)
2455                                 {
2456                                         float f;
2457                                         Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2458                                         f = RSurf_FogVertex(vertex3f);
2459                                         VectorScale(color4f + 4*i, f, color4f);
2460                                 }
2461                                 color4f[3] = 1;
2462                         }
2463                 }
2464                 break;
2465         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2466                 if (VectorLength2(diffusecolor) > 0)
2467                 {
2468                         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)
2469                         {
2470                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2471                                 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2472                                 {
2473                                         Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2474                                         if ((dot = DotProduct(n, v)) < 0)
2475                                         {
2476                                                 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2477                                                 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2478                                                 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2479                                                 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2480                                         }
2481                                         else
2482                                         {
2483                                                 color4f[0] = ambientcolor[0] * distintensity;
2484                                                 color4f[1] = ambientcolor[1] * distintensity;
2485                                                 color4f[2] = ambientcolor[2] * distintensity;
2486                                         }
2487                                         if (r_refdef.fogenabled)
2488                                         {
2489                                                 float f;
2490                                                 f = RSurf_FogVertex(vertex3f);
2491                                                 VectorScale(color4f, f, color4f);
2492                                         }
2493                                 }
2494                                 else
2495                                         VectorClear(color4f);
2496                                 color4f[3] = 1;
2497                         }
2498                 }
2499                 else
2500                 {
2501                         for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2502                         {
2503                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2504                                 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2505                                 {
2506                                         color4f[0] = ambientcolor[0] * distintensity;
2507                                         color4f[1] = ambientcolor[1] * distintensity;
2508                                         color4f[2] = ambientcolor[2] * distintensity;
2509                                         if (r_refdef.fogenabled)
2510                                         {
2511                                                 float f;
2512                                                 f = RSurf_FogVertex(vertex3f);
2513                                                 VectorScale(color4f, f, color4f);
2514                                         }
2515                                 }
2516                                 else
2517                                         VectorClear(color4f);
2518                                 color4f[3] = 1;
2519                         }
2520                 }
2521                 break;
2522         case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2523                 if (VectorLength2(diffusecolor) > 0)
2524                 {
2525                         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)
2526                         {
2527                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2528                                 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2529                                 {
2530                                         distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2531                                         Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2532                                         if ((dot = DotProduct(n, v)) < 0)
2533                                         {
2534                                                 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2535                                                 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2536                                                 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2537                                                 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2538                                         }
2539                                         else
2540                                         {
2541                                                 color4f[0] = ambientcolor[0] * distintensity;
2542                                                 color4f[1] = ambientcolor[1] * distintensity;
2543                                                 color4f[2] = ambientcolor[2] * distintensity;
2544                                         }
2545                                         if (r_refdef.fogenabled)
2546                                         {
2547                                                 float f;
2548                                                 f = RSurf_FogVertex(vertex3f);
2549                                                 VectorScale(color4f, f, color4f);
2550                                         }
2551                                 }
2552                                 else
2553                                         VectorClear(color4f);
2554                                 color4f[3] = 1;
2555                         }
2556                 }
2557                 else
2558                 {
2559                         for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2560                         {
2561                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2562                                 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2563                                 {
2564                                         distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2565                                         color4f[0] = ambientcolor[0] * distintensity;
2566                                         color4f[1] = ambientcolor[1] * distintensity;
2567                                         color4f[2] = ambientcolor[2] * distintensity;
2568                                         if (r_refdef.fogenabled)
2569                                         {
2570                                                 float f;
2571                                                 f = RSurf_FogVertex(vertex3f);
2572                                                 VectorScale(color4f, f, color4f);
2573                                         }
2574                                 }
2575                                 else
2576                                         VectorClear(color4f);
2577                                 color4f[3] = 1;
2578                         }
2579                 }
2580                 break;
2581         default:
2582                 break;
2583         }
2584 }
2585
2586 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2587 {
2588         // used to display how many times a surface is lit for level design purposes
2589         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
2590         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
2591         RSurf_DrawBatch();
2592 }
2593
2594 static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
2595 {
2596         // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2597         R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL);
2598         if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2599                 GL_DepthFunc(GL_EQUAL);
2600         RSurf_DrawBatch();
2601         if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2602                 GL_DepthFunc(GL_LEQUAL);
2603 }
2604
2605 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2606 {
2607         int renders;
2608         int i;
2609         int stop;
2610         int newfirstvertex;
2611         int newlastvertex;
2612         int newnumtriangles;
2613         int *newe;
2614         const int *e;
2615         float *c;
2616         int maxtriangles = 4096;
2617         static int newelements[4096*3];
2618         R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2);
2619         for (renders = 0;renders < 4;renders++)
2620         {
2621                 stop = true;
2622                 newfirstvertex = 0;
2623                 newlastvertex = 0;
2624                 newnumtriangles = 0;
2625                 newe = newelements;
2626                 // due to low fillrate on the cards this vertex lighting path is
2627                 // designed for, we manually cull all triangles that do not
2628                 // contain a lit vertex
2629                 // this builds batches of triangles from multiple surfaces and
2630                 // renders them at once
2631                 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2632                 {
2633                         if (VectorLength2(rsurface.array_passcolor4f + e[0] * 4) + VectorLength2(rsurface.array_passcolor4f + e[1] * 4) + VectorLength2(rsurface.array_passcolor4f + e[2] * 4) >= 0.01)
2634                         {
2635                                 if (newnumtriangles)
2636                                 {
2637                                         newfirstvertex = min(newfirstvertex, e[0]);
2638                                         newlastvertex  = max(newlastvertex, e[0]);
2639                                 }
2640                                 else
2641                                 {
2642                                         newfirstvertex = e[0];
2643                                         newlastvertex = e[0];
2644                                 }
2645                                 newfirstvertex = min(newfirstvertex, e[1]);
2646                                 newlastvertex  = max(newlastvertex, e[1]);
2647                                 newfirstvertex = min(newfirstvertex, e[2]);
2648                                 newlastvertex  = max(newlastvertex, e[2]);
2649                                 newe[0] = e[0];
2650                                 newe[1] = e[1];
2651                                 newe[2] = e[2];
2652                                 newnumtriangles++;
2653                                 newe += 3;
2654                                 if (newnumtriangles >= maxtriangles)
2655                                 {
2656                                         R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
2657                                         newnumtriangles = 0;
2658                                         newe = newelements;
2659                                         stop = false;
2660                                 }
2661                         }
2662                 }
2663                 if (newnumtriangles >= 1)
2664                 {
2665                         R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
2666                         stop = false;
2667                 }
2668                 // if we couldn't find any lit triangles, exit early
2669                 if (stop)
2670                         break;
2671                 // now reduce the intensity for the next overbright pass
2672                 // we have to clamp to 0 here incase the drivers have improper
2673                 // handling of negative colors
2674                 // (some old drivers even have improper handling of >1 color)
2675                 stop = true;
2676                 for (i = 0, c = rsurface.array_passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2677                 {
2678                         if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2679                         {
2680                                 c[0] = max(0, c[0] - 1);
2681                                 c[1] = max(0, c[1] - 1);
2682                                 c[2] = max(0, c[2] - 1);
2683                                 stop = false;
2684                         }
2685                         else
2686                                 VectorClear(c);
2687                 }
2688                 // another check...
2689                 if (stop)
2690                         break;
2691         }
2692 }
2693
2694 static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale)
2695 {
2696         // OpenGL 1.1 path (anything)
2697         float ambientcolorbase[3], diffusecolorbase[3];
2698         float ambientcolorpants[3], diffusecolorpants[3];
2699         float ambientcolorshirt[3], diffusecolorshirt[3];
2700         const float *surfacecolor = rsurface.texture->dlightcolor;
2701         const float *surfacepants = rsurface.colormap_pantscolor;
2702         const float *surfaceshirt = rsurface.colormap_shirtcolor;
2703         rtexture_t *basetexture = rsurface.texture->basetexture;
2704         rtexture_t *pantstexture = rsurface.texture->pantstexture;
2705         rtexture_t *shirttexture = rsurface.texture->shirttexture;
2706         qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
2707         qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
2708         ambientscale *= 2 * r_refdef.view.colorscale;
2709         diffusescale *= 2 * r_refdef.view.colorscale;
2710         ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
2711         diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
2712         ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
2713         diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
2714         ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
2715         diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
2716         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (diffusescale > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD, texturenumsurfaces, texturesurfacelist);
2717         R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2718         R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.array_passcolor4f, 0, 0);
2719         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
2720         R_Mesh_TexBind(0, basetexture);
2721         R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2722         R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
2723         switch(r_shadow_rendermode)
2724         {
2725         case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2726                 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
2727                 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2728                 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2729                 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2730                 break;
2731         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2732                 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
2733                 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
2734                 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
2735                 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2736                 // fall through
2737         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2738                 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
2739                 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2740                 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2741                 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2742                 break;
2743         case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2744                 break;
2745         default:
2746                 break;
2747         }
2748         //R_Mesh_TexBind(0, basetexture);
2749         R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
2750         if (dopants)
2751         {
2752                 R_Mesh_TexBind(0, pantstexture);
2753                 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
2754         }
2755         if (doshirt)
2756         {
2757                 R_Mesh_TexBind(0, shirttexture);
2758                 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
2759         }
2760 }
2761
2762 extern cvar_t gl_lightmaps;
2763 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2764 {
2765         float ambientscale, diffusescale, specularscale;
2766         qboolean negated;
2767         float lightcolor[3];
2768         VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
2769         ambientscale = rsurface.rtlight->ambientscale;
2770         diffusescale = rsurface.rtlight->diffusescale;
2771         specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2772         if (!r_shadow_usenormalmap.integer)
2773         {
2774                 ambientscale += 1.0f * diffusescale;
2775                 diffusescale = 0;
2776                 specularscale = 0;
2777         }
2778         if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
2779                 return;
2780         negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
2781         if(negated)
2782         {
2783                 VectorNegate(lightcolor, lightcolor);
2784                 switch(vid.renderpath)
2785                 {
2786                 case RENDERPATH_GL11:
2787                 case RENDERPATH_GL13:
2788                 case RENDERPATH_GL20:
2789                 case RENDERPATH_CGGL:
2790                         qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
2791                         break;
2792                 case RENDERPATH_D3D9:
2793 #ifdef SUPPORTD3D
2794                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
2795 #endif
2796                         break;
2797                 case RENDERPATH_D3D10:
2798                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2799                         break;
2800                 case RENDERPATH_D3D11:
2801                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2802                         break;
2803                 }
2804         }
2805         RSurf_SetupDepthAndCulling();
2806         switch (r_shadow_rendermode)
2807         {
2808         case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2809                 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2810                 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
2811                 break;
2812         case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2813                 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale, specularscale);
2814                 break;
2815         case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2816         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2817         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2818         case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2819                 R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale);
2820                 break;
2821         default:
2822                 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2823                 break;
2824         }
2825         if(negated)
2826         {
2827                 switch(vid.renderpath)
2828                 {
2829                 case RENDERPATH_GL11:
2830                 case RENDERPATH_GL13:
2831                 case RENDERPATH_GL20:
2832                 case RENDERPATH_CGGL:
2833                         qglBlendEquationEXT(GL_FUNC_ADD_EXT);
2834                         break;
2835                 case RENDERPATH_D3D9:
2836 #ifdef SUPPORTD3D
2837                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
2838 #endif
2839                         break;
2840                 case RENDERPATH_D3D10:
2841                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2842                         break;
2843                 case RENDERPATH_D3D11:
2844                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2845                         break;
2846                 }
2847         }
2848 }
2849
2850 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)
2851 {
2852         matrix4x4_t tempmatrix = *matrix;
2853         Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2854
2855         // if this light has been compiled before, free the associated data
2856         R_RTLight_Uncompile(rtlight);
2857
2858         // clear it completely to avoid any lingering data
2859         memset(rtlight, 0, sizeof(*rtlight));
2860
2861         // copy the properties
2862         rtlight->matrix_lighttoworld = tempmatrix;
2863         Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2864         Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2865         rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2866         VectorCopy(color, rtlight->color);
2867         rtlight->cubemapname[0] = 0;
2868         if (cubemapname && cubemapname[0])
2869                 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2870         rtlight->shadow = shadow;
2871         rtlight->corona = corona;
2872         rtlight->style = style;
2873         rtlight->isstatic = isstatic;
2874         rtlight->coronasizescale = coronasizescale;
2875         rtlight->ambientscale = ambientscale;
2876         rtlight->diffusescale = diffusescale;
2877         rtlight->specularscale = specularscale;
2878         rtlight->flags = flags;
2879
2880         // compute derived data
2881         //rtlight->cullradius = rtlight->radius;
2882         //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2883         rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2884         rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2885         rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2886         rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2887         rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2888         rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2889 }
2890
2891 // compiles rtlight geometry
2892 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2893 void R_RTLight_Compile(rtlight_t *rtlight)
2894 {
2895         int i;
2896         int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2897         int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
2898         entity_render_t *ent = r_refdef.scene.worldentity;
2899         dp_model_t *model = r_refdef.scene.worldmodel;
2900         unsigned char *data;
2901         shadowmesh_t *mesh;
2902
2903         // compile the light
2904         rtlight->compiled = true;
2905         rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
2906         rtlight->static_numleafs = 0;
2907         rtlight->static_numleafpvsbytes = 0;
2908         rtlight->static_leaflist = NULL;
2909         rtlight->static_leafpvs = NULL;
2910         rtlight->static_numsurfaces = 0;
2911         rtlight->static_surfacelist = NULL;
2912         rtlight->static_shadowmap_receivers = 0x3F;
2913         rtlight->static_shadowmap_casters = 0x3F;
2914         rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2915         rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2916         rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2917         rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2918         rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2919         rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2920
2921         if (model && model->GetLightInfo)
2922         {
2923                 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
2924                 r_shadow_compilingrtlight = rtlight;
2925                 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);
2926                 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2927                 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
2928                 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
2929                 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
2930                 rtlight->static_numsurfaces = numsurfaces;
2931                 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2932                 rtlight->static_numleafs = numleafs;
2933                 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2934                 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2935                 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2936                 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
2937                 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
2938                 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
2939                 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
2940                 if (rtlight->static_numsurfaces)
2941                         memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2942                 if (rtlight->static_numleafs)
2943                         memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2944                 if (rtlight->static_numleafpvsbytes)
2945                         memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2946                 if (rtlight->static_numshadowtrispvsbytes)
2947                         memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
2948                 if (rtlight->static_numlighttrispvsbytes)
2949                         memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
2950                 switch (rtlight->shadowmode)
2951                 {
2952                 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2953                         if (model->CompileShadowMap && rtlight->shadow)
2954                                 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2955                         break;
2956                 default:
2957                         if (model->CompileShadowVolume && rtlight->shadow)
2958                                 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2959                         break;
2960                 }
2961                 // now we're done compiling the rtlight
2962                 r_shadow_compilingrtlight = NULL;
2963         }
2964
2965
2966         // use smallest available cullradius - box radius or light radius
2967         //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2968         //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2969
2970         shadowzpasstris = 0;
2971         if (rtlight->static_meshchain_shadow_zpass)
2972                 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
2973                         shadowzpasstris += mesh->numtriangles;
2974
2975         shadowzfailtris = 0;
2976         if (rtlight->static_meshchain_shadow_zfail)
2977                 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
2978                         shadowzfailtris += mesh->numtriangles;
2979
2980         lighttris = 0;
2981         if (rtlight->static_numlighttrispvsbytes)
2982                 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
2983                         if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
2984                                 lighttris++;
2985
2986         shadowtris = 0;
2987         if (rtlight->static_numlighttrispvsbytes)
2988                 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
2989                         if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
2990                                 shadowtris++;
2991
2992         if (developer_extra.integer)
2993                 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);
2994 }
2995
2996 void R_RTLight_Uncompile(rtlight_t *rtlight)
2997 {
2998         if (rtlight->compiled)
2999         {
3000                 if (rtlight->static_meshchain_shadow_zpass)
3001                         Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3002                 rtlight->static_meshchain_shadow_zpass = NULL;
3003                 if (rtlight->static_meshchain_shadow_zfail)
3004                         Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3005                 rtlight->static_meshchain_shadow_zfail = NULL;
3006                 if (rtlight->static_meshchain_shadow_shadowmap)
3007                         Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3008                 rtlight->static_meshchain_shadow_shadowmap = NULL;
3009                 // these allocations are grouped
3010                 if (rtlight->static_surfacelist)
3011                         Mem_Free(rtlight->static_surfacelist);
3012                 rtlight->static_numleafs = 0;
3013                 rtlight->static_numleafpvsbytes = 0;
3014                 rtlight->static_leaflist = NULL;
3015                 rtlight->static_leafpvs = NULL;
3016                 rtlight->static_numsurfaces = 0;
3017                 rtlight->static_surfacelist = NULL;
3018                 rtlight->static_numshadowtrispvsbytes = 0;
3019                 rtlight->static_shadowtrispvs = NULL;
3020                 rtlight->static_numlighttrispvsbytes = 0;
3021                 rtlight->static_lighttrispvs = NULL;
3022                 rtlight->compiled = false;
3023         }
3024 }
3025
3026 void R_Shadow_UncompileWorldLights(void)
3027 {
3028         size_t lightindex;
3029         dlight_t *light;
3030         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3031         for (lightindex = 0;lightindex < range;lightindex++)
3032         {
3033                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3034                 if (!light)
3035                         continue;
3036                 R_RTLight_Uncompile(&light->rtlight);
3037         }
3038 }
3039
3040 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3041 {
3042         int i, j;
3043         mplane_t plane;
3044         // reset the count of frustum planes
3045         // see rtlight->cached_frustumplanes definition for how much this array
3046         // can hold
3047         rtlight->cached_numfrustumplanes = 0;
3048
3049         // haven't implemented a culling path for ortho rendering
3050         if (!r_refdef.view.useperspective)
3051         {
3052                 // check if the light is on screen and copy the 4 planes if it is
3053                 for (i = 0;i < 4;i++)
3054                         if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3055                                 break;
3056                 if (i == 4)
3057                         for (i = 0;i < 4;i++)
3058                                 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3059                 return;
3060         }
3061
3062 #if 1
3063         // generate a deformed frustum that includes the light origin, this is
3064         // used to cull shadow casting surfaces that can not possibly cast a
3065         // shadow onto the visible light-receiving surfaces, which can be a
3066         // performance gain
3067         //
3068         // if the light origin is onscreen the result will be 4 planes exactly
3069         // if the light origin is offscreen on only one axis the result will
3070         // be exactly 5 planes (split-side case)
3071         // if the light origin is offscreen on two axes the result will be
3072         // exactly 4 planes (stretched corner case)
3073         for (i = 0;i < 4;i++)
3074         {
3075                 // quickly reject standard frustum planes that put the light
3076                 // origin outside the frustum
3077                 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3078                         continue;
3079                 // copy the plane
3080                 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3081         }
3082         // if all the standard frustum planes were accepted, the light is onscreen
3083         // otherwise we need to generate some more planes below...
3084         if (rtlight->cached_numfrustumplanes < 4)
3085         {
3086                 // at least one of the stock frustum planes failed, so we need to
3087                 // create one or two custom planes to enclose the light origin
3088                 for (i = 0;i < 4;i++)
3089                 {
3090                         // create a plane using the view origin and light origin, and a
3091                         // single point from the frustum corner set
3092                         TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3093                         VectorNormalize(plane.normal);
3094                         plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3095                         // see if this plane is backwards and flip it if so
3096                         for (j = 0;j < 4;j++)
3097                                 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3098                                         break;
3099                         if (j < 4)
3100                         {
3101                                 VectorNegate(plane.normal, plane.normal);
3102                                 plane.dist *= -1;
3103                                 // flipped plane, test again to see if it is now valid
3104                                 for (j = 0;j < 4;j++)
3105                                         if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3106                                                 break;
3107                                 // if the plane is still not valid, then it is dividing the
3108                                 // frustum and has to be rejected
3109                                 if (j < 4)
3110                                         continue;
3111                         }
3112                         // we have created a valid plane, compute extra info
3113                         PlaneClassify(&plane);
3114                         // copy the plane
3115                         rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3116 #if 1
3117                         // if we've found 5 frustum planes then we have constructed a
3118                         // proper split-side case and do not need to keep searching for
3119                         // planes to enclose the light origin
3120                         if (rtlight->cached_numfrustumplanes == 5)
3121                                 break;
3122 #endif
3123                 }
3124         }
3125 #endif
3126
3127 #if 0
3128         for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3129         {
3130                 plane = rtlight->cached_frustumplanes[i];
3131                 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));
3132         }
3133 #endif
3134
3135 #if 0
3136         // now add the light-space box planes if the light box is rotated, as any
3137         // caster outside the oriented light box is irrelevant (even if it passed
3138         // the worldspace light box, which is axial)
3139         if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3140         {
3141                 for (i = 0;i < 6;i++)
3142                 {
3143                         vec3_t v;
3144                         VectorClear(v);
3145                         v[i >> 1] = (i & 1) ? -1 : 1;
3146                         Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3147                         VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3148                         plane.dist = VectorNormalizeLength(plane.normal);
3149                         plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3150                         rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3151                 }
3152         }
3153 #endif
3154
3155 #if 0
3156         // add the world-space reduced box planes
3157         for (i = 0;i < 6;i++)
3158         {
3159                 VectorClear(plane.normal);
3160                 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3161                 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3162                 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3163         }
3164 #endif
3165
3166 #if 0
3167         {
3168         int j, oldnum;
3169         vec3_t points[8];
3170         vec_t bestdist;
3171         // reduce all plane distances to tightly fit the rtlight cull box, which
3172         // is in worldspace
3173         VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3174         VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3175         VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3176         VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3177         VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3178         VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3179         VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3180         VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3181         oldnum = rtlight->cached_numfrustumplanes;
3182         rtlight->cached_numfrustumplanes = 0;
3183         for (j = 0;j < oldnum;j++)
3184         {
3185                 // find the nearest point on the box to this plane
3186                 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3187                 for (i = 1;i < 8;i++)
3188                 {
3189                         dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3190                         if (bestdist > dist)
3191                                 bestdist = dist;
3192                 }
3193                 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);
3194                 // if the nearest point is near or behind the plane, we want this
3195                 // plane, otherwise the plane is useless as it won't cull anything
3196                 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3197                 {
3198                         PlaneClassify(&rtlight->cached_frustumplanes[j]);
3199                         rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3200                 }
3201         }
3202         }
3203 #endif
3204 }
3205
3206 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3207 {
3208         shadowmesh_t *mesh;
3209
3210         RSurf_ActiveWorldEntity();
3211
3212         if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3213         {
3214                 CHECKGLERROR
3215                 GL_CullFace(GL_NONE);
3216         mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3217         for (;mesh;mesh = mesh->next)
3218         {
3219                         if (!mesh->sidetotals[r_shadow_shadowmapside])
3220                                 continue;
3221             r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3222             R_Mesh_PrepareVertices_Position(mesh->numverts, mesh->vertexposition, mesh->vertexpositionbuffer);
3223             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);
3224         }
3225         CHECKGLERROR
3226     }
3227         else if (r_refdef.scene.worldentity->model)
3228                 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);
3229
3230         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3231 }
3232
3233 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3234 {
3235         qboolean zpass = false;
3236         shadowmesh_t *mesh;
3237         int t, tend;
3238         int surfacelistindex;
3239         msurface_t *surface;
3240
3241         RSurf_ActiveWorldEntity();
3242
3243         if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3244         {
3245                 CHECKGLERROR
3246                 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
3247                 {
3248                         zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3249                         R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3250                 }
3251                 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3252                 for (;mesh;mesh = mesh->next)
3253                 {
3254                         r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3255                         R_Mesh_PrepareVertices_Position(mesh->numverts, mesh->vertexposition, mesh->vertexpositionbuffer);
3256                         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3257                         {
3258                                 // increment stencil if frontface is infront of depthbuffer
3259                                 GL_CullFace(r_refdef.view.cullface_back);
3260                                 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
3261                                 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);
3262                                 // decrement stencil if backface is infront of depthbuffer
3263                                 GL_CullFace(r_refdef.view.cullface_front);
3264                                 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
3265                         }
3266                         else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3267                         {
3268                                 // decrement stencil if backface is behind depthbuffer
3269                                 GL_CullFace(r_refdef.view.cullface_front);
3270                                 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
3271                                 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);
3272                                 // increment stencil if frontface is behind depthbuffer
3273                                 GL_CullFace(r_refdef.view.cullface_back);
3274                                 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
3275                         }
3276                         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);
3277                 }
3278                 CHECKGLERROR
3279         }
3280         else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
3281         {
3282                 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
3283                 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3284                 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3285                 {
3286                         surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3287                         for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3288                                 if (CHECKPVSBIT(trispvs, t))
3289                                         shadowmarklist[numshadowmark++] = t;
3290                 }
3291                 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);
3292         }
3293         else if (numsurfaces)
3294                 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);
3295
3296         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3297 }
3298
3299 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3300 {
3301         vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3302         vec_t relativeshadowradius;
3303         RSurf_ActiveModelEntity(ent, false, false, false);
3304         Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3305         // we need to re-init the shader for each entity because the matrix changed
3306         relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3307         relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3308         relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3309         relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3310         relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3311         relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3312         relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3313         switch (r_shadow_rendermode)
3314         {
3315         case R_SHADOW_RENDERMODE_SHADOWMAP2D:
3316                 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3317                 break;
3318         default:
3319                 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3320                 break;
3321         }
3322         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3323 }
3324
3325 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3326 {
3327         // set up properties for rendering light onto this entity
3328         RSurf_ActiveModelEntity(ent, true, true, false);
3329         GL_AlphaTest(false);
3330         Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3331         Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3332         Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3333         Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3334 }
3335
3336 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3337 {
3338         if (!r_refdef.scene.worldmodel->DrawLight)
3339                 return;
3340
3341         // set up properties for rendering light onto this entity
3342         RSurf_ActiveWorldEntity();
3343         GL_AlphaTest(false);
3344         rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3345         Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3346         Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3347         VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3348
3349         r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3350
3351         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3352 }
3353
3354 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3355 {
3356         dp_model_t *model = ent->model;
3357         if (!model->DrawLight)
3358                 return;
3359
3360         R_Shadow_SetupEntityLight(ent);
3361
3362         model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3363
3364         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3365 }
3366
3367 void R_Shadow_PrepareLight(rtlight_t *rtlight)
3368 {
3369         int i;
3370         float f;
3371         int numleafs, numsurfaces;
3372         int *leaflist, *surfacelist;
3373         unsigned char *leafpvs;
3374         unsigned char *shadowtrispvs;
3375         unsigned char *lighttrispvs;
3376         //unsigned char *surfacesides;
3377         int numlightentities;
3378         int numlightentities_noselfshadow;
3379         int numshadowentities;
3380         int numshadowentities_noselfshadow;
3381         static entity_render_t *lightentities[MAX_EDICTS];
3382         static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3383         static entity_render_t *shadowentities[MAX_EDICTS];
3384         static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3385         qboolean nolight;
3386
3387         rtlight->draw = false;
3388
3389         // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3390         // skip lights that are basically invisible (color 0 0 0)
3391         nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3392
3393         // loading is done before visibility checks because loading should happen
3394         // all at once at the start of a level, not when it stalls gameplay.
3395         // (especially important to benchmarks)
3396         // compile light
3397         if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3398         {
3399                 if (rtlight->compiled)
3400                         R_RTLight_Uncompile(rtlight);
3401                 R_RTLight_Compile(rtlight);
3402         }
3403
3404         // load cubemap
3405         rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3406
3407         // look up the light style value at this time
3408         f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3409         VectorScale(rtlight->color, f, rtlight->currentcolor);
3410         /*
3411         if (rtlight->selected)
3412         {
3413                 f = 2 + sin(realtime * M_PI * 4.0);
3414                 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3415         }
3416         */
3417
3418         // if lightstyle is currently off, don't draw the light
3419         if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3420                 return;
3421
3422         // skip processing on corona-only lights
3423         if (nolight)
3424                 return;
3425
3426         // if the light box is offscreen, skip it
3427         if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3428                 return;
3429
3430         VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3431         VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3432
3433         R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3434
3435         if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3436         {
3437                 // compiled light, world available and can receive realtime lighting
3438                 // retrieve leaf information
3439                 numleafs = rtlight->static_numleafs;
3440                 leaflist = rtlight->static_leaflist;
3441                 leafpvs = rtlight->static_leafpvs;
3442                 numsurfaces = rtlight->static_numsurfaces;
3443                 surfacelist = rtlight->static_surfacelist;
3444                 //surfacesides = NULL;
3445                 shadowtrispvs = rtlight->static_shadowtrispvs;
3446                 lighttrispvs = rtlight->static_lighttrispvs;
3447         }
3448         else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3449         {
3450                 // dynamic light, world available and can receive realtime lighting
3451                 // calculate lit surfaces and leafs
3452                 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);
3453                 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3454                 leaflist = r_shadow_buffer_leaflist;
3455                 leafpvs = r_shadow_buffer_leafpvs;
3456                 surfacelist = r_shadow_buffer_surfacelist;
3457                 //surfacesides = r_shadow_buffer_surfacesides;
3458                 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3459                 lighttrispvs = r_shadow_buffer_lighttrispvs;
3460                 // if the reduced leaf bounds are offscreen, skip it
3461                 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3462                         return;
3463         }
3464         else
3465         {
3466                 // no world
3467                 numleafs = 0;
3468                 leaflist = NULL;
3469                 leafpvs = NULL;
3470                 numsurfaces = 0;
3471                 surfacelist = NULL;
3472                 //surfacesides = NULL;
3473                 shadowtrispvs = NULL;
3474                 lighttrispvs = NULL;
3475         }
3476         // check if light is illuminating any visible leafs
3477         if (numleafs)
3478         {
3479                 for (i = 0;i < numleafs;i++)
3480                         if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3481                                 break;
3482                 if (i == numleafs)
3483                         return;
3484         }
3485
3486         // make a list of lit entities and shadow casting entities
3487         numlightentities = 0;
3488         numlightentities_noselfshadow = 0;
3489         numshadowentities = 0;
3490         numshadowentities_noselfshadow = 0;
3491
3492         // add dynamic entities that are lit by the light
3493         for (i = 0;i < r_refdef.scene.numentities;i++)
3494         {
3495                 dp_model_t *model;
3496                 entity_render_t *ent = r_refdef.scene.entities[i];
3497                 vec3_t org;
3498                 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3499                         continue;
3500                 // skip the object entirely if it is not within the valid
3501                 // shadow-casting region (which includes the lit region)
3502                 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3503                         continue;
3504                 if (!(model = ent->model))
3505                         continue;
3506                 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3507                 {
3508                         // this entity wants to receive light, is visible, and is
3509                         // inside the light box
3510                         // TODO: check if the surfaces in the model can receive light
3511                         // so now check if it's in a leaf seen by the light
3512                         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))
3513                                 continue;
3514                         if (ent->flags & RENDER_NOSELFSHADOW)
3515                                 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3516                         else
3517                                 lightentities[numlightentities++] = ent;
3518                         // since it is lit, it probably also casts a shadow...
3519                         // about the VectorDistance2 - light emitting entities should not cast their own shadow
3520                         Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3521                         if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3522                         {
3523                                 // note: exterior models without the RENDER_NOSELFSHADOW
3524                                 // flag still create a RENDER_NOSELFSHADOW shadow but
3525                                 // are lit normally, this means that they are
3526                                 // self-shadowing but do not shadow other
3527                                 // RENDER_NOSELFSHADOW entities such as the gun
3528                                 // (very weird, but keeps the player shadow off the gun)
3529                                 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3530                                         shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3531                                 else
3532                                         shadowentities[numshadowentities++] = ent;
3533                         }
3534                 }
3535                 else if (ent->flags & RENDER_SHADOW)
3536                 {
3537                         // this entity is not receiving light, but may still need to
3538                         // cast a shadow...
3539                         // TODO: check if the surfaces in the model can cast shadow
3540                         // now check if it is in a leaf seen by the light
3541                         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))
3542                                 continue;
3543                         // about the VectorDistance2 - light emitting entities should not cast their own shadow
3544                         Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3545                         if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3546                         {
3547                                 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3548                                         shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3549                                 else
3550                                         shadowentities[numshadowentities++] = ent;
3551                         }
3552                 }
3553         }
3554
3555         // return if there's nothing at all to light
3556         if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3557                 return;
3558
3559         // count this light in the r_speeds
3560         r_refdef.stats.lights++;
3561
3562         // flag it as worth drawing later
3563         rtlight->draw = true;
3564
3565         // cache all the animated entities that cast a shadow but are not visible
3566         for (i = 0;i < numshadowentities;i++)
3567                 if (!shadowentities[i]->animcache_vertex3f)
3568                         R_AnimCache_GetEntity(shadowentities[i], false, false);
3569         for (i = 0;i < numshadowentities_noselfshadow;i++)
3570                 if (!shadowentities_noselfshadow[i]->animcache_vertex3f)
3571                         R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3572
3573         // allocate some temporary memory for rendering this light later in the frame
3574         // reusable buffers need to be copied, static data can be used as-is
3575         rtlight->cached_numlightentities               = numlightentities;
3576         rtlight->cached_numlightentities_noselfshadow  = numlightentities_noselfshadow;
3577         rtlight->cached_numshadowentities              = numshadowentities;
3578         rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3579         rtlight->cached_numsurfaces                    = numsurfaces;
3580         rtlight->cached_lightentities                  = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3581         rtlight->cached_lightentities_noselfshadow     = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3582         rtlight->cached_shadowentities                 = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3583         rtlight->cached_shadowentities_noselfshadow    = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3584         if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3585         {
3586                 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
3587                 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3588                 rtlight->cached_shadowtrispvs                  =   (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3589                 rtlight->cached_lighttrispvs                   =   (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3590                 rtlight->cached_surfacelist                    =              (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3591         }
3592         else
3593         {
3594                 // compiled light data
3595                 rtlight->cached_shadowtrispvs = shadowtrispvs;
3596                 rtlight->cached_lighttrispvs = lighttrispvs;
3597                 rtlight->cached_surfacelist = surfacelist;
3598         }
3599 }
3600
3601 void R_Shadow_DrawLight(rtlight_t *rtlight)
3602 {
3603         int i;
3604         int numsurfaces;
3605         unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
3606         int numlightentities;
3607         int numlightentities_noselfshadow;
3608         int numshadowentities;
3609         int numshadowentities_noselfshadow;
3610         entity_render_t **lightentities;
3611         entity_render_t **lightentities_noselfshadow;
3612         entity_render_t **shadowentities;
3613         entity_render_t **shadowentities_noselfshadow;
3614         int *surfacelist;
3615         static unsigned char entitysides[MAX_EDICTS];
3616         static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3617         vec3_t nearestpoint;
3618         vec_t distance;
3619         qboolean castshadows;
3620         int lodlinear;
3621
3622         // check if we cached this light this frame (meaning it is worth drawing)
3623         if (!rtlight->draw)
3624                 return;
3625
3626         // if R_FrameData_Store ran out of space we skip anything dependent on it
3627         if (r_framedata_failed)
3628                 return;
3629
3630         numlightentities = rtlight->cached_numlightentities;
3631         numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3632         numshadowentities = rtlight->cached_numshadowentities;
3633         numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3634         numsurfaces = rtlight->cached_numsurfaces;
3635         lightentities = rtlight->cached_lightentities;
3636         lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3637         shadowentities = rtlight->cached_shadowentities;
3638         shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3639         shadowtrispvs = rtlight->cached_shadowtrispvs;
3640         lighttrispvs = rtlight->cached_lighttrispvs;
3641         surfacelist = rtlight->cached_surfacelist;
3642
3643         // set up a scissor rectangle for this light
3644         if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3645                 return;
3646
3647         // don't let sound skip if going slow
3648         if (r_refdef.scene.extraupdate)
3649                 S_ExtraUpdate ();
3650
3651         // make this the active rtlight for rendering purposes
3652         R_Shadow_RenderMode_ActiveLight(rtlight);
3653
3654         if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3655         {
3656                 // optionally draw visible shape of the shadow volumes
3657                 // for performance analysis by level designers
3658                 R_Shadow_RenderMode_VisibleShadowVolumes();
3659                 if (numsurfaces)
3660                         R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3661                 for (i = 0;i < numshadowentities;i++)
3662                         R_Shadow_DrawEntityShadow(shadowentities[i]);
3663                 for (i = 0;i < numshadowentities_noselfshadow;i++)
3664                         R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3665                 R_Shadow_RenderMode_VisibleLighting(false, false);
3666         }
3667
3668         if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3669         {
3670                 // optionally draw the illuminated areas
3671                 // for performance analysis by level designers
3672                 R_Shadow_RenderMode_VisibleLighting(false, false);
3673                 if (numsurfaces)
3674                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3675                 for (i = 0;i < numlightentities;i++)
3676                         R_Shadow_DrawEntityLight(lightentities[i]);
3677                 for (i = 0;i < numlightentities_noselfshadow;i++)
3678                         R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3679         }
3680
3681         castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3682
3683         nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3684         nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3685         nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3686         distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3687
3688         lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
3689         //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3690         lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3691
3692         if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
3693         {
3694                 float borderbias;
3695                 int side;
3696                 int size;
3697                 int castermask = 0;
3698                 int receivermask = 0;
3699                 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3700                 Matrix4x4_Abs(&radiustolight);
3701
3702                 r_shadow_shadowmaplod = 0;
3703                 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
3704                         if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
3705                                 r_shadow_shadowmaplod = i;
3706
3707                 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3708                         
3709                 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3710
3711                 surfacesides = NULL;
3712                 if (numsurfaces)
3713                 {
3714                         if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3715                         {
3716                                 castermask = rtlight->static_shadowmap_casters;
3717                                 receivermask = rtlight->static_shadowmap_receivers;
3718                         }
3719                         else
3720                         {
3721                                 surfacesides = r_shadow_buffer_surfacesides;
3722                                 for(i = 0;i < numsurfaces;i++)
3723                                 {
3724                                         msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3725                                         surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);           
3726                                         castermask |= surfacesides[i];
3727                                         receivermask |= surfacesides[i];
3728                                 }
3729                         }
3730                 }
3731                 if (receivermask < 0x3F) 
3732                 {
3733                         for (i = 0;i < numlightentities;i++)
3734                                 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3735                         if (receivermask < 0x3F)
3736                                 for(i = 0; i < numlightentities_noselfshadow;i++)
3737                                         receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3738                 }
3739
3740                 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3741
3742                 if (receivermask)
3743                 {
3744                         for (i = 0;i < numshadowentities;i++)
3745                                 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3746                         for (i = 0;i < numshadowentities_noselfshadow;i++)
3747                                 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias)); 
3748                 }
3749
3750                 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
3751
3752                 // render shadow casters into 6 sided depth texture
3753                 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
3754                 {
3755                         R_Shadow_RenderMode_ShadowMap(side, receivermask, size);
3756                         if (! (castermask & (1 << side))) continue;
3757                         if (numsurfaces)
3758                                 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3759                         for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
3760                                 R_Shadow_DrawEntityShadow(shadowentities[i]);
3761                 }
3762
3763                 if (numlightentities_noselfshadow)
3764                 {
3765                         // render lighting using the depth texture as shadowmap
3766                         // draw lighting in the unmasked areas
3767                         R_Shadow_RenderMode_Lighting(false, false, true);
3768                         for (i = 0;i < numlightentities_noselfshadow;i++)
3769                                 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3770                 }
3771
3772                 // render shadow casters into 6 sided depth texture
3773                 if (numshadowentities_noselfshadow)
3774                 {
3775                         for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
3776                         {
3777                                 R_Shadow_RenderMode_ShadowMap(side, 0, size);
3778                                 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
3779                                         R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3780                         }
3781                 }
3782
3783                 // render lighting using the depth texture as shadowmap
3784                 // draw lighting in the unmasked areas
3785                 R_Shadow_RenderMode_Lighting(false, false, true);
3786                 // draw lighting in the unmasked areas
3787                 if (numsurfaces)
3788                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3789                 for (i = 0;i < numlightentities;i++)
3790                         R_Shadow_DrawEntityLight(lightentities[i]);
3791         }
3792         else if (castshadows && vid.stencil)
3793         {
3794                 // draw stencil shadow volumes to mask off pixels that are in shadow
3795                 // so that they won't receive lighting
3796                 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
3797                 R_Shadow_ClearStencil();
3798
3799                 if (numsurfaces)
3800                         R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3801                 for (i = 0;i < numshadowentities;i++)
3802                         R_Shadow_DrawEntityShadow(shadowentities[i]);
3803
3804                 // draw lighting in the unmasked areas
3805                 R_Shadow_RenderMode_Lighting(true, false, false);
3806                 for (i = 0;i < numlightentities_noselfshadow;i++)
3807                         R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3808
3809                 for (i = 0;i < numshadowentities_noselfshadow;i++)
3810                         R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3811
3812                 // draw lighting in the unmasked areas
3813                 R_Shadow_RenderMode_Lighting(true, false, false);
3814                 if (numsurfaces)
3815                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3816                 for (i = 0;i < numlightentities;i++)
3817                         R_Shadow_DrawEntityLight(lightentities[i]);
3818         }
3819         else
3820         {
3821                 // draw lighting in the unmasked areas
3822                 R_Shadow_RenderMode_Lighting(false, false, false);
3823                 if (numsurfaces)
3824                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3825                 for (i = 0;i < numlightentities;i++)
3826                         R_Shadow_DrawEntityLight(lightentities[i]);
3827                 for (i = 0;i < numlightentities_noselfshadow;i++)
3828                         R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3829         }
3830
3831         if (r_shadow_usingdeferredprepass)
3832         {
3833                 // when rendering deferred lighting, we simply rasterize the box
3834                 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
3835                         R_Shadow_RenderMode_DrawDeferredLight(false, true);
3836                 else if (castshadows && vid.stencil)
3837                         R_Shadow_RenderMode_DrawDeferredLight(true, false);
3838                 else
3839                         R_Shadow_RenderMode_DrawDeferredLight(false, false);
3840         }
3841 }
3842
3843 static void R_Shadow_FreeDeferred(void)
3844 {
3845         R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
3846         r_shadow_prepassgeometryfbo = 0;
3847
3848         R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingfbo);
3849         r_shadow_prepasslightingfbo = 0;
3850
3851         if (r_shadow_prepassgeometrydepthtexture)
3852                 R_FreeTexture(r_shadow_prepassgeometrydepthtexture);
3853         r_shadow_prepassgeometrydepthtexture = NULL;
3854
3855         if (r_shadow_prepassgeometrydepthcolortexture)
3856                 R_FreeTexture(r_shadow_prepassgeometrydepthcolortexture);
3857         r_shadow_prepassgeometrydepthcolortexture = NULL;
3858
3859         if (r_shadow_prepassgeometrynormalmaptexture)
3860                 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
3861         r_shadow_prepassgeometrynormalmaptexture = NULL;
3862
3863         if (r_shadow_prepasslightingdiffusetexture)
3864                 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
3865         r_shadow_prepasslightingdiffusetexture = NULL;
3866
3867         if (r_shadow_prepasslightingspeculartexture)
3868                 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
3869         r_shadow_prepasslightingspeculartexture = NULL;
3870 }
3871
3872 void R_Shadow_DrawPrepass(void)
3873 {
3874         int i;
3875         int flag;
3876         int lnum;
3877         size_t lightindex;
3878         dlight_t *light;
3879         size_t range;
3880         entity_render_t *ent;
3881         float clearcolor[4];
3882
3883         GL_AlphaTest(false);
3884         R_Mesh_ResetTextureState();
3885         GL_DepthMask(true);
3886         GL_ColorMask(1,1,1,1);
3887         GL_BlendFunc(GL_ONE, GL_ZERO);
3888         GL_Color(1,1,1,1);
3889         GL_DepthTest(true);
3890         R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
3891         Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
3892         GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
3893         if (r_timereport_active)
3894                 R_TimeReport("prepasscleargeom");
3895
3896         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
3897                 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
3898         if (r_timereport_active)
3899                 R_TimeReport("prepassworld");
3900
3901         for (i = 0;i < r_refdef.scene.numentities;i++)
3902         {
3903                 if (!r_refdef.viewcache.entityvisible[i])
3904                         continue;
3905                 ent = r_refdef.scene.entities[i];
3906                 if (ent->model && ent->model->DrawPrepass != NULL)
3907                         ent->model->DrawPrepass(ent);
3908         }
3909
3910         if (r_timereport_active)
3911                 R_TimeReport("prepassmodels");
3912
3913         GL_DepthMask(false);
3914         GL_ColorMask(1,1,1,1);
3915         GL_Color(1,1,1,1);
3916         GL_DepthTest(true);
3917         R_Mesh_SetRenderTargets(r_shadow_prepasslightingfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
3918         Vector4Set(clearcolor, 0, 0, 0, 0);
3919         GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
3920         if (r_timereport_active)
3921                 R_TimeReport("prepassclearlit");
3922
3923         R_Shadow_RenderMode_Begin();
3924
3925         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3926         if (r_shadow_debuglight.integer >= 0)
3927         {
3928                 lightindex = r_shadow_debuglight.integer;
3929                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3930                 if (light && (light->flags & flag))
3931                         R_Shadow_DrawLight(&light->rtlight);
3932         }
3933         else
3934         {
3935                 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3936                 for (lightindex = 0;lightindex < range;lightindex++)
3937                 {
3938                         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3939                         if (light && (light->flags & flag))
3940                                 R_Shadow_DrawLight(&light->rtlight);
3941                 }
3942         }
3943         if (r_refdef.scene.rtdlight)
3944                 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3945                         R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
3946
3947         R_Mesh_ResetRenderTargets();
3948
3949         R_Shadow_RenderMode_End();
3950
3951         if (r_timereport_active)
3952                 R_TimeReport("prepasslights");
3953 }
3954
3955 void R_Shadow_DrawLightSprites(void);
3956 void R_Shadow_PrepareLights(void)
3957 {
3958         int flag;
3959         int lnum;
3960         size_t lightindex;
3961         dlight_t *light;
3962         size_t range;
3963         float f;
3964         GLenum status;
3965
3966         if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
3967                 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
3968                 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) || 
3969                 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer || 
3970                 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer || 
3971                 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
3972                 R_Shadow_FreeShadowMaps();
3973
3974         r_shadow_usingshadowmaportho = false;
3975
3976         switch (vid.renderpath)
3977         {
3978         case RENDERPATH_GL20:
3979         case RENDERPATH_CGGL:
3980         case RENDERPATH_D3D9:
3981         case RENDERPATH_D3D10:
3982         case RENDERPATH_D3D11:
3983                 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
3984                 {
3985                         r_shadow_usingdeferredprepass = false;
3986                         if (r_shadow_prepass_width)
3987                                 R_Shadow_FreeDeferred();
3988                         r_shadow_prepass_width = r_shadow_prepass_height = 0;
3989                         break;
3990                 }
3991
3992                 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
3993                 {
3994                         R_Shadow_FreeDeferred();
3995
3996                         r_shadow_usingdeferredprepass = true;
3997                         r_shadow_prepass_width = vid.width;
3998                         r_shadow_prepass_height = vid.height;
3999                         r_shadow_prepassgeometrydepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false);
4000                         switch (vid.renderpath)
4001                         {
4002                         case RENDERPATH_D3D9:
4003                                 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);
4004                                 break;
4005                         default:
4006                                 break;
4007                         }
4008                         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);
4009                         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);
4010                         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);
4011
4012                         // set up the geometry pass fbo (depth + normalmap)
4013                         r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4014                         R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
4015                         // render depth into one texture and normalmap into the other
4016                         if (qglDrawBuffersARB)
4017                         {
4018                                 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
4019                                 qglReadBuffer(GL_NONE);CHECKGLERROR
4020                                 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4021                                 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4022                                 {
4023                                         Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4024                                         Cvar_SetValueQuick(&r_shadow_deferred, 0);
4025                                         r_shadow_usingdeferredprepass = false;
4026                                 }
4027                         }
4028
4029                         // set up the lighting pass fbo (diffuse + specular)
4030                         r_shadow_prepasslightingfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4031                         R_Mesh_SetRenderTargets(r_shadow_prepasslightingfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4032                         // render diffuse into one texture and specular into another,
4033                         // with depth and normalmap bound as textures,
4034                         // with depth bound as attachment as well
4035                         if (qglDrawBuffersARB)
4036                         {
4037                                 qglDrawBuffersARB(2, r_shadow_prepasslightingdrawbuffers);CHECKGLERROR
4038                                 qglReadBuffer(GL_NONE);CHECKGLERROR
4039                                 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4040                                 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4041                                 {
4042                                         Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4043                                         Cvar_SetValueQuick(&r_shadow_deferred, 0);
4044                                         r_shadow_usingdeferredprepass = false;
4045                                 }
4046                         }
4047                 }
4048                 break;
4049         case RENDERPATH_GL13:
4050         case RENDERPATH_GL11:
4051                 r_shadow_usingdeferredprepass = false;
4052                 break;
4053         }
4054
4055         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);
4056
4057         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4058         if (r_shadow_debuglight.integer >= 0)
4059         {
4060                 lightindex = r_shadow_debuglight.integer;
4061                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4062                 if (light && (light->flags & flag))
4063                         R_Shadow_PrepareLight(&light->rtlight);
4064         }
4065         else
4066         {
4067                 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4068                 for (lightindex = 0;lightindex < range;lightindex++)
4069                 {
4070                         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4071                         if (light && (light->flags & flag))
4072                                 R_Shadow_PrepareLight(&light->rtlight);
4073                 }
4074         }
4075         if (r_refdef.scene.rtdlight)
4076         {
4077                 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4078                         R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4079         }
4080         else if(gl_flashblend.integer)
4081         {
4082                 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4083                 {
4084                         rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4085                         f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4086                         VectorScale(rtlight->color, f, rtlight->currentcolor);
4087                 }
4088         }
4089
4090         if (r_editlights.integer)
4091                 R_Shadow_DrawLightSprites();
4092 }
4093
4094 void R_Shadow_DrawLights(void)
4095 {
4096         int flag;
4097         int lnum;
4098         size_t lightindex;
4099         dlight_t *light;
4100         size_t range;
4101
4102         R_Shadow_RenderMode_Begin();
4103
4104         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4105         if (r_shadow_debuglight.integer >= 0)
4106         {
4107                 lightindex = r_shadow_debuglight.integer;
4108                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4109                 if (light && (light->flags & flag))
4110                         R_Shadow_DrawLight(&light->rtlight);
4111         }
4112         else
4113         {
4114                 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4115                 for (lightindex = 0;lightindex < range;lightindex++)
4116                 {
4117                         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4118                         if (light && (light->flags & flag))
4119                                 R_Shadow_DrawLight(&light->rtlight);
4120                 }
4121         }
4122         if (r_refdef.scene.rtdlight)
4123                 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4124                         R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4125
4126         R_Shadow_RenderMode_End();
4127 }
4128
4129 extern const float r_screenvertex3f[12];
4130 extern void R_SetupView(qboolean allowwaterclippingplane);
4131 extern void R_ResetViewRendering3D(void);
4132 extern void R_ResetViewRendering2D(void);
4133 extern cvar_t r_shadows;
4134 extern cvar_t r_shadows_darken;
4135 extern cvar_t r_shadows_drawafterrtlighting;
4136 extern cvar_t r_shadows_castfrombmodels;
4137 extern cvar_t r_shadows_throwdistance;
4138 extern cvar_t r_shadows_throwdirection;
4139 extern cvar_t r_shadows_focus;
4140 extern cvar_t r_shadows_shadowmapscale;
4141
4142 void R_Shadow_PrepareModelShadows(void)
4143 {
4144         int i;
4145         float scale, size, radius, dot1, dot2;
4146         vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4147         entity_render_t *ent;
4148
4149         if (!r_refdef.scene.numentities)
4150                 return;
4151
4152         switch (r_shadow_shadowmode)
4153         {
4154         case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4155                 if (r_shadows.integer >= 2) 
4156                         break;
4157                 // fall through
4158         case R_SHADOW_SHADOWMODE_STENCIL:
4159                 for (i = 0;i < r_refdef.scene.numentities;i++)
4160                 {
4161                         ent = r_refdef.scene.entities[i];
4162                         if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4163                                 R_AnimCache_GetEntity(ent, false, false);
4164                 }
4165                 return;
4166         default:
4167                 return;
4168         }
4169
4170         size = 2*r_shadow_shadowmapmaxsize;
4171         scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4172         radius = 0.5f * size / scale;
4173
4174         Math_atov(r_shadows_throwdirection.string, shadowdir);
4175         VectorNormalize(shadowdir);
4176         dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4177         dot2 = DotProduct(r_refdef.view.up, shadowdir);
4178         if (fabs(dot1) <= fabs(dot2))
4179                 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4180         else
4181                 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4182         VectorNormalize(shadowforward);
4183         CrossProduct(shadowdir, shadowforward, shadowright);
4184         Math_atov(r_shadows_focus.string, shadowfocus);
4185         VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4186         VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4187         VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4188         VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4189         if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4190                 dot1 = 1;
4191         VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4192
4193         shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4194         shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4195         shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4196         shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4197         shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4198         shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4199
4200         for (i = 0;i < r_refdef.scene.numentities;i++)
4201         {
4202                 ent = r_refdef.scene.entities[i];
4203                 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4204                         continue;
4205                 // cast shadows from anything of the map (submodels are optional)
4206                 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4207                         R_AnimCache_GetEntity(ent, false, false);
4208         }
4209 }
4210
4211 void R_DrawModelShadowMaps(void)
4212 {
4213         int i;
4214         float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4215         entity_render_t *ent;
4216         vec3_t relativelightorigin;
4217         vec3_t relativelightdirection, relativeforward, relativeright;
4218         vec3_t relativeshadowmins, relativeshadowmaxs;
4219         vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4220         float m[12];
4221         matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4222         r_viewport_t viewport;
4223         GLuint fbo = 0;
4224         float clearcolor[4];
4225
4226         if (!r_refdef.scene.numentities)
4227                 return;
4228
4229         switch (r_shadow_shadowmode)
4230         {
4231         case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4232                 break;
4233         default:
4234                 return;
4235         }
4236
4237         R_ResetViewRendering3D();
4238         R_Shadow_RenderMode_Begin();
4239         R_Shadow_RenderMode_ActiveLight(NULL);
4240
4241         switch (r_shadow_shadowmode)
4242         {
4243         case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4244                 if (!r_shadow_shadowmap2dtexture)
4245                         R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
4246                 fbo = r_shadow_fbo2d;
4247                 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
4248                 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
4249                 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
4250                 break;
4251         default:
4252                 break;
4253         }
4254
4255         size = 2*r_shadow_shadowmapmaxsize;
4256         scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4257         radius = 0.5f / scale;
4258         nearclip = -r_shadows_throwdistance.value;
4259         farclip = r_shadows_throwdistance.value;
4260         bias = r_shadow_shadowmapping_bias.value * r_shadow_shadowmapping_nearclip.value / (2 * r_shadows_throwdistance.value) * (1024.0f / size);
4261
4262         r_shadow_shadowmap_parameters[0] = size;
4263         r_shadow_shadowmap_parameters[1] = size;
4264         r_shadow_shadowmap_parameters[2] = 1.0;
4265         r_shadow_shadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4266
4267         Math_atov(r_shadows_throwdirection.string, shadowdir);
4268         VectorNormalize(shadowdir);
4269         Math_atov(r_shadows_focus.string, shadowfocus);
4270         VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4271         VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4272         VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4273         VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4274         dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4275         dot2 = DotProduct(r_refdef.view.up, shadowdir);
4276         if (fabs(dot1) <= fabs(dot2)) 
4277                 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4278         else
4279                 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4280         VectorNormalize(shadowforward);
4281         VectorM(scale, shadowforward, &m[0]);
4282         if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4283                 dot1 = 1;
4284         m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4285         CrossProduct(shadowdir, shadowforward, shadowright);
4286         VectorM(scale, shadowright, &m[4]);
4287         m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4288         VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4289         m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4290         Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4291         Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4292         R_Viewport_InitOrtho(&viewport, &cameramatrix, 0, 0, size, size, 0, 0, 1, 1, 0, -1, NULL); 
4293
4294         VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4295
4296         R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
4297         R_SetupShader_DepthOrShadow();
4298         GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
4299         GL_DepthMask(true);
4300         GL_DepthTest(true);
4301         R_SetViewport(&viewport);
4302         GL_Scissor(viewport.x, viewport.y, min(viewport.width + r_shadow_shadowmapborder, 2*r_shadow_shadowmapmaxsize), viewport.height + r_shadow_shadowmapborder);
4303         Vector4Set(clearcolor, 1,1,1,1);
4304         // in D3D9 we have to render to a color texture shadowmap
4305         // in GL we render directly to a depth texture only
4306         if (r_shadow_shadowmap2dtexture)
4307                 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4308         else
4309                 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4310         // render into a slightly restricted region so that the borders of the
4311         // shadowmap area fade away, rather than streaking across everything
4312         // outside the usable area
4313         GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4314
4315 #if 0
4316         // debugging
4317         R_Mesh_ResetRenderTargets();
4318         R_SetupShader_ShowDepth();
4319         GL_ColorMask(1,1,1,1);
4320         GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4321 #endif
4322
4323         for (i = 0;i < r_refdef.scene.numentities;i++)
4324         {
4325                 ent = r_refdef.scene.entities[i];
4326
4327                 // cast shadows from anything of the map (submodels are optional)
4328                 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4329                 {
4330                         relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4331                         Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4332                         Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4333                         Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4334                         Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4335                         relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4336                         relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4337                         relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4338                         relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4339                         relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4340                         relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4341                         RSurf_ActiveModelEntity(ent, false, false, false);
4342                         ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4343                         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4344                 }
4345         }
4346
4347 #if 0
4348         if (r_test.integer)
4349         {
4350                 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
4351                 CHECKGLERROR
4352                 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
4353                 CHECKGLERROR
4354                 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
4355                 Cvar_SetValueQuick(&r_test, 0);
4356                 Z_Free(rawpixels);
4357         }
4358 #endif
4359
4360         R_Shadow_RenderMode_End();
4361
4362         Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4363         Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4364         Matrix4x4_CreateScale3(&scalematrix, size, -size, 1); 
4365         Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4366         Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4367         Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4368
4369         switch (vid.renderpath)
4370         {
4371                 case RENDERPATH_D3D9:
4372                 case RENDERPATH_D3D10:
4373                 case RENDERPATH_D3D11:
4374 #ifdef OPENGL_ORIENTATION
4375                 r_shadow_shadowmapmatrix.m[0][0]        *= -1.0f;
4376                 r_shadow_shadowmapmatrix.m[0][1]        *= -1.0f;
4377                 r_shadow_shadowmapmatrix.m[0][2]        *= -1.0f;
4378                 r_shadow_shadowmapmatrix.m[0][3]        *= -1.0f;
4379 #else
4380                 r_shadow_shadowmapmatrix.m[0][0]        *= -1.0f;
4381                 r_shadow_shadowmapmatrix.m[1][0]        *= -1.0f;
4382                 r_shadow_shadowmapmatrix.m[2][0]        *= -1.0f;
4383                 r_shadow_shadowmapmatrix.m[3][0]        *= -1.0f;
4384 #endif
4385                 break;
4386         }
4387
4388         r_shadow_usingshadowmaportho = true;
4389         switch (r_shadow_shadowmode)
4390         {
4391         case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4392                 r_shadow_usingshadowmap2d = true;
4393                 break;
4394         default:
4395                 break;
4396         }
4397 }
4398
4399 void R_DrawModelShadows(void)
4400 {
4401         int i;
4402         float relativethrowdistance;
4403         entity_render_t *ent;
4404         vec3_t relativelightorigin;
4405         vec3_t relativelightdirection;
4406         vec3_t relativeshadowmins, relativeshadowmaxs;
4407         vec3_t tmp, shadowdir;
4408
4409         if (!r_refdef.scene.numentities || !vid.stencil || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
4410                 return;
4411
4412         R_ResetViewRendering3D();
4413         //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4414         //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4415         R_Shadow_RenderMode_Begin();
4416         R_Shadow_RenderMode_ActiveLight(NULL);
4417         r_shadow_lightscissor[0] = r_refdef.view.x;
4418         r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4419         r_shadow_lightscissor[2] = r_refdef.view.width;
4420         r_shadow_lightscissor[3] = r_refdef.view.height;
4421         R_Shadow_RenderMode_StencilShadowVolumes(false);
4422
4423         // get shadow dir
4424         if (r_shadows.integer == 2)
4425         {
4426                 Math_atov(r_shadows_throwdirection.string, shadowdir);
4427                 VectorNormalize(shadowdir);
4428         }
4429
4430         R_Shadow_ClearStencil();
4431
4432         for (i = 0;i < r_refdef.scene.numentities;i++)
4433         {
4434                 ent = r_refdef.scene.entities[i];
4435
4436                 // cast shadows from anything of the map (submodels are optional)
4437                 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4438                 {
4439                         relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4440                         VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4441                         VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4442                         if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4443                                 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4444                         else
4445                         {
4446                                 if(ent->entitynumber != 0)
4447                                 {
4448                                         if(ent->entitynumber >= MAX_EDICTS) // csqc entity
4449                                         {
4450                                                 // FIXME handle this
4451                                                 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4452                                         }
4453                                         else
4454                                         {
4455                                                 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4456                                                 int entnum, entnum2, recursion;
4457                                                 entnum = entnum2 = ent->entitynumber;
4458                                                 for(recursion = 32; recursion > 0; --recursion)
4459                                                 {
4460                                                         entnum2 = cl.entities[entnum].state_current.tagentity;
4461                                                         if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4462                                                                 entnum = entnum2;
4463                                                         else
4464                                                                 break;
4465                                                 }
4466                                                 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4467                                                 {
4468                                                         VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4469                                                         // transform into modelspace of OUR entity
4470                                                         Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4471                                                         Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4472                                                 }
4473                                                 else
4474                                                         VectorNegate(ent->modellight_lightdir, relativelightdirection);
4475                                         }
4476                                 }
4477                                 else
4478                                         VectorNegate(ent->modellight_lightdir, relativelightdirection);
4479                         }
4480
4481                         VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4482                         RSurf_ActiveModelEntity(ent, false, false, false);
4483                         ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4484                         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4485                 }
4486         }
4487
4488         // not really the right mode, but this will disable any silly stencil features
4489         R_Shadow_RenderMode_End();
4490
4491         // set up ortho view for rendering this pass
4492         //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4493         //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4494         //GL_ScissorTest(true);
4495         //R_EntityMatrix(&identitymatrix);
4496         //R_Mesh_ResetTextureState();
4497         R_ResetViewRendering2D();
4498
4499         // set up a darkening blend on shadowed areas
4500         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4501         //GL_DepthRange(0, 1);
4502         //GL_DepthTest(false);
4503         //GL_DepthMask(false);
4504         //GL_PolygonOffset(0, 0);CHECKGLERROR
4505         GL_Color(0, 0, 0, r_shadows_darken.value);
4506         //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4507         //GL_DepthFunc(GL_ALWAYS);
4508         R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
4509
4510         // apply the blend to the shadowed areas
4511         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
4512         R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4513         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4514
4515         // restore the viewport
4516         R_SetViewport(&r_refdef.view.viewport);
4517
4518         // restore other state to normal
4519         //R_Shadow_RenderMode_End();
4520 }
4521
4522 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4523 {
4524         float zdist;
4525         vec3_t centerorigin;
4526         float vertex3f[12];
4527         // if it's too close, skip it
4528         if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4529                 return;
4530         zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4531         if (zdist < 32)
4532                 return;
4533         if (usequery && r_numqueries + 2 <= r_maxqueries)
4534         {
4535                 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4536                 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4537                 // 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
4538                 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4539
4540                 switch(vid.renderpath)
4541                 {
4542                 case RENDERPATH_GL20:
4543                 case RENDERPATH_GL13:
4544                 case RENDERPATH_GL11:
4545                 case RENDERPATH_CGGL:
4546                         CHECKGLERROR
4547                         // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
4548                         qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4549                         GL_DepthFunc(GL_ALWAYS);
4550                         R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4551                         R_Mesh_PrepareVertices_Position_Arrays(4, vertex3f);
4552                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4553                         qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4554                         GL_DepthFunc(GL_LEQUAL);
4555                         qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4556                         R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4557                         R_Mesh_PrepareVertices_Position_Arrays(4, vertex3f);
4558                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4559                         qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4560                         CHECKGLERROR
4561                         break;
4562                 case RENDERPATH_D3D9:
4563                         Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4564                         break;
4565                 case RENDERPATH_D3D10:
4566                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4567                         break;
4568                 case RENDERPATH_D3D11:
4569                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4570                         break;
4571                 }
4572         }
4573         rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4574 }
4575
4576 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4577
4578 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4579 {
4580         vec3_t color;
4581         GLint allpixels = 0, visiblepixels = 0;
4582         // now we have to check the query result
4583         if (rtlight->corona_queryindex_visiblepixels)
4584         {
4585                 switch(vid.renderpath)
4586                 {
4587                 case RENDERPATH_GL20:
4588                 case RENDERPATH_GL13:
4589                 case RENDERPATH_GL11:
4590                 case RENDERPATH_CGGL:
4591                         CHECKGLERROR
4592                         qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4593                         qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4594                         CHECKGLERROR
4595                         break;
4596                 case RENDERPATH_D3D9:
4597                         Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4598                         break;
4599                 case RENDERPATH_D3D10:
4600                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4601                         break;
4602                 case RENDERPATH_D3D11:
4603                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4604                         break;
4605                 }
4606                 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4607                 if (visiblepixels < 1 || allpixels < 1)
4608                         return;
4609                 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4610                 cscale *= rtlight->corona_visibility;
4611         }
4612         else
4613         {
4614                 // FIXME: these traces should scan all render entities instead of cl.world
4615                 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4616                         return;
4617         }
4618         VectorScale(rtlight->currentcolor, cscale, color);
4619         if (VectorLength(color) > (1.0f / 256.0f))
4620         {
4621                 float vertex3f[12];
4622                 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
4623                 if(negated)
4624                 {
4625                         VectorNegate(color, color);
4626                         switch(vid.renderpath)
4627                         {
4628                         case RENDERPATH_GL11:
4629                         case RENDERPATH_GL13:
4630                         case RENDERPATH_GL20:
4631                         case RENDERPATH_CGGL:
4632                                 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
4633                                 break;
4634                         case RENDERPATH_D3D9:
4635 #ifdef SUPPORTD3D
4636                                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
4637 #endif
4638                                 break;
4639                         case RENDERPATH_D3D10:
4640                                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4641                                 break;
4642                         case RENDERPATH_D3D11:
4643                                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4644                                 break;
4645                         }
4646                 }
4647                 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4648                 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);
4649                 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4650                 if(negated)
4651                 {
4652                         switch(vid.renderpath)
4653                         {
4654                         case RENDERPATH_GL11:
4655                         case RENDERPATH_GL13:
4656                         case RENDERPATH_GL20:
4657                         case RENDERPATH_CGGL:
4658                                 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
4659                                 break;
4660                         case RENDERPATH_D3D9:
4661 #ifdef SUPPORTD3D
4662                                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
4663 #endif
4664                                 break;
4665                         case RENDERPATH_D3D10:
4666                                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4667                                 break;
4668                         case RENDERPATH_D3D11:
4669                                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4670                                 break;
4671                         }
4672                 }
4673         }
4674 }
4675
4676 void R_Shadow_DrawCoronas(void)
4677 {
4678         int i, flag;
4679         qboolean usequery = false;
4680         size_t lightindex;
4681         dlight_t *light;
4682         rtlight_t *rtlight;
4683         size_t range;
4684         if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4685                 return;
4686         if (r_waterstate.renderingscene)
4687                 return;
4688         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4689         R_EntityMatrix(&identitymatrix);
4690
4691         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4692
4693         // check occlusion of coronas
4694         // use GL_ARB_occlusion_query if available
4695         // otherwise use raytraces
4696         r_numqueries = 0;
4697         switch (vid.renderpath)
4698         {
4699         case RENDERPATH_GL11:
4700         case RENDERPATH_GL13:
4701         case RENDERPATH_GL20:
4702         case RENDERPATH_CGGL:
4703                 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
4704                 if (usequery)
4705                 {
4706                         GL_ColorMask(0,0,0,0);
4707                         if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4708                         if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4709                         {
4710                                 i = r_maxqueries;
4711                                 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4712                                 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4713                                 CHECKGLERROR
4714                                 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4715                                 CHECKGLERROR
4716                         }
4717                         RSurf_ActiveWorldEntity();
4718                         GL_BlendFunc(GL_ONE, GL_ZERO);
4719                         GL_CullFace(GL_NONE);
4720                         GL_DepthMask(false);
4721                         GL_DepthRange(0, 1);
4722                         GL_PolygonOffset(0, 0);
4723                         GL_DepthTest(true);
4724                         R_Mesh_ResetTextureState();
4725                         R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4726                 }
4727                 break;
4728         case RENDERPATH_D3D9:
4729                 usequery = false;
4730                 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4731                 break;
4732         case RENDERPATH_D3D10:
4733                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4734                 break;
4735         case RENDERPATH_D3D11:
4736                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4737                 break;
4738         }
4739         for (lightindex = 0;lightindex < range;lightindex++)
4740         {
4741                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4742                 if (!light)
4743                         continue;
4744                 rtlight = &light->rtlight;
4745                 rtlight->corona_visibility = 0;
4746                 rtlight->corona_queryindex_visiblepixels = 0;
4747                 rtlight->corona_queryindex_allpixels = 0;
4748                 if (!(rtlight->flags & flag))
4749                         continue;
4750                 if (rtlight->corona <= 0)
4751                         continue;
4752                 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4753                         continue;
4754                 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4755         }
4756         for (i = 0;i < r_refdef.scene.numlights;i++)
4757         {
4758                 rtlight = r_refdef.scene.lights[i];
4759                 rtlight->corona_visibility = 0;
4760                 rtlight->corona_queryindex_visiblepixels = 0;
4761                 rtlight->corona_queryindex_allpixels = 0;
4762                 if (!(rtlight->flags & flag))
4763                         continue;
4764                 if (rtlight->corona <= 0)
4765                         continue;
4766                 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4767         }
4768         if (usequery)
4769                 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4770
4771         // now draw the coronas using the query data for intensity info
4772         for (lightindex = 0;lightindex < range;lightindex++)
4773         {
4774                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4775                 if (!light)
4776                         continue;
4777                 rtlight = &light->rtlight;
4778                 if (rtlight->corona_visibility <= 0)
4779                         continue;
4780                 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4781         }
4782         for (i = 0;i < r_refdef.scene.numlights;i++)
4783         {
4784                 rtlight = r_refdef.scene.lights[i];
4785                 if (rtlight->corona_visibility <= 0)
4786                         continue;
4787                 if (gl_flashblend.integer)
4788                         R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4789                 else
4790                         R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4791         }
4792 }
4793
4794
4795
4796 dlight_t *R_Shadow_NewWorldLight(void)
4797 {
4798         return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4799 }
4800
4801 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)
4802 {
4803         matrix4x4_t matrix;
4804         // validate parameters
4805         if (style < 0 || style >= MAX_LIGHTSTYLES)
4806         {
4807                 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4808                 style = 0;
4809         }
4810         if (!cubemapname)
4811                 cubemapname = "";
4812
4813         // copy to light properties
4814         VectorCopy(origin, light->origin);
4815         light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4816         light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4817         light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4818         /*
4819         light->color[0] = max(color[0], 0);
4820         light->color[1] = max(color[1], 0);
4821         light->color[2] = max(color[2], 0);
4822         */
4823         light->color[0] = color[0];
4824         light->color[1] = color[1];
4825         light->color[2] = color[2];
4826         light->radius = max(radius, 0);
4827         light->style = style;
4828         light->shadow = shadowenable;
4829         light->corona = corona;
4830         strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4831         light->coronasizescale = coronasizescale;
4832         light->ambientscale = ambientscale;
4833         light->diffusescale = diffusescale;
4834         light->specularscale = specularscale;
4835         light->flags = flags;
4836
4837         // update renderable light data
4838         Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4839         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);
4840 }
4841
4842 void R_Shadow_FreeWorldLight(dlight_t *light)
4843 {
4844         if (r_shadow_selectedlight == light)
4845                 r_shadow_selectedlight = NULL;
4846         R_RTLight_Uncompile(&light->rtlight);
4847         Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4848 }
4849
4850 void R_Shadow_ClearWorldLights(void)
4851 {
4852         size_t lightindex;
4853         dlight_t *light;
4854         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4855         for (lightindex = 0;lightindex < range;lightindex++)
4856         {
4857                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4858                 if (light)
4859                         R_Shadow_FreeWorldLight(light);
4860         }
4861         r_shadow_selectedlight = NULL;
4862 }
4863
4864 void R_Shadow_SelectLight(dlight_t *light)
4865 {
4866         if (r_shadow_selectedlight)
4867                 r_shadow_selectedlight->selected = false;
4868         r_shadow_selectedlight = light;
4869         if (r_shadow_selectedlight)
4870                 r_shadow_selectedlight->selected = true;
4871 }
4872
4873 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4874 {
4875         // this is never batched (there can be only one)
4876         float vertex3f[12];
4877         R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4878         RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4879         R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4880 }
4881
4882 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4883 {
4884         float intensity;
4885         float s;
4886         vec3_t spritecolor;
4887         skinframe_t *skinframe;
4888         float vertex3f[12];
4889
4890         // this is never batched (due to the ent parameter changing every time)
4891         // so numsurfaces == 1 and surfacelist[0] == lightnumber
4892         const dlight_t *light = (dlight_t *)ent;
4893         s = EDLIGHTSPRSIZE;
4894
4895         R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4896
4897         intensity = 0.5f;
4898         VectorScale(light->color, intensity, spritecolor);
4899         if (VectorLength(spritecolor) < 0.1732f)
4900                 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4901         if (VectorLength(spritecolor) > 1.0f)
4902                 VectorNormalize(spritecolor);
4903
4904         // draw light sprite
4905         if (light->cubemapname[0] && !light->shadow)
4906                 skinframe = r_editlights_sprcubemapnoshadowlight;
4907         else if (light->cubemapname[0])
4908                 skinframe = r_editlights_sprcubemaplight;
4909         else if (!light->shadow)
4910                 skinframe = r_editlights_sprnoshadowlight;
4911         else
4912                 skinframe = r_editlights_sprlight;
4913
4914         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);
4915         R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4916
4917         // draw selection sprite if light is selected
4918         if (light->selected)
4919         {
4920                 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4921                 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4922                 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4923         }
4924 }
4925
4926 void R_Shadow_DrawLightSprites(void)
4927 {
4928         size_t lightindex;
4929         dlight_t *light;
4930         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4931         for (lightindex = 0;lightindex < range;lightindex++)
4932         {
4933                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4934                 if (light)
4935                         R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4936         }
4937         if (!r_editlights_lockcursor)
4938                 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4939 }
4940
4941 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4942 {
4943         unsigned int range;
4944         dlight_t *light;
4945         rtlight_t *rtlight;
4946         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4947         if (lightindex >= range)
4948                 return -1;
4949         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4950         if (!light)
4951                 return 0;
4952         rtlight = &light->rtlight;
4953         //if (!(rtlight->flags & flag))
4954         //      return 0;
4955         VectorCopy(rtlight->shadoworigin, origin);
4956         *radius = rtlight->radius;
4957         VectorCopy(rtlight->color, color);
4958         return 1;
4959 }
4960
4961 void R_Shadow_SelectLightInView(void)
4962 {
4963         float bestrating, rating, temp[3];
4964         dlight_t *best;
4965         size_t lightindex;
4966         dlight_t *light;
4967         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4968         best = NULL;
4969         bestrating = 0;
4970
4971         if (r_editlights_lockcursor)
4972                 return;
4973         for (lightindex = 0;lightindex < range;lightindex++)
4974         {
4975                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4976                 if (!light)
4977                         continue;
4978                 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4979                 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4980                 if (rating >= 0.95)
4981                 {
4982                         rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4983                         if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
4984                         {
4985                                 bestrating = rating;
4986                                 best = light;
4987                         }
4988                 }
4989         }
4990         R_Shadow_SelectLight(best);
4991 }
4992
4993 void R_Shadow_LoadWorldLights(void)
4994 {
4995         int n, a, style, shadow, flags;
4996         char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4997         float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4998         if (cl.worldmodel == NULL)
4999         {
5000                 Con_Print("No map loaded.\n");
5001                 return;
5002         }
5003         dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5004         lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5005         if (lightsstring)
5006         {
5007                 s = lightsstring;
5008                 n = 0;
5009                 while (*s)
5010                 {
5011                         t = s;
5012                         /*
5013                         shadow = true;
5014                         for (;COM_Parse(t, true) && strcmp(
5015                         if (COM_Parse(t, true))
5016                         {
5017                                 if (com_token[0] == '!')
5018                                 {
5019                                         shadow = false;
5020                                         origin[0] = atof(com_token+1);
5021                                 }
5022                                 else
5023                                         origin[0] = atof(com_token);
5024                                 if (Com_Parse(t
5025                         }
5026                         */
5027                         t = s;
5028                         while (*s && *s != '\n' && *s != '\r')
5029                                 s++;
5030                         if (!*s)
5031                                 break;
5032                         tempchar = *s;
5033                         shadow = true;
5034                         // check for modifier flags
5035                         if (*t == '!')
5036                         {
5037                                 shadow = false;
5038                                 t++;
5039                         }
5040                         *s = 0;
5041 #if _MSC_VER >= 1400
5042 #define sscanf sscanf_s
5043 #endif
5044                         cubemapname[sizeof(cubemapname)-1] = 0;
5045 #if MAX_QPATH != 128
5046 #error update this code if MAX_QPATH changes
5047 #endif
5048                         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
5049 #if _MSC_VER >= 1400
5050 , sizeof(cubemapname)
5051 #endif
5052 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
5053                         *s = tempchar;
5054                         if (a < 18)
5055                                 flags = LIGHTFLAG_REALTIMEMODE;
5056                         if (a < 17)
5057                                 specularscale = 1;
5058                         if (a < 16)
5059                                 diffusescale = 1;
5060                         if (a < 15)
5061                                 ambientscale = 0;
5062                         if (a < 14)
5063                                 coronasizescale = 0.25f;
5064                         if (a < 13)
5065                                 VectorClear(angles);
5066                         if (a < 10)
5067                                 corona = 0;
5068                         if (a < 9 || !strcmp(cubemapname, "\"\""))
5069                                 cubemapname[0] = 0;
5070                         // remove quotes on cubemapname
5071                         if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
5072                         {
5073                                 size_t namelen;
5074                                 namelen = strlen(cubemapname) - 2;
5075                                 memmove(cubemapname, cubemapname + 1, namelen);
5076                                 cubemapname[namelen] = '\0';
5077                         }
5078                         if (a < 8)
5079                         {
5080                                 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);
5081                                 break;
5082                         }
5083                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5084                         if (*s == '\r')
5085                                 s++;
5086                         if (*s == '\n')
5087                                 s++;
5088                         n++;
5089                 }
5090                 if (*s)
5091                         Con_Printf("invalid rtlights file \"%s\"\n", name);
5092                 Mem_Free(lightsstring);
5093         }
5094 }
5095
5096 void R_Shadow_SaveWorldLights(void)
5097 {
5098         size_t lightindex;
5099         dlight_t *light;
5100         size_t bufchars, bufmaxchars;
5101         char *buf, *oldbuf;
5102         char name[MAX_QPATH];
5103         char line[MAX_INPUTLINE];
5104         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5105         // I hate lines which are 3 times my screen size :( --blub
5106         if (!range)
5107                 return;
5108         if (cl.worldmodel == NULL)
5109         {
5110                 Con_Print("No map loaded.\n");
5111                 return;
5112         }
5113         dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5114         bufchars = bufmaxchars = 0;
5115         buf = NULL;
5116         for (lightindex = 0;lightindex < range;lightindex++)
5117         {
5118                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5119                 if (!light)
5120                         continue;
5121                 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5122                         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);
5123                 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5124                         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]);
5125                 else
5126                         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);
5127                 if (bufchars + strlen(line) > bufmaxchars)
5128                 {
5129                         bufmaxchars = bufchars + strlen(line) + 2048;
5130                         oldbuf = buf;
5131                         buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5132                         if (oldbuf)
5133                         {
5134                                 if (bufchars)
5135                                         memcpy(buf, oldbuf, bufchars);
5136                                 Mem_Free(oldbuf);
5137                         }
5138                 }
5139                 if (strlen(line))
5140                 {
5141                         memcpy(buf + bufchars, line, strlen(line));
5142                         bufchars += strlen(line);
5143                 }
5144         }
5145         if (bufchars)
5146                 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5147         if (buf)
5148                 Mem_Free(buf);
5149 }
5150
5151 void R_Shadow_LoadLightsFile(void)
5152 {
5153         int n, a, style;
5154         char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5155         float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5156         if (cl.worldmodel == NULL)
5157         {
5158                 Con_Print("No map loaded.\n");
5159                 return;
5160         }
5161         dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
5162         lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5163         if (lightsstring)
5164         {
5165                 s = lightsstring;
5166                 n = 0;
5167                 while (*s)
5168                 {
5169                         t = s;
5170                         while (*s && *s != '\n' && *s != '\r')
5171                                 s++;
5172                         if (!*s)
5173                                 break;
5174                         tempchar = *s;
5175                         *s = 0;
5176                         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);
5177                         *s = tempchar;
5178                         if (a < 14)
5179                         {
5180                                 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);
5181                                 break;
5182                         }
5183                         radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5184                         radius = bound(15, radius, 4096);
5185                         VectorScale(color, (2.0f / (8388608.0f)), color);
5186                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5187                         if (*s == '\r')
5188                                 s++;
5189                         if (*s == '\n')
5190                                 s++;
5191                         n++;
5192                 }
5193                 if (*s)
5194                         Con_Printf("invalid lights file \"%s\"\n", name);
5195                 Mem_Free(lightsstring);
5196         }
5197 }
5198
5199 // tyrlite/hmap2 light types in the delay field
5200 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5201
5202 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5203 {
5204         int entnum;
5205         int style;
5206         int islight;
5207         int skin;
5208         int pflags;
5209         //int effects;
5210         int type;
5211         int n;
5212         char *entfiledata;
5213         const char *data;
5214         float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5215         char key[256], value[MAX_INPUTLINE];
5216
5217         if (cl.worldmodel == NULL)
5218         {
5219                 Con_Print("No map loaded.\n");
5220                 return;
5221         }
5222         // try to load a .ent file first
5223         dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5224         data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5225         // and if that is not found, fall back to the bsp file entity string
5226         if (!data)
5227                 data = cl.worldmodel->brush.entities;
5228         if (!data)
5229                 return;
5230         for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5231         {
5232                 type = LIGHTTYPE_MINUSX;
5233                 origin[0] = origin[1] = origin[2] = 0;
5234                 originhack[0] = originhack[1] = originhack[2] = 0;
5235                 angles[0] = angles[1] = angles[2] = 0;
5236                 color[0] = color[1] = color[2] = 1;
5237                 light[0] = light[1] = light[2] = 1;light[3] = 300;
5238                 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5239                 fadescale = 1;
5240                 lightscale = 1;
5241                 style = 0;
5242                 skin = 0;
5243                 pflags = 0;
5244                 //effects = 0;
5245                 islight = false;
5246                 while (1)
5247                 {
5248                         if (!COM_ParseToken_Simple(&data, false, false))
5249                                 break; // error
5250                         if (com_token[0] == '}')
5251                                 break; // end of entity
5252                         if (com_token[0] == '_')
5253                                 strlcpy(key, com_token + 1, sizeof(key));
5254                         else
5255                                 strlcpy(key, com_token, sizeof(key));
5256                         while (key[strlen(key)-1] == ' ') // remove trailing spaces
5257                                 key[strlen(key)-1] = 0;
5258                         if (!COM_ParseToken_Simple(&data, false, false))
5259                                 break; // error
5260                         strlcpy(value, com_token, sizeof(value));
5261
5262                         // now that we have the key pair worked out...
5263                         if (!strcmp("light", key))
5264                         {
5265                                 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5266                                 if (n == 1)
5267                                 {
5268                                         // quake
5269                                         light[0] = vec[0] * (1.0f / 256.0f);
5270                                         light[1] = vec[0] * (1.0f / 256.0f);
5271                                         light[2] = vec[0] * (1.0f / 256.0f);
5272                                         light[3] = vec[0];
5273                                 }
5274                                 else if (n == 4)
5275                                 {
5276                                         // halflife
5277                                         light[0] = vec[0] * (1.0f / 255.0f);
5278                                         light[1] = vec[1] * (1.0f / 255.0f);
5279                                         light[2] = vec[2] * (1.0f / 255.0f);
5280                                         light[3] = vec[3];
5281                                 }
5282                         }
5283                         else if (!strcmp("delay", key))
5284                                 type = atoi(value);
5285                         else if (!strcmp("origin", key))
5286                                 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5287                         else if (!strcmp("angle", key))
5288                                 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5289                         else if (!strcmp("angles", key))
5290                                 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5291                         else if (!strcmp("color", key))
5292                                 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5293                         else if (!strcmp("wait", key))
5294                                 fadescale = atof(value);
5295                         else if (!strcmp("classname", key))
5296                         {
5297                                 if (!strncmp(value, "light", 5))
5298                                 {
5299                                         islight = true;
5300                                         if (!strcmp(value, "light_fluoro"))
5301                                         {
5302                                                 originhack[0] = 0;
5303                                                 originhack[1] = 0;
5304                                                 originhack[2] = 0;
5305                                                 overridecolor[0] = 1;
5306                                                 overridecolor[1] = 1;
5307                                                 overridecolor[2] = 1;
5308                                         }
5309                                         if (!strcmp(value, "light_fluorospark"))
5310                                         {
5311                                                 originhack[0] = 0;
5312                                                 originhack[1] = 0;
5313                                                 originhack[2] = 0;
5314                                                 overridecolor[0] = 1;
5315                                                 overridecolor[1] = 1;
5316                                                 overridecolor[2] = 1;
5317                                         }
5318                                         if (!strcmp(value, "light_globe"))
5319                                         {
5320                                                 originhack[0] = 0;
5321                                                 originhack[1] = 0;
5322                                                 originhack[2] = 0;
5323                                                 overridecolor[0] = 1;
5324                                                 overridecolor[1] = 0.8;
5325                                                 overridecolor[2] = 0.4;
5326                                         }
5327                                         if (!strcmp(value, "light_flame_large_yellow"))
5328                                         {
5329                                                 originhack[0] = 0;
5330                                                 originhack[1] = 0;
5331                                                 originhack[2] = 0;
5332                                                 overridecolor[0] = 1;
5333                                                 overridecolor[1] = 0.5;
5334                                                 overridecolor[2] = 0.1;
5335                                         }
5336                                         if (!strcmp(value, "light_flame_small_yellow"))
5337                                         {
5338                                                 originhack[0] = 0;
5339                                                 originhack[1] = 0;
5340                                                 originhack[2] = 0;
5341                                                 overridecolor[0] = 1;
5342                                                 overridecolor[1] = 0.5;
5343                                                 overridecolor[2] = 0.1;
5344                                         }
5345                                         if (!strcmp(value, "light_torch_small_white"))
5346                                         {
5347                                                 originhack[0] = 0;
5348                                                 originhack[1] = 0;
5349                                                 originhack[2] = 0;
5350                                                 overridecolor[0] = 1;
5351                                                 overridecolor[1] = 0.5;
5352                                                 overridecolor[2] = 0.1;
5353                                         }
5354                                         if (!strcmp(value, "light_torch_small_walltorch"))
5355                                         {
5356                                                 originhack[0] = 0;
5357                                                 originhack[1] = 0;
5358                                                 originhack[2] = 0;
5359                                                 overridecolor[0] = 1;
5360                                                 overridecolor[1] = 0.5;
5361                                                 overridecolor[2] = 0.1;
5362                                         }
5363                                 }
5364                         }
5365                         else if (!strcmp("style", key))
5366                                 style = atoi(value);
5367                         else if (!strcmp("skin", key))
5368                                 skin = (int)atof(value);
5369                         else if (!strcmp("pflags", key))
5370                                 pflags = (int)atof(value);
5371                         //else if (!strcmp("effects", key))
5372                         //      effects = (int)atof(value);
5373                         else if (cl.worldmodel->type == mod_brushq3)
5374                         {
5375                                 if (!strcmp("scale", key))
5376                                         lightscale = atof(value);
5377                                 if (!strcmp("fade", key))
5378                                         fadescale = atof(value);
5379                         }
5380                 }
5381                 if (!islight)
5382                         continue;
5383                 if (lightscale <= 0)
5384                         lightscale = 1;
5385                 if (fadescale <= 0)
5386                         fadescale = 1;
5387                 if (color[0] == color[1] && color[0] == color[2])
5388                 {
5389                         color[0] *= overridecolor[0];
5390                         color[1] *= overridecolor[1];
5391                         color[2] *= overridecolor[2];
5392                 }
5393                 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5394                 color[0] = color[0] * light[0];
5395                 color[1] = color[1] * light[1];
5396                 color[2] = color[2] * light[2];
5397                 switch (type)
5398                 {
5399                 case LIGHTTYPE_MINUSX:
5400                         break;
5401                 case LIGHTTYPE_RECIPX:
5402                         radius *= 2;
5403                         VectorScale(color, (1.0f / 16.0f), color);
5404                         break;
5405                 case LIGHTTYPE_RECIPXX:
5406                         radius *= 2;
5407                         VectorScale(color, (1.0f / 16.0f), color);
5408                         break;
5409                 default:
5410                 case LIGHTTYPE_NONE:
5411                         break;
5412                 case LIGHTTYPE_SUN:
5413                         break;
5414                 case LIGHTTYPE_MINUSXX:
5415                         break;
5416                 }
5417                 VectorAdd(origin, originhack, origin);
5418                 if (radius >= 1)
5419                         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);
5420         }
5421         if (entfiledata)
5422                 Mem_Free(entfiledata);
5423 }
5424
5425
5426 void R_Shadow_SetCursorLocationForView(void)
5427 {
5428         vec_t dist, push;
5429         vec3_t dest, endpos;
5430         trace_t trace;
5431         VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5432         trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5433         if (trace.fraction < 1)
5434         {
5435                 dist = trace.fraction * r_editlights_cursordistance.value;
5436                 push = r_editlights_cursorpushback.value;
5437                 if (push > dist)
5438                         push = dist;
5439                 push = -push;
5440                 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5441                 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5442         }
5443         else
5444         {
5445                 VectorClear( endpos );
5446         }
5447         r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5448         r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5449         r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5450 }
5451
5452 void R_Shadow_UpdateWorldLightSelection(void)
5453 {
5454         if (r_editlights.integer)
5455         {
5456                 R_Shadow_SetCursorLocationForView();
5457                 R_Shadow_SelectLightInView();
5458         }
5459         else
5460                 R_Shadow_SelectLight(NULL);
5461 }
5462
5463 void R_Shadow_EditLights_Clear_f(void)
5464 {
5465         R_Shadow_ClearWorldLights();
5466 }
5467
5468 void R_Shadow_EditLights_Reload_f(void)
5469 {
5470         if (!cl.worldmodel)
5471                 return;
5472         strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
5473         R_Shadow_ClearWorldLights();
5474         R_Shadow_LoadWorldLights();
5475         if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5476         {
5477                 R_Shadow_LoadLightsFile();
5478                 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5479                         R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5480         }
5481 }
5482
5483 void R_Shadow_EditLights_Save_f(void)
5484 {
5485         if (!cl.worldmodel)
5486                 return;
5487         R_Shadow_SaveWorldLights();
5488 }
5489
5490 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5491 {
5492         R_Shadow_ClearWorldLights();
5493         R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5494 }
5495
5496 void R_Shadow_EditLights_ImportLightsFile_f(void)
5497 {
5498         R_Shadow_ClearWorldLights();
5499         R_Shadow_LoadLightsFile();
5500 }
5501
5502 void R_Shadow_EditLights_Spawn_f(void)
5503 {
5504         vec3_t color;
5505         if (!r_editlights.integer)
5506         {
5507                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
5508                 return;
5509         }
5510         if (Cmd_Argc() != 1)
5511         {
5512                 Con_Print("r_editlights_spawn does not take parameters\n");
5513                 return;
5514         }
5515         color[0] = color[1] = color[2] = 1;
5516         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5517 }
5518
5519 void R_Shadow_EditLights_Edit_f(void)
5520 {
5521         vec3_t origin, angles, color;
5522         vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5523         int style, shadows, flags, normalmode, realtimemode;
5524         char cubemapname[MAX_INPUTLINE];
5525         if (!r_editlights.integer)
5526         {
5527                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
5528                 return;
5529         }
5530         if (!r_shadow_selectedlight)
5531         {
5532                 Con_Print("No selected light.\n");
5533                 return;
5534         }
5535         VectorCopy(r_shadow_selectedlight->origin, origin);
5536         VectorCopy(r_shadow_selectedlight->angles, angles);
5537         VectorCopy(r_shadow_selectedlight->color, color);
5538         radius = r_shadow_selectedlight->radius;
5539         style = r_shadow_selectedlight->style;
5540         if (r_shadow_selectedlight->cubemapname)
5541                 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5542         else
5543                 cubemapname[0] = 0;
5544         shadows = r_shadow_selectedlight->shadow;
5545         corona = r_shadow_selectedlight->corona;
5546         coronasizescale = r_shadow_selectedlight->coronasizescale;
5547         ambientscale = r_shadow_selectedlight->ambientscale;
5548         diffusescale = r_shadow_selectedlight->diffusescale;
5549         specularscale = r_shadow_selectedlight->specularscale;
5550         flags = r_shadow_selectedlight->flags;
5551         normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5552         realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5553         if (!strcmp(Cmd_Argv(1), "origin"))
5554         {
5555                 if (Cmd_Argc() != 5)
5556                 {
5557                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5558                         return;
5559                 }
5560                 origin[0] = atof(Cmd_Argv(2));
5561                 origin[1] = atof(Cmd_Argv(3));
5562                 origin[2] = atof(Cmd_Argv(4));
5563         }
5564         else if (!strcmp(Cmd_Argv(1), "originx"))
5565         {
5566                 if (Cmd_Argc() != 3)
5567                 {
5568                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5569                         return;
5570                 }
5571                 origin[0] = atof(Cmd_Argv(2));
5572         }
5573         else if (!strcmp(Cmd_Argv(1), "originy"))
5574         {
5575                 if (Cmd_Argc() != 3)
5576                 {
5577                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5578                         return;
5579                 }
5580                 origin[1] = atof(Cmd_Argv(2));
5581         }
5582         else if (!strcmp(Cmd_Argv(1), "originz"))
5583         {
5584                 if (Cmd_Argc() != 3)
5585                 {
5586                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5587                         return;
5588                 }
5589                 origin[2] = atof(Cmd_Argv(2));
5590         }
5591         else if (!strcmp(Cmd_Argv(1), "move"))
5592         {
5593                 if (Cmd_Argc() != 5)
5594                 {
5595                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5596                         return;
5597                 }
5598                 origin[0] += atof(Cmd_Argv(2));
5599                 origin[1] += atof(Cmd_Argv(3));
5600                 origin[2] += atof(Cmd_Argv(4));
5601         }
5602         else if (!strcmp(Cmd_Argv(1), "movex"))
5603         {
5604                 if (Cmd_Argc() != 3)
5605                 {
5606                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5607                         return;
5608                 }
5609                 origin[0] += atof(Cmd_Argv(2));
5610         }
5611         else if (!strcmp(Cmd_Argv(1), "movey"))
5612         {
5613                 if (Cmd_Argc() != 3)
5614                 {
5615                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5616                         return;
5617                 }
5618                 origin[1] += atof(Cmd_Argv(2));
5619         }
5620         else if (!strcmp(Cmd_Argv(1), "movez"))
5621         {
5622                 if (Cmd_Argc() != 3)
5623                 {
5624                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5625                         return;
5626                 }
5627                 origin[2] += atof(Cmd_Argv(2));
5628         }
5629         else if (!strcmp(Cmd_Argv(1), "angles"))
5630         {
5631                 if (Cmd_Argc() != 5)
5632                 {
5633                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5634                         return;
5635                 }
5636                 angles[0] = atof(Cmd_Argv(2));
5637                 angles[1] = atof(Cmd_Argv(3));
5638                 angles[2] = atof(Cmd_Argv(4));
5639         }
5640         else if (!strcmp(Cmd_Argv(1), "anglesx"))
5641         {
5642                 if (Cmd_Argc() != 3)
5643                 {
5644                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5645                         return;
5646                 }
5647                 angles[0] = atof(Cmd_Argv(2));
5648         }
5649         else if (!strcmp(Cmd_Argv(1), "anglesy"))
5650         {
5651                 if (Cmd_Argc() != 3)
5652                 {
5653                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5654                         return;
5655                 }
5656                 angles[1] = atof(Cmd_Argv(2));
5657         }
5658         else if (!strcmp(Cmd_Argv(1), "anglesz"))
5659         {
5660                 if (Cmd_Argc() != 3)
5661                 {
5662                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5663                         return;
5664                 }
5665                 angles[2] = atof(Cmd_Argv(2));
5666         }
5667         else if (!strcmp(Cmd_Argv(1), "color"))
5668         {
5669                 if (Cmd_Argc() != 5)
5670                 {
5671                         Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5672                         return;
5673                 }
5674                 color[0] = atof(Cmd_Argv(2));
5675                 color[1] = atof(Cmd_Argv(3));
5676                 color[2] = atof(Cmd_Argv(4));
5677         }
5678         else if (!strcmp(Cmd_Argv(1), "radius"))
5679         {
5680                 if (Cmd_Argc() != 3)
5681                 {
5682                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5683                         return;
5684                 }
5685                 radius = atof(Cmd_Argv(2));
5686         }
5687         else if (!strcmp(Cmd_Argv(1), "colorscale"))
5688         {
5689                 if (Cmd_Argc() == 3)
5690                 {
5691                         double scale = atof(Cmd_Argv(2));
5692                         color[0] *= scale;
5693                         color[1] *= scale;
5694                         color[2] *= scale;
5695                 }
5696                 else
5697                 {
5698                         if (Cmd_Argc() != 5)
5699                         {
5700                                 Con_Printf("usage: r_editlights_edit %s red green blue  (OR grey instead of red green blue)\n", Cmd_Argv(1));
5701                                 return;
5702                         }
5703                         color[0] *= atof(Cmd_Argv(2));
5704                         color[1] *= atof(Cmd_Argv(3));
5705                         color[2] *= atof(Cmd_Argv(4));
5706                 }
5707         }
5708         else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5709         {
5710                 if (Cmd_Argc() != 3)
5711                 {
5712                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5713                         return;
5714                 }
5715                 radius *= atof(Cmd_Argv(2));
5716         }
5717         else if (!strcmp(Cmd_Argv(1), "style"))
5718         {
5719                 if (Cmd_Argc() != 3)
5720                 {
5721                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5722                         return;
5723                 }
5724                 style = atoi(Cmd_Argv(2));
5725         }
5726         else if (!strcmp(Cmd_Argv(1), "cubemap"))
5727         {
5728                 if (Cmd_Argc() > 3)
5729                 {
5730                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5731                         return;
5732                 }
5733                 if (Cmd_Argc() == 3)
5734                         strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5735                 else
5736                         cubemapname[0] = 0;
5737         }
5738         else if (!strcmp(Cmd_Argv(1), "shadows"))
5739         {
5740                 if (Cmd_Argc() != 3)
5741                 {
5742                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5743                         return;
5744                 }
5745                 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5746         }
5747         else if (!strcmp(Cmd_Argv(1), "corona"))
5748         {
5749                 if (Cmd_Argc() != 3)
5750                 {
5751                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5752                         return;
5753                 }
5754                 corona = atof(Cmd_Argv(2));
5755         }
5756         else if (!strcmp(Cmd_Argv(1), "coronasize"))
5757         {
5758                 if (Cmd_Argc() != 3)
5759                 {
5760                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5761                         return;
5762                 }
5763                 coronasizescale = atof(Cmd_Argv(2));
5764         }
5765         else if (!strcmp(Cmd_Argv(1), "ambient"))
5766         {
5767                 if (Cmd_Argc() != 3)
5768                 {
5769                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5770                         return;
5771                 }
5772                 ambientscale = atof(Cmd_Argv(2));
5773         }
5774         else if (!strcmp(Cmd_Argv(1), "diffuse"))
5775         {
5776                 if (Cmd_Argc() != 3)
5777                 {
5778                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5779                         return;
5780                 }
5781                 diffusescale = atof(Cmd_Argv(2));
5782         }
5783         else if (!strcmp(Cmd_Argv(1), "specular"))
5784         {
5785                 if (Cmd_Argc() != 3)
5786                 {
5787                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5788                         return;
5789                 }
5790                 specularscale = atof(Cmd_Argv(2));
5791         }
5792         else if (!strcmp(Cmd_Argv(1), "normalmode"))
5793         {
5794                 if (Cmd_Argc() != 3)
5795                 {
5796                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5797                         return;
5798                 }
5799                 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5800         }
5801         else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5802         {
5803                 if (Cmd_Argc() != 3)
5804                 {
5805                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5806                         return;
5807                 }
5808                 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5809         }
5810         else
5811         {
5812                 Con_Print("usage: r_editlights_edit [property] [value]\n");
5813                 Con_Print("Selected light's properties:\n");
5814                 Con_Printf("Origin       : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5815                 Con_Printf("Angles       : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5816                 Con_Printf("Color        : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5817                 Con_Printf("Radius       : %f\n", r_shadow_selectedlight->radius);
5818                 Con_Printf("Corona       : %f\n", r_shadow_selectedlight->corona);
5819                 Con_Printf("Style        : %i\n", r_shadow_selectedlight->style);
5820                 Con_Printf("Shadows      : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5821                 Con_Printf("Cubemap      : %s\n", r_shadow_selectedlight->cubemapname);
5822                 Con_Printf("CoronaSize   : %f\n", r_shadow_selectedlight->coronasizescale);
5823                 Con_Printf("Ambient      : %f\n", r_shadow_selectedlight->ambientscale);
5824                 Con_Printf("Diffuse      : %f\n", r_shadow_selectedlight->diffusescale);
5825                 Con_Printf("Specular     : %f\n", r_shadow_selectedlight->specularscale);
5826                 Con_Printf("NormalMode   : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5827                 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5828                 return;
5829         }
5830         flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5831         R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5832 }
5833
5834 void R_Shadow_EditLights_EditAll_f(void)
5835 {
5836         size_t lightindex;
5837         dlight_t *light, *oldselected;
5838         size_t range;
5839
5840         if (!r_editlights.integer)
5841         {
5842                 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5843                 return;
5844         }
5845
5846         oldselected = r_shadow_selectedlight;
5847         // EditLights doesn't seem to have a "remove" command or something so:
5848         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5849         for (lightindex = 0;lightindex < range;lightindex++)
5850         {
5851                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5852                 if (!light)
5853                         continue;
5854                 R_Shadow_SelectLight(light);
5855                 R_Shadow_EditLights_Edit_f();
5856         }
5857         // return to old selected (to not mess editing once selection is locked)
5858         R_Shadow_SelectLight(oldselected);
5859 }
5860
5861 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5862 {
5863         int lightnumber, lightcount;
5864         size_t lightindex, range;
5865         dlight_t *light;
5866         float x, y;
5867         char temp[256];
5868         if (!r_editlights.integer)
5869                 return;
5870         x = vid_conwidth.value - 240;
5871         y = 5;
5872         DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5873         lightnumber = -1;
5874         lightcount = 0;
5875         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5876         for (lightindex = 0;lightindex < range;lightindex++)
5877         {
5878                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5879                 if (!light)
5880                         continue;
5881                 if (light == r_shadow_selectedlight)
5882                         lightnumber = lightindex;
5883                 lightcount++;
5884         }
5885         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;
5886         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;
5887         y += 8;
5888         if (r_shadow_selectedlight == NULL)
5889                 return;
5890         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;
5891         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;
5892         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;
5893         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;
5894         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;
5895         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;
5896         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;
5897         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;
5898         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;
5899         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;
5900         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;
5901         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;
5902         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;
5903         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;
5904         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;
5905 }
5906
5907 void R_Shadow_EditLights_ToggleShadow_f(void)
5908 {
5909         if (!r_editlights.integer)
5910         {
5911                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
5912                 return;
5913         }
5914         if (!r_shadow_selectedlight)
5915         {
5916                 Con_Print("No selected light.\n");
5917                 return;
5918         }
5919         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);
5920 }
5921
5922 void R_Shadow_EditLights_ToggleCorona_f(void)
5923 {
5924         if (!r_editlights.integer)
5925         {
5926                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
5927                 return;
5928         }
5929         if (!r_shadow_selectedlight)
5930         {
5931                 Con_Print("No selected light.\n");
5932                 return;
5933         }
5934         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);
5935 }
5936
5937 void R_Shadow_EditLights_Remove_f(void)
5938 {
5939         if (!r_editlights.integer)
5940         {
5941                 Con_Print("Cannot remove light when not in editing mode.  Set r_editlights to 1.\n");
5942                 return;
5943         }
5944         if (!r_shadow_selectedlight)
5945         {
5946                 Con_Print("No selected light.\n");
5947                 return;
5948         }
5949         R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5950         r_shadow_selectedlight = NULL;
5951 }
5952
5953 void R_Shadow_EditLights_Help_f(void)
5954 {
5955         Con_Print(
5956 "Documentation on r_editlights system:\n"
5957 "Settings:\n"
5958 "r_editlights : enable/disable editing mode\n"
5959 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5960 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5961 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5962 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5963 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5964 "Commands:\n"
5965 "r_editlights_help : this help\n"
5966 "r_editlights_clear : remove all lights\n"
5967 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5968 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
5969 "r_editlights_save : save to .rtlights file\n"
5970 "r_editlights_spawn : create a light with default settings\n"
5971 "r_editlights_edit command : edit selected light - more documentation below\n"
5972 "r_editlights_remove : remove selected light\n"
5973 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5974 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5975 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5976 "Edit commands:\n"
5977 "origin x y z : set light location\n"
5978 "originx x: set x component of light location\n"
5979 "originy y: set y component of light location\n"
5980 "originz z: set z component of light location\n"
5981 "move x y z : adjust light location\n"
5982 "movex x: adjust x component of light location\n"
5983 "movey y: adjust y component of light location\n"
5984 "movez z: adjust z component of light location\n"
5985 "angles x y z : set light angles\n"
5986 "anglesx x: set x component of light angles\n"
5987 "anglesy y: set y component of light angles\n"
5988 "anglesz z: set z component of light angles\n"
5989 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5990 "radius radius : set radius (size) of light\n"
5991 "colorscale grey : multiply color of light (1 does nothing)\n"
5992 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5993 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5994 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5995 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5996 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5997 "shadows 1/0 : turn on/off shadows\n"
5998 "corona n : set corona intensity\n"
5999 "coronasize n : set corona size (0-1)\n"
6000 "ambient n : set ambient intensity (0-1)\n"
6001 "diffuse n : set diffuse intensity (0-1)\n"
6002 "specular n : set specular intensity (0-1)\n"
6003 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
6004 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
6005 "<nothing> : print light properties to console\n"
6006         );
6007 }
6008
6009 void R_Shadow_EditLights_CopyInfo_f(void)
6010 {
6011         if (!r_editlights.integer)
6012         {
6013                 Con_Print("Cannot copy light info when not in editing mode.  Set r_editlights to 1.\n");
6014                 return;
6015         }
6016         if (!r_shadow_selectedlight)
6017         {
6018                 Con_Print("No selected light.\n");
6019                 return;
6020         }
6021         VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
6022         VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
6023         r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
6024         r_shadow_bufferlight.style = r_shadow_selectedlight->style;
6025         if (r_shadow_selectedlight->cubemapname)
6026                 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
6027         else
6028                 r_shadow_bufferlight.cubemapname[0] = 0;
6029         r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
6030         r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
6031         r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
6032         r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
6033         r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
6034         r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
6035         r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
6036 }
6037
6038 void R_Shadow_EditLights_PasteInfo_f(void)
6039 {
6040         if (!r_editlights.integer)
6041         {
6042                 Con_Print("Cannot paste light info when not in editing mode.  Set r_editlights to 1.\n");
6043                 return;
6044         }
6045         if (!r_shadow_selectedlight)
6046         {
6047                 Con_Print("No selected light.\n");
6048                 return;
6049         }
6050         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);
6051 }
6052
6053 void R_Shadow_EditLights_Lock_f(void)
6054 {
6055         if (!r_editlights.integer)
6056         {
6057                 Con_Print("Cannot lock on light when not in editing mode.  Set r_editlights to 1.\n");
6058                 return;
6059         }
6060         if (r_editlights_lockcursor)
6061         {
6062                 r_editlights_lockcursor = false;
6063                 return;
6064         }
6065         if (!r_shadow_selectedlight)
6066         {
6067                 Con_Print("No selected light to lock on.\n");
6068                 return;
6069         }
6070         r_editlights_lockcursor = true;
6071 }
6072
6073 void R_Shadow_EditLights_Init(void)
6074 {
6075         Cvar_RegisterVariable(&r_editlights);
6076         Cvar_RegisterVariable(&r_editlights_cursordistance);
6077         Cvar_RegisterVariable(&r_editlights_cursorpushback);
6078         Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6079         Cvar_RegisterVariable(&r_editlights_cursorgrid);
6080         Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6081         Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6082         Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6083         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)");
6084         Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6085         Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6086         Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6087         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)");
6088         Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6089         Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6090         Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6091         Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6092         Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6093         Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6094         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)");
6095         Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
6096 }
6097
6098
6099
6100 /*
6101 =============================================================================
6102
6103 LIGHT SAMPLING
6104
6105 =============================================================================
6106 */
6107
6108 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
6109 {
6110         VectorClear(diffusecolor);
6111         VectorClear(diffusenormal);
6112
6113         if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6114         {
6115                 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient;
6116                 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
6117         }
6118         else
6119                 VectorSet(ambientcolor, 1, 1, 1);
6120
6121         if (dynamic)
6122         {
6123                 int i;
6124                 float f, v[3];
6125                 rtlight_t *light;
6126                 for (i = 0;i < r_refdef.scene.numlights;i++)
6127                 {
6128                         light = r_refdef.scene.lights[i];
6129                         Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
6130                         f = 1 - VectorLength2(v);
6131                         if (f > 0 && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
6132                                 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);
6133                 }
6134         }
6135 }