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