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