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