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