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