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