]> icculus.org git repositories - divverent/darkplaces.git/blob - r_shadow.c
nudgeoutofsolid: check for bmodelstartsolid, not startsolid. Allows multiple player...
[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, *shadowtrispvs, *lighttrispvs, *surfacesides;
3418         int numlightentities;
3419         int numlightentities_noselfshadow;
3420         int numshadowentities;
3421         int numshadowentities_noselfshadow;
3422         static entity_render_t *lightentities[MAX_EDICTS];
3423         static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3424         static entity_render_t *shadowentities[MAX_EDICTS];
3425         static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3426
3427         rtlight->draw = false;
3428
3429         // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3430         // skip lights that are basically invisible (color 0 0 0)
3431         if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
3432                 return;
3433
3434         // loading is done before visibility checks because loading should happen
3435         // all at once at the start of a level, not when it stalls gameplay.
3436         // (especially important to benchmarks)
3437         // compile light
3438         if (rtlight->isstatic && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3439         {
3440                 if (rtlight->compiled)
3441                         R_RTLight_Uncompile(rtlight);
3442                 R_RTLight_Compile(rtlight);
3443         }
3444
3445         // load cubemap
3446         rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3447
3448         // look up the light style value at this time
3449         f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3450         VectorScale(rtlight->color, f, rtlight->currentcolor);
3451         /*
3452         if (rtlight->selected)
3453         {
3454                 f = 2 + sin(realtime * M_PI * 4.0);
3455                 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3456         }
3457         */
3458
3459         // if lightstyle is currently off, don't draw the light
3460         if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3461                 return;
3462
3463         // if the light box is offscreen, skip it
3464         if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3465                 return;
3466
3467         VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3468         VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3469
3470         R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3471
3472         if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3473         {
3474                 // compiled light, world available and can receive realtime lighting
3475                 // retrieve leaf information
3476                 numleafs = rtlight->static_numleafs;
3477                 leaflist = rtlight->static_leaflist;
3478                 leafpvs = rtlight->static_leafpvs;
3479                 numsurfaces = rtlight->static_numsurfaces;
3480                 surfacelist = rtlight->static_surfacelist;
3481                 surfacesides = NULL;
3482                 shadowtrispvs = rtlight->static_shadowtrispvs;
3483                 lighttrispvs = rtlight->static_lighttrispvs;
3484         }
3485         else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3486         {
3487                 // dynamic light, world available and can receive realtime lighting
3488                 // calculate lit surfaces and leafs
3489                 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);
3490                 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3491                 leaflist = r_shadow_buffer_leaflist;
3492                 leafpvs = r_shadow_buffer_leafpvs;
3493                 surfacelist = r_shadow_buffer_surfacelist;
3494                 surfacesides = r_shadow_buffer_surfacesides;
3495                 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3496                 lighttrispvs = r_shadow_buffer_lighttrispvs;
3497                 // if the reduced leaf bounds are offscreen, skip it
3498                 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3499                         return;
3500         }
3501         else
3502         {
3503                 // no world
3504                 numleafs = 0;
3505                 leaflist = NULL;
3506                 leafpvs = NULL;
3507                 numsurfaces = 0;
3508                 surfacelist = NULL;
3509                 surfacesides = NULL;
3510                 shadowtrispvs = NULL;
3511                 lighttrispvs = NULL;
3512         }
3513         // check if light is illuminating any visible leafs
3514         if (numleafs)
3515         {
3516                 for (i = 0;i < numleafs;i++)
3517                         if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3518                                 break;
3519                 if (i == numleafs)
3520                         return;
3521         }
3522
3523         // make a list of lit entities and shadow casting entities
3524         numlightentities = 0;
3525         numlightentities_noselfshadow = 0;
3526         numshadowentities = 0;
3527         numshadowentities_noselfshadow = 0;
3528
3529         // add dynamic entities that are lit by the light
3530         for (i = 0;i < r_refdef.scene.numentities;i++)
3531         {
3532                 dp_model_t *model;
3533                 entity_render_t *ent = r_refdef.scene.entities[i];
3534                 vec3_t org;
3535                 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3536                         continue;
3537                 // skip the object entirely if it is not within the valid
3538                 // shadow-casting region (which includes the lit region)
3539                 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3540                         continue;
3541                 if (!(model = ent->model))
3542                         continue;
3543                 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3544                 {
3545                         // this entity wants to receive light, is visible, and is
3546                         // inside the light box
3547                         // TODO: check if the surfaces in the model can receive light
3548                         // so now check if it's in a leaf seen by the light
3549                         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))
3550                                 continue;
3551                         if (ent->flags & RENDER_NOSELFSHADOW)
3552                                 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3553                         else
3554                                 lightentities[numlightentities++] = ent;
3555                         // since it is lit, it probably also casts a shadow...
3556                         // about the VectorDistance2 - light emitting entities should not cast their own shadow
3557                         Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3558                         if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3559                         {
3560                                 // note: exterior models without the RENDER_NOSELFSHADOW
3561                                 // flag still create a RENDER_NOSELFSHADOW shadow but
3562                                 // are lit normally, this means that they are
3563                                 // self-shadowing but do not shadow other
3564                                 // RENDER_NOSELFSHADOW entities such as the gun
3565                                 // (very weird, but keeps the player shadow off the gun)
3566                                 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3567                                         shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3568                                 else
3569                                         shadowentities[numshadowentities++] = ent;
3570                         }
3571                 }
3572                 else if (ent->flags & RENDER_SHADOW)
3573                 {
3574                         // this entity is not receiving light, but may still need to
3575                         // cast a shadow...
3576                         // TODO: check if the surfaces in the model can cast shadow
3577                         // now check if it is in a leaf seen by the light
3578                         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))
3579                                 continue;
3580                         // about the VectorDistance2 - light emitting entities should not cast their own shadow
3581                         Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3582                         if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3583                         {
3584                                 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3585                                         shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3586                                 else
3587                                         shadowentities[numshadowentities++] = ent;
3588                         }
3589                 }
3590         }
3591
3592         // return if there's nothing at all to light
3593         if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3594                 return;
3595
3596         // count this light in the r_speeds
3597         r_refdef.stats.lights++;
3598
3599         // flag it as worth drawing later
3600         rtlight->draw = true;
3601
3602         // cache all the animated entities that cast a shadow but are not visible
3603         for (i = 0;i < numshadowentities;i++)
3604                 if (!shadowentities[i]->animcache_vertex3f)
3605                         R_AnimCache_GetEntity(shadowentities[i], false, false);
3606         for (i = 0;i < numshadowentities_noselfshadow;i++)
3607                 if (!shadowentities_noselfshadow[i]->animcache_vertex3f)
3608                         R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3609
3610         // allocate some temporary memory for rendering this light later in the frame
3611         // reusable buffers need to be copied, static data can be used as-is
3612         rtlight->cached_numlightentities               = numlightentities;
3613         rtlight->cached_numlightentities_noselfshadow  = numlightentities_noselfshadow;
3614         rtlight->cached_numshadowentities              = numshadowentities;
3615         rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3616         rtlight->cached_numsurfaces                    = numsurfaces;
3617         rtlight->cached_lightentities                  = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3618         rtlight->cached_lightentities_noselfshadow     = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3619         rtlight->cached_shadowentities                 = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3620         rtlight->cached_shadowentities_noselfshadow    = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3621         if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3622         {
3623                 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
3624                 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3625                 rtlight->cached_shadowtrispvs                  =   (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3626                 rtlight->cached_lighttrispvs                   =   (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3627                 rtlight->cached_surfacelist                    =              (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3628         }
3629         else
3630         {
3631                 // compiled light data
3632                 rtlight->cached_shadowtrispvs = shadowtrispvs;
3633                 rtlight->cached_lighttrispvs = lighttrispvs;
3634                 rtlight->cached_surfacelist = surfacelist;
3635         }
3636 }
3637
3638 void R_Shadow_DrawLight(rtlight_t *rtlight)
3639 {
3640         int i;
3641         int numsurfaces;
3642         unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
3643         int numlightentities;
3644         int numlightentities_noselfshadow;
3645         int numshadowentities;
3646         int numshadowentities_noselfshadow;
3647         entity_render_t **lightentities;
3648         entity_render_t **lightentities_noselfshadow;
3649         entity_render_t **shadowentities;
3650         entity_render_t **shadowentities_noselfshadow;
3651         int *surfacelist;
3652         static unsigned char entitysides[MAX_EDICTS];
3653         static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3654         vec3_t nearestpoint;
3655         vec_t distance;
3656         qboolean castshadows;
3657         int lodlinear;
3658
3659         // check if we cached this light this frame (meaning it is worth drawing)
3660         if (!rtlight->draw)
3661                 return;
3662
3663         // if R_FrameData_Store ran out of space we skip anything dependent on it
3664         if (r_framedata_failed)
3665                 return;
3666
3667         numlightentities = rtlight->cached_numlightentities;
3668         numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3669         numshadowentities = rtlight->cached_numshadowentities;
3670         numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3671         numsurfaces = rtlight->cached_numsurfaces;
3672         lightentities = rtlight->cached_lightentities;
3673         lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3674         shadowentities = rtlight->cached_shadowentities;
3675         shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3676         shadowtrispvs = rtlight->cached_shadowtrispvs;
3677         lighttrispvs = rtlight->cached_lighttrispvs;
3678         surfacelist = rtlight->cached_surfacelist;
3679
3680         // set up a scissor rectangle for this light
3681         if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3682                 return;
3683
3684         // don't let sound skip if going slow
3685         if (r_refdef.scene.extraupdate)
3686                 S_ExtraUpdate ();
3687
3688         // make this the active rtlight for rendering purposes
3689         R_Shadow_RenderMode_ActiveLight(rtlight);
3690
3691         if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3692         {
3693                 // optionally draw visible shape of the shadow volumes
3694                 // for performance analysis by level designers
3695                 R_Shadow_RenderMode_VisibleShadowVolumes();
3696                 if (numsurfaces)
3697                         R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3698                 for (i = 0;i < numshadowentities;i++)
3699                         R_Shadow_DrawEntityShadow(shadowentities[i]);
3700                 for (i = 0;i < numshadowentities_noselfshadow;i++)
3701                         R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3702                 R_Shadow_RenderMode_VisibleLighting(false, false);
3703         }
3704
3705         if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3706         {
3707                 // optionally draw the illuminated areas
3708                 // for performance analysis by level designers
3709                 R_Shadow_RenderMode_VisibleLighting(false, false);
3710                 if (numsurfaces)
3711                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3712                 for (i = 0;i < numlightentities;i++)
3713                         R_Shadow_DrawEntityLight(lightentities[i]);
3714                 for (i = 0;i < numlightentities_noselfshadow;i++)
3715                         R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3716         }
3717
3718         castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3719
3720         nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3721         nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3722         nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3723         distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3724
3725         lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
3726         //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3727         lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3728
3729         if (castshadows && (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE))
3730         {
3731                 float borderbias;
3732                 int side;
3733                 int size;
3734                 int castermask = 0;
3735                 int receivermask = 0;
3736                 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3737                 Matrix4x4_Abs(&radiustolight);
3738
3739                 r_shadow_shadowmaplod = 0;
3740                 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
3741                         if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
3742                                 r_shadow_shadowmaplod = i;
3743
3744                 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
3745                         size = max(1, r_shadow_shadowmapmaxsize >> r_shadow_shadowmaplod);
3746                 else
3747                         size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3748                         
3749                 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3750
3751                 surfacesides = NULL;
3752                 if (numsurfaces)
3753                 {
3754                         if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3755                         {
3756                                 castermask = rtlight->static_shadowmap_casters;
3757                                 receivermask = rtlight->static_shadowmap_receivers;
3758                         }
3759                         else
3760                         {
3761                                 surfacesides = r_shadow_buffer_surfacesides;
3762                                 for(i = 0;i < numsurfaces;i++)
3763                                 {
3764                                         msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3765                                         surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);           
3766                                         castermask |= surfacesides[i];
3767                                         receivermask |= surfacesides[i];
3768                                 }
3769                         }
3770                 }
3771                 if (receivermask < 0x3F) 
3772                 {
3773                         for (i = 0;i < numlightentities;i++)
3774                                 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3775                         if (receivermask < 0x3F)
3776                                 for(i = 0; i < numlightentities_noselfshadow;i++)
3777                                         receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3778                 }
3779
3780                 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3781
3782                 if (receivermask)
3783                 {
3784                         for (i = 0;i < numshadowentities;i++)
3785                                 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3786                         for (i = 0;i < numshadowentities_noselfshadow;i++)
3787                                 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias)); 
3788                 }
3789
3790                 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
3791
3792                 // render shadow casters into 6 sided depth texture
3793                 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
3794                 {
3795                         R_Shadow_RenderMode_ShadowMap(side, receivermask, size);
3796                         if (! (castermask & (1 << side))) continue;
3797                         if (numsurfaces)
3798                                 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3799                         for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
3800                                 R_Shadow_DrawEntityShadow(shadowentities[i]);
3801                 }
3802
3803                 if (numlightentities_noselfshadow)
3804                 {
3805                         // render lighting using the depth texture as shadowmap
3806                         // draw lighting in the unmasked areas
3807                         R_Shadow_RenderMode_Lighting(false, false, true);
3808                         for (i = 0;i < numlightentities_noselfshadow;i++)
3809                                 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3810                 }
3811
3812                 // render shadow casters into 6 sided depth texture
3813                 if (numshadowentities_noselfshadow)
3814                 {
3815                         for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
3816                         {
3817                                 R_Shadow_RenderMode_ShadowMap(side, 0, size);
3818                                 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
3819                                         R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3820                         }
3821                 }
3822
3823                 // render lighting using the depth texture as shadowmap
3824                 // draw lighting in the unmasked areas
3825                 R_Shadow_RenderMode_Lighting(false, false, true);
3826                 // draw lighting in the unmasked areas
3827                 if (numsurfaces)
3828                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3829                 for (i = 0;i < numlightentities;i++)
3830                         R_Shadow_DrawEntityLight(lightentities[i]);
3831         }
3832         else if (castshadows && vid.stencil)
3833         {
3834                 // draw stencil shadow volumes to mask off pixels that are in shadow
3835                 // so that they won't receive lighting
3836                 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
3837                 R_Shadow_ClearStencil();
3838
3839                 if (numsurfaces)
3840                         R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3841                 for (i = 0;i < numshadowentities;i++)
3842                         R_Shadow_DrawEntityShadow(shadowentities[i]);
3843
3844                 // draw lighting in the unmasked areas
3845                 R_Shadow_RenderMode_Lighting(true, false, false);
3846                 for (i = 0;i < numlightentities_noselfshadow;i++)
3847                         R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3848
3849                 for (i = 0;i < numshadowentities_noselfshadow;i++)
3850                         R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3851
3852                 // draw lighting in the unmasked areas
3853                 R_Shadow_RenderMode_Lighting(true, false, false);
3854                 if (numsurfaces)
3855                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3856                 for (i = 0;i < numlightentities;i++)
3857                         R_Shadow_DrawEntityLight(lightentities[i]);
3858         }
3859         else
3860         {
3861                 // draw lighting in the unmasked areas
3862                 R_Shadow_RenderMode_Lighting(false, false, false);
3863                 if (numsurfaces)
3864                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3865                 for (i = 0;i < numlightentities;i++)
3866                         R_Shadow_DrawEntityLight(lightentities[i]);
3867                 for (i = 0;i < numlightentities_noselfshadow;i++)
3868                         R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3869         }
3870
3871         if (r_shadow_usingdeferredprepass)
3872         {
3873                 // when rendering deferred lighting, we simply rasterize the box
3874                 if (castshadows && (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE))
3875                         R_Shadow_RenderMode_DrawDeferredLight(false, true);
3876                 else if (castshadows && vid.stencil)
3877                         R_Shadow_RenderMode_DrawDeferredLight(true, false);
3878                 else
3879                         R_Shadow_RenderMode_DrawDeferredLight(false, false);
3880         }
3881 }
3882
3883 static void R_Shadow_FreeDeferred(void)
3884 {
3885         if (r_shadow_prepassgeometryfbo)
3886                 qglDeleteFramebuffersEXT(1, &r_shadow_prepassgeometryfbo);CHECKGLERROR
3887         r_shadow_prepassgeometryfbo = 0;
3888
3889         if (r_shadow_prepasslightingfbo)
3890                 qglDeleteFramebuffersEXT(1, &r_shadow_prepasslightingfbo);CHECKGLERROR
3891         r_shadow_prepasslightingfbo = 0;
3892
3893         if (r_shadow_prepassgeometrydepthtexture)
3894                 R_FreeTexture(r_shadow_prepassgeometrydepthtexture);
3895         r_shadow_prepassgeometrydepthtexture = NULL;
3896
3897         if (r_shadow_prepassgeometrynormalmaptexture)
3898                 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
3899         r_shadow_prepassgeometrynormalmaptexture = NULL;
3900
3901         if (r_shadow_prepasslightingdiffusetexture)
3902                 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
3903         r_shadow_prepasslightingdiffusetexture = NULL;
3904
3905         if (r_shadow_prepasslightingspeculartexture)
3906                 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
3907         r_shadow_prepasslightingspeculartexture = NULL;
3908 }
3909
3910 void R_Shadow_DrawPrepass(void)
3911 {
3912         int i;
3913         int flag;
3914         int lnum;
3915         size_t lightindex;
3916         dlight_t *light;
3917         size_t range;
3918         entity_render_t *ent;
3919
3920         GL_AlphaTest(false);
3921         R_Mesh_ColorPointer(NULL, 0, 0);
3922         R_Mesh_ResetTextureState();
3923         GL_DepthMask(true);
3924         GL_ColorMask(1,1,1,1);
3925         GL_BlendFunc(GL_ONE, GL_ZERO);
3926         GL_Color(1,1,1,1);
3927         GL_DepthTest(true);
3928         qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepassgeometryfbo);CHECKGLERROR
3929         qglClearColor(0.5f,0.5f,0.5f,1.0f);CHECKGLERROR
3930         GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);CHECKGLERROR
3931
3932         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
3933                 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
3934         if (r_timereport_active)
3935                 R_TimeReport("prepassworld");
3936
3937         for (i = 0;i < r_refdef.scene.numentities;i++)
3938         {
3939                 if (!r_refdef.viewcache.entityvisible[i])
3940                         continue;
3941                 ent = r_refdef.scene.entities[i];
3942                 if (ent->model && ent->model->DrawPrepass != NULL)
3943                         ent->model->DrawPrepass(ent);
3944         }
3945
3946         if (r_timereport_active)
3947                 R_TimeReport("prepassmodels");
3948
3949         GL_DepthMask(false);
3950         GL_ColorMask(1,1,1,1);
3951         GL_Color(1,1,1,1);
3952         GL_DepthTest(true);
3953         qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR
3954         qglClearColor(0.0f,0.0f,0.0f,0.0f);CHECKGLERROR
3955         GL_Clear(GL_COLOR_BUFFER_BIT);CHECKGLERROR
3956         if (r_refdef.fogenabled)
3957                 qglClearColor(r_refdef.fogcolor[0],r_refdef.fogcolor[1],r_refdef.fogcolor[2],0);CHECKGLERROR
3958
3959         R_Shadow_RenderMode_Begin();
3960
3961         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3962         if (r_shadow_debuglight.integer >= 0)
3963         {
3964                 lightindex = r_shadow_debuglight.integer;
3965                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3966                 if (light && (light->flags & flag))
3967                         R_Shadow_DrawLight(&light->rtlight);
3968         }
3969         else
3970         {
3971                 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3972                 for (lightindex = 0;lightindex < range;lightindex++)
3973                 {
3974                         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3975                         if (light && (light->flags & flag))
3976                                 R_Shadow_DrawLight(&light->rtlight);
3977                 }
3978         }
3979         if (r_refdef.scene.rtdlight)
3980                 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3981                         R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
3982
3983         qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
3984         if (r_refdef.fogenabled)
3985                 qglClearColor(r_refdef.fogcolor[0],r_refdef.fogcolor[1],r_refdef.fogcolor[2],0);CHECKGLERROR
3986
3987         R_Shadow_RenderMode_End();
3988
3989         if (r_timereport_active)
3990                 R_TimeReport("prepasslights");
3991 }
3992
3993 void R_Shadow_DrawLightSprites(void);
3994 void R_Shadow_PrepareLights(void)
3995 {
3996         int flag;
3997         int lnum;
3998         size_t lightindex;
3999         dlight_t *light;
4000         size_t range;
4001         float f;
4002         GLenum status;
4003
4004         if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
4005                 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4006                 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0) || 
4007                 r_shadow_shadowmaptexturetype != r_shadow_shadowmapping_texturetype.integer ||
4008                 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer || 
4009                 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer || 
4010                 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
4011                 R_Shadow_FreeShadowMaps();
4012
4013         switch (vid.renderpath)
4014         {
4015         case RENDERPATH_GL20:
4016         case RENDERPATH_CGGL:
4017                 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
4018                 {
4019                         r_shadow_usingdeferredprepass = false;
4020                         if (r_shadow_prepass_width)
4021                                 R_Shadow_FreeDeferred();
4022                         r_shadow_prepass_width = r_shadow_prepass_height = 0;
4023                         break;
4024                 }
4025
4026                 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4027                 {
4028                         R_Shadow_FreeDeferred();
4029
4030                         r_shadow_usingdeferredprepass = true;
4031                         r_shadow_prepass_width = vid.width;
4032                         r_shadow_prepass_height = vid.height;
4033                         r_shadow_prepassgeometrydepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false);
4034                         r_shadow_prepassgeometrynormalmaptexture = R_LoadTexture2D(r_shadow_texturepool, "prepassgeometrynormalmap", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
4035                         r_shadow_prepasslightingdiffusetexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingdiffuse", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
4036                         r_shadow_prepasslightingspeculartexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingspecular", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
4037
4038                         // set up the geometry pass fbo (depth + normalmap)
4039                         qglGenFramebuffersEXT(1, &r_shadow_prepassgeometryfbo);CHECKGLERROR
4040                         qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepassgeometryfbo);CHECKGLERROR
4041                         qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepassgeometrydepthtexture), 0);CHECKGLERROR
4042                         qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepassgeometrynormalmaptexture), 0);CHECKGLERROR
4043                         // render depth into one texture and normalmap into the other
4044                         if (qglDrawBuffersARB)
4045                         {
4046                                 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
4047                                 qglReadBuffer(GL_NONE);CHECKGLERROR
4048                         }
4049                         status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4050                         if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4051                         {
4052                                 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4053                                 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4054                                 r_shadow_usingdeferredprepass = false;
4055                         }
4056
4057                         // set up the lighting pass fbo (diffuse + specular)
4058                         qglGenFramebuffersEXT(1, &r_shadow_prepasslightingfbo);CHECKGLERROR
4059                         qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR
4060                         qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepassgeometrydepthtexture), 0);CHECKGLERROR
4061                         qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepasslightingdiffusetexture), 0);CHECKGLERROR
4062                         qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepasslightingspeculartexture), 0);CHECKGLERROR
4063                         // render diffuse into one texture and specular into another,
4064                         // with depth and normalmap bound as textures,
4065                         // with depth bound as attachment as well
4066                         if (qglDrawBuffersARB)
4067                         {
4068                                 qglDrawBuffersARB(2, r_shadow_prepasslightingdrawbuffers);CHECKGLERROR
4069                                 qglReadBuffer(GL_NONE);CHECKGLERROR
4070                         }
4071                         status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4072                         if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4073                         {
4074                                 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4075                                 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4076                                 r_shadow_usingdeferredprepass = false;
4077                         }
4078                 }
4079                 break;
4080         case RENDERPATH_GL13:
4081         case RENDERPATH_GL11:
4082                 r_shadow_usingdeferredprepass = false;
4083                 break;
4084         }
4085
4086         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);
4087
4088         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4089         if (r_shadow_debuglight.integer >= 0)
4090         {
4091                 lightindex = r_shadow_debuglight.integer;
4092                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4093                 if (light && (light->flags & flag))
4094                         R_Shadow_PrepareLight(&light->rtlight);
4095         }
4096         else
4097         {
4098                 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4099                 for (lightindex = 0;lightindex < range;lightindex++)
4100                 {
4101                         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4102                         if (light && (light->flags & flag))
4103                                 R_Shadow_PrepareLight(&light->rtlight);
4104                 }
4105         }
4106         if (r_refdef.scene.rtdlight)
4107         {
4108                 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4109                         R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4110         }
4111         else if(gl_flashblend.integer)
4112         {
4113                 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4114                 {
4115                         rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4116                         f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4117                         VectorScale(rtlight->color, f, rtlight->currentcolor);
4118                 }
4119         }
4120
4121         if (r_editlights.integer)
4122                 R_Shadow_DrawLightSprites();
4123 }
4124
4125 void R_Shadow_DrawLights(void)
4126 {
4127         int flag;
4128         int lnum;
4129         size_t lightindex;
4130         dlight_t *light;
4131         size_t range;
4132
4133         R_Shadow_RenderMode_Begin();
4134
4135         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4136         if (r_shadow_debuglight.integer >= 0)
4137         {
4138                 lightindex = r_shadow_debuglight.integer;
4139                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4140                 if (light && (light->flags & flag))
4141                         R_Shadow_DrawLight(&light->rtlight);
4142         }
4143         else
4144         {
4145                 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4146                 for (lightindex = 0;lightindex < range;lightindex++)
4147                 {
4148                         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4149                         if (light && (light->flags & flag))
4150                                 R_Shadow_DrawLight(&light->rtlight);
4151                 }
4152         }
4153         if (r_refdef.scene.rtdlight)
4154                 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4155                         R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4156
4157         R_Shadow_RenderMode_End();
4158 }
4159
4160 extern const float r_screenvertex3f[12];
4161 extern void R_SetupView(qboolean allowwaterclippingplane);
4162 extern void R_ResetViewRendering3D(void);
4163 extern void R_ResetViewRendering2D(void);
4164 extern cvar_t r_shadows;
4165 extern cvar_t r_shadows_darken;
4166 extern cvar_t r_shadows_drawafterrtlighting;
4167 extern cvar_t r_shadows_castfrombmodels;
4168 extern cvar_t r_shadows_throwdistance;
4169 extern cvar_t r_shadows_throwdirection;
4170 void R_DrawModelShadows(void)
4171 {
4172         int i;
4173         float relativethrowdistance;
4174         entity_render_t *ent;
4175         vec3_t relativelightorigin;
4176         vec3_t relativelightdirection;
4177         vec3_t relativeshadowmins, relativeshadowmaxs;
4178         vec3_t tmp, shadowdir;
4179
4180         if (!r_refdef.scene.numentities || !vid.stencil)
4181                 return;
4182
4183         CHECKGLERROR
4184         R_ResetViewRendering3D();
4185         //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4186         //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4187         R_Shadow_RenderMode_Begin();
4188         R_Shadow_RenderMode_ActiveLight(NULL);
4189         r_shadow_lightscissor[0] = r_refdef.view.x;
4190         r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4191         r_shadow_lightscissor[2] = r_refdef.view.width;
4192         r_shadow_lightscissor[3] = r_refdef.view.height;
4193         R_Shadow_RenderMode_StencilShadowVolumes(false);
4194
4195         // get shadow dir
4196         if (r_shadows.integer == 2)
4197         {
4198                 Math_atov(r_shadows_throwdirection.string, shadowdir);
4199                 VectorNormalize(shadowdir);
4200         }
4201
4202         R_Shadow_ClearStencil();
4203
4204         for (i = 0;i < r_refdef.scene.numentities;i++)
4205         {
4206                 ent = r_refdef.scene.entities[i];
4207
4208                 // cast shadows from anything of the map (submodels are optional)
4209                 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4210                 {
4211                         relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4212                         VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4213                         VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4214                         if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4215                                 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4216                         else
4217                         {
4218                                 if(ent->entitynumber != 0)
4219                                 {
4220                                         // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4221                                         int entnum, entnum2, recursion;
4222                                         entnum = entnum2 = ent->entitynumber;
4223                                         for(recursion = 32; recursion > 0; --recursion)
4224                                         {
4225                                                 entnum2 = cl.entities[entnum].state_current.tagentity;
4226                                                 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4227                                                         entnum = entnum2;
4228                                                 else
4229                                                         break;
4230                                         }
4231                                         if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4232                                         {
4233                                                 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4234                                                 // transform into modelspace of OUR entity
4235                                                 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4236                                                 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4237                                         }
4238                                         else
4239                                                 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4240                                 }
4241                                 else
4242                                         VectorNegate(ent->modellight_lightdir, relativelightdirection);
4243                         }
4244
4245                         VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4246                         RSurf_ActiveModelEntity(ent, false, false, false);
4247                         ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4248                         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4249                 }
4250         }
4251
4252         // not really the right mode, but this will disable any silly stencil features
4253         R_Shadow_RenderMode_End();
4254
4255         // set up ortho view for rendering this pass
4256         //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4257         //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4258         //GL_ScissorTest(true);
4259         //R_EntityMatrix(&identitymatrix);
4260         //R_Mesh_ResetTextureState();
4261         R_ResetViewRendering2D();
4262         R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
4263         R_Mesh_ColorPointer(NULL, 0, 0);
4264         R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4265
4266         // set up a darkening blend on shadowed areas
4267         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4268         //GL_DepthRange(0, 1);
4269         //GL_DepthTest(false);
4270         //GL_DepthMask(false);
4271         //GL_PolygonOffset(0, 0);CHECKGLERROR
4272         GL_Color(0, 0, 0, r_shadows_darken.value);
4273         //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4274         //qglDepthFunc(GL_ALWAYS);CHECKGLERROR
4275         qglEnable(GL_STENCIL_TEST);CHECKGLERROR
4276         qglStencilMask(255);CHECKGLERROR
4277         qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
4278         qglStencilFunc(GL_NOTEQUAL, 128, 255);CHECKGLERROR
4279
4280         // apply the blend to the shadowed areas
4281         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4282
4283         // restore the viewport
4284         R_SetViewport(&r_refdef.view.viewport);
4285
4286         // restore other state to normal
4287         //R_Shadow_RenderMode_End();
4288 }
4289
4290 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4291 {
4292         float zdist;
4293         vec3_t centerorigin;
4294         float vertex3f[12];
4295         // if it's too close, skip it
4296         if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4297                 return;
4298         zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4299         if (zdist < 32)
4300                 return;
4301         if (usequery && r_numqueries + 2 <= r_maxqueries)
4302         {
4303                 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4304                 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4305                 // 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
4306                 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4307
4308                 CHECKGLERROR
4309                 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use qglDepthFunc instead
4310                 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4311                 qglDepthFunc(GL_ALWAYS);
4312                 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4313                 R_Mesh_VertexPointer(vertex3f, 0, 0);
4314                 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4315                 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4316                 qglDepthFunc(GL_LEQUAL);
4317                 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4318                 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4319                 R_Mesh_VertexPointer(vertex3f, 0, 0);
4320                 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4321                 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4322                 CHECKGLERROR
4323         }
4324         rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4325 }
4326
4327 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4328
4329 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4330 {
4331         vec3_t color;
4332         GLint allpixels = 0, visiblepixels = 0;
4333         // now we have to check the query result
4334         if (rtlight->corona_queryindex_visiblepixels)
4335         {
4336                 CHECKGLERROR
4337                 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4338                 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4339                 CHECKGLERROR
4340                 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4341                 if (visiblepixels < 1 || allpixels < 1)
4342                         return;
4343                 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4344                 cscale *= rtlight->corona_visibility;
4345         }
4346         else
4347         {
4348                 // FIXME: these traces should scan all render entities instead of cl.world
4349                 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4350                         return;
4351         }
4352         VectorScale(rtlight->currentcolor, cscale, color);
4353         if (VectorLength(color) > (1.0f / 256.0f))
4354         {
4355                 float vertex3f[12];
4356                 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
4357                 if(negated)
4358                 {
4359                         VectorNegate(color, color);
4360                         qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
4361                 }
4362                 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4363                 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);
4364                 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4365                 if(negated)
4366                         qglBlendEquationEXT(GL_FUNC_ADD_EXT);
4367         }
4368 }
4369
4370 void R_Shadow_DrawCoronas(void)
4371 {
4372         int i, flag;
4373         qboolean usequery;
4374         size_t lightindex;
4375         dlight_t *light;
4376         rtlight_t *rtlight;
4377         size_t range;
4378         if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4379                 return;
4380         if (r_waterstate.renderingscene)
4381                 return;
4382         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4383         R_EntityMatrix(&identitymatrix);
4384
4385         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4386
4387         // check occlusion of coronas
4388         // use GL_ARB_occlusion_query if available
4389         // otherwise use raytraces
4390         r_numqueries = 0;
4391         usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
4392         if (usequery)
4393         {
4394                 GL_ColorMask(0,0,0,0);
4395                 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4396                 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4397                 {
4398                         i = r_maxqueries;
4399                         r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4400                         r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4401                         CHECKGLERROR
4402                         qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4403                         CHECKGLERROR
4404                 }
4405                 RSurf_ActiveWorldEntity();
4406                 GL_BlendFunc(GL_ONE, GL_ZERO);
4407                 GL_CullFace(GL_NONE);
4408                 GL_DepthMask(false);
4409                 GL_DepthRange(0, 1);
4410                 GL_PolygonOffset(0, 0);
4411                 GL_DepthTest(true);
4412                 R_Mesh_ColorPointer(NULL, 0, 0);
4413                 R_Mesh_ResetTextureState();
4414                 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4415         }
4416         for (lightindex = 0;lightindex < range;lightindex++)
4417         {
4418                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4419                 if (!light)
4420                         continue;
4421                 rtlight = &light->rtlight;
4422                 rtlight->corona_visibility = 0;
4423                 rtlight->corona_queryindex_visiblepixels = 0;
4424                 rtlight->corona_queryindex_allpixels = 0;
4425                 if (!(rtlight->flags & flag))
4426                         continue;
4427                 if (rtlight->corona <= 0)
4428                         continue;
4429                 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4430                         continue;
4431                 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4432         }
4433         for (i = 0;i < r_refdef.scene.numlights;i++)
4434         {
4435                 rtlight = r_refdef.scene.lights[i];
4436                 rtlight->corona_visibility = 0;
4437                 rtlight->corona_queryindex_visiblepixels = 0;
4438                 rtlight->corona_queryindex_allpixels = 0;
4439                 if (!(rtlight->flags & flag))
4440                         continue;
4441                 if (rtlight->corona <= 0)
4442                         continue;
4443                 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4444         }
4445         if (usequery)
4446                 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4447
4448         // now draw the coronas using the query data for intensity info
4449         for (lightindex = 0;lightindex < range;lightindex++)
4450         {
4451                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4452                 if (!light)
4453                         continue;
4454                 rtlight = &light->rtlight;
4455                 if (rtlight->corona_visibility <= 0)
4456                         continue;
4457                 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4458         }
4459         for (i = 0;i < r_refdef.scene.numlights;i++)
4460         {
4461                 rtlight = r_refdef.scene.lights[i];
4462                 if (rtlight->corona_visibility <= 0)
4463                         continue;
4464                 if (gl_flashblend.integer)
4465                         R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4466                 else
4467                         R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4468         }
4469 }
4470
4471
4472
4473 dlight_t *R_Shadow_NewWorldLight(void)
4474 {
4475         return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4476 }
4477
4478 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)
4479 {
4480         matrix4x4_t matrix;
4481         // validate parameters
4482         if (style < 0 || style >= MAX_LIGHTSTYLES)
4483         {
4484                 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4485                 style = 0;
4486         }
4487         if (!cubemapname)
4488                 cubemapname = "";
4489
4490         // copy to light properties
4491         VectorCopy(origin, light->origin);
4492         light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4493         light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4494         light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4495         /*
4496         light->color[0] = max(color[0], 0);
4497         light->color[1] = max(color[1], 0);
4498         light->color[2] = max(color[2], 0);
4499         */
4500         light->color[0] = color[0];
4501         light->color[1] = color[1];
4502         light->color[2] = color[2];
4503         light->radius = max(radius, 0);
4504         light->style = style;
4505         light->shadow = shadowenable;
4506         light->corona = corona;
4507         strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4508         light->coronasizescale = coronasizescale;
4509         light->ambientscale = ambientscale;
4510         light->diffusescale = diffusescale;
4511         light->specularscale = specularscale;
4512         light->flags = flags;
4513
4514         // update renderable light data
4515         Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4516         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);
4517 }
4518
4519 void R_Shadow_FreeWorldLight(dlight_t *light)
4520 {
4521         if (r_shadow_selectedlight == light)
4522                 r_shadow_selectedlight = NULL;
4523         R_RTLight_Uncompile(&light->rtlight);
4524         Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4525 }
4526
4527 void R_Shadow_ClearWorldLights(void)
4528 {
4529         size_t lightindex;
4530         dlight_t *light;
4531         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4532         for (lightindex = 0;lightindex < range;lightindex++)
4533         {
4534                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4535                 if (light)
4536                         R_Shadow_FreeWorldLight(light);
4537         }
4538         r_shadow_selectedlight = NULL;
4539 }
4540
4541 void R_Shadow_SelectLight(dlight_t *light)
4542 {
4543         if (r_shadow_selectedlight)
4544                 r_shadow_selectedlight->selected = false;
4545         r_shadow_selectedlight = light;
4546         if (r_shadow_selectedlight)
4547                 r_shadow_selectedlight->selected = true;
4548 }
4549
4550 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4551 {
4552         // this is never batched (there can be only one)
4553         float vertex3f[12];
4554         R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4555         RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4556         R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4557 }
4558
4559 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4560 {
4561         float intensity;
4562         float s;
4563         vec3_t spritecolor;
4564         skinframe_t *skinframe;
4565         float vertex3f[12];
4566
4567         // this is never batched (due to the ent parameter changing every time)
4568         // so numsurfaces == 1 and surfacelist[0] == lightnumber
4569         const dlight_t *light = (dlight_t *)ent;
4570         s = EDLIGHTSPRSIZE;
4571
4572         R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4573
4574         intensity = 0.5f;
4575         VectorScale(light->color, intensity, spritecolor);
4576         if (VectorLength(spritecolor) < 0.1732f)
4577                 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4578         if (VectorLength(spritecolor) > 1.0f)
4579                 VectorNormalize(spritecolor);
4580
4581         // draw light sprite
4582         if (light->cubemapname[0] && !light->shadow)
4583                 skinframe = r_editlights_sprcubemapnoshadowlight;
4584         else if (light->cubemapname[0])
4585                 skinframe = r_editlights_sprcubemaplight;
4586         else if (!light->shadow)
4587                 skinframe = r_editlights_sprnoshadowlight;
4588         else
4589                 skinframe = r_editlights_sprlight;
4590
4591         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);
4592         R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4593
4594         // draw selection sprite if light is selected
4595         if (light->selected)
4596         {
4597                 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4598                 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4599                 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4600         }
4601 }
4602
4603 void R_Shadow_DrawLightSprites(void)
4604 {
4605         size_t lightindex;
4606         dlight_t *light;
4607         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4608         for (lightindex = 0;lightindex < range;lightindex++)
4609         {
4610                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4611                 if (light)
4612                         R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4613         }
4614         R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4615 }
4616
4617 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4618 {
4619         unsigned int range;
4620         dlight_t *light;
4621         rtlight_t *rtlight;
4622         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4623         if (lightindex >= range)
4624                 return -1;
4625         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4626         if (!light)
4627                 return 0;
4628         rtlight = &light->rtlight;
4629         //if (!(rtlight->flags & flag))
4630         //      return 0;
4631         VectorCopy(rtlight->shadoworigin, origin);
4632         *radius = rtlight->radius;
4633         VectorCopy(rtlight->color, color);
4634         return 1;
4635 }
4636
4637 void R_Shadow_SelectLightInView(void)
4638 {
4639         float bestrating, rating, temp[3];
4640         dlight_t *best;
4641         size_t lightindex;
4642         dlight_t *light;
4643         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4644         best = NULL;
4645         bestrating = 0;
4646         for (lightindex = 0;lightindex < range;lightindex++)
4647         {
4648                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4649                 if (!light)
4650                         continue;
4651                 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4652                 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4653                 if (rating >= 0.95)
4654                 {
4655                         rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4656                         if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
4657                         {
4658                                 bestrating = rating;
4659                                 best = light;
4660                         }
4661                 }
4662         }
4663         R_Shadow_SelectLight(best);
4664 }
4665
4666 void R_Shadow_LoadWorldLights(void)
4667 {
4668         int n, a, style, shadow, flags;
4669         char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4670         float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4671         if (cl.worldmodel == NULL)
4672         {
4673                 Con_Print("No map loaded.\n");
4674                 return;
4675         }
4676         FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4677         strlcat (name, ".rtlights", sizeof (name));
4678         lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4679         if (lightsstring)
4680         {
4681                 s = lightsstring;
4682                 n = 0;
4683                 while (*s)
4684                 {
4685                         t = s;
4686                         /*
4687                         shadow = true;
4688                         for (;COM_Parse(t, true) && strcmp(
4689                         if (COM_Parse(t, true))
4690                         {
4691                                 if (com_token[0] == '!')
4692                                 {
4693                                         shadow = false;
4694                                         origin[0] = atof(com_token+1);
4695                                 }
4696                                 else
4697                                         origin[0] = atof(com_token);
4698                                 if (Com_Parse(t
4699                         }
4700                         */
4701                         t = s;
4702                         while (*s && *s != '\n' && *s != '\r')
4703                                 s++;
4704                         if (!*s)
4705                                 break;
4706                         tempchar = *s;
4707                         shadow = true;
4708                         // check for modifier flags
4709                         if (*t == '!')
4710                         {
4711                                 shadow = false;
4712                                 t++;
4713                         }
4714                         *s = 0;
4715 #if _MSC_VER >= 1400
4716 #define sscanf sscanf_s
4717 #endif
4718                         cubemapname[sizeof(cubemapname)-1] = 0;
4719 #if MAX_QPATH != 128
4720 #error update this code if MAX_QPATH changes
4721 #endif
4722                         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
4723 #if _MSC_VER >= 1400
4724 , sizeof(cubemapname)
4725 #endif
4726 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4727                         *s = tempchar;
4728                         if (a < 18)
4729                                 flags = LIGHTFLAG_REALTIMEMODE;
4730                         if (a < 17)
4731                                 specularscale = 1;
4732                         if (a < 16)
4733                                 diffusescale = 1;
4734                         if (a < 15)
4735                                 ambientscale = 0;
4736                         if (a < 14)
4737                                 coronasizescale = 0.25f;
4738                         if (a < 13)
4739                                 VectorClear(angles);
4740                         if (a < 10)
4741                                 corona = 0;
4742                         if (a < 9 || !strcmp(cubemapname, "\"\""))
4743                                 cubemapname[0] = 0;
4744                         // remove quotes on cubemapname
4745                         if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4746                         {
4747                                 size_t namelen;
4748                                 namelen = strlen(cubemapname) - 2;
4749                                 memmove(cubemapname, cubemapname + 1, namelen);
4750                                 cubemapname[namelen] = '\0';
4751                         }
4752                         if (a < 8)
4753                         {
4754                                 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);
4755                                 break;
4756                         }
4757                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4758                         if (*s == '\r')
4759                                 s++;
4760                         if (*s == '\n')
4761                                 s++;
4762                         n++;
4763                 }
4764                 if (*s)
4765                         Con_Printf("invalid rtlights file \"%s\"\n", name);
4766                 Mem_Free(lightsstring);
4767         }
4768 }
4769
4770 void R_Shadow_SaveWorldLights(void)
4771 {
4772         size_t lightindex;
4773         dlight_t *light;
4774         size_t bufchars, bufmaxchars;
4775         char *buf, *oldbuf;
4776         char name[MAX_QPATH];
4777         char line[MAX_INPUTLINE];
4778         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
4779         // I hate lines which are 3 times my screen size :( --blub
4780         if (!range)
4781                 return;
4782         if (cl.worldmodel == NULL)
4783         {
4784                 Con_Print("No map loaded.\n");
4785                 return;
4786         }
4787         FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4788         strlcat (name, ".rtlights", sizeof (name));
4789         bufchars = bufmaxchars = 0;
4790         buf = NULL;
4791         for (lightindex = 0;lightindex < range;lightindex++)
4792         {
4793                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4794                 if (!light)
4795                         continue;
4796                 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
4797                         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);
4798                 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
4799                         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]);
4800                 else
4801                         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);
4802                 if (bufchars + strlen(line) > bufmaxchars)
4803                 {
4804                         bufmaxchars = bufchars + strlen(line) + 2048;
4805                         oldbuf = buf;
4806                         buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
4807                         if (oldbuf)
4808                         {
4809                                 if (bufchars)
4810                                         memcpy(buf, oldbuf, bufchars);
4811                                 Mem_Free(oldbuf);
4812                         }
4813                 }
4814                 if (strlen(line))
4815                 {
4816                         memcpy(buf + bufchars, line, strlen(line));
4817                         bufchars += strlen(line);
4818                 }
4819         }
4820         if (bufchars)
4821                 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
4822         if (buf)
4823                 Mem_Free(buf);
4824 }
4825
4826 void R_Shadow_LoadLightsFile(void)
4827 {
4828         int n, a, style;
4829         char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
4830         float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
4831         if (cl.worldmodel == NULL)
4832         {
4833                 Con_Print("No map loaded.\n");
4834                 return;
4835         }
4836         FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4837         strlcat (name, ".lights", sizeof (name));
4838         lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4839         if (lightsstring)
4840         {
4841                 s = lightsstring;
4842                 n = 0;
4843                 while (*s)
4844                 {
4845                         t = s;
4846                         while (*s && *s != '\n' && *s != '\r')
4847                                 s++;
4848                         if (!*s)
4849                                 break;
4850                         tempchar = *s;
4851                         *s = 0;
4852                         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);
4853                         *s = tempchar;
4854                         if (a < 14)
4855                         {
4856                                 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);
4857                                 break;
4858                         }
4859                         radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
4860                         radius = bound(15, radius, 4096);
4861                         VectorScale(color, (2.0f / (8388608.0f)), color);
4862                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
4863                         if (*s == '\r')
4864                                 s++;
4865                         if (*s == '\n')
4866                                 s++;
4867                         n++;
4868                 }
4869                 if (*s)
4870                         Con_Printf("invalid lights file \"%s\"\n", name);
4871                 Mem_Free(lightsstring);
4872         }
4873 }
4874
4875 // tyrlite/hmap2 light types in the delay field
4876 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
4877
4878 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
4879 {
4880         int entnum, style, islight, skin, pflags, effects, type, n;
4881         char *entfiledata;
4882         const char *data;
4883         float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
4884         char key[256], value[MAX_INPUTLINE];
4885
4886         if (cl.worldmodel == NULL)
4887         {
4888                 Con_Print("No map loaded.\n");
4889                 return;
4890         }
4891         // try to load a .ent file first
4892         FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
4893         strlcat (key, ".ent", sizeof (key));
4894         data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
4895         // and if that is not found, fall back to the bsp file entity string
4896         if (!data)
4897                 data = cl.worldmodel->brush.entities;
4898         if (!data)
4899                 return;
4900         for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
4901         {
4902                 type = LIGHTTYPE_MINUSX;
4903                 origin[0] = origin[1] = origin[2] = 0;
4904                 originhack[0] = originhack[1] = originhack[2] = 0;
4905                 angles[0] = angles[1] = angles[2] = 0;
4906                 color[0] = color[1] = color[2] = 1;
4907                 light[0] = light[1] = light[2] = 1;light[3] = 300;
4908                 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
4909                 fadescale = 1;
4910                 lightscale = 1;
4911                 style = 0;
4912                 skin = 0;
4913                 pflags = 0;
4914                 effects = 0;
4915                 islight = false;
4916                 while (1)
4917                 {
4918                         if (!COM_ParseToken_Simple(&data, false, false))
4919                                 break; // error
4920                         if (com_token[0] == '}')
4921                                 break; // end of entity
4922                         if (com_token[0] == '_')
4923                                 strlcpy(key, com_token + 1, sizeof(key));
4924                         else
4925                                 strlcpy(key, com_token, sizeof(key));
4926                         while (key[strlen(key)-1] == ' ') // remove trailing spaces
4927                                 key[strlen(key)-1] = 0;
4928                         if (!COM_ParseToken_Simple(&data, false, false))
4929                                 break; // error
4930                         strlcpy(value, com_token, sizeof(value));
4931
4932                         // now that we have the key pair worked out...
4933                         if (!strcmp("light", key))
4934                         {
4935                                 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
4936                                 if (n == 1)
4937                                 {
4938                                         // quake
4939                                         light[0] = vec[0] * (1.0f / 256.0f);
4940                                         light[1] = vec[0] * (1.0f / 256.0f);
4941                                         light[2] = vec[0] * (1.0f / 256.0f);
4942                                         light[3] = vec[0];
4943                                 }
4944                                 else if (n == 4)
4945                                 {
4946                                         // halflife
4947                                         light[0] = vec[0] * (1.0f / 255.0f);
4948                                         light[1] = vec[1] * (1.0f / 255.0f);
4949                                         light[2] = vec[2] * (1.0f / 255.0f);
4950                                         light[3] = vec[3];
4951                                 }
4952                         }
4953                         else if (!strcmp("delay", key))
4954                                 type = atoi(value);
4955                         else if (!strcmp("origin", key))
4956                                 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
4957                         else if (!strcmp("angle", key))
4958                                 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
4959                         else if (!strcmp("angles", key))
4960                                 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
4961                         else if (!strcmp("color", key))
4962                                 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
4963                         else if (!strcmp("wait", key))
4964                                 fadescale = atof(value);
4965                         else if (!strcmp("classname", key))
4966                         {
4967                                 if (!strncmp(value, "light", 5))
4968                                 {
4969                                         islight = true;
4970                                         if (!strcmp(value, "light_fluoro"))
4971                                         {
4972                                                 originhack[0] = 0;
4973                                                 originhack[1] = 0;
4974                                                 originhack[2] = 0;
4975                                                 overridecolor[0] = 1;
4976                                                 overridecolor[1] = 1;
4977                                                 overridecolor[2] = 1;
4978                                         }
4979                                         if (!strcmp(value, "light_fluorospark"))
4980                                         {
4981                                                 originhack[0] = 0;
4982                                                 originhack[1] = 0;
4983                                                 originhack[2] = 0;
4984                                                 overridecolor[0] = 1;
4985                                                 overridecolor[1] = 1;
4986                                                 overridecolor[2] = 1;
4987                                         }
4988                                         if (!strcmp(value, "light_globe"))
4989                                         {
4990                                                 originhack[0] = 0;
4991                                                 originhack[1] = 0;
4992                                                 originhack[2] = 0;
4993                                                 overridecolor[0] = 1;
4994                                                 overridecolor[1] = 0.8;
4995                                                 overridecolor[2] = 0.4;
4996                                         }
4997                                         if (!strcmp(value, "light_flame_large_yellow"))
4998                                         {
4999                                                 originhack[0] = 0;
5000                                                 originhack[1] = 0;
5001                                                 originhack[2] = 0;
5002                                                 overridecolor[0] = 1;
5003                                                 overridecolor[1] = 0.5;
5004                                                 overridecolor[2] = 0.1;
5005                                         }
5006                                         if (!strcmp(value, "light_flame_small_yellow"))
5007                                         {
5008                                                 originhack[0] = 0;
5009                                                 originhack[1] = 0;
5010                                                 originhack[2] = 0;
5011                                                 overridecolor[0] = 1;
5012                                                 overridecolor[1] = 0.5;
5013                                                 overridecolor[2] = 0.1;
5014                                         }
5015                                         if (!strcmp(value, "light_torch_small_white"))
5016                                         {
5017                                                 originhack[0] = 0;
5018                                                 originhack[1] = 0;
5019                                                 originhack[2] = 0;
5020                                                 overridecolor[0] = 1;
5021                                                 overridecolor[1] = 0.5;
5022                                                 overridecolor[2] = 0.1;
5023                                         }
5024                                         if (!strcmp(value, "light_torch_small_walltorch"))
5025                                         {
5026                                                 originhack[0] = 0;
5027                                                 originhack[1] = 0;
5028                                                 originhack[2] = 0;
5029                                                 overridecolor[0] = 1;
5030                                                 overridecolor[1] = 0.5;
5031                                                 overridecolor[2] = 0.1;
5032                                         }
5033                                 }
5034                         }
5035                         else if (!strcmp("style", key))
5036                                 style = atoi(value);
5037                         else if (!strcmp("skin", key))
5038                                 skin = (int)atof(value);
5039                         else if (!strcmp("pflags", key))
5040                                 pflags = (int)atof(value);
5041                         else if (!strcmp("effects", key))
5042                                 effects = (int)atof(value);
5043                         else if (cl.worldmodel->type == mod_brushq3)
5044                         {
5045                                 if (!strcmp("scale", key))
5046                                         lightscale = atof(value);
5047                                 if (!strcmp("fade", key))
5048                                         fadescale = atof(value);
5049                         }
5050                 }
5051                 if (!islight)
5052                         continue;
5053                 if (lightscale <= 0)
5054                         lightscale = 1;
5055                 if (fadescale <= 0)
5056                         fadescale = 1;
5057                 if (color[0] == color[1] && color[0] == color[2])
5058                 {
5059                         color[0] *= overridecolor[0];
5060                         color[1] *= overridecolor[1];
5061                         color[2] *= overridecolor[2];
5062                 }
5063                 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5064                 color[0] = color[0] * light[0];
5065                 color[1] = color[1] * light[1];
5066                 color[2] = color[2] * light[2];
5067                 switch (type)
5068                 {
5069                 case LIGHTTYPE_MINUSX:
5070                         break;
5071                 case LIGHTTYPE_RECIPX:
5072                         radius *= 2;
5073                         VectorScale(color, (1.0f / 16.0f), color);
5074                         break;
5075                 case LIGHTTYPE_RECIPXX:
5076                         radius *= 2;
5077                         VectorScale(color, (1.0f / 16.0f), color);
5078                         break;
5079                 default:
5080                 case LIGHTTYPE_NONE:
5081                         break;
5082                 case LIGHTTYPE_SUN:
5083                         break;
5084                 case LIGHTTYPE_MINUSXX:
5085                         break;
5086                 }
5087                 VectorAdd(origin, originhack, origin);
5088                 if (radius >= 1)
5089                         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);
5090         }
5091         if (entfiledata)
5092                 Mem_Free(entfiledata);
5093 }
5094
5095
5096 void R_Shadow_SetCursorLocationForView(void)
5097 {
5098         vec_t dist, push;
5099         vec3_t dest, endpos;
5100         trace_t trace;
5101         VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5102         trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5103         if (trace.fraction < 1)
5104         {
5105                 dist = trace.fraction * r_editlights_cursordistance.value;
5106                 push = r_editlights_cursorpushback.value;
5107                 if (push > dist)
5108                         push = dist;
5109                 push = -push;
5110                 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5111                 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5112         }
5113         else
5114         {
5115                 VectorClear( endpos );
5116         }
5117         r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5118         r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5119         r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5120 }
5121
5122 void R_Shadow_UpdateWorldLightSelection(void)
5123 {
5124         if (r_editlights.integer)
5125         {
5126                 R_Shadow_SetCursorLocationForView();
5127                 R_Shadow_SelectLightInView();
5128         }
5129         else
5130                 R_Shadow_SelectLight(NULL);
5131 }
5132
5133 void R_Shadow_EditLights_Clear_f(void)
5134 {
5135         R_Shadow_ClearWorldLights();
5136 }
5137
5138 void R_Shadow_EditLights_Reload_f(void)
5139 {
5140         if (!cl.worldmodel)
5141                 return;
5142         strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
5143         R_Shadow_ClearWorldLights();
5144         R_Shadow_LoadWorldLights();
5145         if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5146         {
5147                 R_Shadow_LoadLightsFile();
5148                 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5149                         R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5150         }
5151 }
5152
5153 void R_Shadow_EditLights_Save_f(void)
5154 {
5155         if (!cl.worldmodel)
5156                 return;
5157         R_Shadow_SaveWorldLights();
5158 }
5159
5160 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5161 {
5162         R_Shadow_ClearWorldLights();
5163         R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5164 }
5165
5166 void R_Shadow_EditLights_ImportLightsFile_f(void)
5167 {
5168         R_Shadow_ClearWorldLights();
5169         R_Shadow_LoadLightsFile();
5170 }
5171
5172 void R_Shadow_EditLights_Spawn_f(void)
5173 {
5174         vec3_t color;
5175         if (!r_editlights.integer)
5176         {
5177                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
5178                 return;
5179         }
5180         if (Cmd_Argc() != 1)
5181         {
5182                 Con_Print("r_editlights_spawn does not take parameters\n");
5183                 return;
5184         }
5185         color[0] = color[1] = color[2] = 1;
5186         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5187 }
5188
5189 void R_Shadow_EditLights_Edit_f(void)
5190 {
5191         vec3_t origin, angles, color;
5192         vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5193         int style, shadows, flags, normalmode, realtimemode;
5194         char cubemapname[MAX_INPUTLINE];
5195         if (!r_editlights.integer)
5196         {
5197                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
5198                 return;
5199         }
5200         if (!r_shadow_selectedlight)
5201         {
5202                 Con_Print("No selected light.\n");
5203                 return;
5204         }
5205         VectorCopy(r_shadow_selectedlight->origin, origin);
5206         VectorCopy(r_shadow_selectedlight->angles, angles);
5207         VectorCopy(r_shadow_selectedlight->color, color);
5208         radius = r_shadow_selectedlight->radius;
5209         style = r_shadow_selectedlight->style;
5210         if (r_shadow_selectedlight->cubemapname)
5211                 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5212         else
5213                 cubemapname[0] = 0;
5214         shadows = r_shadow_selectedlight->shadow;
5215         corona = r_shadow_selectedlight->corona;
5216         coronasizescale = r_shadow_selectedlight->coronasizescale;
5217         ambientscale = r_shadow_selectedlight->ambientscale;
5218         diffusescale = r_shadow_selectedlight->diffusescale;
5219         specularscale = r_shadow_selectedlight->specularscale;
5220         flags = r_shadow_selectedlight->flags;
5221         normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5222         realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5223         if (!strcmp(Cmd_Argv(1), "origin"))
5224         {
5225                 if (Cmd_Argc() != 5)
5226                 {
5227                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5228                         return;
5229                 }
5230                 origin[0] = atof(Cmd_Argv(2));
5231                 origin[1] = atof(Cmd_Argv(3));
5232                 origin[2] = atof(Cmd_Argv(4));
5233         }
5234         else if (!strcmp(Cmd_Argv(1), "originx"))
5235         {
5236                 if (Cmd_Argc() != 3)
5237                 {
5238                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5239                         return;
5240                 }
5241                 origin[0] = atof(Cmd_Argv(2));
5242         }
5243         else if (!strcmp(Cmd_Argv(1), "originy"))
5244         {
5245                 if (Cmd_Argc() != 3)
5246                 {
5247                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5248                         return;
5249                 }
5250                 origin[1] = atof(Cmd_Argv(2));
5251         }
5252         else if (!strcmp(Cmd_Argv(1), "originz"))
5253         {
5254                 if (Cmd_Argc() != 3)
5255                 {
5256                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5257                         return;
5258                 }
5259                 origin[2] = atof(Cmd_Argv(2));
5260         }
5261         else if (!strcmp(Cmd_Argv(1), "move"))
5262         {
5263                 if (Cmd_Argc() != 5)
5264                 {
5265                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5266                         return;
5267                 }
5268                 origin[0] += atof(Cmd_Argv(2));
5269                 origin[1] += atof(Cmd_Argv(3));
5270                 origin[2] += atof(Cmd_Argv(4));
5271         }
5272         else if (!strcmp(Cmd_Argv(1), "movex"))
5273         {
5274                 if (Cmd_Argc() != 3)
5275                 {
5276                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5277                         return;
5278                 }
5279                 origin[0] += atof(Cmd_Argv(2));
5280         }
5281         else if (!strcmp(Cmd_Argv(1), "movey"))
5282         {
5283                 if (Cmd_Argc() != 3)
5284                 {
5285                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5286                         return;
5287                 }
5288                 origin[1] += atof(Cmd_Argv(2));
5289         }
5290         else if (!strcmp(Cmd_Argv(1), "movez"))
5291         {
5292                 if (Cmd_Argc() != 3)
5293                 {
5294                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5295                         return;
5296                 }
5297                 origin[2] += atof(Cmd_Argv(2));
5298         }
5299         else if (!strcmp(Cmd_Argv(1), "angles"))
5300         {
5301                 if (Cmd_Argc() != 5)
5302                 {
5303                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5304                         return;
5305                 }
5306                 angles[0] = atof(Cmd_Argv(2));
5307                 angles[1] = atof(Cmd_Argv(3));
5308                 angles[2] = atof(Cmd_Argv(4));
5309         }
5310         else if (!strcmp(Cmd_Argv(1), "anglesx"))
5311         {
5312                 if (Cmd_Argc() != 3)
5313                 {
5314                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5315                         return;
5316                 }
5317                 angles[0] = atof(Cmd_Argv(2));
5318         }
5319         else if (!strcmp(Cmd_Argv(1), "anglesy"))
5320         {
5321                 if (Cmd_Argc() != 3)
5322                 {
5323                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5324                         return;
5325                 }
5326                 angles[1] = atof(Cmd_Argv(2));
5327         }
5328         else if (!strcmp(Cmd_Argv(1), "anglesz"))
5329         {
5330                 if (Cmd_Argc() != 3)
5331                 {
5332                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5333                         return;
5334                 }
5335                 angles[2] = atof(Cmd_Argv(2));
5336         }
5337         else if (!strcmp(Cmd_Argv(1), "color"))
5338         {
5339                 if (Cmd_Argc() != 5)
5340                 {
5341                         Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5342                         return;
5343                 }
5344                 color[0] = atof(Cmd_Argv(2));
5345                 color[1] = atof(Cmd_Argv(3));
5346                 color[2] = atof(Cmd_Argv(4));
5347         }
5348         else if (!strcmp(Cmd_Argv(1), "radius"))
5349         {
5350                 if (Cmd_Argc() != 3)
5351                 {
5352                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5353                         return;
5354                 }
5355                 radius = atof(Cmd_Argv(2));
5356         }
5357         else if (!strcmp(Cmd_Argv(1), "colorscale"))
5358         {
5359                 if (Cmd_Argc() == 3)
5360                 {
5361                         double scale = atof(Cmd_Argv(2));
5362                         color[0] *= scale;
5363                         color[1] *= scale;
5364                         color[2] *= scale;
5365                 }
5366                 else
5367                 {
5368                         if (Cmd_Argc() != 5)
5369                         {
5370                                 Con_Printf("usage: r_editlights_edit %s red green blue  (OR grey instead of red green blue)\n", Cmd_Argv(1));
5371                                 return;
5372                         }
5373                         color[0] *= atof(Cmd_Argv(2));
5374                         color[1] *= atof(Cmd_Argv(3));
5375                         color[2] *= atof(Cmd_Argv(4));
5376                 }
5377         }
5378         else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5379         {
5380                 if (Cmd_Argc() != 3)
5381                 {
5382                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5383                         return;
5384                 }
5385                 radius *= atof(Cmd_Argv(2));
5386         }
5387         else if (!strcmp(Cmd_Argv(1), "style"))
5388         {
5389                 if (Cmd_Argc() != 3)
5390                 {
5391                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5392                         return;
5393                 }
5394                 style = atoi(Cmd_Argv(2));
5395         }
5396         else if (!strcmp(Cmd_Argv(1), "cubemap"))
5397         {
5398                 if (Cmd_Argc() > 3)
5399                 {
5400                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5401                         return;
5402                 }
5403                 if (Cmd_Argc() == 3)
5404                         strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5405                 else
5406                         cubemapname[0] = 0;
5407         }
5408         else if (!strcmp(Cmd_Argv(1), "shadows"))
5409         {
5410                 if (Cmd_Argc() != 3)
5411                 {
5412                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5413                         return;
5414                 }
5415                 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5416         }
5417         else if (!strcmp(Cmd_Argv(1), "corona"))
5418         {
5419                 if (Cmd_Argc() != 3)
5420                 {
5421                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5422                         return;
5423                 }
5424                 corona = atof(Cmd_Argv(2));
5425         }
5426         else if (!strcmp(Cmd_Argv(1), "coronasize"))
5427         {
5428                 if (Cmd_Argc() != 3)
5429                 {
5430                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5431                         return;
5432                 }
5433                 coronasizescale = atof(Cmd_Argv(2));
5434         }
5435         else if (!strcmp(Cmd_Argv(1), "ambient"))
5436         {
5437                 if (Cmd_Argc() != 3)
5438                 {
5439                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5440                         return;
5441                 }
5442                 ambientscale = atof(Cmd_Argv(2));
5443         }
5444         else if (!strcmp(Cmd_Argv(1), "diffuse"))
5445         {
5446                 if (Cmd_Argc() != 3)
5447                 {
5448                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5449                         return;
5450                 }
5451                 diffusescale = atof(Cmd_Argv(2));
5452         }
5453         else if (!strcmp(Cmd_Argv(1), "specular"))
5454         {
5455                 if (Cmd_Argc() != 3)
5456                 {
5457                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5458                         return;
5459                 }
5460                 specularscale = atof(Cmd_Argv(2));
5461         }
5462         else if (!strcmp(Cmd_Argv(1), "normalmode"))
5463         {
5464                 if (Cmd_Argc() != 3)
5465                 {
5466                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5467                         return;
5468                 }
5469                 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5470         }
5471         else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5472         {
5473                 if (Cmd_Argc() != 3)
5474                 {
5475                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5476                         return;
5477                 }
5478                 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5479         }
5480         else
5481         {
5482                 Con_Print("usage: r_editlights_edit [property] [value]\n");
5483                 Con_Print("Selected light's properties:\n");
5484                 Con_Printf("Origin       : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5485                 Con_Printf("Angles       : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5486                 Con_Printf("Color        : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5487                 Con_Printf("Radius       : %f\n", r_shadow_selectedlight->radius);
5488                 Con_Printf("Corona       : %f\n", r_shadow_selectedlight->corona);
5489                 Con_Printf("Style        : %i\n", r_shadow_selectedlight->style);
5490                 Con_Printf("Shadows      : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5491                 Con_Printf("Cubemap      : %s\n", r_shadow_selectedlight->cubemapname);
5492                 Con_Printf("CoronaSize   : %f\n", r_shadow_selectedlight->coronasizescale);
5493                 Con_Printf("Ambient      : %f\n", r_shadow_selectedlight->ambientscale);
5494                 Con_Printf("Diffuse      : %f\n", r_shadow_selectedlight->diffusescale);
5495                 Con_Printf("Specular     : %f\n", r_shadow_selectedlight->specularscale);
5496                 Con_Printf("NormalMode   : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5497                 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5498                 return;
5499         }
5500         flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5501         R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5502 }
5503
5504 void R_Shadow_EditLights_EditAll_f(void)
5505 {
5506         size_t lightindex;
5507         dlight_t *light;
5508         size_t range;
5509
5510         if (!r_editlights.integer)
5511         {
5512                 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5513                 return;
5514         }
5515
5516         // EditLights doesn't seem to have a "remove" command or something so:
5517         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5518         for (lightindex = 0;lightindex < range;lightindex++)
5519         {
5520                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5521                 if (!light)
5522                         continue;
5523                 R_Shadow_SelectLight(light);
5524                 R_Shadow_EditLights_Edit_f();
5525         }
5526 }
5527
5528 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5529 {
5530         int lightnumber, lightcount;
5531         size_t lightindex, range;
5532         dlight_t *light;
5533         float x, y;
5534         char temp[256];
5535         if (!r_editlights.integer)
5536                 return;
5537         x = vid_conwidth.value - 240;
5538         y = 5;
5539         DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5540         lightnumber = -1;
5541         lightcount = 0;
5542         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5543         for (lightindex = 0;lightindex < range;lightindex++)
5544         {
5545                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5546                 if (!light)
5547                         continue;
5548                 if (light == r_shadow_selectedlight)
5549                         lightnumber = lightindex;
5550                 lightcount++;
5551         }
5552         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;
5553         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;
5554         y += 8;
5555         if (r_shadow_selectedlight == NULL)
5556                 return;
5557         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;
5558         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;
5559         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;
5560         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;
5561         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;
5562         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;
5563         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;
5564         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;
5565         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;
5566         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;
5567         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;
5568         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;
5569         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;
5570         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;
5571         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;
5572 }
5573
5574 void R_Shadow_EditLights_ToggleShadow_f(void)
5575 {
5576         if (!r_editlights.integer)
5577         {
5578                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
5579                 return;
5580         }
5581         if (!r_shadow_selectedlight)
5582         {
5583                 Con_Print("No selected light.\n");
5584                 return;
5585         }
5586         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);
5587 }
5588
5589 void R_Shadow_EditLights_ToggleCorona_f(void)
5590 {
5591         if (!r_editlights.integer)
5592         {
5593                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
5594                 return;
5595         }
5596         if (!r_shadow_selectedlight)
5597         {
5598                 Con_Print("No selected light.\n");
5599                 return;
5600         }
5601         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);
5602 }
5603
5604 void R_Shadow_EditLights_Remove_f(void)
5605 {
5606         if (!r_editlights.integer)
5607         {
5608                 Con_Print("Cannot remove light when not in editing mode.  Set r_editlights to 1.\n");
5609                 return;
5610         }
5611         if (!r_shadow_selectedlight)
5612         {
5613                 Con_Print("No selected light.\n");
5614                 return;
5615         }
5616         R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5617         r_shadow_selectedlight = NULL;
5618 }
5619
5620 void R_Shadow_EditLights_Help_f(void)
5621 {
5622         Con_Print(
5623 "Documentation on r_editlights system:\n"
5624 "Settings:\n"
5625 "r_editlights : enable/disable editing mode\n"
5626 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5627 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5628 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5629 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5630 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5631 "Commands:\n"
5632 "r_editlights_help : this help\n"
5633 "r_editlights_clear : remove all lights\n"
5634 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5635 "r_editlights_save : save to .rtlights file\n"
5636 "r_editlights_spawn : create a light with default settings\n"
5637 "r_editlights_edit command : edit selected light - more documentation below\n"
5638 "r_editlights_remove : remove selected light\n"
5639 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5640 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5641 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5642 "Edit commands:\n"
5643 "origin x y z : set light location\n"
5644 "originx x: set x component of light location\n"
5645 "originy y: set y component of light location\n"
5646 "originz z: set z component of light location\n"
5647 "move x y z : adjust light location\n"
5648 "movex x: adjust x component of light location\n"
5649 "movey y: adjust y component of light location\n"
5650 "movez z: adjust z component of light location\n"
5651 "angles x y z : set light angles\n"
5652 "anglesx x: set x component of light angles\n"
5653 "anglesy y: set y component of light angles\n"
5654 "anglesz z: set z component of light angles\n"
5655 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5656 "radius radius : set radius (size) of light\n"
5657 "colorscale grey : multiply color of light (1 does nothing)\n"
5658 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5659 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5660 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5661 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5662 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5663 "shadows 1/0 : turn on/off shadows\n"
5664 "corona n : set corona intensity\n"
5665 "coronasize n : set corona size (0-1)\n"
5666 "ambient n : set ambient intensity (0-1)\n"
5667 "diffuse n : set diffuse intensity (0-1)\n"
5668 "specular n : set specular intensity (0-1)\n"
5669 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5670 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5671 "<nothing> : print light properties to console\n"
5672         );
5673 }
5674
5675 void R_Shadow_EditLights_CopyInfo_f(void)
5676 {
5677         if (!r_editlights.integer)
5678         {
5679                 Con_Print("Cannot copy light info when not in editing mode.  Set r_editlights to 1.\n");
5680                 return;
5681         }
5682         if (!r_shadow_selectedlight)
5683         {
5684                 Con_Print("No selected light.\n");
5685                 return;
5686         }
5687         VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5688         VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5689         r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5690         r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5691         if (r_shadow_selectedlight->cubemapname)
5692                 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5693         else
5694                 r_shadow_bufferlight.cubemapname[0] = 0;
5695         r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5696         r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5697         r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5698         r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5699         r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5700         r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5701         r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5702 }
5703
5704 void R_Shadow_EditLights_PasteInfo_f(void)
5705 {
5706         if (!r_editlights.integer)
5707         {
5708                 Con_Print("Cannot paste light info when not in editing mode.  Set r_editlights to 1.\n");
5709                 return;
5710         }
5711         if (!r_shadow_selectedlight)
5712         {
5713                 Con_Print("No selected light.\n");
5714                 return;
5715         }
5716         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);
5717 }
5718
5719 void R_Shadow_EditLights_Init(void)
5720 {
5721         Cvar_RegisterVariable(&r_editlights);
5722         Cvar_RegisterVariable(&r_editlights_cursordistance);
5723         Cvar_RegisterVariable(&r_editlights_cursorpushback);
5724         Cvar_RegisterVariable(&r_editlights_cursorpushoff);
5725         Cvar_RegisterVariable(&r_editlights_cursorgrid);
5726         Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
5727         Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
5728         Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
5729         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)");
5730         Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
5731         Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
5732         Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
5733         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)");
5734         Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
5735         Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
5736         Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
5737         Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
5738         Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
5739         Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
5740         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)");
5741 }
5742
5743
5744
5745 /*
5746 =============================================================================
5747
5748 LIGHT SAMPLING
5749
5750 =============================================================================
5751 */
5752
5753 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
5754 {
5755         VectorClear(diffusecolor);
5756         VectorClear(diffusenormal);
5757
5758         if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
5759         {
5760                 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient;
5761                 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
5762         }
5763         else
5764                 VectorSet(ambientcolor, 1, 1, 1);
5765
5766         if (dynamic)
5767         {
5768                 int i;
5769                 float f, v[3];
5770                 rtlight_t *light;
5771                 for (i = 0;i < r_refdef.scene.numlights;i++)
5772                 {
5773                         light = r_refdef.scene.lights[i];
5774                         Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
5775                         f = 1 - VectorLength2(v);
5776                         if (f > 0 && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
5777                                 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);
5778                 }
5779         }
5780 }