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