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