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