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