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