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