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