]> icculus.org git repositories - divverent/darkplaces.git/blob - r_shadow.c
factored R_Shadow_MakeShadowMap out of R_Shadow_RenderMode_ShadowMap so it can be...
[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 static void R_Shadow_MakeShadowMap(int side, int size)
2045 {
2046         int status;
2047         switch (r_shadow_shadowmode)
2048         {
2049         case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2050                 if (r_shadow_shadowmap2dtexture) return;
2051                 r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", size*2, size*(vid.support.arb_texture_non_power_of_two ? 3 : 4), r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2052                 qglGenFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
2053                 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
2054                 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_shadowmap2dtexture), 0);CHECKGLERROR
2055                 break;
2056         case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
2057                 if (r_shadow_shadowmaprectangletexture) return;
2058                 r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", size*2, size*3, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2059                 qglGenFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
2060                 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
2061                 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_shadowmaprectangletexture), 0);CHECKGLERROR
2062                 break;
2063         case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
2064                 if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]) return;
2065                 r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", size, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2066                 qglGenFramebuffersEXT(1, &r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2067                 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2068                 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
2069                 break;
2070         default:
2071                 return;
2072         }
2073         // render depth into the fbo, do not render color at all
2074         qglDrawBuffer(GL_NONE);CHECKGLERROR
2075         qglReadBuffer(GL_NONE);CHECKGLERROR
2076         status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2077         if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer))
2078         {
2079                 Con_Printf("R_Shadow_MakeShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2080                 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2081                 Cvar_SetValueQuick(&r_shadow_deferred, 0);
2082         }
2083 }
2084         
2085 void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
2086 {
2087         float nearclip, farclip, bias;
2088         r_viewport_t viewport;
2089         GLuint fbo = 0;
2090         CHECKGLERROR
2091         nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2092         farclip = 1.0f;
2093         bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2094         r_shadow_shadowmap_parameters[2] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2095         r_shadow_shadowmap_parameters[3] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2096         r_shadow_shadowmapside = side;
2097         r_shadow_shadowmapsize = size;
2098         switch (r_shadow_shadowmode)
2099         {
2100         case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2101                 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2102                 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2103                 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2104                 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
2105
2106                 // complex unrolled cube approach (more flexible)
2107                 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2108                         R_Shadow_MakeVSDCT();
2109                 if (!r_shadow_shadowmap2dtexture)
2110                         R_Shadow_MakeShadowMap(side, r_shadow_shadowmapmaxsize);
2111                 CHECKGLERROR
2112                 if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d;
2113                 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
2114                 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
2115                 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2116                 break;
2117         case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
2118                 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2119                 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2120                 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2121                 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE) goto init_done;
2122
2123                 // complex unrolled cube approach (more flexible)
2124                 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2125                         R_Shadow_MakeVSDCT();
2126                 if (!r_shadow_shadowmaprectangletexture)
2127                         R_Shadow_MakeShadowMap(side, r_shadow_shadowmapmaxsize);
2128                 CHECKGLERROR
2129                 if(r_shadow_shadowmaprectangletexture) fbo = r_shadow_fborectangle;
2130                 r_shadow_shadowmap_texturescale[0] = 1.0f;
2131                 r_shadow_shadowmap_texturescale[1] = 1.0f;
2132                 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
2133                 break;
2134         case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
2135                 r_shadow_shadowmap_parameters[0] = 1.0f;
2136                 r_shadow_shadowmap_parameters[1] = 1.0f;
2137                 R_Viewport_InitCubeSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, nearclip, farclip, NULL);
2138                 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE) goto init_done;
2139
2140                 // simple cube approach
2141                 if (!r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
2142                         R_Shadow_MakeShadowMap(side, size);
2143                 CHECKGLERROR
2144                 if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]) fbo = r_shadow_fbocubeside[r_shadow_shadowmaplod];
2145                 r_shadow_shadowmap_texturescale[0] = 0.0f;
2146                 r_shadow_shadowmap_texturescale[1] = 0.0f;
2147                 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE;
2148                 break;
2149         default:
2150                 break;
2151         }
2152
2153         R_Shadow_RenderMode_Reset();
2154         if (fbo)
2155         {
2156                 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);CHECKGLERROR
2157                 R_SetupShader_DepthOrShadow();
2158         }
2159         else
2160         {
2161                 R_SetupShader_ShowDepth();
2162                 qglClearColor(1,1,1,1);CHECKGLERROR
2163         }
2164         CHECKGLERROR
2165         GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2166         GL_DepthMask(true);
2167         GL_DepthTest(true);
2168         qglClearDepth(1);
2169         CHECKGLERROR
2170
2171 init_done:
2172         R_SetViewport(&viewport);
2173         if(r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE)
2174         {
2175                 int flipped = (side & 1) ^ (side >> 2);
2176                 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2177                 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2178                 GL_CullFace(r_refdef.view.cullface_back);
2179                 if ((clear & ((2 << side) - 1)) == (1 << side)) // only clear if the side is the first in the mask
2180                 {
2181                         // get tightest scissor rectangle that encloses all viewports in the clear mask
2182                         int x1 = clear & 0x15 ? 0 : size;
2183                         int x2 = clear & 0x2A ? 2 * size : size;
2184                         int y1 = clear & 0x03 ? 0 : (clear & 0xC ? size : 2 * size);
2185                         int y2 = clear & 0x30 ? 3 * size : (clear & 0xC ? 2 * size : size);
2186                         GL_Scissor(x1, y1, x2 - x1, y2 - y1);
2187                         GL_Clear(GL_DEPTH_BUFFER_BIT);
2188                 }
2189                 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2190         }
2191         else if(r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE)
2192         {
2193                 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
2194                 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2195                 if (clear)
2196                         GL_Clear(GL_DEPTH_BUFFER_BIT);
2197         }
2198         CHECKGLERROR
2199 }
2200
2201 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2202 {
2203         if (transparent)
2204         {
2205                 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2206                 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2207                 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2208                 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2209         }
2210         CHECKGLERROR
2211         R_Shadow_RenderMode_Reset();
2212         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2213         if (!transparent)
2214         {
2215                 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2216         }
2217         if (stenciltest)
2218         {
2219                 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2220                 // only draw light where this geometry was already rendered AND the
2221                 // stencil is 128 (values other than this mean shadow)
2222                 qglStencilFunc(GL_EQUAL, 128, 255);CHECKGLERROR
2223         }
2224         r_shadow_rendermode = r_shadow_lightingrendermode;
2225         // do global setup needed for the chosen lighting mode
2226         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2227         {
2228                 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2229                 CHECKGLERROR
2230         }
2231         if (shadowmapping)
2232         {
2233                 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
2234                         r_shadow_usingshadowmap2d = true;
2235                 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
2236                         r_shadow_usingshadowmaprect = true;
2237                 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
2238                         r_shadow_usingshadowmapcube = true;
2239         }
2240         R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
2241         CHECKGLERROR
2242 }
2243
2244 static const unsigned short bboxelements[36] =
2245 {
2246         5, 1, 3, 5, 3, 7,
2247         6, 2, 0, 6, 0, 4,
2248         7, 3, 2, 7, 2, 6,
2249         4, 0, 1, 4, 1, 5,
2250         4, 5, 7, 4, 7, 6,
2251         1, 0, 2, 1, 2, 3,
2252 };
2253
2254 static const float bboxpoints[8][3] =
2255 {
2256         {-1,-1,-1},
2257         { 1,-1,-1},
2258         {-1, 1,-1},
2259         { 1, 1,-1},
2260         {-1,-1, 1},
2261         { 1,-1, 1},
2262         {-1, 1, 1},
2263         { 1, 1, 1},
2264 };
2265
2266 void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadowmapping)
2267 {
2268         int i;
2269         float vertex3f[8*3];
2270         const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2271         CHECKGLERROR
2272         R_Shadow_RenderMode_Reset();
2273         r_shadow_rendermode = r_shadow_lightingrendermode;
2274         // do global setup needed for the chosen lighting mode
2275         {
2276                 R_EntityMatrix(&identitymatrix);
2277                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2278                 if (stenciltest)
2279                 {
2280                         qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2281                         // only draw light where this geometry was already rendered AND the
2282                         // stencil is 128 (values other than this mean shadow)
2283                         qglStencilFunc(GL_EQUAL, 128, 255);CHECKGLERROR
2284                 }
2285                 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR
2286                 if (shadowmapping)
2287                 {
2288                         if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
2289                                 r_shadow_usingshadowmap2d = true;
2290                         else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
2291                                 r_shadow_usingshadowmaprect = true;
2292                         else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
2293                                 r_shadow_usingshadowmapcube = true;
2294                 }
2295
2296                 // render the lighting
2297                 R_SetupShader_DeferredLight(rsurface.rtlight);
2298                 for (i = 0;i < 8;i++)
2299                         Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2300                 CHECKGLERROR
2301                 R_Mesh_VertexPointer(vertex3f, 0, 0);
2302                 R_Mesh_ColorPointer(NULL, 0, 0);
2303                 GL_ColorMask(1,1,1,1);
2304                 GL_DepthMask(false);
2305                 GL_DepthRange(0, 1);
2306                 GL_PolygonOffset(0, 0);
2307                 GL_DepthTest(true);
2308                 qglDepthFunc(GL_GREATER);CHECKGLERROR
2309                 GL_CullFace(r_refdef.view.cullface_back);
2310                 R_Mesh_Draw(0, 8, 0, 12, NULL, bboxelements, 0, 0);
2311         }
2312 }
2313
2314 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2315 {
2316         CHECKGLERROR
2317         R_Shadow_RenderMode_Reset();
2318         GL_BlendFunc(GL_ONE, GL_ONE);
2319         GL_DepthRange(0, 1);
2320         GL_DepthTest(r_showshadowvolumes.integer < 2);
2321         GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2322         GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2323         GL_CullFace(GL_NONE);
2324         r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2325 }
2326
2327 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2328 {
2329         CHECKGLERROR
2330         R_Shadow_RenderMode_Reset();
2331         GL_BlendFunc(GL_ONE, GL_ONE);
2332         GL_DepthRange(0, 1);
2333         GL_DepthTest(r_showlighting.integer < 2);
2334         GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2335         if (!transparent)
2336         {
2337                 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2338         }
2339         if (stenciltest)
2340         {
2341                 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2342                 qglStencilFunc(GL_EQUAL, 128, 255);CHECKGLERROR
2343         }
2344         r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2345 }
2346
2347 void R_Shadow_RenderMode_End(void)
2348 {
2349         CHECKGLERROR
2350         R_Shadow_RenderMode_Reset();
2351         R_Shadow_RenderMode_ActiveLight(NULL);
2352         GL_DepthMask(true);
2353         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2354         r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2355 }
2356
2357 int bboxedges[12][2] =
2358 {
2359         // top
2360         {0, 1}, // +X
2361         {0, 2}, // +Y
2362         {1, 3}, // Y, +X
2363         {2, 3}, // X, +Y
2364         // bottom
2365         {4, 5}, // +X
2366         {4, 6}, // +Y
2367         {5, 7}, // Y, +X
2368         {6, 7}, // X, +Y
2369         // verticals
2370         {0, 4}, // +Z
2371         {1, 5}, // X, +Z
2372         {2, 6}, // Y, +Z
2373         {3, 7}, // XY, +Z
2374 };
2375
2376 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2377 {
2378         int i, ix1, iy1, ix2, iy2;
2379         float x1, y1, x2, y2;
2380         vec4_t v, v2;
2381         float vertex[20][3];
2382         int j, k;
2383         vec4_t plane4f;
2384         int numvertices;
2385         float corner[8][4];
2386         float dist[8];
2387         int sign[8];
2388         float f;
2389
2390         r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2391         r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2392         r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2393         r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2394
2395         if (!r_shadow_scissor.integer)
2396                 return false;
2397
2398         // if view is inside the light box, just say yes it's visible
2399         if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
2400                 return false;
2401
2402         x1 = y1 = x2 = y2 = 0;
2403
2404         // transform all corners that are infront of the nearclip plane
2405         VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
2406         plane4f[3] = r_refdef.view.frustum[4].dist;
2407         numvertices = 0;
2408         for (i = 0;i < 8;i++)
2409         {
2410                 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
2411                 dist[i] = DotProduct4(corner[i], plane4f);
2412                 sign[i] = dist[i] > 0;
2413                 if (!sign[i])
2414                 {
2415                         VectorCopy(corner[i], vertex[numvertices]);
2416                         numvertices++;
2417                 }
2418         }
2419         // if some points are behind the nearclip, add clipped edge points to make
2420         // sure that the scissor boundary is complete
2421         if (numvertices > 0 && numvertices < 8)
2422         {
2423                 // add clipped edge points
2424                 for (i = 0;i < 12;i++)
2425                 {
2426                         j = bboxedges[i][0];
2427                         k = bboxedges[i][1];
2428                         if (sign[j] != sign[k])
2429                         {
2430                                 f = dist[j] / (dist[j] - dist[k]);
2431                                 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
2432                                 numvertices++;
2433                         }
2434                 }
2435         }
2436
2437         // if we have no points to check, the light is behind the view plane
2438         if (!numvertices)
2439                 return true;
2440
2441         // if we have some points to transform, check what screen area is covered
2442         x1 = y1 = x2 = y2 = 0;
2443         v[3] = 1.0f;
2444         //Con_Printf("%i vertices to transform...\n", numvertices);
2445         for (i = 0;i < numvertices;i++)
2446         {
2447                 VectorCopy(vertex[i], v);
2448                 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
2449                 //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]);
2450                 if (i)
2451                 {
2452                         if (x1 > v2[0]) x1 = v2[0];
2453                         if (x2 < v2[0]) x2 = v2[0];
2454                         if (y1 > v2[1]) y1 = v2[1];
2455                         if (y2 < v2[1]) y2 = v2[1];
2456                 }
2457                 else
2458                 {
2459                         x1 = x2 = v2[0];
2460                         y1 = y2 = v2[1];
2461                 }
2462         }
2463
2464         // now convert the scissor rectangle to integer screen coordinates
2465         ix1 = (int)(x1 - 1.0f);
2466         iy1 = vid.height - (int)(y2 - 1.0f);
2467         ix2 = (int)(x2 + 1.0f);
2468         iy2 = vid.height - (int)(y1 + 1.0f);
2469         //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
2470
2471         // clamp it to the screen
2472         if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
2473         if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
2474         if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
2475         if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
2476
2477         // if it is inside out, it's not visible
2478         if (ix2 <= ix1 || iy2 <= iy1)
2479                 return true;
2480
2481         // the light area is visible, set up the scissor rectangle
2482         r_shadow_lightscissor[0] = ix1;
2483         r_shadow_lightscissor[1] = iy1;
2484         r_shadow_lightscissor[2] = ix2 - ix1;
2485         r_shadow_lightscissor[3] = iy2 - iy1;
2486
2487         r_refdef.stats.lights_scissored++;
2488         return false;
2489 }
2490
2491 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
2492 {
2493         const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2494         const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2495         float *color4f = rsurface.array_color4f + 4 * firstvertex;
2496         float dist, dot, distintensity, shadeintensity, v[3], n[3];
2497         switch (r_shadow_rendermode)
2498         {
2499         case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2500         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2501                 if (VectorLength2(diffusecolor) > 0)
2502                 {
2503                         for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2504                         {
2505                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2506                                 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2507                                 if ((dot = DotProduct(n, v)) < 0)
2508                                 {
2509                                         shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2510                                         VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2511                                 }
2512                                 else
2513                                         VectorCopy(ambientcolor, color4f);
2514                                 if (r_refdef.fogenabled)
2515                                 {
2516                                         float f;
2517                                         f = RSurf_FogVertex(vertex3f);
2518                                         VectorScale(color4f, f, color4f);
2519                                 }
2520                                 color4f[3] = 1;
2521                         }
2522                 }
2523                 else
2524                 {
2525                         for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2526                         {
2527                                 VectorCopy(ambientcolor, color4f);
2528                                 if (r_refdef.fogenabled)
2529                                 {
2530                                         float f;
2531                                         Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2532                                         f = RSurf_FogVertex(vertex3f);
2533                                         VectorScale(color4f, f, color4f);
2534                                 }
2535                                 color4f[3] = 1;
2536                         }
2537                 }
2538                 break;
2539         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2540                 if (VectorLength2(diffusecolor) > 0)
2541                 {
2542                         for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2543                         {
2544                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2545                                 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2546                                 {
2547                                         Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2548                                         if ((dot = DotProduct(n, v)) < 0)
2549                                         {
2550                                                 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2551                                                 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2552                                                 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2553                                                 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2554                                         }
2555                                         else
2556                                         {
2557                                                 color4f[0] = ambientcolor[0] * distintensity;
2558                                                 color4f[1] = ambientcolor[1] * distintensity;
2559                                                 color4f[2] = ambientcolor[2] * distintensity;
2560                                         }
2561                                         if (r_refdef.fogenabled)
2562                                         {
2563                                                 float f;
2564                                                 f = RSurf_FogVertex(vertex3f);
2565                                                 VectorScale(color4f, f, color4f);
2566                                         }
2567                                 }
2568                                 else
2569                                         VectorClear(color4f);
2570                                 color4f[3] = 1;
2571                         }
2572                 }
2573                 else
2574                 {
2575                         for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2576                         {
2577                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2578                                 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2579                                 {
2580                                         color4f[0] = ambientcolor[0] * distintensity;
2581                                         color4f[1] = ambientcolor[1] * distintensity;
2582                                         color4f[2] = ambientcolor[2] * distintensity;
2583                                         if (r_refdef.fogenabled)
2584                                         {
2585                                                 float f;
2586                                                 f = RSurf_FogVertex(vertex3f);
2587                                                 VectorScale(color4f, f, color4f);
2588                                         }
2589                                 }
2590                                 else
2591                                         VectorClear(color4f);
2592                                 color4f[3] = 1;
2593                         }
2594                 }
2595                 break;
2596         case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2597                 if (VectorLength2(diffusecolor) > 0)
2598                 {
2599                         for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2600                         {
2601                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2602                                 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2603                                 {
2604                                         distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2605                                         Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2606                                         if ((dot = DotProduct(n, v)) < 0)
2607                                         {
2608                                                 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2609                                                 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2610                                                 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2611                                                 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2612                                         }
2613                                         else
2614                                         {
2615                                                 color4f[0] = ambientcolor[0] * distintensity;
2616                                                 color4f[1] = ambientcolor[1] * distintensity;
2617                                                 color4f[2] = ambientcolor[2] * distintensity;
2618                                         }
2619                                         if (r_refdef.fogenabled)
2620                                         {
2621                                                 float f;
2622                                                 f = RSurf_FogVertex(vertex3f);
2623                                                 VectorScale(color4f, f, color4f);
2624                                         }
2625                                 }
2626                                 else
2627                                         VectorClear(color4f);
2628                                 color4f[3] = 1;
2629                         }
2630                 }
2631                 else
2632                 {
2633                         for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2634                         {
2635                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2636                                 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2637                                 {
2638                                         distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2639                                         color4f[0] = ambientcolor[0] * distintensity;
2640                                         color4f[1] = ambientcolor[1] * distintensity;
2641                                         color4f[2] = ambientcolor[2] * distintensity;
2642                                         if (r_refdef.fogenabled)
2643                                         {
2644                                                 float f;
2645                                                 f = RSurf_FogVertex(vertex3f);
2646                                                 VectorScale(color4f, f, color4f);
2647                                         }
2648                                 }
2649                                 else
2650                                         VectorClear(color4f);
2651                                 color4f[3] = 1;
2652                         }
2653                 }
2654                 break;
2655         default:
2656                 break;
2657         }
2658 }
2659
2660 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)
2661 {
2662         // used to display how many times a surface is lit for level design purposes
2663         R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2664 }
2665
2666 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)
2667 {
2668         // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2669         R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
2670         if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2671         {
2672                 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2673         }
2674         R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2675         if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2676         {
2677                 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2678         }
2679 }
2680
2681 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2682 {
2683         int renders;
2684         int i;
2685         int stop;
2686         int newfirstvertex;
2687         int newlastvertex;
2688         int newnumtriangles;
2689         int *newe;
2690         const int *e;
2691         float *c;
2692         int maxtriangles = 4096;
2693         static int newelements[4096*3];
2694         R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
2695         for (renders = 0;renders < 4;renders++)
2696         {
2697                 stop = true;
2698                 newfirstvertex = 0;
2699                 newlastvertex = 0;
2700                 newnumtriangles = 0;
2701                 newe = newelements;
2702                 // due to low fillrate on the cards this vertex lighting path is
2703                 // designed for, we manually cull all triangles that do not
2704                 // contain a lit vertex
2705                 // this builds batches of triangles from multiple surfaces and
2706                 // renders them at once
2707                 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2708                 {
2709                         if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
2710                         {
2711                                 if (newnumtriangles)
2712                                 {
2713                                         newfirstvertex = min(newfirstvertex, e[0]);
2714                                         newlastvertex  = max(newlastvertex, e[0]);
2715                                 }
2716                                 else
2717                                 {
2718                                         newfirstvertex = e[0];
2719                                         newlastvertex = e[0];
2720                                 }
2721                                 newfirstvertex = min(newfirstvertex, e[1]);
2722                                 newlastvertex  = max(newlastvertex, e[1]);
2723                                 newfirstvertex = min(newfirstvertex, e[2]);
2724                                 newlastvertex  = max(newlastvertex, e[2]);
2725                                 newe[0] = e[0];
2726                                 newe[1] = e[1];
2727                                 newe[2] = e[2];
2728                                 newnumtriangles++;
2729                                 newe += 3;
2730                                 if (newnumtriangles >= maxtriangles)
2731                                 {
2732                                         R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2733                                         newnumtriangles = 0;
2734                                         newe = newelements;
2735                                         stop = false;
2736                                 }
2737                         }
2738                 }
2739                 if (newnumtriangles >= 1)
2740                 {
2741                         R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2742                         stop = false;
2743                 }
2744                 // if we couldn't find any lit triangles, exit early
2745                 if (stop)
2746                         break;
2747                 // now reduce the intensity for the next overbright pass
2748                 // we have to clamp to 0 here incase the drivers have improper
2749                 // handling of negative colors
2750                 // (some old drivers even have improper handling of >1 color)
2751                 stop = true;
2752                 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2753                 {
2754                         if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2755                         {
2756                                 c[0] = max(0, c[0] - 1);
2757                                 c[1] = max(0, c[1] - 1);
2758                                 c[2] = max(0, c[2] - 1);
2759                                 stop = false;
2760                         }
2761                         else
2762                                 VectorClear(c);
2763                 }
2764                 // another check...
2765                 if (stop)
2766                         break;
2767         }
2768 }
2769
2770 static void R_Shadow_RenderLighting_Light_Vertex(int firstvertex, int numvertices, int numtriangles, const int *element3i, const vec3_t lightcolor, float ambientscale, float diffusescale)
2771 {
2772         // OpenGL 1.1 path (anything)
2773         float ambientcolorbase[3], diffusecolorbase[3];
2774         float ambientcolorpants[3], diffusecolorpants[3];
2775         float ambientcolorshirt[3], diffusecolorshirt[3];
2776         const float *surfacecolor = rsurface.texture->dlightcolor;
2777         const float *surfacepants = rsurface.colormap_pantscolor;
2778         const float *surfaceshirt = rsurface.colormap_shirtcolor;
2779         rtexture_t *basetexture = rsurface.texture->basetexture;
2780         rtexture_t *pantstexture = rsurface.texture->pantstexture;
2781         rtexture_t *shirttexture = rsurface.texture->shirttexture;
2782         qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
2783         qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
2784         ambientscale *= 2 * r_refdef.view.colorscale;
2785         diffusescale *= 2 * r_refdef.view.colorscale;
2786         ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
2787         diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
2788         ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
2789         diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
2790         ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
2791         diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
2792         R_Mesh_TexBind(0, basetexture);
2793         R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2794         R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
2795         R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
2796         switch(r_shadow_rendermode)
2797         {
2798         case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2799                 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
2800                 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2801                 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2802                 R_Mesh_TexCoordPointer(1, 3, rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
2803                 break;
2804         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2805                 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
2806                 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
2807                 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
2808                 R_Mesh_TexCoordPointer(2, 3, rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
2809                 // fall through
2810         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2811                 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
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_VERTEX:
2817                 break;
2818         default:
2819                 break;
2820         }
2821         //R_Mesh_TexBind(0, basetexture);
2822         R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
2823         if (dopants)
2824         {
2825                 R_Mesh_TexBind(0, pantstexture);
2826                 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
2827         }
2828         if (doshirt)
2829         {
2830                 R_Mesh_TexBind(0, shirttexture);
2831                 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
2832         }
2833 }
2834
2835 extern cvar_t gl_lightmaps;
2836 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)
2837 {
2838         float ambientscale, diffusescale, specularscale;
2839         qboolean negated;
2840         float lightcolor[3];
2841         VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
2842         ambientscale = rsurface.rtlight->ambientscale;
2843         diffusescale = rsurface.rtlight->diffusescale;
2844         specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2845         if (!r_shadow_usenormalmap.integer)
2846         {
2847                 ambientscale += 1.0f * diffusescale;
2848                 diffusescale = 0;
2849                 specularscale = 0;
2850         }
2851         if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
2852                 return;
2853         negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
2854         if(negated)
2855         {
2856                 VectorNegate(lightcolor, lightcolor);
2857                 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
2858         }
2859         RSurf_SetupDepthAndCulling();
2860         switch (r_shadow_rendermode)
2861         {
2862         case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2863                 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2864                 R_Shadow_RenderLighting_VisibleLighting(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2865                 break;
2866         case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2867                 R_Shadow_RenderLighting_Light_GLSL(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolor, ambientscale, diffusescale, specularscale);
2868                 break;
2869         case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2870         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2871         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2872         case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2873                 R_Shadow_RenderLighting_Light_Vertex(firstvertex, numvertices, numtriangles, element3i + firsttriangle * 3, lightcolor, ambientscale, diffusescale);
2874                 break;
2875         default:
2876                 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2877                 break;
2878         }
2879         if(negated)
2880                 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
2881 }
2882
2883 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)
2884 {
2885         matrix4x4_t tempmatrix = *matrix;
2886         Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2887
2888         // if this light has been compiled before, free the associated data
2889         R_RTLight_Uncompile(rtlight);
2890
2891         // clear it completely to avoid any lingering data
2892         memset(rtlight, 0, sizeof(*rtlight));
2893
2894         // copy the properties
2895         rtlight->matrix_lighttoworld = tempmatrix;
2896         Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2897         Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2898         rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2899         VectorCopy(color, rtlight->color);
2900         rtlight->cubemapname[0] = 0;
2901         if (cubemapname && cubemapname[0])
2902                 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2903         rtlight->shadow = shadow;
2904         rtlight->corona = corona;
2905         rtlight->style = style;
2906         rtlight->isstatic = isstatic;
2907         rtlight->coronasizescale = coronasizescale;
2908         rtlight->ambientscale = ambientscale;
2909         rtlight->diffusescale = diffusescale;
2910         rtlight->specularscale = specularscale;
2911         rtlight->flags = flags;
2912
2913         // compute derived data
2914         //rtlight->cullradius = rtlight->radius;
2915         //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2916         rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2917         rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2918         rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2919         rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2920         rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2921         rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2922 }
2923
2924 // compiles rtlight geometry
2925 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2926 void R_RTLight_Compile(rtlight_t *rtlight)
2927 {
2928         int i;
2929         int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2930         int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
2931         entity_render_t *ent = r_refdef.scene.worldentity;
2932         dp_model_t *model = r_refdef.scene.worldmodel;
2933         unsigned char *data;
2934         shadowmesh_t *mesh;
2935
2936         // compile the light
2937         rtlight->compiled = true;
2938         rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
2939         rtlight->static_numleafs = 0;
2940         rtlight->static_numleafpvsbytes = 0;
2941         rtlight->static_leaflist = NULL;
2942         rtlight->static_leafpvs = NULL;
2943         rtlight->static_numsurfaces = 0;
2944         rtlight->static_surfacelist = NULL;
2945         rtlight->static_shadowmap_receivers = 0x3F;
2946         rtlight->static_shadowmap_casters = 0x3F;
2947         rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2948         rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2949         rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2950         rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2951         rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2952         rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2953
2954         if (model && model->GetLightInfo)
2955         {
2956                 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
2957                 r_shadow_compilingrtlight = rtlight;
2958                 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);
2959                 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2960                 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
2961                 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
2962                 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
2963                 rtlight->static_numsurfaces = numsurfaces;
2964                 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2965                 rtlight->static_numleafs = numleafs;
2966                 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2967                 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2968                 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2969                 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
2970                 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
2971                 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
2972                 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
2973                 if (rtlight->static_numsurfaces)
2974                         memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2975                 if (rtlight->static_numleafs)
2976                         memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2977                 if (rtlight->static_numleafpvsbytes)
2978                         memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2979                 if (rtlight->static_numshadowtrispvsbytes)
2980                         memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
2981                 if (rtlight->static_numlighttrispvsbytes)
2982                         memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
2983                 switch (rtlight->shadowmode)
2984                 {
2985                 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2986                 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
2987                 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
2988                         if (model->CompileShadowMap && rtlight->shadow)
2989                                 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2990                         break;
2991                 default:
2992                         if (model->CompileShadowVolume && rtlight->shadow)
2993                                 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2994                         break;
2995                 }
2996                 // now we're done compiling the rtlight
2997                 r_shadow_compilingrtlight = NULL;
2998         }
2999
3000
3001         // use smallest available cullradius - box radius or light radius
3002         //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3003         //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3004
3005         shadowzpasstris = 0;
3006         if (rtlight->static_meshchain_shadow_zpass)
3007                 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3008                         shadowzpasstris += mesh->numtriangles;
3009
3010         shadowzfailtris = 0;
3011         if (rtlight->static_meshchain_shadow_zfail)
3012                 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3013                         shadowzfailtris += mesh->numtriangles;
3014
3015         lighttris = 0;
3016         if (rtlight->static_numlighttrispvsbytes)
3017                 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3018                         if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3019                                 lighttris++;
3020
3021         shadowtris = 0;
3022         if (rtlight->static_numlighttrispvsbytes)
3023                 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3024                         if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3025                                 shadowtris++;
3026
3027         if (developer_extra.integer)
3028                 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);
3029 }
3030
3031 void R_RTLight_Uncompile(rtlight_t *rtlight)
3032 {
3033         if (rtlight->compiled)
3034         {
3035                 if (rtlight->static_meshchain_shadow_zpass)
3036                         Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3037                 rtlight->static_meshchain_shadow_zpass = NULL;
3038                 if (rtlight->static_meshchain_shadow_zfail)
3039                         Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3040                 rtlight->static_meshchain_shadow_zfail = NULL;
3041                 if (rtlight->static_meshchain_shadow_shadowmap)
3042                         Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3043                 rtlight->static_meshchain_shadow_shadowmap = NULL;
3044                 // these allocations are grouped
3045                 if (rtlight->static_surfacelist)
3046                         Mem_Free(rtlight->static_surfacelist);
3047                 rtlight->static_numleafs = 0;
3048                 rtlight->static_numleafpvsbytes = 0;
3049                 rtlight->static_leaflist = NULL;
3050                 rtlight->static_leafpvs = NULL;
3051                 rtlight->static_numsurfaces = 0;
3052                 rtlight->static_surfacelist = NULL;
3053                 rtlight->static_numshadowtrispvsbytes = 0;
3054                 rtlight->static_shadowtrispvs = NULL;
3055                 rtlight->static_numlighttrispvsbytes = 0;
3056                 rtlight->static_lighttrispvs = NULL;
3057                 rtlight->compiled = false;
3058         }
3059 }
3060
3061 void R_Shadow_UncompileWorldLights(void)
3062 {
3063         size_t lightindex;
3064         dlight_t *light;
3065         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3066         for (lightindex = 0;lightindex < range;lightindex++)
3067         {
3068                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3069                 if (!light)
3070                         continue;
3071                 R_RTLight_Uncompile(&light->rtlight);
3072         }
3073 }
3074
3075 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3076 {
3077         int i, j;
3078         mplane_t plane;
3079         // reset the count of frustum planes
3080         // see rtlight->cached_frustumplanes definition for how much this array
3081         // can hold
3082         rtlight->cached_numfrustumplanes = 0;
3083
3084         // haven't implemented a culling path for ortho rendering
3085         if (!r_refdef.view.useperspective)
3086         {
3087                 // check if the light is on screen and copy the 4 planes if it is
3088                 for (i = 0;i < 4;i++)
3089                         if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3090                                 break;
3091                 if (i == 4)
3092                         for (i = 0;i < 4;i++)
3093                                 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3094                 return;
3095         }
3096
3097 #if 1
3098         // generate a deformed frustum that includes the light origin, this is
3099         // used to cull shadow casting surfaces that can not possibly cast a
3100         // shadow onto the visible light-receiving surfaces, which can be a
3101         // performance gain
3102         //
3103         // if the light origin is onscreen the result will be 4 planes exactly
3104         // if the light origin is offscreen on only one axis the result will
3105         // be exactly 5 planes (split-side case)
3106         // if the light origin is offscreen on two axes the result will be
3107         // exactly 4 planes (stretched corner case)
3108         for (i = 0;i < 4;i++)
3109         {
3110                 // quickly reject standard frustum planes that put the light
3111                 // origin outside the frustum
3112                 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3113                         continue;
3114                 // copy the plane
3115                 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3116         }
3117         // if all the standard frustum planes were accepted, the light is onscreen
3118         // otherwise we need to generate some more planes below...
3119         if (rtlight->cached_numfrustumplanes < 4)
3120         {
3121                 // at least one of the stock frustum planes failed, so we need to
3122                 // create one or two custom planes to enclose the light origin
3123                 for (i = 0;i < 4;i++)
3124                 {
3125                         // create a plane using the view origin and light origin, and a
3126                         // single point from the frustum corner set
3127                         TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3128                         VectorNormalize(plane.normal);
3129                         plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3130                         // see if this plane is backwards and flip it if so
3131                         for (j = 0;j < 4;j++)
3132                                 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3133                                         break;
3134                         if (j < 4)
3135                         {
3136                                 VectorNegate(plane.normal, plane.normal);
3137                                 plane.dist *= -1;
3138                                 // flipped plane, test again to see if it is now valid
3139                                 for (j = 0;j < 4;j++)
3140                                         if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3141                                                 break;
3142                                 // if the plane is still not valid, then it is dividing the
3143                                 // frustum and has to be rejected
3144                                 if (j < 4)
3145                                         continue;
3146                         }
3147                         // we have created a valid plane, compute extra info
3148                         PlaneClassify(&plane);
3149                         // copy the plane
3150                         rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3151 #if 1
3152                         // if we've found 5 frustum planes then we have constructed a
3153                         // proper split-side case and do not need to keep searching for
3154                         // planes to enclose the light origin
3155                         if (rtlight->cached_numfrustumplanes == 5)
3156                                 break;
3157 #endif
3158                 }
3159         }
3160 #endif
3161
3162 #if 0
3163         for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3164         {
3165                 plane = rtlight->cached_frustumplanes[i];
3166                 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));
3167         }
3168 #endif
3169
3170 #if 0
3171         // now add the light-space box planes if the light box is rotated, as any
3172         // caster outside the oriented light box is irrelevant (even if it passed
3173         // the worldspace light box, which is axial)
3174         if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3175         {
3176                 for (i = 0;i < 6;i++)
3177                 {
3178                         vec3_t v;
3179                         VectorClear(v);
3180                         v[i >> 1] = (i & 1) ? -1 : 1;
3181                         Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3182                         VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3183                         plane.dist = VectorNormalizeLength(plane.normal);
3184                         plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3185                         rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3186                 }
3187         }
3188 #endif
3189
3190 #if 0
3191         // add the world-space reduced box planes
3192         for (i = 0;i < 6;i++)
3193         {
3194                 VectorClear(plane.normal);
3195                 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3196                 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3197                 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3198         }
3199 #endif
3200
3201 #if 0
3202         {
3203         int j, oldnum;
3204         vec3_t points[8];
3205         vec_t bestdist;
3206         // reduce all plane distances to tightly fit the rtlight cull box, which
3207         // is in worldspace
3208         VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3209         VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3210         VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3211         VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3212         VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3213         VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3214         VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3215         VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3216         oldnum = rtlight->cached_numfrustumplanes;
3217         rtlight->cached_numfrustumplanes = 0;
3218         for (j = 0;j < oldnum;j++)
3219         {
3220                 // find the nearest point on the box to this plane
3221                 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3222                 for (i = 1;i < 8;i++)
3223                 {
3224                         dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3225                         if (bestdist > dist)
3226                                 bestdist = dist;
3227                 }
3228                 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);
3229                 // if the nearest point is near or behind the plane, we want this
3230                 // plane, otherwise the plane is useless as it won't cull anything
3231                 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3232                 {
3233                         PlaneClassify(&rtlight->cached_frustumplanes[j]);
3234                         rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3235                 }
3236         }
3237         }
3238 #endif
3239 }
3240
3241 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3242 {
3243         shadowmesh_t *mesh;
3244
3245         RSurf_ActiveWorldEntity();
3246
3247         if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3248         {
3249                 CHECKGLERROR
3250                 GL_CullFace(GL_NONE);
3251         mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3252         for (;mesh;mesh = mesh->next)
3253         {
3254                         if (!mesh->sidetotals[r_shadow_shadowmapside])
3255                                 continue;
3256             r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3257             R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3258             R_Mesh_Draw(0, mesh->numverts, mesh->sideoffsets[r_shadow_shadowmapside], mesh->sidetotals[r_shadow_shadowmapside], mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3259         }
3260         CHECKGLERROR
3261     }
3262         else if (r_refdef.scene.worldentity->model)
3263                 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);
3264
3265         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3266 }
3267
3268 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3269 {
3270         qboolean zpass = false;
3271         shadowmesh_t *mesh;
3272         int t, tend;
3273         int surfacelistindex;
3274         msurface_t *surface;
3275
3276         RSurf_ActiveWorldEntity();
3277
3278         if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3279         {
3280                 CHECKGLERROR
3281                 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
3282                 {
3283                         zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3284                         R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3285                 }
3286                 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3287                 for (;mesh;mesh = mesh->next)
3288                 {
3289                         r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3290                         R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3291                         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3292                         {
3293                                 // increment stencil if frontface is infront of depthbuffer
3294                                 GL_CullFace(r_refdef.view.cullface_back);
3295                                 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
3296                                 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3297                                 // decrement stencil if backface is infront of depthbuffer
3298                                 GL_CullFace(r_refdef.view.cullface_front);
3299                                 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
3300                         }
3301                         else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3302                         {
3303                                 // decrement stencil if backface is behind depthbuffer
3304                                 GL_CullFace(r_refdef.view.cullface_front);
3305                                 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
3306                                 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3307                                 // increment stencil if frontface is behind depthbuffer
3308                                 GL_CullFace(r_refdef.view.cullface_back);
3309                                 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
3310                         }
3311                         R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3312                 }
3313                 CHECKGLERROR
3314         }
3315         else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
3316         {
3317                 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
3318                 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3319                 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3320                 {
3321                         surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3322                         for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3323                                 if (CHECKPVSBIT(trispvs, t))
3324                                         shadowmarklist[numshadowmark++] = t;
3325                 }
3326                 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);
3327         }
3328         else if (numsurfaces)
3329                 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);
3330
3331         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3332 }
3333
3334 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3335 {
3336         vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3337         vec_t relativeshadowradius;
3338         RSurf_ActiveModelEntity(ent, false, false, false);
3339         Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3340         // we need to re-init the shader for each entity because the matrix changed
3341         relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3342         relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3343         relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3344         relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3345         relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3346         relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3347         relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3348         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
3349         {
3350                 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3351         }
3352         else
3353                 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3354         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3355 }
3356
3357 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3358 {
3359         // set up properties for rendering light onto this entity
3360         RSurf_ActiveModelEntity(ent, true, true, false);
3361         GL_AlphaTest(false);
3362         Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3363         Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3364         Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3365         Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3366 }
3367
3368 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3369 {
3370         if (!r_refdef.scene.worldmodel->DrawLight)
3371                 return;
3372
3373         // set up properties for rendering light onto this entity
3374         RSurf_ActiveWorldEntity();
3375         GL_AlphaTest(false);
3376         rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3377         Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3378         Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3379         VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3380
3381         r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3382
3383         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3384 }
3385
3386 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3387 {
3388         dp_model_t *model = ent->model;
3389         if (!model->DrawLight)
3390                 return;
3391
3392         R_Shadow_SetupEntityLight(ent);
3393
3394         model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3395
3396         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3397 }
3398
3399 void R_Shadow_PrepareLight(rtlight_t *rtlight)
3400 {
3401         int i;
3402         float f;
3403         int numleafs, numsurfaces;
3404         int *leaflist, *surfacelist;
3405         unsigned char *leafpvs;
3406         unsigned char *shadowtrispvs;
3407         unsigned char *lighttrispvs;
3408         //unsigned char *surfacesides;
3409         int numlightentities;
3410         int numlightentities_noselfshadow;
3411         int numshadowentities;
3412         int numshadowentities_noselfshadow;
3413         static entity_render_t *lightentities[MAX_EDICTS];
3414         static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3415         static entity_render_t *shadowentities[MAX_EDICTS];
3416         static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3417
3418         rtlight->draw = false;
3419
3420         // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3421         // skip lights that are basically invisible (color 0 0 0)
3422         if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
3423                 return;
3424
3425         // loading is done before visibility checks because loading should happen
3426         // all at once at the start of a level, not when it stalls gameplay.
3427         // (especially important to benchmarks)
3428         // compile light
3429         if (rtlight->isstatic && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3430         {
3431                 if (rtlight->compiled)
3432                         R_RTLight_Uncompile(rtlight);
3433                 R_RTLight_Compile(rtlight);
3434         }
3435
3436         // load cubemap
3437         rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3438
3439         // look up the light style value at this time
3440         f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3441         VectorScale(rtlight->color, f, rtlight->currentcolor);
3442         /*
3443         if (rtlight->selected)
3444         {
3445                 f = 2 + sin(realtime * M_PI * 4.0);
3446                 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3447         }
3448         */
3449
3450         // if lightstyle is currently off, don't draw the light
3451         if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3452                 return;
3453
3454         // if the light box is offscreen, skip it
3455         if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3456                 return;
3457
3458         VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3459         VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3460
3461         R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3462
3463         if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3464         {
3465                 // compiled light, world available and can receive realtime lighting
3466                 // retrieve leaf information
3467                 numleafs = rtlight->static_numleafs;
3468                 leaflist = rtlight->static_leaflist;
3469                 leafpvs = rtlight->static_leafpvs;
3470                 numsurfaces = rtlight->static_numsurfaces;
3471                 surfacelist = rtlight->static_surfacelist;
3472                 //surfacesides = NULL;
3473                 shadowtrispvs = rtlight->static_shadowtrispvs;
3474                 lighttrispvs = rtlight->static_lighttrispvs;
3475         }
3476         else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3477         {
3478                 // dynamic light, world available and can receive realtime lighting
3479                 // calculate lit surfaces and leafs
3480                 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);
3481                 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3482                 leaflist = r_shadow_buffer_leaflist;
3483                 leafpvs = r_shadow_buffer_leafpvs;
3484                 surfacelist = r_shadow_buffer_surfacelist;
3485                 //surfacesides = r_shadow_buffer_surfacesides;
3486                 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3487                 lighttrispvs = r_shadow_buffer_lighttrispvs;
3488                 // if the reduced leaf bounds are offscreen, skip it
3489                 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3490                         return;
3491         }
3492         else
3493         {
3494                 // no world
3495                 numleafs = 0;
3496                 leaflist = NULL;
3497                 leafpvs = NULL;
3498                 numsurfaces = 0;
3499                 surfacelist = NULL;
3500                 //surfacesides = NULL;
3501                 shadowtrispvs = NULL;
3502                 lighttrispvs = NULL;
3503         }
3504         // check if light is illuminating any visible leafs
3505         if (numleafs)
3506         {
3507                 for (i = 0;i < numleafs;i++)
3508                         if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3509                                 break;
3510                 if (i == numleafs)
3511                         return;
3512         }
3513
3514         // make a list of lit entities and shadow casting entities
3515         numlightentities = 0;
3516         numlightentities_noselfshadow = 0;
3517         numshadowentities = 0;
3518         numshadowentities_noselfshadow = 0;
3519
3520         // add dynamic entities that are lit by the light
3521         for (i = 0;i < r_refdef.scene.numentities;i++)
3522         {
3523                 dp_model_t *model;
3524                 entity_render_t *ent = r_refdef.scene.entities[i];
3525                 vec3_t org;
3526                 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3527                         continue;
3528                 // skip the object entirely if it is not within the valid
3529                 // shadow-casting region (which includes the lit region)
3530                 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3531                         continue;
3532                 if (!(model = ent->model))
3533                         continue;
3534                 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3535                 {
3536                         // this entity wants to receive light, is visible, and is
3537                         // inside the light box
3538                         // TODO: check if the surfaces in the model can receive light
3539                         // so now check if it's in a leaf seen by the light
3540                         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))
3541                                 continue;
3542                         if (ent->flags & RENDER_NOSELFSHADOW)
3543                                 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3544                         else
3545                                 lightentities[numlightentities++] = ent;
3546                         // since it is lit, it probably also casts a shadow...
3547                         // about the VectorDistance2 - light emitting entities should not cast their own shadow
3548                         Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3549                         if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3550                         {
3551                                 // note: exterior models without the RENDER_NOSELFSHADOW
3552                                 // flag still create a RENDER_NOSELFSHADOW shadow but
3553                                 // are lit normally, this means that they are
3554                                 // self-shadowing but do not shadow other
3555                                 // RENDER_NOSELFSHADOW entities such as the gun
3556                                 // (very weird, but keeps the player shadow off the gun)
3557                                 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3558                                         shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3559                                 else
3560                                         shadowentities[numshadowentities++] = ent;
3561                         }
3562                 }
3563                 else if (ent->flags & RENDER_SHADOW)
3564                 {
3565                         // this entity is not receiving light, but may still need to
3566                         // cast a shadow...
3567                         // TODO: check if the surfaces in the model can cast shadow
3568                         // now check if it is in a leaf seen by the light
3569                         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))
3570                                 continue;
3571                         // about the VectorDistance2 - light emitting entities should not cast their own shadow
3572                         Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3573                         if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3574                         {
3575                                 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3576                                         shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3577                                 else
3578                                         shadowentities[numshadowentities++] = ent;
3579                         }
3580                 }
3581         }
3582
3583         // return if there's nothing at all to light
3584         if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3585                 return;
3586
3587         // count this light in the r_speeds
3588         r_refdef.stats.lights++;
3589
3590         // flag it as worth drawing later
3591         rtlight->draw = true;
3592
3593         // cache all the animated entities that cast a shadow but are not visible
3594         for (i = 0;i < numshadowentities;i++)
3595                 if (!shadowentities[i]->animcache_vertex3f)
3596                         R_AnimCache_GetEntity(shadowentities[i], false, false);
3597         for (i = 0;i < numshadowentities_noselfshadow;i++)
3598                 if (!shadowentities_noselfshadow[i]->animcache_vertex3f)
3599                         R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3600
3601         // allocate some temporary memory for rendering this light later in the frame
3602         // reusable buffers need to be copied, static data can be used as-is
3603         rtlight->cached_numlightentities               = numlightentities;
3604         rtlight->cached_numlightentities_noselfshadow  = numlightentities_noselfshadow;
3605         rtlight->cached_numshadowentities              = numshadowentities;
3606         rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3607         rtlight->cached_numsurfaces                    = numsurfaces;
3608         rtlight->cached_lightentities                  = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3609         rtlight->cached_lightentities_noselfshadow     = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3610         rtlight->cached_shadowentities                 = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3611         rtlight->cached_shadowentities_noselfshadow    = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3612         if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3613         {
3614                 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
3615                 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3616                 rtlight->cached_shadowtrispvs                  =   (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3617                 rtlight->cached_lighttrispvs                   =   (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3618                 rtlight->cached_surfacelist                    =              (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3619         }
3620         else
3621         {
3622                 // compiled light data
3623                 rtlight->cached_shadowtrispvs = shadowtrispvs;
3624                 rtlight->cached_lighttrispvs = lighttrispvs;
3625                 rtlight->cached_surfacelist = surfacelist;
3626         }
3627 }
3628
3629 void R_Shadow_DrawLight(rtlight_t *rtlight)
3630 {
3631         int i;
3632         int numsurfaces;
3633         unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
3634         int numlightentities;
3635         int numlightentities_noselfshadow;
3636         int numshadowentities;
3637         int numshadowentities_noselfshadow;
3638         entity_render_t **lightentities;
3639         entity_render_t **lightentities_noselfshadow;
3640         entity_render_t **shadowentities;
3641         entity_render_t **shadowentities_noselfshadow;
3642         int *surfacelist;
3643         static unsigned char entitysides[MAX_EDICTS];
3644         static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3645         vec3_t nearestpoint;
3646         vec_t distance;
3647         qboolean castshadows;
3648         int lodlinear;
3649
3650         // check if we cached this light this frame (meaning it is worth drawing)
3651         if (!rtlight->draw)
3652                 return;
3653
3654         // if R_FrameData_Store ran out of space we skip anything dependent on it
3655         if (r_framedata_failed)
3656                 return;
3657
3658         numlightentities = rtlight->cached_numlightentities;
3659         numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3660         numshadowentities = rtlight->cached_numshadowentities;
3661         numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3662         numsurfaces = rtlight->cached_numsurfaces;
3663         lightentities = rtlight->cached_lightentities;
3664         lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3665         shadowentities = rtlight->cached_shadowentities;
3666         shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3667         shadowtrispvs = rtlight->cached_shadowtrispvs;
3668         lighttrispvs = rtlight->cached_lighttrispvs;
3669         surfacelist = rtlight->cached_surfacelist;
3670
3671         // set up a scissor rectangle for this light
3672         if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3673                 return;
3674
3675         // don't let sound skip if going slow
3676         if (r_refdef.scene.extraupdate)
3677                 S_ExtraUpdate ();
3678
3679         // make this the active rtlight for rendering purposes
3680         R_Shadow_RenderMode_ActiveLight(rtlight);
3681
3682         if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3683         {
3684                 // optionally draw visible shape of the shadow volumes
3685                 // for performance analysis by level designers
3686                 R_Shadow_RenderMode_VisibleShadowVolumes();
3687                 if (numsurfaces)
3688                         R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3689                 for (i = 0;i < numshadowentities;i++)
3690                         R_Shadow_DrawEntityShadow(shadowentities[i]);
3691                 for (i = 0;i < numshadowentities_noselfshadow;i++)
3692                         R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3693                 R_Shadow_RenderMode_VisibleLighting(false, false);
3694         }
3695
3696         if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3697         {
3698                 // optionally draw the illuminated areas
3699                 // for performance analysis by level designers
3700                 R_Shadow_RenderMode_VisibleLighting(false, false);
3701                 if (numsurfaces)
3702                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3703                 for (i = 0;i < numlightentities;i++)
3704                         R_Shadow_DrawEntityLight(lightentities[i]);
3705                 for (i = 0;i < numlightentities_noselfshadow;i++)
3706                         R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3707         }
3708
3709         castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3710
3711         nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3712         nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3713         nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3714         distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3715
3716         lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
3717         //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3718         lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3719
3720         if (castshadows && (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE))
3721         {
3722                 float borderbias;
3723                 int side;
3724                 int size;
3725                 int castermask = 0;
3726                 int receivermask = 0;
3727                 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3728                 Matrix4x4_Abs(&radiustolight);
3729
3730                 r_shadow_shadowmaplod = 0;
3731                 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
3732                         if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
3733                                 r_shadow_shadowmaplod = i;
3734
3735                 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
3736                         size = max(1, r_shadow_shadowmapmaxsize >> r_shadow_shadowmaplod);
3737                 else
3738                         size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3739                         
3740                 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3741
3742                 surfacesides = NULL;
3743                 if (numsurfaces)
3744                 {
3745                         if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3746                         {
3747                                 castermask = rtlight->static_shadowmap_casters;
3748                                 receivermask = rtlight->static_shadowmap_receivers;
3749                         }
3750                         else
3751                         {
3752                                 surfacesides = r_shadow_buffer_surfacesides;
3753                                 for(i = 0;i < numsurfaces;i++)
3754                                 {
3755                                         msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3756                                         surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);           
3757                                         castermask |= surfacesides[i];
3758                                         receivermask |= surfacesides[i];
3759                                 }
3760                         }
3761                 }
3762                 if (receivermask < 0x3F) 
3763                 {
3764                         for (i = 0;i < numlightentities;i++)
3765                                 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3766                         if (receivermask < 0x3F)
3767                                 for(i = 0; i < numlightentities_noselfshadow;i++)
3768                                         receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3769                 }
3770
3771                 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3772
3773                 if (receivermask)
3774                 {
3775                         for (i = 0;i < numshadowentities;i++)
3776                                 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3777                         for (i = 0;i < numshadowentities_noselfshadow;i++)
3778                                 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias)); 
3779                 }
3780
3781                 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
3782
3783                 // render shadow casters into 6 sided depth texture
3784                 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
3785                 {
3786                         R_Shadow_RenderMode_ShadowMap(side, receivermask, size);
3787                         if (! (castermask & (1 << side))) continue;
3788                         if (numsurfaces)
3789                                 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3790                         for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
3791                                 R_Shadow_DrawEntityShadow(shadowentities[i]);
3792                 }
3793
3794                 if (numlightentities_noselfshadow)
3795                 {
3796                         // render lighting using the depth texture as shadowmap
3797                         // draw lighting in the unmasked areas
3798                         R_Shadow_RenderMode_Lighting(false, false, true);
3799                         for (i = 0;i < numlightentities_noselfshadow;i++)
3800                                 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3801                 }
3802
3803                 // render shadow casters into 6 sided depth texture
3804                 if (numshadowentities_noselfshadow)
3805                 {
3806                         for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
3807                         {
3808                                 R_Shadow_RenderMode_ShadowMap(side, 0, size);
3809                                 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
3810                                         R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3811                         }
3812                 }
3813
3814                 // render lighting using the depth texture as shadowmap
3815                 // draw lighting in the unmasked areas
3816                 R_Shadow_RenderMode_Lighting(false, false, true);
3817                 // draw lighting in the unmasked areas
3818                 if (numsurfaces)
3819                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3820                 for (i = 0;i < numlightentities;i++)
3821                         R_Shadow_DrawEntityLight(lightentities[i]);
3822         }
3823         else if (castshadows && vid.stencil)
3824         {
3825                 // draw stencil shadow volumes to mask off pixels that are in shadow
3826                 // so that they won't receive lighting
3827                 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
3828                 R_Shadow_ClearStencil();
3829
3830                 if (numsurfaces)
3831                         R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3832                 for (i = 0;i < numshadowentities;i++)
3833                         R_Shadow_DrawEntityShadow(shadowentities[i]);
3834
3835                 // draw lighting in the unmasked areas
3836                 R_Shadow_RenderMode_Lighting(true, false, false);
3837                 for (i = 0;i < numlightentities_noselfshadow;i++)
3838                         R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3839
3840                 for (i = 0;i < numshadowentities_noselfshadow;i++)
3841                         R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3842
3843                 // draw lighting in the unmasked areas
3844                 R_Shadow_RenderMode_Lighting(true, false, false);
3845                 if (numsurfaces)
3846                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3847                 for (i = 0;i < numlightentities;i++)
3848                         R_Shadow_DrawEntityLight(lightentities[i]);
3849         }
3850         else
3851         {
3852                 // draw lighting in the unmasked areas
3853                 R_Shadow_RenderMode_Lighting(false, 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                 for (i = 0;i < numlightentities_noselfshadow;i++)
3859                         R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3860         }
3861
3862         if (r_shadow_usingdeferredprepass)
3863         {
3864                 // when rendering deferred lighting, we simply rasterize the box
3865                 if (castshadows && (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE))
3866                         R_Shadow_RenderMode_DrawDeferredLight(false, true);
3867                 else if (castshadows && vid.stencil)
3868                         R_Shadow_RenderMode_DrawDeferredLight(true, false);
3869                 else
3870                         R_Shadow_RenderMode_DrawDeferredLight(false, false);
3871         }
3872 }
3873
3874 static void R_Shadow_FreeDeferred(void)
3875 {
3876         if (r_shadow_prepassgeometryfbo)
3877                 qglDeleteFramebuffersEXT(1, &r_shadow_prepassgeometryfbo);CHECKGLERROR
3878         r_shadow_prepassgeometryfbo = 0;
3879
3880         if (r_shadow_prepasslightingfbo)
3881                 qglDeleteFramebuffersEXT(1, &r_shadow_prepasslightingfbo);CHECKGLERROR
3882         r_shadow_prepasslightingfbo = 0;
3883
3884         if (r_shadow_prepassgeometrydepthtexture)
3885                 R_FreeTexture(r_shadow_prepassgeometrydepthtexture);
3886         r_shadow_prepassgeometrydepthtexture = NULL;
3887
3888         if (r_shadow_prepassgeometrynormalmaptexture)
3889                 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
3890         r_shadow_prepassgeometrynormalmaptexture = NULL;
3891
3892         if (r_shadow_prepasslightingdiffusetexture)
3893                 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
3894         r_shadow_prepasslightingdiffusetexture = NULL;
3895
3896         if (r_shadow_prepasslightingspeculartexture)
3897                 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
3898         r_shadow_prepasslightingspeculartexture = NULL;
3899 }
3900
3901 void R_Shadow_DrawPrepass(void)
3902 {
3903         int i;
3904         int flag;
3905         int lnum;
3906         size_t lightindex;
3907         dlight_t *light;
3908         size_t range;
3909         entity_render_t *ent;
3910
3911         GL_AlphaTest(false);
3912         R_Mesh_ColorPointer(NULL, 0, 0);
3913         R_Mesh_ResetTextureState();
3914         GL_DepthMask(true);
3915         GL_ColorMask(1,1,1,1);
3916         GL_BlendFunc(GL_ONE, GL_ZERO);
3917         GL_Color(1,1,1,1);
3918         GL_DepthTest(true);
3919         qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepassgeometryfbo);CHECKGLERROR
3920         qglClearColor(0.5f,0.5f,0.5f,1.0f);CHECKGLERROR
3921         GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);CHECKGLERROR
3922
3923         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
3924                 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
3925         if (r_timereport_active)
3926                 R_TimeReport("prepassworld");
3927
3928         for (i = 0;i < r_refdef.scene.numentities;i++)
3929         {
3930                 if (!r_refdef.viewcache.entityvisible[i])
3931                         continue;
3932                 ent = r_refdef.scene.entities[i];
3933                 if (ent->model && ent->model->DrawPrepass != NULL)
3934                         ent->model->DrawPrepass(ent);
3935         }
3936
3937         if (r_timereport_active)
3938                 R_TimeReport("prepassmodels");
3939
3940         GL_DepthMask(false);
3941         GL_ColorMask(1,1,1,1);
3942         GL_Color(1,1,1,1);
3943         GL_DepthTest(true);
3944         qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR
3945         qglClearColor(0.0f,0.0f,0.0f,0.0f);CHECKGLERROR
3946         GL_Clear(GL_COLOR_BUFFER_BIT);CHECKGLERROR
3947         if (r_refdef.fogenabled)
3948                 qglClearColor(r_refdef.fogcolor[0],r_refdef.fogcolor[1],r_refdef.fogcolor[2],0);CHECKGLERROR
3949
3950         R_Shadow_RenderMode_Begin();
3951
3952         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3953         if (r_shadow_debuglight.integer >= 0)
3954         {
3955                 lightindex = r_shadow_debuglight.integer;
3956                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3957                 if (light && (light->flags & flag))
3958                         R_Shadow_DrawLight(&light->rtlight);
3959         }
3960         else
3961         {
3962                 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3963                 for (lightindex = 0;lightindex < range;lightindex++)
3964                 {
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         }
3970         if (r_refdef.scene.rtdlight)
3971                 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3972                         R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
3973
3974         qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
3975         if (r_refdef.fogenabled)
3976                 qglClearColor(r_refdef.fogcolor[0],r_refdef.fogcolor[1],r_refdef.fogcolor[2],0);CHECKGLERROR
3977
3978         R_Shadow_RenderMode_End();
3979
3980         if (r_timereport_active)
3981                 R_TimeReport("prepasslights");
3982 }
3983
3984 void R_Shadow_DrawLightSprites(void);
3985 void R_Shadow_PrepareLights(void)
3986 {
3987         int flag;
3988         int lnum;
3989         size_t lightindex;
3990         dlight_t *light;
3991         size_t range;
3992         float f;
3993         GLenum status;
3994
3995         if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
3996                 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
3997                 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0) || 
3998                 r_shadow_shadowmaptexturetype != r_shadow_shadowmapping_texturetype.integer ||
3999                 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer || 
4000                 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer || 
4001                 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
4002                 R_Shadow_FreeShadowMaps();
4003
4004         switch (vid.renderpath)
4005         {
4006         case RENDERPATH_GL20:
4007         case RENDERPATH_CGGL:
4008                 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
4009                 {
4010                         r_shadow_usingdeferredprepass = false;
4011                         if (r_shadow_prepass_width)
4012                                 R_Shadow_FreeDeferred();
4013                         r_shadow_prepass_width = r_shadow_prepass_height = 0;
4014                         break;
4015                 }
4016
4017                 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4018                 {
4019                         R_Shadow_FreeDeferred();
4020
4021                         r_shadow_usingdeferredprepass = true;
4022                         r_shadow_prepass_width = vid.width;
4023                         r_shadow_prepass_height = vid.height;
4024                         r_shadow_prepassgeometrydepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false);
4025                         r_shadow_prepassgeometrynormalmaptexture = R_LoadTexture2D(r_shadow_texturepool, "prepassgeometrynormalmap", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
4026                         r_shadow_prepasslightingdiffusetexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingdiffuse", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
4027                         r_shadow_prepasslightingspeculartexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingspecular", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
4028
4029                         // set up the geometry pass fbo (depth + normalmap)
4030                         qglGenFramebuffersEXT(1, &r_shadow_prepassgeometryfbo);CHECKGLERROR
4031                         qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepassgeometryfbo);CHECKGLERROR
4032                         qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepassgeometrydepthtexture), 0);CHECKGLERROR
4033                         qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepassgeometrynormalmaptexture), 0);CHECKGLERROR
4034                         // render depth into one texture and normalmap into the other
4035                         if (qglDrawBuffersARB)
4036                         {
4037                                 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
4038                                 qglReadBuffer(GL_NONE);CHECKGLERROR
4039                         }
4040                         status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4041                         if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4042                         {
4043                                 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4044                                 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4045                                 r_shadow_usingdeferredprepass = false;
4046                         }
4047
4048                         // set up the lighting pass fbo (diffuse + specular)
4049                         qglGenFramebuffersEXT(1, &r_shadow_prepasslightingfbo);CHECKGLERROR
4050                         qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR
4051                         qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepassgeometrydepthtexture), 0);CHECKGLERROR
4052                         qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepasslightingdiffusetexture), 0);CHECKGLERROR
4053                         qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepasslightingspeculartexture), 0);CHECKGLERROR
4054                         // render diffuse into one texture and specular into another,
4055                         // with depth and normalmap bound as textures,
4056                         // with depth bound as attachment as well
4057                         if (qglDrawBuffersARB)
4058                         {
4059                                 qglDrawBuffersARB(2, r_shadow_prepasslightingdrawbuffers);CHECKGLERROR
4060                                 qglReadBuffer(GL_NONE);CHECKGLERROR
4061                         }
4062                         status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4063                         if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4064                         {
4065                                 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4066                                 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4067                                 r_shadow_usingdeferredprepass = false;
4068                         }
4069                 }
4070                 break;
4071         case RENDERPATH_GL13:
4072         case RENDERPATH_GL11:
4073                 r_shadow_usingdeferredprepass = false;
4074                 break;
4075         }
4076
4077         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);
4078
4079         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4080         if (r_shadow_debuglight.integer >= 0)
4081         {
4082                 lightindex = r_shadow_debuglight.integer;
4083                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4084                 if (light && (light->flags & flag))
4085                         R_Shadow_PrepareLight(&light->rtlight);
4086         }
4087         else
4088         {
4089                 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4090                 for (lightindex = 0;lightindex < range;lightindex++)
4091                 {
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         }
4097         if (r_refdef.scene.rtdlight)
4098         {
4099                 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4100                         R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4101         }
4102         else if(gl_flashblend.integer)
4103         {
4104                 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4105                 {
4106                         rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4107                         f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4108                         VectorScale(rtlight->color, f, rtlight->currentcolor);
4109                 }
4110         }
4111
4112         if (r_editlights.integer)
4113                 R_Shadow_DrawLightSprites();
4114 }
4115
4116 void R_Shadow_DrawLights(void)
4117 {
4118         int flag;
4119         int lnum;
4120         size_t lightindex;
4121         dlight_t *light;
4122         size_t range;
4123
4124         R_Shadow_RenderMode_Begin();
4125
4126         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4127         if (r_shadow_debuglight.integer >= 0)
4128         {
4129                 lightindex = r_shadow_debuglight.integer;
4130                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4131                 if (light && (light->flags & flag))
4132                         R_Shadow_DrawLight(&light->rtlight);
4133         }
4134         else
4135         {
4136                 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4137                 for (lightindex = 0;lightindex < range;lightindex++)
4138                 {
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         }
4144         if (r_refdef.scene.rtdlight)
4145                 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4146                         R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4147
4148         R_Shadow_RenderMode_End();
4149 }
4150
4151 extern const float r_screenvertex3f[12];
4152 extern void R_SetupView(qboolean allowwaterclippingplane);
4153 extern void R_ResetViewRendering3D(void);
4154 extern void R_ResetViewRendering2D(void);
4155 extern cvar_t r_shadows;
4156 extern cvar_t r_shadows_darken;
4157 extern cvar_t r_shadows_drawafterrtlighting;
4158 extern cvar_t r_shadows_castfrombmodels;
4159 extern cvar_t r_shadows_throwdistance;
4160 extern cvar_t r_shadows_throwdirection;
4161 void R_DrawModelShadows(void)
4162 {
4163         int i;
4164         float relativethrowdistance;
4165         entity_render_t *ent;
4166         vec3_t relativelightorigin;
4167         vec3_t relativelightdirection;
4168         vec3_t relativeshadowmins, relativeshadowmaxs;
4169         vec3_t tmp, shadowdir;
4170
4171         if (!r_refdef.scene.numentities || !vid.stencil)
4172                 return;
4173
4174         CHECKGLERROR
4175         R_ResetViewRendering3D();
4176         //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4177         //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4178         R_Shadow_RenderMode_Begin();
4179         R_Shadow_RenderMode_ActiveLight(NULL);
4180         r_shadow_lightscissor[0] = r_refdef.view.x;
4181         r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4182         r_shadow_lightscissor[2] = r_refdef.view.width;
4183         r_shadow_lightscissor[3] = r_refdef.view.height;
4184         R_Shadow_RenderMode_StencilShadowVolumes(false);
4185
4186         // get shadow dir
4187         if (r_shadows.integer == 2)
4188         {
4189                 Math_atov(r_shadows_throwdirection.string, shadowdir);
4190                 VectorNormalize(shadowdir);
4191         }
4192
4193         R_Shadow_ClearStencil();
4194
4195         for (i = 0;i < r_refdef.scene.numentities;i++)
4196         {
4197                 ent = r_refdef.scene.entities[i];
4198
4199                 // cast shadows from anything of the map (submodels are optional)
4200                 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4201                 {
4202                         relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4203                         VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4204                         VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4205                         if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4206                                 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4207                         else
4208                         {
4209                                 if(ent->entitynumber != 0)
4210                                 {
4211                                         // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4212                                         int entnum, entnum2, recursion;
4213                                         entnum = entnum2 = ent->entitynumber;
4214                                         for(recursion = 32; recursion > 0; --recursion)
4215                                         {
4216                                                 entnum2 = cl.entities[entnum].state_current.tagentity;
4217                                                 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4218                                                         entnum = entnum2;
4219                                                 else
4220                                                         break;
4221                                         }
4222                                         if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4223                                         {
4224                                                 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4225                                                 // transform into modelspace of OUR entity
4226                                                 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4227                                                 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4228                                         }
4229                                         else
4230                                                 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4231                                 }
4232                                 else
4233                                         VectorNegate(ent->modellight_lightdir, relativelightdirection);
4234                         }
4235
4236                         VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4237                         RSurf_ActiveModelEntity(ent, false, false, false);
4238                         ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4239                         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4240                 }
4241         }
4242
4243         // not really the right mode, but this will disable any silly stencil features
4244         R_Shadow_RenderMode_End();
4245
4246         // set up ortho view for rendering this pass
4247         //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4248         //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4249         //GL_ScissorTest(true);
4250         //R_EntityMatrix(&identitymatrix);
4251         //R_Mesh_ResetTextureState();
4252         R_ResetViewRendering2D();
4253         R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
4254         R_Mesh_ColorPointer(NULL, 0, 0);
4255         R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4256
4257         // set up a darkening blend on shadowed areas
4258         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4259         //GL_DepthRange(0, 1);
4260         //GL_DepthTest(false);
4261         //GL_DepthMask(false);
4262         //GL_PolygonOffset(0, 0);CHECKGLERROR
4263         GL_Color(0, 0, 0, r_shadows_darken.value);
4264         //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4265         //qglDepthFunc(GL_ALWAYS);CHECKGLERROR
4266         qglEnable(GL_STENCIL_TEST);CHECKGLERROR
4267         qglStencilMask(255);CHECKGLERROR
4268         qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
4269         qglStencilFunc(GL_NOTEQUAL, 128, 255);CHECKGLERROR
4270
4271         // apply the blend to the shadowed areas
4272         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4273
4274         // restore the viewport
4275         R_SetViewport(&r_refdef.view.viewport);
4276
4277         // restore other state to normal
4278         //R_Shadow_RenderMode_End();
4279 }
4280
4281 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4282 {
4283         float zdist;
4284         vec3_t centerorigin;
4285         float vertex3f[12];
4286         // if it's too close, skip it
4287         if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4288                 return;
4289         zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4290         if (zdist < 32)
4291                 return;
4292         if (usequery && r_numqueries + 2 <= r_maxqueries)
4293         {
4294                 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4295                 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4296                 // 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
4297                 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4298
4299                 CHECKGLERROR
4300                 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use qglDepthFunc instead
4301                 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4302                 qglDepthFunc(GL_ALWAYS);
4303                 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4304                 R_Mesh_VertexPointer(vertex3f, 0, 0);
4305                 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4306                 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4307                 qglDepthFunc(GL_LEQUAL);
4308                 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4309                 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4310                 R_Mesh_VertexPointer(vertex3f, 0, 0);
4311                 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4312                 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4313                 CHECKGLERROR
4314         }
4315         rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4316 }
4317
4318 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4319
4320 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4321 {
4322         vec3_t color;
4323         GLint allpixels = 0, visiblepixels = 0;
4324         // now we have to check the query result
4325         if (rtlight->corona_queryindex_visiblepixels)
4326         {
4327                 CHECKGLERROR
4328                 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4329                 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4330                 CHECKGLERROR
4331                 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4332                 if (visiblepixels < 1 || allpixels < 1)
4333                         return;
4334                 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4335                 cscale *= rtlight->corona_visibility;
4336         }
4337         else
4338         {
4339                 // FIXME: these traces should scan all render entities instead of cl.world
4340                 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4341                         return;
4342         }
4343         VectorScale(rtlight->currentcolor, cscale, color);
4344         if (VectorLength(color) > (1.0f / 256.0f))
4345         {
4346                 float vertex3f[12];
4347                 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
4348                 if(negated)
4349                 {
4350                         VectorNegate(color, color);
4351                         qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
4352                 }
4353                 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4354                 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);
4355                 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4356                 if(negated)
4357                         qglBlendEquationEXT(GL_FUNC_ADD_EXT);
4358         }
4359 }
4360
4361 void R_Shadow_DrawCoronas(void)
4362 {
4363         int i, flag;
4364         qboolean usequery;
4365         size_t lightindex;
4366         dlight_t *light;
4367         rtlight_t *rtlight;
4368         size_t range;
4369         if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4370                 return;
4371         if (r_waterstate.renderingscene)
4372                 return;
4373         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4374         R_EntityMatrix(&identitymatrix);
4375
4376         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4377
4378         // check occlusion of coronas
4379         // use GL_ARB_occlusion_query if available
4380         // otherwise use raytraces
4381         r_numqueries = 0;
4382         usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
4383         if (usequery)
4384         {
4385                 GL_ColorMask(0,0,0,0);
4386                 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4387                 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4388                 {
4389                         i = r_maxqueries;
4390                         r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4391                         r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4392                         CHECKGLERROR
4393                         qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4394                         CHECKGLERROR
4395                 }
4396                 RSurf_ActiveWorldEntity();
4397                 GL_BlendFunc(GL_ONE, GL_ZERO);
4398                 GL_CullFace(GL_NONE);
4399                 GL_DepthMask(false);
4400                 GL_DepthRange(0, 1);
4401                 GL_PolygonOffset(0, 0);
4402                 GL_DepthTest(true);
4403                 R_Mesh_ColorPointer(NULL, 0, 0);
4404                 R_Mesh_ResetTextureState();
4405                 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4406         }
4407         for (lightindex = 0;lightindex < range;lightindex++)
4408         {
4409                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4410                 if (!light)
4411                         continue;
4412                 rtlight = &light->rtlight;
4413                 rtlight->corona_visibility = 0;
4414                 rtlight->corona_queryindex_visiblepixels = 0;
4415                 rtlight->corona_queryindex_allpixels = 0;
4416                 if (!(rtlight->flags & flag))
4417                         continue;
4418                 if (rtlight->corona <= 0)
4419                         continue;
4420                 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4421                         continue;
4422                 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4423         }
4424         for (i = 0;i < r_refdef.scene.numlights;i++)
4425         {
4426                 rtlight = r_refdef.scene.lights[i];
4427                 rtlight->corona_visibility = 0;
4428                 rtlight->corona_queryindex_visiblepixels = 0;
4429                 rtlight->corona_queryindex_allpixels = 0;
4430                 if (!(rtlight->flags & flag))
4431                         continue;
4432                 if (rtlight->corona <= 0)
4433                         continue;
4434                 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4435         }
4436         if (usequery)
4437                 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4438
4439         // now draw the coronas using the query data for intensity info
4440         for (lightindex = 0;lightindex < range;lightindex++)
4441         {
4442                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4443                 if (!light)
4444                         continue;
4445                 rtlight = &light->rtlight;
4446                 if (rtlight->corona_visibility <= 0)
4447                         continue;
4448                 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4449         }
4450         for (i = 0;i < r_refdef.scene.numlights;i++)
4451         {
4452                 rtlight = r_refdef.scene.lights[i];
4453                 if (rtlight->corona_visibility <= 0)
4454                         continue;
4455                 if (gl_flashblend.integer)
4456                         R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4457                 else
4458                         R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4459         }
4460 }
4461
4462
4463
4464 dlight_t *R_Shadow_NewWorldLight(void)
4465 {
4466         return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4467 }
4468
4469 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)
4470 {
4471         matrix4x4_t matrix;
4472         // validate parameters
4473         if (style < 0 || style >= MAX_LIGHTSTYLES)
4474         {
4475                 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4476                 style = 0;
4477         }
4478         if (!cubemapname)
4479                 cubemapname = "";
4480
4481         // copy to light properties
4482         VectorCopy(origin, light->origin);
4483         light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4484         light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4485         light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4486         /*
4487         light->color[0] = max(color[0], 0);
4488         light->color[1] = max(color[1], 0);
4489         light->color[2] = max(color[2], 0);
4490         */
4491         light->color[0] = color[0];
4492         light->color[1] = color[1];
4493         light->color[2] = color[2];
4494         light->radius = max(radius, 0);
4495         light->style = style;
4496         light->shadow = shadowenable;
4497         light->corona = corona;
4498         strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4499         light->coronasizescale = coronasizescale;
4500         light->ambientscale = ambientscale;
4501         light->diffusescale = diffusescale;
4502         light->specularscale = specularscale;
4503         light->flags = flags;
4504
4505         // update renderable light data
4506         Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4507         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);
4508 }
4509
4510 void R_Shadow_FreeWorldLight(dlight_t *light)
4511 {
4512         if (r_shadow_selectedlight == light)
4513                 r_shadow_selectedlight = NULL;
4514         R_RTLight_Uncompile(&light->rtlight);
4515         Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4516 }
4517
4518 void R_Shadow_ClearWorldLights(void)
4519 {
4520         size_t lightindex;
4521         dlight_t *light;
4522         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4523         for (lightindex = 0;lightindex < range;lightindex++)
4524         {
4525                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4526                 if (light)
4527                         R_Shadow_FreeWorldLight(light);
4528         }
4529         r_shadow_selectedlight = NULL;
4530 }
4531
4532 void R_Shadow_SelectLight(dlight_t *light)
4533 {
4534         if (r_shadow_selectedlight)
4535                 r_shadow_selectedlight->selected = false;
4536         r_shadow_selectedlight = light;
4537         if (r_shadow_selectedlight)
4538                 r_shadow_selectedlight->selected = true;
4539 }
4540
4541 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4542 {
4543         // this is never batched (there can be only one)
4544         float vertex3f[12];
4545         R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4546         RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4547         R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4548 }
4549
4550 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4551 {
4552         float intensity;
4553         float s;
4554         vec3_t spritecolor;
4555         skinframe_t *skinframe;
4556         float vertex3f[12];
4557
4558         // this is never batched (due to the ent parameter changing every time)
4559         // so numsurfaces == 1 and surfacelist[0] == lightnumber
4560         const dlight_t *light = (dlight_t *)ent;
4561         s = EDLIGHTSPRSIZE;
4562
4563         R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4564
4565         intensity = 0.5f;
4566         VectorScale(light->color, intensity, spritecolor);
4567         if (VectorLength(spritecolor) < 0.1732f)
4568                 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4569         if (VectorLength(spritecolor) > 1.0f)
4570                 VectorNormalize(spritecolor);
4571
4572         // draw light sprite
4573         if (light->cubemapname[0] && !light->shadow)
4574                 skinframe = r_editlights_sprcubemapnoshadowlight;
4575         else if (light->cubemapname[0])
4576                 skinframe = r_editlights_sprcubemaplight;
4577         else if (!light->shadow)
4578                 skinframe = r_editlights_sprnoshadowlight;
4579         else
4580                 skinframe = r_editlights_sprlight;
4581
4582         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);
4583         R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4584
4585         // draw selection sprite if light is selected
4586         if (light->selected)
4587         {
4588                 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4589                 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4590                 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4591         }
4592 }
4593
4594 void R_Shadow_DrawLightSprites(void)
4595 {
4596         size_t lightindex;
4597         dlight_t *light;
4598         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4599         for (lightindex = 0;lightindex < range;lightindex++)
4600         {
4601                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4602                 if (light)
4603                         R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4604         }
4605         R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4606 }
4607
4608 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4609 {
4610         unsigned int range;
4611         dlight_t *light;
4612         rtlight_t *rtlight;
4613         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4614         if (lightindex >= range)
4615                 return -1;
4616         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4617         if (!light)
4618                 return 0;
4619         rtlight = &light->rtlight;
4620         //if (!(rtlight->flags & flag))
4621         //      return 0;
4622         VectorCopy(rtlight->shadoworigin, origin);
4623         *radius = rtlight->radius;
4624         VectorCopy(rtlight->color, color);
4625         return 1;
4626 }
4627
4628 void R_Shadow_SelectLightInView(void)
4629 {
4630         float bestrating, rating, temp[3];
4631         dlight_t *best;
4632         size_t lightindex;
4633         dlight_t *light;
4634         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4635         best = NULL;
4636         bestrating = 0;
4637         for (lightindex = 0;lightindex < range;lightindex++)
4638         {
4639                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4640                 if (!light)
4641                         continue;
4642                 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4643                 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4644                 if (rating >= 0.95)
4645                 {
4646                         rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4647                         if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
4648                         {
4649                                 bestrating = rating;
4650                                 best = light;
4651                         }
4652                 }
4653         }
4654         R_Shadow_SelectLight(best);
4655 }
4656
4657 void R_Shadow_LoadWorldLights(void)
4658 {
4659         int n, a, style, shadow, flags;
4660         char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4661         float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4662         if (cl.worldmodel == NULL)
4663         {
4664                 Con_Print("No map loaded.\n");
4665                 return;
4666         }
4667         FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4668         strlcat (name, ".rtlights", sizeof (name));
4669         lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4670         if (lightsstring)
4671         {
4672                 s = lightsstring;
4673                 n = 0;
4674                 while (*s)
4675                 {
4676                         t = s;
4677                         /*
4678                         shadow = true;
4679                         for (;COM_Parse(t, true) && strcmp(
4680                         if (COM_Parse(t, true))
4681                         {
4682                                 if (com_token[0] == '!')
4683                                 {
4684                                         shadow = false;
4685                                         origin[0] = atof(com_token+1);
4686                                 }
4687                                 else
4688                                         origin[0] = atof(com_token);
4689                                 if (Com_Parse(t
4690                         }
4691                         */
4692                         t = s;
4693                         while (*s && *s != '\n' && *s != '\r')
4694                                 s++;
4695                         if (!*s)
4696                                 break;
4697                         tempchar = *s;
4698                         shadow = true;
4699                         // check for modifier flags
4700                         if (*t == '!')
4701                         {
4702                                 shadow = false;
4703                                 t++;
4704                         }
4705                         *s = 0;
4706 #if _MSC_VER >= 1400
4707 #define sscanf sscanf_s
4708 #endif
4709                         cubemapname[sizeof(cubemapname)-1] = 0;
4710 #if MAX_QPATH != 128
4711 #error update this code if MAX_QPATH changes
4712 #endif
4713                         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
4714 #if _MSC_VER >= 1400
4715 , sizeof(cubemapname)
4716 #endif
4717 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4718                         *s = tempchar;
4719                         if (a < 18)
4720                                 flags = LIGHTFLAG_REALTIMEMODE;
4721                         if (a < 17)
4722                                 specularscale = 1;
4723                         if (a < 16)
4724                                 diffusescale = 1;
4725                         if (a < 15)
4726                                 ambientscale = 0;
4727                         if (a < 14)
4728                                 coronasizescale = 0.25f;
4729                         if (a < 13)
4730                                 VectorClear(angles);
4731                         if (a < 10)
4732                                 corona = 0;
4733                         if (a < 9 || !strcmp(cubemapname, "\"\""))
4734                                 cubemapname[0] = 0;
4735                         // remove quotes on cubemapname
4736                         if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4737                         {
4738                                 size_t namelen;
4739                                 namelen = strlen(cubemapname) - 2;
4740                                 memmove(cubemapname, cubemapname + 1, namelen);
4741                                 cubemapname[namelen] = '\0';
4742                         }
4743                         if (a < 8)
4744                         {
4745                                 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);
4746                                 break;
4747                         }
4748                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4749                         if (*s == '\r')
4750                                 s++;
4751                         if (*s == '\n')
4752                                 s++;
4753                         n++;
4754                 }
4755                 if (*s)
4756                         Con_Printf("invalid rtlights file \"%s\"\n", name);
4757                 Mem_Free(lightsstring);
4758         }
4759 }
4760
4761 void R_Shadow_SaveWorldLights(void)
4762 {
4763         size_t lightindex;
4764         dlight_t *light;
4765         size_t bufchars, bufmaxchars;
4766         char *buf, *oldbuf;
4767         char name[MAX_QPATH];
4768         char line[MAX_INPUTLINE];
4769         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
4770         // I hate lines which are 3 times my screen size :( --blub
4771         if (!range)
4772                 return;
4773         if (cl.worldmodel == NULL)
4774         {
4775                 Con_Print("No map loaded.\n");
4776                 return;
4777         }
4778         FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4779         strlcat (name, ".rtlights", sizeof (name));
4780         bufchars = bufmaxchars = 0;
4781         buf = NULL;
4782         for (lightindex = 0;lightindex < range;lightindex++)
4783         {
4784                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4785                 if (!light)
4786                         continue;
4787                 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
4788                         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);
4789                 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
4790                         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]);
4791                 else
4792                         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);
4793                 if (bufchars + strlen(line) > bufmaxchars)
4794                 {
4795                         bufmaxchars = bufchars + strlen(line) + 2048;
4796                         oldbuf = buf;
4797                         buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
4798                         if (oldbuf)
4799                         {
4800                                 if (bufchars)
4801                                         memcpy(buf, oldbuf, bufchars);
4802                                 Mem_Free(oldbuf);
4803                         }
4804                 }
4805                 if (strlen(line))
4806                 {
4807                         memcpy(buf + bufchars, line, strlen(line));
4808                         bufchars += strlen(line);
4809                 }
4810         }
4811         if (bufchars)
4812                 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
4813         if (buf)
4814                 Mem_Free(buf);
4815 }
4816
4817 void R_Shadow_LoadLightsFile(void)
4818 {
4819         int n, a, style;
4820         char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
4821         float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
4822         if (cl.worldmodel == NULL)
4823         {
4824                 Con_Print("No map loaded.\n");
4825                 return;
4826         }
4827         FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4828         strlcat (name, ".lights", sizeof (name));
4829         lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4830         if (lightsstring)
4831         {
4832                 s = lightsstring;
4833                 n = 0;
4834                 while (*s)
4835                 {
4836                         t = s;
4837                         while (*s && *s != '\n' && *s != '\r')
4838                                 s++;
4839                         if (!*s)
4840                                 break;
4841                         tempchar = *s;
4842                         *s = 0;
4843                         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);
4844                         *s = tempchar;
4845                         if (a < 14)
4846                         {
4847                                 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);
4848                                 break;
4849                         }
4850                         radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
4851                         radius = bound(15, radius, 4096);
4852                         VectorScale(color, (2.0f / (8388608.0f)), color);
4853                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
4854                         if (*s == '\r')
4855                                 s++;
4856                         if (*s == '\n')
4857                                 s++;
4858                         n++;
4859                 }
4860                 if (*s)
4861                         Con_Printf("invalid lights file \"%s\"\n", name);
4862                 Mem_Free(lightsstring);
4863         }
4864 }
4865
4866 // tyrlite/hmap2 light types in the delay field
4867 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
4868
4869 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
4870 {
4871         int entnum;
4872         int style;
4873         int islight;
4874         int skin;
4875         int pflags;
4876         //int effects;
4877         int type;
4878         int n;
4879         char *entfiledata;
4880         const char *data;
4881         float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
4882         char key[256], value[MAX_INPUTLINE];
4883
4884         if (cl.worldmodel == NULL)
4885         {
4886                 Con_Print("No map loaded.\n");
4887                 return;
4888         }
4889         // try to load a .ent file first
4890         FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
4891         strlcat (key, ".ent", sizeof (key));
4892         data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
4893         // and if that is not found, fall back to the bsp file entity string
4894         if (!data)
4895                 data = cl.worldmodel->brush.entities;
4896         if (!data)
4897                 return;
4898         for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
4899         {
4900                 type = LIGHTTYPE_MINUSX;
4901                 origin[0] = origin[1] = origin[2] = 0;
4902                 originhack[0] = originhack[1] = originhack[2] = 0;
4903                 angles[0] = angles[1] = angles[2] = 0;
4904                 color[0] = color[1] = color[2] = 1;
4905                 light[0] = light[1] = light[2] = 1;light[3] = 300;
4906                 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
4907                 fadescale = 1;
4908                 lightscale = 1;
4909                 style = 0;
4910                 skin = 0;
4911                 pflags = 0;
4912                 //effects = 0;
4913                 islight = false;
4914                 while (1)
4915                 {
4916                         if (!COM_ParseToken_Simple(&data, false, false))
4917                                 break; // error
4918                         if (com_token[0] == '}')
4919                                 break; // end of entity
4920                         if (com_token[0] == '_')
4921                                 strlcpy(key, com_token + 1, sizeof(key));
4922                         else
4923                                 strlcpy(key, com_token, sizeof(key));
4924                         while (key[strlen(key)-1] == ' ') // remove trailing spaces
4925                                 key[strlen(key)-1] = 0;
4926                         if (!COM_ParseToken_Simple(&data, false, false))
4927                                 break; // error
4928                         strlcpy(value, com_token, sizeof(value));
4929
4930                         // now that we have the key pair worked out...
4931                         if (!strcmp("light", key))
4932                         {
4933                                 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
4934                                 if (n == 1)
4935                                 {
4936                                         // quake
4937                                         light[0] = vec[0] * (1.0f / 256.0f);
4938                                         light[1] = vec[0] * (1.0f / 256.0f);
4939                                         light[2] = vec[0] * (1.0f / 256.0f);
4940                                         light[3] = vec[0];
4941                                 }
4942                                 else if (n == 4)
4943                                 {
4944                                         // halflife
4945                                         light[0] = vec[0] * (1.0f / 255.0f);
4946                                         light[1] = vec[1] * (1.0f / 255.0f);
4947                                         light[2] = vec[2] * (1.0f / 255.0f);
4948                                         light[3] = vec[3];
4949                                 }
4950                         }
4951                         else if (!strcmp("delay", key))
4952                                 type = atoi(value);
4953                         else if (!strcmp("origin", key))
4954                                 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
4955                         else if (!strcmp("angle", key))
4956                                 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
4957                         else if (!strcmp("angles", key))
4958                                 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
4959                         else if (!strcmp("color", key))
4960                                 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
4961                         else if (!strcmp("wait", key))
4962                                 fadescale = atof(value);
4963                         else if (!strcmp("classname", key))
4964                         {
4965                                 if (!strncmp(value, "light", 5))
4966                                 {
4967                                         islight = true;
4968                                         if (!strcmp(value, "light_fluoro"))
4969                                         {
4970                                                 originhack[0] = 0;
4971                                                 originhack[1] = 0;
4972                                                 originhack[2] = 0;
4973                                                 overridecolor[0] = 1;
4974                                                 overridecolor[1] = 1;
4975                                                 overridecolor[2] = 1;
4976                                         }
4977                                         if (!strcmp(value, "light_fluorospark"))
4978                                         {
4979                                                 originhack[0] = 0;
4980                                                 originhack[1] = 0;
4981                                                 originhack[2] = 0;
4982                                                 overridecolor[0] = 1;
4983                                                 overridecolor[1] = 1;
4984                                                 overridecolor[2] = 1;
4985                                         }
4986                                         if (!strcmp(value, "light_globe"))
4987                                         {
4988                                                 originhack[0] = 0;
4989                                                 originhack[1] = 0;
4990                                                 originhack[2] = 0;
4991                                                 overridecolor[0] = 1;
4992                                                 overridecolor[1] = 0.8;
4993                                                 overridecolor[2] = 0.4;
4994                                         }
4995                                         if (!strcmp(value, "light_flame_large_yellow"))
4996                                         {
4997                                                 originhack[0] = 0;
4998                                                 originhack[1] = 0;
4999                                                 originhack[2] = 0;
5000                                                 overridecolor[0] = 1;
5001                                                 overridecolor[1] = 0.5;
5002                                                 overridecolor[2] = 0.1;
5003                                         }
5004                                         if (!strcmp(value, "light_flame_small_yellow"))
5005                                         {
5006                                                 originhack[0] = 0;
5007                                                 originhack[1] = 0;
5008                                                 originhack[2] = 0;
5009                                                 overridecolor[0] = 1;
5010                                                 overridecolor[1] = 0.5;
5011                                                 overridecolor[2] = 0.1;
5012                                         }
5013                                         if (!strcmp(value, "light_torch_small_white"))
5014                                         {
5015                                                 originhack[0] = 0;
5016                                                 originhack[1] = 0;
5017                                                 originhack[2] = 0;
5018                                                 overridecolor[0] = 1;
5019                                                 overridecolor[1] = 0.5;
5020                                                 overridecolor[2] = 0.1;
5021                                         }
5022                                         if (!strcmp(value, "light_torch_small_walltorch"))
5023                                         {
5024                                                 originhack[0] = 0;
5025                                                 originhack[1] = 0;
5026                                                 originhack[2] = 0;
5027                                                 overridecolor[0] = 1;
5028                                                 overridecolor[1] = 0.5;
5029                                                 overridecolor[2] = 0.1;
5030                                         }
5031                                 }
5032                         }
5033                         else if (!strcmp("style", key))
5034                                 style = atoi(value);
5035                         else if (!strcmp("skin", key))
5036                                 skin = (int)atof(value);
5037                         else if (!strcmp("pflags", key))
5038                                 pflags = (int)atof(value);
5039                         //else if (!strcmp("effects", key))
5040                         //      effects = (int)atof(value);
5041                         else if (cl.worldmodel->type == mod_brushq3)
5042                         {
5043                                 if (!strcmp("scale", key))
5044                                         lightscale = atof(value);
5045                                 if (!strcmp("fade", key))
5046                                         fadescale = atof(value);
5047                         }
5048                 }
5049                 if (!islight)
5050                         continue;
5051                 if (lightscale <= 0)
5052                         lightscale = 1;
5053                 if (fadescale <= 0)
5054                         fadescale = 1;
5055                 if (color[0] == color[1] && color[0] == color[2])
5056                 {
5057                         color[0] *= overridecolor[0];
5058                         color[1] *= overridecolor[1];
5059                         color[2] *= overridecolor[2];
5060                 }
5061                 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5062                 color[0] = color[0] * light[0];
5063                 color[1] = color[1] * light[1];
5064                 color[2] = color[2] * light[2];
5065                 switch (type)
5066                 {
5067                 case LIGHTTYPE_MINUSX:
5068                         break;
5069                 case LIGHTTYPE_RECIPX:
5070                         radius *= 2;
5071                         VectorScale(color, (1.0f / 16.0f), color);
5072                         break;
5073                 case LIGHTTYPE_RECIPXX:
5074                         radius *= 2;
5075                         VectorScale(color, (1.0f / 16.0f), color);
5076                         break;
5077                 default:
5078                 case LIGHTTYPE_NONE:
5079                         break;
5080                 case LIGHTTYPE_SUN:
5081                         break;
5082                 case LIGHTTYPE_MINUSXX:
5083                         break;
5084                 }
5085                 VectorAdd(origin, originhack, origin);
5086                 if (radius >= 1)
5087                         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);
5088         }
5089         if (entfiledata)
5090                 Mem_Free(entfiledata);
5091 }
5092
5093
5094 void R_Shadow_SetCursorLocationForView(void)
5095 {
5096         vec_t dist, push;
5097         vec3_t dest, endpos;
5098         trace_t trace;
5099         VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5100         trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5101         if (trace.fraction < 1)
5102         {
5103                 dist = trace.fraction * r_editlights_cursordistance.value;
5104                 push = r_editlights_cursorpushback.value;
5105                 if (push > dist)
5106                         push = dist;
5107                 push = -push;
5108                 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5109                 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5110         }
5111         else
5112         {
5113                 VectorClear( endpos );
5114         }
5115         r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5116         r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5117         r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5118 }
5119
5120 void R_Shadow_UpdateWorldLightSelection(void)
5121 {
5122         if (r_editlights.integer)
5123         {
5124                 R_Shadow_SetCursorLocationForView();
5125                 R_Shadow_SelectLightInView();
5126         }
5127         else
5128                 R_Shadow_SelectLight(NULL);
5129 }
5130
5131 void R_Shadow_EditLights_Clear_f(void)
5132 {
5133         R_Shadow_ClearWorldLights();
5134 }
5135
5136 void R_Shadow_EditLights_Reload_f(void)
5137 {
5138         if (!cl.worldmodel)
5139                 return;
5140         strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
5141         R_Shadow_ClearWorldLights();
5142         R_Shadow_LoadWorldLights();
5143         if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5144         {
5145                 R_Shadow_LoadLightsFile();
5146                 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5147                         R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5148         }
5149 }
5150
5151 void R_Shadow_EditLights_Save_f(void)
5152 {
5153         if (!cl.worldmodel)
5154                 return;
5155         R_Shadow_SaveWorldLights();
5156 }
5157
5158 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5159 {
5160         R_Shadow_ClearWorldLights();
5161         R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5162 }
5163
5164 void R_Shadow_EditLights_ImportLightsFile_f(void)
5165 {
5166         R_Shadow_ClearWorldLights();
5167         R_Shadow_LoadLightsFile();
5168 }
5169
5170 void R_Shadow_EditLights_Spawn_f(void)
5171 {
5172         vec3_t color;
5173         if (!r_editlights.integer)
5174         {
5175                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
5176                 return;
5177         }
5178         if (Cmd_Argc() != 1)
5179         {
5180                 Con_Print("r_editlights_spawn does not take parameters\n");
5181                 return;
5182         }
5183         color[0] = color[1] = color[2] = 1;
5184         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5185 }
5186
5187 void R_Shadow_EditLights_Edit_f(void)
5188 {
5189         vec3_t origin, angles, color;
5190         vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5191         int style, shadows, flags, normalmode, realtimemode;
5192         char cubemapname[MAX_INPUTLINE];
5193         if (!r_editlights.integer)
5194         {
5195                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
5196                 return;
5197         }
5198         if (!r_shadow_selectedlight)
5199         {
5200                 Con_Print("No selected light.\n");
5201                 return;
5202         }
5203         VectorCopy(r_shadow_selectedlight->origin, origin);
5204         VectorCopy(r_shadow_selectedlight->angles, angles);
5205         VectorCopy(r_shadow_selectedlight->color, color);
5206         radius = r_shadow_selectedlight->radius;
5207         style = r_shadow_selectedlight->style;
5208         if (r_shadow_selectedlight->cubemapname)
5209                 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5210         else
5211                 cubemapname[0] = 0;
5212         shadows = r_shadow_selectedlight->shadow;
5213         corona = r_shadow_selectedlight->corona;
5214         coronasizescale = r_shadow_selectedlight->coronasizescale;
5215         ambientscale = r_shadow_selectedlight->ambientscale;
5216         diffusescale = r_shadow_selectedlight->diffusescale;
5217         specularscale = r_shadow_selectedlight->specularscale;
5218         flags = r_shadow_selectedlight->flags;
5219         normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5220         realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5221         if (!strcmp(Cmd_Argv(1), "origin"))
5222         {
5223                 if (Cmd_Argc() != 5)
5224                 {
5225                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5226                         return;
5227                 }
5228                 origin[0] = atof(Cmd_Argv(2));
5229                 origin[1] = atof(Cmd_Argv(3));
5230                 origin[2] = atof(Cmd_Argv(4));
5231         }
5232         else if (!strcmp(Cmd_Argv(1), "originx"))
5233         {
5234                 if (Cmd_Argc() != 3)
5235                 {
5236                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5237                         return;
5238                 }
5239                 origin[0] = atof(Cmd_Argv(2));
5240         }
5241         else if (!strcmp(Cmd_Argv(1), "originy"))
5242         {
5243                 if (Cmd_Argc() != 3)
5244                 {
5245                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5246                         return;
5247                 }
5248                 origin[1] = atof(Cmd_Argv(2));
5249         }
5250         else if (!strcmp(Cmd_Argv(1), "originz"))
5251         {
5252                 if (Cmd_Argc() != 3)
5253                 {
5254                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5255                         return;
5256                 }
5257                 origin[2] = atof(Cmd_Argv(2));
5258         }
5259         else if (!strcmp(Cmd_Argv(1), "move"))
5260         {
5261                 if (Cmd_Argc() != 5)
5262                 {
5263                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5264                         return;
5265                 }
5266                 origin[0] += atof(Cmd_Argv(2));
5267                 origin[1] += atof(Cmd_Argv(3));
5268                 origin[2] += atof(Cmd_Argv(4));
5269         }
5270         else if (!strcmp(Cmd_Argv(1), "movex"))
5271         {
5272                 if (Cmd_Argc() != 3)
5273                 {
5274                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5275                         return;
5276                 }
5277                 origin[0] += atof(Cmd_Argv(2));
5278         }
5279         else if (!strcmp(Cmd_Argv(1), "movey"))
5280         {
5281                 if (Cmd_Argc() != 3)
5282                 {
5283                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5284                         return;
5285                 }
5286                 origin[1] += atof(Cmd_Argv(2));
5287         }
5288         else if (!strcmp(Cmd_Argv(1), "movez"))
5289         {
5290                 if (Cmd_Argc() != 3)
5291                 {
5292                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5293                         return;
5294                 }
5295                 origin[2] += atof(Cmd_Argv(2));
5296         }
5297         else if (!strcmp(Cmd_Argv(1), "angles"))
5298         {
5299                 if (Cmd_Argc() != 5)
5300                 {
5301                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5302                         return;
5303                 }
5304                 angles[0] = atof(Cmd_Argv(2));
5305                 angles[1] = atof(Cmd_Argv(3));
5306                 angles[2] = atof(Cmd_Argv(4));
5307         }
5308         else if (!strcmp(Cmd_Argv(1), "anglesx"))
5309         {
5310                 if (Cmd_Argc() != 3)
5311                 {
5312                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5313                         return;
5314                 }
5315                 angles[0] = atof(Cmd_Argv(2));
5316         }
5317         else if (!strcmp(Cmd_Argv(1), "anglesy"))
5318         {
5319                 if (Cmd_Argc() != 3)
5320                 {
5321                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5322                         return;
5323                 }
5324                 angles[1] = atof(Cmd_Argv(2));
5325         }
5326         else if (!strcmp(Cmd_Argv(1), "anglesz"))
5327         {
5328                 if (Cmd_Argc() != 3)
5329                 {
5330                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5331                         return;
5332                 }
5333                 angles[2] = atof(Cmd_Argv(2));
5334         }
5335         else if (!strcmp(Cmd_Argv(1), "color"))
5336         {
5337                 if (Cmd_Argc() != 5)
5338                 {
5339                         Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5340                         return;
5341                 }
5342                 color[0] = atof(Cmd_Argv(2));
5343                 color[1] = atof(Cmd_Argv(3));
5344                 color[2] = atof(Cmd_Argv(4));
5345         }
5346         else if (!strcmp(Cmd_Argv(1), "radius"))
5347         {
5348                 if (Cmd_Argc() != 3)
5349                 {
5350                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5351                         return;
5352                 }
5353                 radius = atof(Cmd_Argv(2));
5354         }
5355         else if (!strcmp(Cmd_Argv(1), "colorscale"))
5356         {
5357                 if (Cmd_Argc() == 3)
5358                 {
5359                         double scale = atof(Cmd_Argv(2));
5360                         color[0] *= scale;
5361                         color[1] *= scale;
5362                         color[2] *= scale;
5363                 }
5364                 else
5365                 {
5366                         if (Cmd_Argc() != 5)
5367                         {
5368                                 Con_Printf("usage: r_editlights_edit %s red green blue  (OR grey instead of red green blue)\n", Cmd_Argv(1));
5369                                 return;
5370                         }
5371                         color[0] *= atof(Cmd_Argv(2));
5372                         color[1] *= atof(Cmd_Argv(3));
5373                         color[2] *= atof(Cmd_Argv(4));
5374                 }
5375         }
5376         else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5377         {
5378                 if (Cmd_Argc() != 3)
5379                 {
5380                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5381                         return;
5382                 }
5383                 radius *= atof(Cmd_Argv(2));
5384         }
5385         else if (!strcmp(Cmd_Argv(1), "style"))
5386         {
5387                 if (Cmd_Argc() != 3)
5388                 {
5389                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5390                         return;
5391                 }
5392                 style = atoi(Cmd_Argv(2));
5393         }
5394         else if (!strcmp(Cmd_Argv(1), "cubemap"))
5395         {
5396                 if (Cmd_Argc() > 3)
5397                 {
5398                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5399                         return;
5400                 }
5401                 if (Cmd_Argc() == 3)
5402                         strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5403                 else
5404                         cubemapname[0] = 0;
5405         }
5406         else if (!strcmp(Cmd_Argv(1), "shadows"))
5407         {
5408                 if (Cmd_Argc() != 3)
5409                 {
5410                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5411                         return;
5412                 }
5413                 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5414         }
5415         else if (!strcmp(Cmd_Argv(1), "corona"))
5416         {
5417                 if (Cmd_Argc() != 3)
5418                 {
5419                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5420                         return;
5421                 }
5422                 corona = atof(Cmd_Argv(2));
5423         }
5424         else if (!strcmp(Cmd_Argv(1), "coronasize"))
5425         {
5426                 if (Cmd_Argc() != 3)
5427                 {
5428                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5429                         return;
5430                 }
5431                 coronasizescale = atof(Cmd_Argv(2));
5432         }
5433         else if (!strcmp(Cmd_Argv(1), "ambient"))
5434         {
5435                 if (Cmd_Argc() != 3)
5436                 {
5437                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5438                         return;
5439                 }
5440                 ambientscale = atof(Cmd_Argv(2));
5441         }
5442         else if (!strcmp(Cmd_Argv(1), "diffuse"))
5443         {
5444                 if (Cmd_Argc() != 3)
5445                 {
5446                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5447                         return;
5448                 }
5449                 diffusescale = atof(Cmd_Argv(2));
5450         }
5451         else if (!strcmp(Cmd_Argv(1), "specular"))
5452         {
5453                 if (Cmd_Argc() != 3)
5454                 {
5455                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5456                         return;
5457                 }
5458                 specularscale = atof(Cmd_Argv(2));
5459         }
5460         else if (!strcmp(Cmd_Argv(1), "normalmode"))
5461         {
5462                 if (Cmd_Argc() != 3)
5463                 {
5464                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5465                         return;
5466                 }
5467                 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5468         }
5469         else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5470         {
5471                 if (Cmd_Argc() != 3)
5472                 {
5473                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5474                         return;
5475                 }
5476                 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5477         }
5478         else
5479         {
5480                 Con_Print("usage: r_editlights_edit [property] [value]\n");
5481                 Con_Print("Selected light's properties:\n");
5482                 Con_Printf("Origin       : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5483                 Con_Printf("Angles       : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5484                 Con_Printf("Color        : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5485                 Con_Printf("Radius       : %f\n", r_shadow_selectedlight->radius);
5486                 Con_Printf("Corona       : %f\n", r_shadow_selectedlight->corona);
5487                 Con_Printf("Style        : %i\n", r_shadow_selectedlight->style);
5488                 Con_Printf("Shadows      : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5489                 Con_Printf("Cubemap      : %s\n", r_shadow_selectedlight->cubemapname);
5490                 Con_Printf("CoronaSize   : %f\n", r_shadow_selectedlight->coronasizescale);
5491                 Con_Printf("Ambient      : %f\n", r_shadow_selectedlight->ambientscale);
5492                 Con_Printf("Diffuse      : %f\n", r_shadow_selectedlight->diffusescale);
5493                 Con_Printf("Specular     : %f\n", r_shadow_selectedlight->specularscale);
5494                 Con_Printf("NormalMode   : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5495                 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5496                 return;
5497         }
5498         flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5499         R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5500 }
5501
5502 void R_Shadow_EditLights_EditAll_f(void)
5503 {
5504         size_t lightindex;
5505         dlight_t *light;
5506         size_t range;
5507
5508         if (!r_editlights.integer)
5509         {
5510                 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5511                 return;
5512         }
5513
5514         // EditLights doesn't seem to have a "remove" command or something so:
5515         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5516         for (lightindex = 0;lightindex < range;lightindex++)
5517         {
5518                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5519                 if (!light)
5520                         continue;
5521                 R_Shadow_SelectLight(light);
5522                 R_Shadow_EditLights_Edit_f();
5523         }
5524 }
5525
5526 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5527 {
5528         int lightnumber, lightcount;
5529         size_t lightindex, range;
5530         dlight_t *light;
5531         float x, y;
5532         char temp[256];
5533         if (!r_editlights.integer)
5534                 return;
5535         x = vid_conwidth.value - 240;
5536         y = 5;
5537         DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5538         lightnumber = -1;
5539         lightcount = 0;
5540         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5541         for (lightindex = 0;lightindex < range;lightindex++)
5542         {
5543                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5544                 if (!light)
5545                         continue;
5546                 if (light == r_shadow_selectedlight)
5547                         lightnumber = lightindex;
5548                 lightcount++;
5549         }
5550         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;
5551         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;
5552         y += 8;
5553         if (r_shadow_selectedlight == NULL)
5554                 return;
5555         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;
5556         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;
5557         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;
5558         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;
5559         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;
5560         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;
5561         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;
5562         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;
5563         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;
5564         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;
5565         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;
5566         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;
5567         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;
5568         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;
5569         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;
5570 }
5571
5572 void R_Shadow_EditLights_ToggleShadow_f(void)
5573 {
5574         if (!r_editlights.integer)
5575         {
5576                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
5577                 return;
5578         }
5579         if (!r_shadow_selectedlight)
5580         {
5581                 Con_Print("No selected light.\n");
5582                 return;
5583         }
5584         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);
5585 }
5586
5587 void R_Shadow_EditLights_ToggleCorona_f(void)
5588 {
5589         if (!r_editlights.integer)
5590         {
5591                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
5592                 return;
5593         }
5594         if (!r_shadow_selectedlight)
5595         {
5596                 Con_Print("No selected light.\n");
5597                 return;
5598         }
5599         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);
5600 }
5601
5602 void R_Shadow_EditLights_Remove_f(void)
5603 {
5604         if (!r_editlights.integer)
5605         {
5606                 Con_Print("Cannot remove light when not in editing mode.  Set r_editlights to 1.\n");
5607                 return;
5608         }
5609         if (!r_shadow_selectedlight)
5610         {
5611                 Con_Print("No selected light.\n");
5612                 return;
5613         }
5614         R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5615         r_shadow_selectedlight = NULL;
5616 }
5617
5618 void R_Shadow_EditLights_Help_f(void)
5619 {
5620         Con_Print(
5621 "Documentation on r_editlights system:\n"
5622 "Settings:\n"
5623 "r_editlights : enable/disable editing mode\n"
5624 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5625 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5626 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5627 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5628 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5629 "Commands:\n"
5630 "r_editlights_help : this help\n"
5631 "r_editlights_clear : remove all lights\n"
5632 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5633 "r_editlights_save : save to .rtlights file\n"
5634 "r_editlights_spawn : create a light with default settings\n"
5635 "r_editlights_edit command : edit selected light - more documentation below\n"
5636 "r_editlights_remove : remove selected light\n"
5637 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5638 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5639 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5640 "Edit commands:\n"
5641 "origin x y z : set light location\n"
5642 "originx x: set x component of light location\n"
5643 "originy y: set y component of light location\n"
5644 "originz z: set z component of light location\n"
5645 "move x y z : adjust light location\n"
5646 "movex x: adjust x component of light location\n"
5647 "movey y: adjust y component of light location\n"
5648 "movez z: adjust z component of light location\n"
5649 "angles x y z : set light angles\n"
5650 "anglesx x: set x component of light angles\n"
5651 "anglesy y: set y component of light angles\n"
5652 "anglesz z: set z component of light angles\n"
5653 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5654 "radius radius : set radius (size) of light\n"
5655 "colorscale grey : multiply color of light (1 does nothing)\n"
5656 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5657 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5658 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5659 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5660 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5661 "shadows 1/0 : turn on/off shadows\n"
5662 "corona n : set corona intensity\n"
5663 "coronasize n : set corona size (0-1)\n"
5664 "ambient n : set ambient intensity (0-1)\n"
5665 "diffuse n : set diffuse intensity (0-1)\n"
5666 "specular n : set specular intensity (0-1)\n"
5667 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5668 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5669 "<nothing> : print light properties to console\n"
5670         );
5671 }
5672
5673 void R_Shadow_EditLights_CopyInfo_f(void)
5674 {
5675         if (!r_editlights.integer)
5676         {
5677                 Con_Print("Cannot copy light info when not in editing mode.  Set r_editlights to 1.\n");
5678                 return;
5679         }
5680         if (!r_shadow_selectedlight)
5681         {
5682                 Con_Print("No selected light.\n");
5683                 return;
5684         }
5685         VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5686         VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5687         r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5688         r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5689         if (r_shadow_selectedlight->cubemapname)
5690                 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5691         else
5692                 r_shadow_bufferlight.cubemapname[0] = 0;
5693         r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5694         r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5695         r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5696         r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5697         r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5698         r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5699         r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5700 }
5701
5702 void R_Shadow_EditLights_PasteInfo_f(void)
5703 {
5704         if (!r_editlights.integer)
5705         {
5706                 Con_Print("Cannot paste light info when not in editing mode.  Set r_editlights to 1.\n");
5707                 return;
5708         }
5709         if (!r_shadow_selectedlight)
5710         {
5711                 Con_Print("No selected light.\n");
5712                 return;
5713         }
5714         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);
5715 }
5716
5717 void R_Shadow_EditLights_Init(void)
5718 {
5719         Cvar_RegisterVariable(&r_editlights);
5720         Cvar_RegisterVariable(&r_editlights_cursordistance);
5721         Cvar_RegisterVariable(&r_editlights_cursorpushback);
5722         Cvar_RegisterVariable(&r_editlights_cursorpushoff);
5723         Cvar_RegisterVariable(&r_editlights_cursorgrid);
5724         Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
5725         Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
5726         Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
5727         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)");
5728         Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
5729         Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
5730         Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
5731         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)");
5732         Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
5733         Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
5734         Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
5735         Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
5736         Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
5737         Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
5738         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)");
5739 }
5740
5741
5742
5743 /*
5744 =============================================================================
5745
5746 LIGHT SAMPLING
5747
5748 =============================================================================
5749 */
5750
5751 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
5752 {
5753         VectorClear(diffusecolor);
5754         VectorClear(diffusenormal);
5755
5756         if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
5757         {
5758                 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient;
5759                 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
5760         }
5761         else
5762                 VectorSet(ambientcolor, 1, 1, 1);
5763
5764         if (dynamic)
5765         {
5766                 int i;
5767                 float f, v[3];
5768                 rtlight_t *light;
5769                 for (i = 0;i < r_refdef.scene.numlights;i++)
5770                 {
5771                         light = r_refdef.scene.lights[i];
5772                         Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
5773                         f = 1 - VectorLength2(v);
5774                         if (f > 0 && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
5775                                 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);
5776                 }
5777         }
5778 }