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