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