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