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