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