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