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