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