65a54f763369f987ac2b2042803d506f10f01a29
[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 float r_shadow_shadowmap_bias;
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 GLuint r_shadow_fborectangle;
180 GLuint r_shadow_fbocubeside[R_SHADOW_SHADOWMAP_NUMCUBEMAPS][6];
181 GLuint r_shadow_fbo2d;
182 int r_shadow_shadowmode;
183 int r_shadow_shadowmapmaxsize;
184 int r_shadow_lightscissor[4];
185
186 int maxshadowtriangles;
187 int *shadowelements;
188
189 int maxshadowvertices;
190 float *shadowvertex3f;
191
192 int maxshadowmark;
193 int numshadowmark;
194 int *shadowmark;
195 int *shadowmarklist;
196 int shadowmarkcount;
197
198 int maxvertexupdate;
199 int *vertexupdate;
200 int *vertexremap;
201 int vertexupdatenum;
202
203 int r_shadow_buffer_numleafpvsbytes;
204 unsigned char *r_shadow_buffer_visitingleafpvs;
205 unsigned char *r_shadow_buffer_leafpvs;
206 int *r_shadow_buffer_leaflist;
207
208 int r_shadow_buffer_numsurfacepvsbytes;
209 unsigned char *r_shadow_buffer_surfacepvs;
210 int *r_shadow_buffer_surfacelist;
211
212 int r_shadow_buffer_numshadowtrispvsbytes;
213 unsigned char *r_shadow_buffer_shadowtrispvs;
214 int r_shadow_buffer_numlighttrispvsbytes;
215 unsigned char *r_shadow_buffer_lighttrispvs;
216
217 rtexturepool_t *r_shadow_texturepool;
218 rtexture_t *r_shadow_attenuationgradienttexture;
219 rtexture_t *r_shadow_attenuation2dtexture;
220 rtexture_t *r_shadow_attenuation3dtexture;
221 rtexture_t *r_shadow_lightcorona;
222 rtexture_t *r_shadow_shadowmaprectangletexture;
223 rtexture_t *r_shadow_shadowmap2dtexture;
224 rtexture_t *r_shadow_shadowmapcubeprojectiontexture;
225 rtexture_t *r_shadow_shadowmapcubetexture[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
226 int r_shadow_shadowmapsize; // changes for each light based on distance
227 int r_shadow_shadowmaplod; // changes for each light based on distance
228
229 // lights are reloaded when this changes
230 char r_shadow_mapname[MAX_QPATH];
231
232 // used only for light filters (cubemaps)
233 rtexturepool_t *r_shadow_filters_texturepool;
234
235 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"};
236 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"};
237 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
238 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
239 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)"};
240 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"};
241 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
242 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
243 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
244 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
245 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
246 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
247 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
248 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"};
249 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000", "how far to cast shadows"};
250 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)"};
251 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
252 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
253 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
254 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
255 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)"};
256 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"};
257 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
258 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
259 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"};
260 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation"};
261 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation"};
262 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)"};
263 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"};
264 cvar_t r_shadow_shadowmapping_filterquality = {CVAR_SAVE, "r_shadow_shadowmapping_filterquality", "0", "shadowmap filter modes: 0 = no filtering, 1 = bilinear, 2 = bilinear small blur (fast), 3 = bilinear large blur (slow)"};
265 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
266 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "1024", "shadowmap size limit"};
267 cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
268 cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
269 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "6", "shadowmap size bias for filtering"};
270 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
271 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
272 cvar_t r_shadow_culltriangles = {0, "r_shadow_culltriangles", "1", "performs more expensive tests to remove unnecessary triangles of lit surfaces"};
273 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
274 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)"};
275 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)"};
276 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
277 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"};
278 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
279 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
280 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
281 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
282 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
283 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
284 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
285 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
286 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
287 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
288
289 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
290 #define ATTENTABLESIZE 256
291 // 1D gradient, 2D circle and 3D sphere attenuation textures
292 #define ATTEN1DSIZE 32
293 #define ATTEN2DSIZE 64
294 #define ATTEN3DSIZE 32
295
296 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
297 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
298 static float r_shadow_attentable[ATTENTABLESIZE+1];
299
300 rtlight_t *r_shadow_compilingrtlight;
301 static memexpandablearray_t r_shadow_worldlightsarray;
302 dlight_t *r_shadow_selectedlight;
303 dlight_t r_shadow_bufferlight;
304 vec3_t r_editlights_cursorlocation;
305
306 extern int con_vislines;
307
308 typedef struct cubemapinfo_s
309 {
310         char basename[64];
311         rtexture_t *texture;
312 }
313 cubemapinfo_t;
314
315 #define MAX_CUBEMAPS 256
316 static int numcubemaps;
317 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
318
319 void R_Shadow_UncompileWorldLights(void);
320 void R_Shadow_ClearWorldLights(void);
321 void R_Shadow_SaveWorldLights(void);
322 void R_Shadow_LoadWorldLights(void);
323 void R_Shadow_LoadLightsFile(void);
324 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
325 void R_Shadow_EditLights_Reload_f(void);
326 void R_Shadow_ValidateCvars(void);
327 static void R_Shadow_MakeTextures(void);
328
329 // VorteX: custom editor light sprites
330 #define EDLIGHTSPRSIZE                  8
331 cachepic_t *r_editlights_sprcursor;
332 cachepic_t *r_editlights_sprlight;
333 cachepic_t *r_editlights_sprnoshadowlight;
334 cachepic_t *r_editlights_sprcubemaplight;
335 cachepic_t *r_editlights_sprcubemapnoshadowlight;
336 cachepic_t *r_editlights_sprselection;
337
338 void R_Shadow_FreeShadowMaps(void)
339 {
340         int i;
341
342         r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, 2048);
343         r_shadow_shadowmode = r_shadow_shadowmapping.integer;
344         r_shadow_shadowmaplod = -1;
345
346         CHECKGLERROR
347         if (r_shadow_fborectangle)
348                 qglDeleteFramebuffersEXT(1, &r_shadow_fborectangle);
349         r_shadow_fborectangle = 0;
350         CHECKGLERROR
351
352         if (r_shadow_fbo2d)
353                 qglDeleteFramebuffersEXT(1, &r_shadow_fbo2d);
354         r_shadow_fbo2d = 0;
355         CHECKGLERROR
356
357         for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
358                 if (r_shadow_fbocubeside[i][0])
359                         qglDeleteFramebuffersEXT(6, r_shadow_fbocubeside[i]);
360         memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
361         CHECKGLERROR
362
363         if (r_shadow_shadowmaprectangletexture)
364                 R_FreeTexture(r_shadow_shadowmaprectangletexture);
365         r_shadow_shadowmaprectangletexture = NULL;
366
367         if (r_shadow_shadowmap2dtexture)
368                 R_FreeTexture(r_shadow_shadowmap2dtexture);
369         r_shadow_shadowmap2dtexture = NULL;
370
371         if (r_shadow_shadowmapcubeprojectiontexture)
372                 R_FreeTexture(r_shadow_shadowmapcubeprojectiontexture);
373         r_shadow_shadowmapcubeprojectiontexture = NULL;
374
375         for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
376                 if (r_shadow_shadowmapcubetexture[i])
377                         R_FreeTexture(r_shadow_shadowmapcubetexture[i]);
378         memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
379
380         CHECKGLERROR
381 }
382
383 void r_shadow_start(void)
384 {
385         // allocate vertex processing arrays
386         numcubemaps = 0;
387         r_shadow_attenuationgradienttexture = NULL;
388         r_shadow_attenuation2dtexture = NULL;
389         r_shadow_attenuation3dtexture = NULL;
390         r_shadow_shadowmaprectangletexture = NULL;
391         memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
392         r_shadow_shadowmapcubeprojectiontexture = NULL;
393         r_shadow_shadowmap2dtexture = NULL;
394         r_shadow_shadowmapmaxsize = 0;
395         r_shadow_shadowmapsize = 0;
396         r_shadow_shadowmaplod = 0;
397         r_shadow_fborectangle = 0;
398         memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
399         r_shadow_fbo2d = 0;
400
401         R_Shadow_FreeShadowMaps();
402
403         r_shadow_texturepool = NULL;
404         r_shadow_filters_texturepool = NULL;
405         R_Shadow_ValidateCvars();
406         R_Shadow_MakeTextures();
407         maxshadowtriangles = 0;
408         shadowelements = NULL;
409         maxshadowvertices = 0;
410         shadowvertex3f = NULL;
411         maxvertexupdate = 0;
412         vertexupdate = NULL;
413         vertexremap = NULL;
414         vertexupdatenum = 0;
415         maxshadowmark = 0;
416         numshadowmark = 0;
417         shadowmark = NULL;
418         shadowmarklist = NULL;
419         shadowmarkcount = 0;
420         r_shadow_buffer_numleafpvsbytes = 0;
421         r_shadow_buffer_visitingleafpvs = NULL;
422         r_shadow_buffer_leafpvs = NULL;
423         r_shadow_buffer_leaflist = NULL;
424         r_shadow_buffer_numsurfacepvsbytes = 0;
425         r_shadow_buffer_surfacepvs = NULL;
426         r_shadow_buffer_surfacelist = NULL;
427         r_shadow_buffer_numshadowtrispvsbytes = 0;
428         r_shadow_buffer_shadowtrispvs = NULL;
429         r_shadow_buffer_numlighttrispvsbytes = 0;
430         r_shadow_buffer_lighttrispvs = NULL;
431 }
432
433 void r_shadow_shutdown(void)
434 {
435         CHECKGLERROR
436         R_Shadow_UncompileWorldLights();
437
438         R_Shadow_FreeShadowMaps();
439
440         CHECKGLERROR
441         numcubemaps = 0;
442         r_shadow_attenuationgradienttexture = NULL;
443         r_shadow_attenuation2dtexture = NULL;
444         r_shadow_attenuation3dtexture = NULL;
445         R_FreeTexturePool(&r_shadow_texturepool);
446         R_FreeTexturePool(&r_shadow_filters_texturepool);
447         maxshadowtriangles = 0;
448         if (shadowelements)
449                 Mem_Free(shadowelements);
450         shadowelements = NULL;
451         if (shadowvertex3f)
452                 Mem_Free(shadowvertex3f);
453         shadowvertex3f = NULL;
454         maxvertexupdate = 0;
455         if (vertexupdate)
456                 Mem_Free(vertexupdate);
457         vertexupdate = NULL;
458         if (vertexremap)
459                 Mem_Free(vertexremap);
460         vertexremap = NULL;
461         vertexupdatenum = 0;
462         maxshadowmark = 0;
463         numshadowmark = 0;
464         if (shadowmark)
465                 Mem_Free(shadowmark);
466         shadowmark = NULL;
467         if (shadowmarklist)
468                 Mem_Free(shadowmarklist);
469         shadowmarklist = NULL;
470         shadowmarkcount = 0;
471         r_shadow_buffer_numleafpvsbytes = 0;
472         if (r_shadow_buffer_visitingleafpvs)
473                 Mem_Free(r_shadow_buffer_visitingleafpvs);
474         r_shadow_buffer_visitingleafpvs = NULL;
475         if (r_shadow_buffer_leafpvs)
476                 Mem_Free(r_shadow_buffer_leafpvs);
477         r_shadow_buffer_leafpvs = NULL;
478         if (r_shadow_buffer_leaflist)
479                 Mem_Free(r_shadow_buffer_leaflist);
480         r_shadow_buffer_leaflist = NULL;
481         r_shadow_buffer_numsurfacepvsbytes = 0;
482         if (r_shadow_buffer_surfacepvs)
483                 Mem_Free(r_shadow_buffer_surfacepvs);
484         r_shadow_buffer_surfacepvs = NULL;
485         if (r_shadow_buffer_surfacelist)
486                 Mem_Free(r_shadow_buffer_surfacelist);
487         r_shadow_buffer_surfacelist = NULL;
488         r_shadow_buffer_numshadowtrispvsbytes = 0;
489         if (r_shadow_buffer_shadowtrispvs)
490                 Mem_Free(r_shadow_buffer_shadowtrispvs);
491         r_shadow_buffer_numlighttrispvsbytes = 0;
492         if (r_shadow_buffer_lighttrispvs)
493                 Mem_Free(r_shadow_buffer_lighttrispvs);
494 }
495
496 void r_shadow_newmap(void)
497 {
498         if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
499                 R_Shadow_EditLights_Reload_f();
500 }
501
502 void R_Shadow_Help_f(void)
503 {
504         Con_Printf(
505 "Documentation on r_shadow system:\n"
506 "Settings:\n"
507 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
508 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
509 "r_shadow_debuglight : render only this light number (-1 = all)\n"
510 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
511 "r_shadow_gloss2intensity : brightness of forced gloss\n"
512 "r_shadow_glossintensity : brightness of textured gloss\n"
513 "r_shadow_lightattenuationlinearscale : used to generate attenuation texture\n"
514 "r_shadow_lightattenuationdividebias : used to generate attenuation texture\n"
515 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
516 "r_shadow_lightradiusscale : scale rendering radius of all lights\n"
517 "r_shadow_portallight : use portal visibility for static light precomputation\n"
518 "r_shadow_projectdistance : shadow volume projection distance\n"
519 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
520 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
521 "r_shadow_realtime_world : use high quality world lighting mode\n"
522 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
523 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
524 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
525 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
526 "r_shadow_scissor : use scissor optimization\n"
527 "r_shadow_polygonfactor : nudge shadow volumes closer/further\n"
528 "r_shadow_polygonoffset : nudge shadow volumes closer/further\n"
529 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
530 "r_showlighting : useful for performance testing; bright = slow!\n"
531 "r_showshadowvolumes : useful for performance testing; bright = slow!\n"
532 "Commands:\n"
533 "r_shadow_help : this help\n"
534         );
535 }
536
537 void R_Shadow_Init(void)
538 {
539         Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
540         Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
541         Cvar_RegisterVariable(&r_shadow_usenormalmap);
542         Cvar_RegisterVariable(&r_shadow_debuglight);
543         Cvar_RegisterVariable(&r_shadow_gloss);
544         Cvar_RegisterVariable(&r_shadow_gloss2intensity);
545         Cvar_RegisterVariable(&r_shadow_glossintensity);
546         Cvar_RegisterVariable(&r_shadow_glossexponent);
547         Cvar_RegisterVariable(&r_shadow_glossexact);
548         Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
549         Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
550         Cvar_RegisterVariable(&r_shadow_lightintensityscale);
551         Cvar_RegisterVariable(&r_shadow_lightradiusscale);
552         Cvar_RegisterVariable(&r_shadow_portallight);
553         Cvar_RegisterVariable(&r_shadow_projectdistance);
554         Cvar_RegisterVariable(&r_shadow_frontsidecasting);
555         Cvar_RegisterVariable(&r_shadow_realtime_dlight);
556         Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
557         Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
558         Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
559         Cvar_RegisterVariable(&r_shadow_realtime_world);
560         Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
561         Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
562         Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
563         Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
564         Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
565         Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
566         Cvar_RegisterVariable(&r_shadow_scissor);
567         Cvar_RegisterVariable(&r_shadow_shadowmapping);
568         Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
569         Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
570         Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
571         Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
572         Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
573         Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
574         Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
575         Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
576         Cvar_RegisterVariable(&r_shadow_culltriangles);
577         Cvar_RegisterVariable(&r_shadow_polygonfactor);
578         Cvar_RegisterVariable(&r_shadow_polygonoffset);
579         Cvar_RegisterVariable(&r_shadow_texture3d);
580         Cvar_RegisterVariable(&r_coronas);
581         Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
582         Cvar_RegisterVariable(&r_coronas_occlusionquery);
583         Cvar_RegisterVariable(&gl_flashblend);
584         Cvar_RegisterVariable(&gl_ext_separatestencil);
585         Cvar_RegisterVariable(&gl_ext_stenciltwoside);
586         if (gamemode == GAME_TENEBRAE)
587         {
588                 Cvar_SetValue("r_shadow_gloss", 2);
589                 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
590         }
591         Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f, "prints documentation on console commands and variables used by realtime lighting and shadowing system");
592         R_Shadow_EditLights_Init();
593         Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
594         maxshadowtriangles = 0;
595         shadowelements = NULL;
596         maxshadowvertices = 0;
597         shadowvertex3f = NULL;
598         maxvertexupdate = 0;
599         vertexupdate = NULL;
600         vertexremap = NULL;
601         vertexupdatenum = 0;
602         maxshadowmark = 0;
603         numshadowmark = 0;
604         shadowmark = NULL;
605         shadowmarklist = NULL;
606         shadowmarkcount = 0;
607         r_shadow_buffer_numleafpvsbytes = 0;
608         r_shadow_buffer_visitingleafpvs = NULL;
609         r_shadow_buffer_leafpvs = NULL;
610         r_shadow_buffer_leaflist = NULL;
611         r_shadow_buffer_numsurfacepvsbytes = 0;
612         r_shadow_buffer_surfacepvs = NULL;
613         r_shadow_buffer_surfacelist = NULL;
614         r_shadow_buffer_shadowtrispvs = NULL;
615         r_shadow_buffer_lighttrispvs = NULL;
616         R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
617 }
618
619 matrix4x4_t matrix_attenuationxyz =
620 {
621         {
622                 {0.5, 0.0, 0.0, 0.5},
623                 {0.0, 0.5, 0.0, 0.5},
624                 {0.0, 0.0, 0.5, 0.5},
625                 {0.0, 0.0, 0.0, 1.0}
626         }
627 };
628
629 matrix4x4_t matrix_attenuationz =
630 {
631         {
632                 {0.0, 0.0, 0.5, 0.5},
633                 {0.0, 0.0, 0.0, 0.5},
634                 {0.0, 0.0, 0.0, 0.5},
635                 {0.0, 0.0, 0.0, 1.0}
636         }
637 };
638
639 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles)
640 {
641         // make sure shadowelements is big enough for this volume
642         if (maxshadowtriangles < numtriangles)
643         {
644                 maxshadowtriangles = numtriangles;
645                 if (shadowelements)
646                         Mem_Free(shadowelements);
647                 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[24]));
648         }
649         // make sure shadowvertex3f is big enough for this volume
650         if (maxshadowvertices < numvertices)
651         {
652                 maxshadowvertices = numvertices;
653                 if (shadowvertex3f)
654                         Mem_Free(shadowvertex3f);
655                 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[6]));
656         }
657 }
658
659 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
660 {
661         int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
662         int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
663         int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
664         int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
665         if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
666         {
667                 if (r_shadow_buffer_visitingleafpvs)
668                         Mem_Free(r_shadow_buffer_visitingleafpvs);
669                 if (r_shadow_buffer_leafpvs)
670                         Mem_Free(r_shadow_buffer_leafpvs);
671                 if (r_shadow_buffer_leaflist)
672                         Mem_Free(r_shadow_buffer_leaflist);
673                 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
674                 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
675                 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
676                 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
677         }
678         if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
679         {
680                 if (r_shadow_buffer_surfacepvs)
681                         Mem_Free(r_shadow_buffer_surfacepvs);
682                 if (r_shadow_buffer_surfacelist)
683                         Mem_Free(r_shadow_buffer_surfacelist);
684                 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
685                 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
686                 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
687         }
688         if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
689         {
690                 if (r_shadow_buffer_shadowtrispvs)
691                         Mem_Free(r_shadow_buffer_shadowtrispvs);
692                 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
693                 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
694         }
695         if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
696         {
697                 if (r_shadow_buffer_lighttrispvs)
698                         Mem_Free(r_shadow_buffer_lighttrispvs);
699                 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
700                 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
701         }
702 }
703
704 void R_Shadow_PrepareShadowMark(int numtris)
705 {
706         // make sure shadowmark is big enough for this volume
707         if (maxshadowmark < numtris)
708         {
709                 maxshadowmark = numtris;
710                 if (shadowmark)
711                         Mem_Free(shadowmark);
712                 if (shadowmarklist)
713                         Mem_Free(shadowmarklist);
714                 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
715                 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
716                 shadowmarkcount = 0;
717         }
718         shadowmarkcount++;
719         // if shadowmarkcount wrapped we clear the array and adjust accordingly
720         if (shadowmarkcount == 0)
721         {
722                 shadowmarkcount = 1;
723                 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
724         }
725         numshadowmark = 0;
726 }
727
728 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)
729 {
730         int i, j;
731         int outtriangles = 0, outvertices = 0;
732         const int *element;
733         const float *vertex;
734         float ratio, direction[3], projectvector[3];
735
736         if (projectdirection)
737                 VectorScale(projectdirection, projectdistance, projectvector);
738         else
739                 VectorClear(projectvector);
740
741         // create the vertices
742         if (projectdirection)
743         {
744                 for (i = 0;i < numshadowmarktris;i++)
745                 {
746                         element = inelement3i + shadowmarktris[i] * 3;
747                         for (j = 0;j < 3;j++)
748                         {
749                                 if (vertexupdate[element[j]] != vertexupdatenum)
750                                 {
751                                         vertexupdate[element[j]] = vertexupdatenum;
752                                         vertexremap[element[j]] = outvertices;
753                                         vertex = invertex3f + element[j] * 3;
754                                         // project one copy of the vertex according to projectvector
755                                         VectorCopy(vertex, outvertex3f);
756                                         VectorAdd(vertex, projectvector, (outvertex3f + 3));
757                                         outvertex3f += 6;
758                                         outvertices += 2;
759                                 }
760                         }
761                 }
762         }
763         else
764         {
765                 for (i = 0;i < numshadowmarktris;i++)
766                 {
767                         element = inelement3i + shadowmarktris[i] * 3;
768                         for (j = 0;j < 3;j++)
769                         {
770                                 if (vertexupdate[element[j]] != vertexupdatenum)
771                                 {
772                                         vertexupdate[element[j]] = vertexupdatenum;
773                                         vertexremap[element[j]] = outvertices;
774                                         vertex = invertex3f + element[j] * 3;
775                                         // project one copy of the vertex to the sphere radius of the light
776                                         // (FIXME: would projecting it to the light box be better?)
777                                         VectorSubtract(vertex, projectorigin, direction);
778                                         ratio = projectdistance / VectorLength(direction);
779                                         VectorCopy(vertex, outvertex3f);
780                                         VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
781                                         outvertex3f += 6;
782                                         outvertices += 2;
783                                 }
784                         }
785                 }
786         }
787
788         if (r_shadow_frontsidecasting.integer)
789         {
790                 for (i = 0;i < numshadowmarktris;i++)
791                 {
792                         int remappedelement[3];
793                         int markindex;
794                         const int *neighbortriangle;
795
796                         markindex = shadowmarktris[i] * 3;
797                         element = inelement3i + markindex;
798                         neighbortriangle = inneighbor3i + markindex;
799                         // output the front and back triangles
800                         outelement3i[0] = vertexremap[element[0]];
801                         outelement3i[1] = vertexremap[element[1]];
802                         outelement3i[2] = vertexremap[element[2]];
803                         outelement3i[3] = vertexremap[element[2]] + 1;
804                         outelement3i[4] = vertexremap[element[1]] + 1;
805                         outelement3i[5] = vertexremap[element[0]] + 1;
806
807                         outelement3i += 6;
808                         outtriangles += 2;
809                         // output the sides (facing outward from this triangle)
810                         if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
811                         {
812                                 remappedelement[0] = vertexremap[element[0]];
813                                 remappedelement[1] = vertexremap[element[1]];
814                                 outelement3i[0] = remappedelement[1];
815                                 outelement3i[1] = remappedelement[0];
816                                 outelement3i[2] = remappedelement[0] + 1;
817                                 outelement3i[3] = remappedelement[1];
818                                 outelement3i[4] = remappedelement[0] + 1;
819                                 outelement3i[5] = remappedelement[1] + 1;
820
821                                 outelement3i += 6;
822                                 outtriangles += 2;
823                         }
824                         if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
825                         {
826                                 remappedelement[1] = vertexremap[element[1]];
827                                 remappedelement[2] = vertexremap[element[2]];
828                                 outelement3i[0] = remappedelement[2];
829                                 outelement3i[1] = remappedelement[1];
830                                 outelement3i[2] = remappedelement[1] + 1;
831                                 outelement3i[3] = remappedelement[2];
832                                 outelement3i[4] = remappedelement[1] + 1;
833                                 outelement3i[5] = remappedelement[2] + 1;
834
835                                 outelement3i += 6;
836                                 outtriangles += 2;
837                         }
838                         if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
839                         {
840                                 remappedelement[0] = vertexremap[element[0]];
841                                 remappedelement[2] = vertexremap[element[2]];
842                                 outelement3i[0] = remappedelement[0];
843                                 outelement3i[1] = remappedelement[2];
844                                 outelement3i[2] = remappedelement[2] + 1;
845                                 outelement3i[3] = remappedelement[0];
846                                 outelement3i[4] = remappedelement[2] + 1;
847                                 outelement3i[5] = remappedelement[0] + 1;
848
849                                 outelement3i += 6;
850                                 outtriangles += 2;
851                         }
852                 }
853         }
854         else
855         {
856                 for (i = 0;i < numshadowmarktris;i++)
857                 {
858                         int remappedelement[3];
859                         int markindex;
860                         const int *neighbortriangle;
861
862                         markindex = shadowmarktris[i] * 3;
863                         element = inelement3i + markindex;
864                         neighbortriangle = inneighbor3i + markindex;
865                         // output the front and back triangles
866                         outelement3i[0] = vertexremap[element[2]];
867                         outelement3i[1] = vertexremap[element[1]];
868                         outelement3i[2] = vertexremap[element[0]];
869                         outelement3i[3] = vertexremap[element[0]] + 1;
870                         outelement3i[4] = vertexremap[element[1]] + 1;
871                         outelement3i[5] = vertexremap[element[2]] + 1;
872
873                         outelement3i += 6;
874                         outtriangles += 2;
875                         // output the sides (facing outward from this triangle)
876                         if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
877                         {
878                                 remappedelement[0] = vertexremap[element[0]];
879                                 remappedelement[1] = vertexremap[element[1]];
880                                 outelement3i[0] = remappedelement[0];
881                                 outelement3i[1] = remappedelement[1];
882                                 outelement3i[2] = remappedelement[1] + 1;
883                                 outelement3i[3] = remappedelement[0];
884                                 outelement3i[4] = remappedelement[1] + 1;
885                                 outelement3i[5] = remappedelement[0] + 1;
886
887                                 outelement3i += 6;
888                                 outtriangles += 2;
889                         }
890                         if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
891                         {
892                                 remappedelement[1] = vertexremap[element[1]];
893                                 remappedelement[2] = vertexremap[element[2]];
894                                 outelement3i[0] = remappedelement[1];
895                                 outelement3i[1] = remappedelement[2];
896                                 outelement3i[2] = remappedelement[2] + 1;
897                                 outelement3i[3] = remappedelement[1];
898                                 outelement3i[4] = remappedelement[2] + 1;
899                                 outelement3i[5] = remappedelement[1] + 1;
900
901                                 outelement3i += 6;
902                                 outtriangles += 2;
903                         }
904                         if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
905                         {
906                                 remappedelement[0] = vertexremap[element[0]];
907                                 remappedelement[2] = vertexremap[element[2]];
908                                 outelement3i[0] = remappedelement[2];
909                                 outelement3i[1] = remappedelement[0];
910                                 outelement3i[2] = remappedelement[0] + 1;
911                                 outelement3i[3] = remappedelement[2];
912                                 outelement3i[4] = remappedelement[0] + 1;
913                                 outelement3i[5] = remappedelement[2] + 1;
914
915                                 outelement3i += 6;
916                                 outtriangles += 2;
917                         }
918                 }
919         }
920         if (outnumvertices)
921                 *outnumvertices = outvertices;
922         return outtriangles;
923 }
924
925 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)
926 {
927         int i, j, k;
928         int outtriangles = 0, outvertices = 0;
929         const int *element;
930         const float *vertex;
931         float ratio, direction[3], projectvector[3];
932         qboolean side[4];
933
934         if (projectdirection)
935                 VectorScale(projectdirection, projectdistance, projectvector);
936         else
937                 VectorClear(projectvector);
938
939         for (i = 0;i < numshadowmarktris;i++)
940         {
941                 int remappedelement[3];
942                 int markindex;
943                 const int *neighbortriangle;
944
945                 markindex = shadowmarktris[i] * 3;
946                 neighbortriangle = inneighbor3i + markindex;
947                 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
948                 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
949                 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
950                 if (side[0] + side[1] + side[2] == 0)
951                         continue;
952
953                 side[3] = side[0];
954                 element = inelement3i + markindex;
955
956                 // create the vertices
957                 for (j = 0;j < 3;j++)
958                 {
959                         if (side[j] + side[j+1] == 0)
960                                 continue;
961                         k = element[j];
962                         if (vertexupdate[k] != vertexupdatenum)
963                         {
964                                 vertexupdate[k] = vertexupdatenum;
965                                 vertexremap[k] = outvertices;
966                                 vertex = invertex3f + k * 3;
967                                 VectorCopy(vertex, outvertex3f);
968                                 if (projectdirection)
969                                 {
970                                         // project one copy of the vertex according to projectvector
971                                         VectorAdd(vertex, projectvector, (outvertex3f + 3));
972                                 }
973                                 else
974                                 {
975                                         // project one copy of the vertex to the sphere radius of the light
976                                         // (FIXME: would projecting it to the light box be better?)
977                                         VectorSubtract(vertex, projectorigin, direction);
978                                         ratio = projectdistance / VectorLength(direction);
979                                         VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
980                                 }
981                                 outvertex3f += 6;
982                                 outvertices += 2;
983                         }
984                 }
985
986                 // output the sides (facing outward from this triangle)
987                 if (!side[0])
988                 {
989                         remappedelement[0] = vertexremap[element[0]];
990                         remappedelement[1] = vertexremap[element[1]];
991                         outelement3i[0] = remappedelement[1];
992                         outelement3i[1] = remappedelement[0];
993                         outelement3i[2] = remappedelement[0] + 1;
994                         outelement3i[3] = remappedelement[1];
995                         outelement3i[4] = remappedelement[0] + 1;
996                         outelement3i[5] = remappedelement[1] + 1;
997
998                         outelement3i += 6;
999                         outtriangles += 2;
1000                 }
1001                 if (!side[1])
1002                 {
1003                         remappedelement[1] = vertexremap[element[1]];
1004                         remappedelement[2] = vertexremap[element[2]];
1005                         outelement3i[0] = remappedelement[2];
1006                         outelement3i[1] = remappedelement[1];
1007                         outelement3i[2] = remappedelement[1] + 1;
1008                         outelement3i[3] = remappedelement[2];
1009                         outelement3i[4] = remappedelement[1] + 1;
1010                         outelement3i[5] = remappedelement[2] + 1;
1011
1012                         outelement3i += 6;
1013                         outtriangles += 2;
1014                 }
1015                 if (!side[2])
1016                 {
1017                         remappedelement[0] = vertexremap[element[0]];
1018                         remappedelement[2] = vertexremap[element[2]];
1019                         outelement3i[0] = remappedelement[0];
1020                         outelement3i[1] = remappedelement[2];
1021                         outelement3i[2] = remappedelement[2] + 1;
1022                         outelement3i[3] = remappedelement[0];
1023                         outelement3i[4] = remappedelement[2] + 1;
1024                         outelement3i[5] = remappedelement[0] + 1;
1025
1026                         outelement3i += 6;
1027                         outtriangles += 2;
1028                 }
1029         }
1030         if (outnumvertices)
1031                 *outnumvertices = outvertices;
1032         return outtriangles;
1033 }
1034
1035 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)
1036 {
1037         int t, tend;
1038         const int *e;
1039         const float *v[3];
1040         float normal[3];
1041         if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1042                 return;
1043         tend = firsttriangle + numtris;
1044         if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1045         {
1046                 // surface box entirely inside light box, no box cull
1047                 if (projectdirection)
1048                 {
1049                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1050                         {
1051                                 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1052                                 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1053                                         shadowmarklist[numshadowmark++] = t;
1054                         }
1055                 }
1056                 else
1057                 {
1058                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1059                                 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1060                                         shadowmarklist[numshadowmark++] = t;
1061                 }
1062         }
1063         else
1064         {
1065                 // surface box not entirely inside light box, cull each triangle
1066                 if (projectdirection)
1067                 {
1068                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1069                         {
1070                                 v[0] = invertex3f + e[0] * 3;
1071                                 v[1] = invertex3f + e[1] * 3;
1072                                 v[2] = invertex3f + e[2] * 3;
1073                                 TriangleNormal(v[0], v[1], v[2], normal);
1074                                 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1075                                  && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1076                                         shadowmarklist[numshadowmark++] = t;
1077                         }
1078                 }
1079                 else
1080                 {
1081                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1082                         {
1083                                 v[0] = invertex3f + e[0] * 3;
1084                                 v[1] = invertex3f + e[1] * 3;
1085                                 v[2] = invertex3f + e[2] * 3;
1086                                 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1087                                  && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1088                                         shadowmarklist[numshadowmark++] = t;
1089                         }
1090                 }
1091         }
1092 }
1093
1094 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1095 {
1096 #if 1
1097         return false;
1098 #else
1099         if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1100                 return false;
1101         // check if the shadow volume intersects the near plane
1102         //
1103         // a ray between the eye and light origin may intersect the caster,
1104         // indicating that the shadow may touch the eye location, however we must
1105         // test the near plane (a polygon), not merely the eye location, so it is
1106         // easiest to enlarge the caster bounding shape slightly for this.
1107         // TODO
1108         return true;
1109 #endif
1110 }
1111
1112 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)
1113 {
1114         int i, tris, outverts;
1115         if (projectdistance < 0.1)
1116         {
1117                 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1118                 return;
1119         }
1120         if (!numverts || !nummarktris)
1121                 return;
1122         // make sure shadowelements is big enough for this volume
1123         if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
1124                 R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
1125
1126         if (maxvertexupdate < numverts)
1127         {
1128                 maxvertexupdate = numverts;
1129                 if (vertexupdate)
1130                         Mem_Free(vertexupdate);
1131                 if (vertexremap)
1132                         Mem_Free(vertexremap);
1133                 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1134                 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1135                 vertexupdatenum = 0;
1136         }
1137         vertexupdatenum++;
1138         if (vertexupdatenum == 0)
1139         {
1140                 vertexupdatenum = 1;
1141                 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1142                 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1143         }
1144
1145         for (i = 0;i < nummarktris;i++)
1146                 shadowmark[marktris[i]] = shadowmarkcount;
1147
1148         if (r_shadow_compilingrtlight)
1149         {
1150                 // if we're compiling an rtlight, capture the mesh
1151                 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1152                 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1153                 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1154                 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1155         }
1156         else
1157         {
1158                 // decide which type of shadow to generate and set stencil mode
1159                 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1160                 // generate the sides or a solid volume, depending on type
1161                 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1162                         tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1163                 else
1164                         tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1165                 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1166                 r_refdef.stats.lights_shadowtriangles += tris;
1167                 CHECKGLERROR
1168                 R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
1169                 GL_LockArrays(0, outverts);
1170                 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1171                 {
1172                         // increment stencil if frontface is infront of depthbuffer
1173                         GL_CullFace(r_refdef.view.cullface_front);
1174                         qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1175                         R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1176                         // decrement stencil if backface is infront of depthbuffer
1177                         GL_CullFace(r_refdef.view.cullface_back);
1178                         qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1179                 }
1180                 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1181                 {
1182                         // decrement stencil if backface is behind depthbuffer
1183                         GL_CullFace(r_refdef.view.cullface_front);
1184                         qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1185                         R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1186                         // increment stencil if frontface is behind depthbuffer
1187                         GL_CullFace(r_refdef.view.cullface_back);
1188                         qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1189                 }
1190                 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1191                 GL_LockArrays(0, 0);
1192                 CHECKGLERROR
1193         }
1194 }
1195
1196 void R_Shadow_ShadowMapFromList(int numverts, int numtris, const float *vertex3f, int vertex3f_bufferobject, int vertex3f_bufferoffset, const int *elements, int nummarktris, const int *marktris)
1197 {
1198         int i, tris = nummarktris;
1199         int *outelement3i;
1200         const int *element;
1201         if (!numverts || !nummarktris)
1202                 return;
1203         // make sure shadowelements is big enough for this mesh
1204         if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
1205                 R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
1206
1207         // gather up the (sparse) triangles into one array
1208         outelement3i = shadowelements;
1209         for (i = 0;i < nummarktris;i++)
1210         {
1211                 element = elements + marktris[i] * 3;
1212                 outelement3i[0] = element[0];
1213                 outelement3i[1] = element[1];
1214                 outelement3i[2] = element[2];
1215                 outelement3i += 3;
1216         }
1217
1218         r_refdef.stats.lights_dynamicshadowtriangles += tris;
1219         r_refdef.stats.lights_shadowtriangles += tris;
1220         R_Mesh_VertexPointer(vertex3f, vertex3f_bufferobject, vertex3f_bufferoffset);
1221         R_Mesh_Draw(0, numverts, 0, tris, shadowelements, NULL, 0, 0);
1222 }
1223
1224 static void R_Shadow_MakeTextures_MakeCorona(void)
1225 {
1226         float dx, dy;
1227         int x, y, a;
1228         unsigned char pixels[32][32][4];
1229         for (y = 0;y < 32;y++)
1230         {
1231                 dy = (y - 15.5f) * (1.0f / 16.0f);
1232                 for (x = 0;x < 32;x++)
1233                 {
1234                         dx = (x - 15.5f) * (1.0f / 16.0f);
1235                         a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1236                         a = bound(0, a, 255);
1237                         pixels[y][x][0] = a;
1238                         pixels[y][x][1] = a;
1239                         pixels[y][x][2] = a;
1240                         pixels[y][x][3] = 255;
1241                 }
1242         }
1243         r_shadow_lightcorona = R_LoadTexture2D(r_shadow_texturepool, "lightcorona", 32, 32, &pixels[0][0][0], TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_FORCELINEAR, NULL);
1244 }
1245
1246 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1247 {
1248         float dist = sqrt(x*x+y*y+z*z);
1249         float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1250         // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1251         return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1252 }
1253
1254 static void R_Shadow_MakeTextures(void)
1255 {
1256         int x, y, z;
1257         float intensity, dist;
1258         unsigned int *data;
1259         R_FreeTexturePool(&r_shadow_texturepool);
1260         r_shadow_texturepool = R_AllocTexturePool();
1261         r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1262         r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1263         data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1264         // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1265         for (x = 0;x <= ATTENTABLESIZE;x++)
1266         {
1267                 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1268                 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1269                 r_shadow_attentable[x] = bound(0, intensity, 1);
1270         }
1271         // 1D gradient texture
1272         for (x = 0;x < ATTEN1DSIZE;x++)
1273                 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1274         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);
1275         // 2D circle texture
1276         for (y = 0;y < ATTEN2DSIZE;y++)
1277                 for (x = 0;x < ATTEN2DSIZE;x++)
1278                         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);
1279         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);
1280         // 3D sphere texture
1281         if (r_shadow_texture3d.integer && gl_texture3d)
1282         {
1283                 for (z = 0;z < ATTEN3DSIZE;z++)
1284                         for (y = 0;y < ATTEN3DSIZE;y++)
1285                                 for (x = 0;x < ATTEN3DSIZE;x++)
1286                                         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));
1287                 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);
1288         }
1289         else
1290                 r_shadow_attenuation3dtexture = NULL;
1291         Mem_Free(data);
1292
1293         R_Shadow_MakeTextures_MakeCorona();
1294
1295         // Editor light sprites
1296         r_editlights_sprcursor = Draw_CachePic ("gfx/editlights/cursor");
1297         r_editlights_sprlight = Draw_CachePic ("gfx/editlights/light");
1298         r_editlights_sprnoshadowlight = Draw_CachePic ("gfx/editlights/noshadow");
1299         r_editlights_sprcubemaplight = Draw_CachePic ("gfx/editlights/cubemaplight");
1300         r_editlights_sprcubemapnoshadowlight = Draw_CachePic ("gfx/editlights/cubemapnoshadowlight");
1301         r_editlights_sprselection = Draw_CachePic ("gfx/editlights/selection");
1302 }
1303
1304 void R_Shadow_ValidateCvars(void)
1305 {
1306         if (r_shadow_texture3d.integer && !gl_texture3d)
1307                 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1308         if (gl_ext_separatestencil.integer && !gl_support_separatestencil)
1309                 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1310         if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1311                 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1312 }
1313
1314 void R_Shadow_RenderMode_Begin(void)
1315 {
1316         GLint drawbuffer;
1317         GLint readbuffer;
1318         R_Shadow_ValidateCvars();
1319
1320         if (!r_shadow_attenuation2dtexture
1321          || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1322          || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1323          || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1324                 R_Shadow_MakeTextures();
1325
1326         CHECKGLERROR
1327         R_Mesh_ColorPointer(NULL, 0, 0);
1328         R_Mesh_ResetTextureState();
1329         GL_BlendFunc(GL_ONE, GL_ZERO);
1330         GL_DepthRange(0, 1);
1331         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1332         GL_DepthTest(true);
1333         GL_DepthMask(false);
1334         GL_Color(0, 0, 0, 1);
1335         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1336
1337         r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1338
1339         if (gl_ext_separatestencil.integer)
1340         {
1341                 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1342                 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1343         }
1344         else if (gl_ext_stenciltwoside.integer)
1345         {
1346                 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1347                 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1348         }
1349         else
1350         {
1351                 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1352                 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1353         }
1354
1355         if (r_glsl.integer && gl_support_fragment_shader)
1356                 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1357         else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
1358                 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
1359         else
1360                 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1361
1362         CHECKGLERROR
1363         qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1364         qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1365         r_shadow_drawbuffer = drawbuffer;
1366         r_shadow_readbuffer = readbuffer;
1367 }
1368
1369 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1370 {
1371         rsurface.rtlight = rtlight;
1372 }
1373
1374 void R_Shadow_RenderMode_Reset(void)
1375 {
1376         CHECKGLERROR
1377         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE)
1378         {
1379                 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1380         }
1381         if (gl_support_ext_framebuffer_object)
1382         {
1383                 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
1384         }
1385         qglDrawBuffer(r_shadow_drawbuffer);CHECKGLERROR
1386         qglReadBuffer(r_shadow_readbuffer);CHECKGLERROR
1387         R_SetViewport(&r_refdef.view.viewport);
1388         GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1389         R_Mesh_ColorPointer(NULL, 0, 0);
1390         R_Mesh_ResetTextureState();
1391         GL_DepthRange(0, 1);
1392         GL_DepthTest(true);
1393         GL_DepthMask(false);
1394         qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1395         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1396         qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1397         qglStencilMask(~0);CHECKGLERROR
1398         qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1399         qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1400         GL_CullFace(r_refdef.view.cullface_back);
1401         GL_Color(1, 1, 1, 1);
1402         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1403         GL_BlendFunc(GL_ONE, GL_ZERO);
1404         R_SetupGenericShader(false);
1405         r_shadow_usingshadowmaprect = false;
1406         r_shadow_usingshadowmapcube = false;
1407         r_shadow_usingshadowmap2d = false;
1408         CHECKGLERROR
1409 }
1410
1411 void R_Shadow_ClearStencil(void)
1412 {
1413         CHECKGLERROR
1414         GL_Clear(GL_STENCIL_BUFFER_BIT);
1415         r_refdef.stats.lights_clears++;
1416 }
1417
1418 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
1419 {
1420         r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
1421         if (r_shadow_rendermode == mode)
1422                 return;
1423         CHECKGLERROR
1424         R_Shadow_RenderMode_Reset();
1425         GL_ColorMask(0, 0, 0, 0);
1426         GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1427         R_SetupDepthOrShadowShader();
1428         qglDepthFunc(GL_LESS);CHECKGLERROR
1429         qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1430         r_shadow_rendermode = mode;
1431         switch(mode)
1432         {
1433         default:
1434                 break;
1435         case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
1436                 GL_CullFace(GL_NONE);
1437                 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1438                 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1439                 break;
1440         case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
1441                 GL_CullFace(GL_NONE);
1442                 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1443                 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1444                 break;
1445         case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
1446                 GL_CullFace(GL_NONE);
1447                 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1448                 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1449                 qglStencilMask(~0);CHECKGLERROR
1450                 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1451                 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1452                 qglStencilMask(~0);CHECKGLERROR
1453                 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1454                 break;
1455         case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
1456                 GL_CullFace(GL_NONE);
1457                 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1458                 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1459                 qglStencilMask(~0);CHECKGLERROR
1460                 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1461                 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1462                 qglStencilMask(~0);CHECKGLERROR
1463                 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1464                 break;
1465         }
1466 }
1467
1468 void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size)
1469 {
1470         int i;
1471         int status;
1472         int maxsize;
1473         float nearclip, farclip;
1474         r_viewport_t viewport;
1475         CHECKGLERROR
1476         maxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, 2048);
1477         nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
1478         farclip = 1.0f;
1479         r_shadow_shadowmap_bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
1480         r_shadow_shadowmap_parameters[0] = 1.0f - r_shadow_shadowmapping_bordersize.value / size;
1481         r_shadow_shadowmap_parameters[1] = 1.0f - r_shadow_shadowmapping_bordersize.value / size;
1482         r_shadow_shadowmap_parameters[2] = -(farclip + nearclip) / (farclip - nearclip);
1483         r_shadow_shadowmap_parameters[3] = -2.0f * nearclip * farclip / (farclip - nearclip);
1484         if (r_shadow_shadowmapping.integer == 1)
1485         {
1486                 // complex unrolled cube approach (more flexible)
1487                 //if (!r_shadow_shadowmapcubeprojectiontexture)
1488                 //      r_shadow_shadowmapcubeprojectiontexture = R_LoadTextureCubeProjection(r_shadow_texturepool, "shadowmapcubeprojection");
1489                 if (!r_shadow_shadowmap2dtexture)
1490                 {
1491 #if 1
1492                         r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", maxsize*2, maxsize*4);
1493                         qglGenFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
1494                         qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
1495                         qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_shadowmap2dtexture), 0);CHECKGLERROR
1496 #endif
1497                 }
1498                 CHECKGLERROR
1499                 R_Shadow_RenderMode_Reset();
1500                 if (r_shadow_shadowmap2dtexture)
1501                 {
1502                         // render depth into the fbo, do not render color at all
1503                         qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
1504                         qglDrawBuffer(GL_NONE);CHECKGLERROR
1505                         qglReadBuffer(GL_NONE);CHECKGLERROR
1506                         status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1507                         if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
1508                         {
1509                                 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1510                                 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1511                         }
1512                         R_SetupDepthOrShadowShader();
1513                 }
1514                 else
1515                 {
1516                         R_SetupShowDepthShader();
1517                         qglClearColor(1,1,1,1);CHECKGLERROR
1518                 }
1519                 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapping_bordersize.integer, nearclip, farclip, NULL);
1520                 r_shadow_shadowmap_texturescale[0] = (float)size / R_TextureWidth(r_shadow_shadowmap2dtexture);
1521                 r_shadow_shadowmap_texturescale[1] = (float)size / R_TextureHeight(r_shadow_shadowmap2dtexture);
1522                 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
1523         }
1524         else if (r_shadow_shadowmapping.integer == 2)
1525         {
1526                 // complex unrolled cube approach (more flexible)
1527                 //if (!r_shadow_shadowmapcubeprojectiontexture)
1528                 //      r_shadow_shadowmapcubeprojectiontexture = R_LoadTextureCubeProjection(r_shadow_texturepool, "shadowmapcubeprojection");
1529                 if (!r_shadow_shadowmaprectangletexture)
1530                 {
1531 #if 1
1532                         r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", maxsize*2, maxsize*4);
1533                         qglGenFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
1534                         qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
1535                         qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_shadowmaprectangletexture), 0);CHECKGLERROR
1536 #endif
1537                 }
1538                 CHECKGLERROR
1539                 R_Shadow_RenderMode_Reset();
1540                 if (r_shadow_shadowmaprectangletexture)
1541                 {
1542                         // render depth into the fbo, do not render color at all
1543                         qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
1544                         qglDrawBuffer(GL_NONE);CHECKGLERROR
1545                         qglReadBuffer(GL_NONE);CHECKGLERROR
1546                         status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1547                         if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
1548                         {
1549                                 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1550                                 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1551                         }
1552                         R_SetupDepthOrShadowShader();
1553                 }
1554                 else
1555                 {
1556                         R_SetupShowDepthShader();
1557                         qglClearColor(1,1,1,1);CHECKGLERROR
1558                 }
1559                 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapping_bordersize.integer, nearclip, farclip, NULL);
1560                 r_shadow_shadowmap_texturescale[0] = size;
1561                 r_shadow_shadowmap_texturescale[1] = size;
1562                 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
1563         }
1564         else if (r_shadow_shadowmapping.integer == 3)
1565         {
1566                 // simple cube approach
1567                 if (!r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
1568                 {
1569 #if 1
1570                         r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", bound(1, maxsize >> r_shadow_shadowmaplod, 2048));
1571                         qglGenFramebuffersEXT(6, r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
1572                         for (i = 0;i < 6;i++)
1573                         {
1574                                 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod][i]);CHECKGLERROR
1575                                 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
1576                         }
1577 #endif
1578                 }
1579                 CHECKGLERROR
1580                 R_Shadow_RenderMode_Reset();
1581                 if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
1582                 {
1583                         // render depth into the fbo, do not render color at all
1584                         qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod][side]);CHECKGLERROR
1585                         qglDrawBuffer(GL_NONE);CHECKGLERROR
1586                         qglReadBuffer(GL_NONE);CHECKGLERROR
1587                         status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1588                         if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
1589                         {
1590                                 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1591                                 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1592                         }
1593                         R_SetupDepthOrShadowShader();
1594                 }
1595                 else
1596                 {
1597                         R_SetupShowDepthShader();
1598                         qglClearColor(1,1,1,1);CHECKGLERROR
1599                 }
1600                 R_Viewport_InitCubeSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, nearclip, farclip, NULL);
1601                 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]);
1602                 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureWidth(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]);
1603                 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE;
1604         }
1605         CHECKGLERROR
1606         R_SetViewport(&viewport);
1607         GL_PolygonOffset(0, 0);
1608         GL_CullFace(GL_NONE); // quake is backwards
1609         GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
1610         GL_DepthMask(true);
1611         GL_DepthTest(true);
1612         qglClearDepth(1);CHECKGLERROR
1613         CHECKGLERROR
1614         if (clear)
1615                 qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |  GL_STENCIL_BUFFER_BIT);
1616         CHECKGLERROR
1617 }
1618
1619 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
1620 {
1621         CHECKGLERROR
1622         R_Shadow_RenderMode_Reset();
1623         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1624         if (!transparent)
1625         {
1626                 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1627         }
1628         if (stenciltest)
1629         {
1630                 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1631                 // only draw light where this geometry was already rendered AND the
1632                 // stencil is 128 (values other than this mean shadow)
1633                 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1634         }
1635         r_shadow_rendermode = r_shadow_lightingrendermode;
1636         // do global setup needed for the chosen lighting mode
1637         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1638         {
1639                 R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap)); // light filter
1640                 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
1641                 CHECKGLERROR
1642                 if (shadowmapping)
1643                 {
1644                         if (r_shadow_shadowmapping.integer == 1)
1645                         {
1646                                 r_shadow_usingshadowmap2d = true;
1647                                 R_Mesh_TexBind(GL20TU_SHADOWMAP2D, R_GetTexture(r_shadow_shadowmap2dtexture));
1648                                 CHECKGLERROR
1649                         }
1650                         else if (r_shadow_shadowmapping.integer == 2)
1651                         {
1652                                 r_shadow_usingshadowmaprect = true;
1653                                 R_Mesh_TexBindRectangle(GL20TU_SHADOWMAPRECT, R_GetTexture(r_shadow_shadowmaprectangletexture));
1654                                 CHECKGLERROR
1655                         }
1656                         else if (r_shadow_shadowmapping.integer == 3)
1657                         {
1658                                 r_shadow_usingshadowmapcube = true;
1659                                 R_Mesh_TexBindCubeMap(GL20TU_SHADOWMAPCUBE, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]));
1660                                 CHECKGLERROR
1661                         }
1662                 }
1663         }
1664         else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_VERTEX)
1665                 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
1666         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1667         CHECKGLERROR
1668 }
1669
1670 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
1671 {
1672         CHECKGLERROR
1673         R_Shadow_RenderMode_Reset();
1674         GL_BlendFunc(GL_ONE, GL_ONE);
1675         GL_DepthRange(0, 1);
1676         GL_DepthTest(r_showshadowvolumes.integer < 2);
1677         GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
1678         GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1679         GL_CullFace(GL_NONE);
1680         r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
1681 }
1682
1683 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
1684 {
1685         CHECKGLERROR
1686         R_Shadow_RenderMode_Reset();
1687         GL_BlendFunc(GL_ONE, GL_ONE);
1688         GL_DepthRange(0, 1);
1689         GL_DepthTest(r_showlighting.integer < 2);
1690         GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
1691         if (!transparent)
1692         {
1693                 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1694         }
1695         if (stenciltest)
1696         {
1697                 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1698                 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1699         }
1700         r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
1701 }
1702
1703 void R_Shadow_RenderMode_End(void)
1704 {
1705         CHECKGLERROR
1706         R_Shadow_RenderMode_Reset();
1707         R_Shadow_RenderMode_ActiveLight(NULL);
1708         GL_DepthMask(true);
1709         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1710         r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1711 }
1712
1713 int bboxedges[12][2] =
1714 {
1715         // top
1716         {0, 1}, // +X
1717         {0, 2}, // +Y
1718         {1, 3}, // Y, +X
1719         {2, 3}, // X, +Y
1720         // bottom
1721         {4, 5}, // +X
1722         {4, 6}, // +Y
1723         {5, 7}, // Y, +X
1724         {6, 7}, // X, +Y
1725         // verticals
1726         {0, 4}, // +Z
1727         {1, 5}, // X, +Z
1728         {2, 6}, // Y, +Z
1729         {3, 7}, // XY, +Z
1730 };
1731
1732 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1733 {
1734         int i, ix1, iy1, ix2, iy2;
1735         float x1, y1, x2, y2;
1736         vec4_t v, v2;
1737         float vertex[20][3];
1738         int j, k;
1739         vec4_t plane4f;
1740         int numvertices;
1741         float corner[8][4];
1742         float dist[8];
1743         int sign[8];
1744         float f;
1745
1746         r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
1747         r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
1748         r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
1749         r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
1750
1751         if (!r_shadow_scissor.integer)
1752                 return false;
1753
1754         // if view is inside the light box, just say yes it's visible
1755         if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
1756                 return false;
1757
1758         x1 = y1 = x2 = y2 = 0;
1759
1760         // transform all corners that are infront of the nearclip plane
1761         VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
1762         plane4f[3] = r_refdef.view.frustum[4].dist;
1763         numvertices = 0;
1764         for (i = 0;i < 8;i++)
1765         {
1766                 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
1767                 dist[i] = DotProduct4(corner[i], plane4f);
1768                 sign[i] = dist[i] > 0;
1769                 if (!sign[i])
1770                 {
1771                         VectorCopy(corner[i], vertex[numvertices]);
1772                         numvertices++;
1773                 }
1774         }
1775         // if some points are behind the nearclip, add clipped edge points to make
1776         // sure that the scissor boundary is complete
1777         if (numvertices > 0 && numvertices < 8)
1778         {
1779                 // add clipped edge points
1780                 for (i = 0;i < 12;i++)
1781                 {
1782                         j = bboxedges[i][0];
1783                         k = bboxedges[i][1];
1784                         if (sign[j] != sign[k])
1785                         {
1786                                 f = dist[j] / (dist[j] - dist[k]);
1787                                 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
1788                                 numvertices++;
1789                         }
1790                 }
1791         }
1792
1793         // if we have no points to check, the light is behind the view plane
1794         if (!numvertices)
1795                 return true;
1796
1797         // if we have some points to transform, check what screen area is covered
1798         x1 = y1 = x2 = y2 = 0;
1799         v[3] = 1.0f;
1800         //Con_Printf("%i vertices to transform...\n", numvertices);
1801         for (i = 0;i < numvertices;i++)
1802         {
1803                 VectorCopy(vertex[i], v);
1804                 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
1805                 //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]);
1806                 if (i)
1807                 {
1808                         if (x1 > v2[0]) x1 = v2[0];
1809                         if (x2 < v2[0]) x2 = v2[0];
1810                         if (y1 > v2[1]) y1 = v2[1];
1811                         if (y2 < v2[1]) y2 = v2[1];
1812                 }
1813                 else
1814                 {
1815                         x1 = x2 = v2[0];
1816                         y1 = y2 = v2[1];
1817                 }
1818         }
1819
1820         // now convert the scissor rectangle to integer screen coordinates
1821         ix1 = (int)(x1 - 1.0f);
1822         iy1 = vid.height - (int)(y2 - 1.0f);
1823         ix2 = (int)(x2 + 1.0f);
1824         iy2 = vid.height - (int)(y1 + 1.0f);
1825         //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1826
1827         // clamp it to the screen
1828         if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
1829         if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
1830         if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
1831         if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
1832
1833         // if it is inside out, it's not visible
1834         if (ix2 <= ix1 || iy2 <= iy1)
1835                 return true;
1836
1837         // the light area is visible, set up the scissor rectangle
1838         r_shadow_lightscissor[0] = ix1;
1839         r_shadow_lightscissor[1] = iy1;
1840         r_shadow_lightscissor[2] = ix2 - ix1;
1841         r_shadow_lightscissor[3] = iy2 - iy1;
1842
1843         r_refdef.stats.lights_scissored++;
1844         return false;
1845 }
1846
1847 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
1848 {
1849         float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1850         float *normal3f = rsurface.normal3f + 3 * firstvertex;
1851         float *color4f = rsurface.array_color4f + 4 * firstvertex;
1852         float dist, dot, distintensity, shadeintensity, v[3], n[3];
1853         if (r_textureunits.integer >= 3)
1854         {
1855                 if (VectorLength2(diffusecolor) > 0)
1856                 {
1857                         for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1858                         {
1859                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1860                                 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1861                                 if ((dot = DotProduct(n, v)) < 0)
1862                                 {
1863                                         shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1864                                         VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
1865                                 }
1866                                 else
1867                                         VectorCopy(ambientcolor, color4f);
1868                                 if (r_refdef.fogenabled)
1869                                 {
1870                                         float f;
1871                                         f = FogPoint_Model(vertex3f);
1872                                         VectorScale(color4f, f, color4f);
1873                                 }
1874                                 color4f[3] = 1;
1875                         }
1876                 }
1877                 else
1878                 {
1879                         for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1880                         {
1881                                 VectorCopy(ambientcolor, color4f);
1882                                 if (r_refdef.fogenabled)
1883                                 {
1884                                         float f;
1885                                         Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1886                                         f = FogPoint_Model(vertex3f);
1887                                         VectorScale(color4f, f, color4f);
1888                                 }
1889                                 color4f[3] = 1;
1890                         }
1891                 }
1892         }
1893         else if (r_textureunits.integer >= 2)
1894         {
1895                 if (VectorLength2(diffusecolor) > 0)
1896                 {
1897                         for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1898                         {
1899                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1900                                 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1901                                 {
1902                                         Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1903                                         if ((dot = DotProduct(n, v)) < 0)
1904                                         {
1905                                                 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1906                                                 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1907                                                 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1908                                                 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1909                                         }
1910                                         else
1911                                         {
1912                                                 color4f[0] = ambientcolor[0] * distintensity;
1913                                                 color4f[1] = ambientcolor[1] * distintensity;
1914                                                 color4f[2] = ambientcolor[2] * distintensity;
1915                                         }
1916                                         if (r_refdef.fogenabled)
1917                                         {
1918                                                 float f;
1919                                                 f = FogPoint_Model(vertex3f);
1920                                                 VectorScale(color4f, f, color4f);
1921                                         }
1922                                 }
1923                                 else
1924                                         VectorClear(color4f);
1925                                 color4f[3] = 1;
1926                         }
1927                 }
1928                 else
1929                 {
1930                         for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1931                         {
1932                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1933                                 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1934                                 {
1935                                         color4f[0] = ambientcolor[0] * distintensity;
1936                                         color4f[1] = ambientcolor[1] * distintensity;
1937                                         color4f[2] = ambientcolor[2] * distintensity;
1938                                         if (r_refdef.fogenabled)
1939                                         {
1940                                                 float f;
1941                                                 f = FogPoint_Model(vertex3f);
1942                                                 VectorScale(color4f, f, color4f);
1943                                         }
1944                                 }
1945                                 else
1946                                         VectorClear(color4f);
1947                                 color4f[3] = 1;
1948                         }
1949                 }
1950         }
1951         else
1952         {
1953                 if (VectorLength2(diffusecolor) > 0)
1954                 {
1955                         for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1956                         {
1957                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1958                                 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1959                                 {
1960                                         distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
1961                                         Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1962                                         if ((dot = DotProduct(n, v)) < 0)
1963                                         {
1964                                                 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1965                                                 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1966                                                 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1967                                                 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1968                                         }
1969                                         else
1970                                         {
1971                                                 color4f[0] = ambientcolor[0] * distintensity;
1972                                                 color4f[1] = ambientcolor[1] * distintensity;
1973                                                 color4f[2] = ambientcolor[2] * distintensity;
1974                                         }
1975                                         if (r_refdef.fogenabled)
1976                                         {
1977                                                 float f;
1978                                                 f = FogPoint_Model(vertex3f);
1979                                                 VectorScale(color4f, f, color4f);
1980                                         }
1981                                 }
1982                                 else
1983                                         VectorClear(color4f);
1984                                 color4f[3] = 1;
1985                         }
1986                 }
1987                 else
1988                 {
1989                         for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1990                         {
1991                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1992                                 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1993                                 {
1994                                         distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
1995                                         color4f[0] = ambientcolor[0] * distintensity;
1996                                         color4f[1] = ambientcolor[1] * distintensity;
1997                                         color4f[2] = ambientcolor[2] * distintensity;
1998                                         if (r_refdef.fogenabled)
1999                                         {
2000                                                 float f;
2001                                                 f = FogPoint_Model(vertex3f);
2002                                                 VectorScale(color4f, f, color4f);
2003                                         }
2004                                 }
2005                                 else
2006                                         VectorClear(color4f);
2007                                 color4f[3] = 1;
2008                         }
2009                 }
2010         }
2011 }
2012
2013 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
2014
2015 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2016 {
2017         int i;
2018         float       *out3f     = rsurface.array_texcoord3f + 3 * firstvertex;
2019         const float *vertex3f  = rsurface.vertex3f         + 3 * firstvertex;
2020         const float *svector3f = rsurface.svector3f        + 3 * firstvertex;
2021         const float *tvector3f = rsurface.tvector3f        + 3 * firstvertex;
2022         const float *normal3f  = rsurface.normal3f         + 3 * firstvertex;
2023         float lightdir[3];
2024         for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2025         {
2026                 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2027                 // the cubemap normalizes this for us
2028                 out3f[0] = DotProduct(svector3f, lightdir);
2029                 out3f[1] = DotProduct(tvector3f, lightdir);
2030                 out3f[2] = DotProduct(normal3f, lightdir);
2031         }
2032 }
2033
2034 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2035 {
2036         int i;
2037         float       *out3f     = rsurface.array_texcoord3f + 3 * firstvertex;
2038         const float *vertex3f  = rsurface.vertex3f         + 3 * firstvertex;
2039         const float *svector3f = rsurface.svector3f        + 3 * firstvertex;
2040         const float *tvector3f = rsurface.tvector3f        + 3 * firstvertex;
2041         const float *normal3f  = rsurface.normal3f         + 3 * firstvertex;
2042         float lightdir[3], eyedir[3], halfdir[3];
2043         for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2044         {
2045                 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2046                 VectorNormalize(lightdir);
2047                 VectorSubtract(rsurface.modelorg, vertex3f, eyedir);
2048                 VectorNormalize(eyedir);
2049                 VectorAdd(lightdir, eyedir, halfdir);
2050                 // the cubemap normalizes this for us
2051                 out3f[0] = DotProduct(svector3f, halfdir);
2052                 out3f[1] = DotProduct(tvector3f, halfdir);
2053                 out3f[2] = DotProduct(normal3f, halfdir);
2054         }
2055 }
2056
2057 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)
2058 {
2059         // used to display how many times a surface is lit for level design purposes
2060         R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2061 }
2062
2063 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)
2064 {
2065         // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2066         R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
2067         if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND))
2068                 R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
2069         else
2070                 R_Mesh_ColorPointer(NULL, 0, 0);
2071         R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2072         R_Mesh_TexMatrix(1, &rsurface.texture->currentbackgroundtexmatrix);
2073         R_Mesh_TexBind(GL20TU_NORMAL, R_GetTexture(rsurface.texture->currentskinframe->nmap));
2074         R_Mesh_TexBind(GL20TU_COLOR, R_GetTexture(rsurface.texture->basetexture));
2075         R_Mesh_TexBind(GL20TU_GLOSS, R_GetTexture(rsurface.texture->glosstexture));
2076         if (rsurface.texture->backgroundcurrentskinframe)
2077         {
2078                 R_Mesh_TexBind(GL20TU_SECONDARY_NORMAL, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->nmap));
2079                 R_Mesh_TexBind(GL20TU_SECONDARY_COLOR, R_GetTexture(rsurface.texture->backgroundbasetexture));
2080                 R_Mesh_TexBind(GL20TU_SECONDARY_GLOSS, R_GetTexture(rsurface.texture->backgroundglosstexture));
2081                 R_Mesh_TexBind(GL20TU_SECONDARY_GLOW, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->glow));
2082         }
2083         //R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap));
2084         R_Mesh_TexBind(GL20TU_FOGMASK, R_GetTexture(r_texture_fogattenuation));
2085         if(rsurface.texture->colormapping)
2086         {
2087                 R_Mesh_TexBind(GL20TU_PANTS, R_GetTexture(rsurface.texture->currentskinframe->pants));
2088                 R_Mesh_TexBind(GL20TU_SHIRT, R_GetTexture(rsurface.texture->currentskinframe->shirt));
2089         }
2090         R_Mesh_TexBind(GL20TU_ATTENUATION, R_GetTexture(r_shadow_attenuationgradienttexture));
2091         R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
2092         R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
2093         R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
2094         R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
2095         if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2096         {
2097                 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2098         }
2099         R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2100         if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2101         {
2102                 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2103         }
2104 }
2105
2106 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)
2107 {
2108         // shared final code for all the dot3 layers
2109         int renders;
2110         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2111         for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
2112         {
2113                 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
2114                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2115         }
2116 }
2117
2118 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)
2119 {
2120         rmeshstate_t m;
2121         // colorscale accounts for how much we multiply the brightness
2122         // during combine.
2123         //
2124         // mult is how many times the final pass of the lighting will be
2125         // performed to get more brightness than otherwise possible.
2126         //
2127         // Limit mult to 64 for sanity sake.
2128         GL_Color(1,1,1,1);
2129         if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
2130         {
2131                 // 3 3D combine path (Geforce3, Radeon 8500)
2132                 memset(&m, 0, sizeof(m));
2133                 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2134                 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2135                 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2136                 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2137                 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2138                 m.tex[1] = R_GetTexture(basetexture);
2139                 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2140                 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2141                 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2142                 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2143                 m.texcubemap[2] = R_GetTexture(rsurface.rtlight->currentcubemap);
2144                 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2145                 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2146                 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2147                 m.texmatrix[2] = rsurface.entitytolight;
2148                 GL_BlendFunc(GL_ONE, GL_ONE);
2149         }
2150         else if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
2151         {
2152                 // 2 3D combine path (Geforce3, original Radeon)
2153                 memset(&m, 0, sizeof(m));
2154                 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2155                 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2156                 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2157                 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2158                 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2159                 m.tex[1] = R_GetTexture(basetexture);
2160                 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2161                 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2162                 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2163                 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2164                 GL_BlendFunc(GL_ONE, GL_ONE);
2165         }
2166         else if (r_textureunits.integer >= 4 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2167         {
2168                 // 4 2D combine path (Geforce3, Radeon 8500)
2169                 memset(&m, 0, sizeof(m));
2170                 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2171                 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2172                 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2173                 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2174                 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2175                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2176                 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2177                 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2178                 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2179                 m.texmatrix[1] = rsurface.entitytoattenuationz;
2180                 m.tex[2] = R_GetTexture(basetexture);
2181                 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2182                 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2183                 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2184                 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2185                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2186                 {
2187                         m.texcubemap[3] = R_GetTexture(rsurface.rtlight->currentcubemap);
2188                         m.pointer_texcoord3f[3] = rsurface.vertex3f;
2189                         m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2190                         m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2191                         m.texmatrix[3] = rsurface.entitytolight;
2192                 }
2193                 GL_BlendFunc(GL_ONE, GL_ONE);
2194         }
2195         else if (r_textureunits.integer >= 3 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2196         {
2197                 // 3 2D combine path (Geforce3, original Radeon)
2198                 memset(&m, 0, sizeof(m));
2199                 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2200                 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2201                 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2202                 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2203                 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2204                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2205                 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2206                 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2207                 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2208                 m.texmatrix[1] = rsurface.entitytoattenuationz;
2209                 m.tex[2] = R_GetTexture(basetexture);
2210                 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2211                 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2212                 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2213                 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2214                 GL_BlendFunc(GL_ONE, GL_ONE);
2215         }
2216         else
2217         {
2218                 // 2/2/2 2D combine path (any dot3 card)
2219                 memset(&m, 0, sizeof(m));
2220                 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2221                 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2222                 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2223                 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2224                 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2225                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2226                 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2227                 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2228                 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2229                 m.texmatrix[1] = rsurface.entitytoattenuationz;
2230                 R_Mesh_TextureState(&m);
2231                 GL_ColorMask(0,0,0,1);
2232                 GL_BlendFunc(GL_ONE, GL_ZERO);
2233                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2234
2235                 // second pass
2236                 memset(&m, 0, sizeof(m));
2237                 m.tex[0] = R_GetTexture(basetexture);
2238                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2239                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2240                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2241                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2242                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2243                 {
2244                         m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2245                         m.pointer_texcoord3f[1] = rsurface.vertex3f;
2246                         m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2247                         m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2248                         m.texmatrix[1] = rsurface.entitytolight;
2249                 }
2250                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2251         }
2252         // this final code is shared
2253         R_Mesh_TextureState(&m);
2254         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);
2255 }
2256
2257 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)
2258 {
2259         rmeshstate_t m;
2260         // colorscale accounts for how much we multiply the brightness
2261         // during combine.
2262         //
2263         // mult is how many times the final pass of the lighting will be
2264         // performed to get more brightness than otherwise possible.
2265         //
2266         // Limit mult to 64 for sanity sake.
2267         GL_Color(1,1,1,1);
2268         // generate normalization cubemap texcoords
2269         R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2270         if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
2271         {
2272                 // 3/2 3D combine path (Geforce3, Radeon 8500)
2273                 memset(&m, 0, sizeof(m));
2274                 m.tex[0] = R_GetTexture(normalmaptexture);
2275                 m.texcombinergb[0] = GL_REPLACE;
2276                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2277                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2278                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2279                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2280                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2281                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2282                 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2283                 m.pointer_texcoord_bufferobject[1] = 0;
2284                 m.pointer_texcoord_bufferoffset[1] = 0;
2285                 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
2286                 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2287                 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2288                 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2289                 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2290                 R_Mesh_TextureState(&m);
2291                 GL_ColorMask(0,0,0,1);
2292                 GL_BlendFunc(GL_ONE, GL_ZERO);
2293                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2294
2295                 // second pass
2296                 memset(&m, 0, sizeof(m));
2297                 m.tex[0] = R_GetTexture(basetexture);
2298                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2299                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2300                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2301                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2302                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2303                 {
2304                         m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2305                         m.pointer_texcoord3f[1] = rsurface.vertex3f;
2306                         m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2307                         m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2308                         m.texmatrix[1] = rsurface.entitytolight;
2309                 }
2310                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2311         }
2312         else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2313         {
2314                 // 1/2/2 3D combine path (original Radeon)
2315                 memset(&m, 0, sizeof(m));
2316                 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2317                 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2318                 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2319                 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2320                 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2321                 R_Mesh_TextureState(&m);
2322                 GL_ColorMask(0,0,0,1);
2323                 GL_BlendFunc(GL_ONE, GL_ZERO);
2324                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2325
2326                 // second pass
2327                 memset(&m, 0, sizeof(m));
2328                 m.tex[0] = R_GetTexture(normalmaptexture);
2329                 m.texcombinergb[0] = GL_REPLACE;
2330                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2331                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2332                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2333                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2334                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2335                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2336                 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2337                 m.pointer_texcoord_bufferobject[1] = 0;
2338                 m.pointer_texcoord_bufferoffset[1] = 0;
2339                 R_Mesh_TextureState(&m);
2340                 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2341                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2342
2343                 // second pass
2344                 memset(&m, 0, sizeof(m));
2345                 m.tex[0] = R_GetTexture(basetexture);
2346                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2347                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2348                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2349                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2350                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2351                 {
2352                         m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2353                         m.pointer_texcoord3f[1] = rsurface.vertex3f;
2354                         m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2355                         m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2356                         m.texmatrix[1] = rsurface.entitytolight;
2357                 }
2358                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2359         }
2360         else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2361         {
2362                 // 2/2 3D combine path (original Radeon)
2363                 memset(&m, 0, sizeof(m));
2364                 m.tex[0] = R_GetTexture(normalmaptexture);
2365                 m.texcombinergb[0] = GL_REPLACE;
2366                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2367                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2368                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2369                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2370                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2371                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2372                 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2373                 m.pointer_texcoord_bufferobject[1] = 0;
2374                 m.pointer_texcoord_bufferoffset[1] = 0;
2375                 R_Mesh_TextureState(&m);
2376                 GL_ColorMask(0,0,0,1);
2377                 GL_BlendFunc(GL_ONE, GL_ZERO);
2378                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2379
2380                 // second pass
2381                 memset(&m, 0, sizeof(m));
2382                 m.tex[0] = R_GetTexture(basetexture);
2383                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2384                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2385                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2386                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2387                 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2388                 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2389                 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2390                 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2391                 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2392                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2393         }
2394         else if (r_textureunits.integer >= 4)
2395         {
2396                 // 4/2 2D combine path (Geforce3, Radeon 8500)
2397                 memset(&m, 0, sizeof(m));
2398                 m.tex[0] = R_GetTexture(normalmaptexture);
2399                 m.texcombinergb[0] = GL_REPLACE;
2400                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2401                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2402                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2403                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2404                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2405                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2406                 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2407                 m.pointer_texcoord_bufferobject[1] = 0;
2408                 m.pointer_texcoord_bufferoffset[1] = 0;
2409                 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2410                 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2411                 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2412                 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2413                 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2414                 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2415                 m.pointer_texcoord3f[3] = rsurface.vertex3f;
2416                 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2417                 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2418                 m.texmatrix[3] = rsurface.entitytoattenuationz;
2419                 R_Mesh_TextureState(&m);
2420                 GL_ColorMask(0,0,0,1);
2421                 GL_BlendFunc(GL_ONE, GL_ZERO);
2422                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2423
2424                 // second pass
2425                 memset(&m, 0, sizeof(m));
2426                 m.tex[0] = R_GetTexture(basetexture);
2427                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2428                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2429                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2430                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2431                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2432                 {
2433                         m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2434                         m.pointer_texcoord3f[1] = rsurface.vertex3f;
2435                         m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2436                         m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2437                         m.texmatrix[1] = rsurface.entitytolight;
2438                 }
2439                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2440         }
2441         else
2442         {
2443                 // 2/2/2 2D combine path (any dot3 card)
2444                 memset(&m, 0, sizeof(m));
2445                 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2446                 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2447                 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2448                 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2449                 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2450                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2451                 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2452                 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2453                 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2454                 m.texmatrix[1] = rsurface.entitytoattenuationz;
2455                 R_Mesh_TextureState(&m);
2456                 GL_ColorMask(0,0,0,1);
2457                 GL_BlendFunc(GL_ONE, GL_ZERO);
2458                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2459
2460                 // second pass
2461                 memset(&m, 0, sizeof(m));
2462                 m.tex[0] = R_GetTexture(normalmaptexture);
2463                 m.texcombinergb[0] = GL_REPLACE;
2464                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2465                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2466                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2467                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2468                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2469                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2470                 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2471                 m.pointer_texcoord_bufferobject[1] = 0;
2472                 m.pointer_texcoord_bufferoffset[1] = 0;
2473                 R_Mesh_TextureState(&m);
2474                 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2475                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2476
2477                 // second pass
2478                 memset(&m, 0, sizeof(m));
2479                 m.tex[0] = R_GetTexture(basetexture);
2480                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2481                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2482                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2483                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2484                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2485                 {
2486                         m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2487                         m.pointer_texcoord3f[1] = rsurface.vertex3f;
2488                         m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2489                         m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2490                         m.texmatrix[1] = rsurface.entitytolight;
2491                 }
2492                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2493         }
2494         // this final code is shared
2495         R_Mesh_TextureState(&m);
2496         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);
2497 }
2498
2499 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)
2500 {
2501         float glossexponent;
2502         rmeshstate_t m;
2503         // FIXME: detect blendsquare!
2504         //if (!gl_support_blendsquare)
2505         //      return;
2506         GL_Color(1,1,1,1);
2507         // generate normalization cubemap texcoords
2508         R_Shadow_GenTexCoords_Specular_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2509         if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2510         {
2511                 // 2/0/0/1/2 3D combine blendsquare path
2512                 memset(&m, 0, sizeof(m));
2513                 m.tex[0] = R_GetTexture(normalmaptexture);
2514                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2515                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2516                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2517                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2518                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2519                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2520                 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2521                 m.pointer_texcoord_bufferobject[1] = 0;
2522                 m.pointer_texcoord_bufferoffset[1] = 0;
2523                 R_Mesh_TextureState(&m);
2524                 GL_ColorMask(0,0,0,1);
2525                 // this squares the result
2526                 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2527                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2528
2529                 // second and third pass
2530                 R_Mesh_ResetTextureState();
2531                 // square alpha in framebuffer a few times to make it shiny
2532                 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2533                 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2534                         R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2535
2536                 // fourth pass
2537                 memset(&m, 0, sizeof(m));
2538                 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2539                 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2540                 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2541                 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2542                 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2543                 R_Mesh_TextureState(&m);
2544                 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2545                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2546
2547                 // fifth pass
2548                 memset(&m, 0, sizeof(m));
2549                 m.tex[0] = R_GetTexture(glosstexture);
2550                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2551                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2552                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2553                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2554                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2555                 {
2556                         m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2557                         m.pointer_texcoord3f[1] = rsurface.vertex3f;
2558                         m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2559                         m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2560                         m.texmatrix[1] = rsurface.entitytolight;
2561                 }
2562                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2563         }
2564         else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
2565         {
2566                 // 2/0/0/2 3D combine blendsquare path
2567                 memset(&m, 0, sizeof(m));
2568                 m.tex[0] = R_GetTexture(normalmaptexture);
2569                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2570                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2571                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2572                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2573                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2574                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2575                 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2576                 m.pointer_texcoord_bufferobject[1] = 0;
2577                 m.pointer_texcoord_bufferoffset[1] = 0;
2578                 R_Mesh_TextureState(&m);
2579                 GL_ColorMask(0,0,0,1);
2580                 // this squares the result
2581                 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2582                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2583
2584                 // second and third pass
2585                 R_Mesh_ResetTextureState();
2586                 // square alpha in framebuffer a few times to make it shiny
2587                 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2588                 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2589                         R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2590
2591                 // fourth pass
2592                 memset(&m, 0, sizeof(m));
2593                 m.tex[0] = R_GetTexture(glosstexture);
2594                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2595                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2596                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2597                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2598                 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2599                 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2600                 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2601                 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2602                 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2603                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2604         }
2605         else
2606         {
2607                 // 2/0/0/2/2 2D combine blendsquare path
2608                 memset(&m, 0, sizeof(m));
2609                 m.tex[0] = R_GetTexture(normalmaptexture);
2610                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2611                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2612                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2613                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2614                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2615                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2616                 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2617                 m.pointer_texcoord_bufferobject[1] = 0;
2618                 m.pointer_texcoord_bufferoffset[1] = 0;
2619                 R_Mesh_TextureState(&m);
2620                 GL_ColorMask(0,0,0,1);
2621                 // this squares the result
2622                 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2623                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2624
2625                 // second and third pass
2626                 R_Mesh_ResetTextureState();
2627                 // square alpha in framebuffer a few times to make it shiny
2628                 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2629                 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2630                         R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2631
2632                 // fourth pass
2633                 memset(&m, 0, sizeof(m));
2634                 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2635                 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2636                 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2637                 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2638                 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2639                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2640                 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2641                 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2642                 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2643                 m.texmatrix[1] = rsurface.entitytoattenuationz;
2644                 R_Mesh_TextureState(&m);
2645                 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2646                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2647
2648                 // fifth pass
2649                 memset(&m, 0, sizeof(m));
2650                 m.tex[0] = R_GetTexture(glosstexture);
2651                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2652                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2653                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2654                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2655                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2656                 {
2657                         m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2658                         m.pointer_texcoord3f[1] = rsurface.vertex3f;
2659                         m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2660                         m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2661                         m.texmatrix[1] = rsurface.entitytolight;
2662                 }
2663                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2664         }
2665         // this final code is shared
2666         R_Mesh_TextureState(&m);
2667         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);
2668 }
2669
2670 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)
2671 {
2672         // ARB path (any Geforce, any Radeon)
2673         qboolean doambient = ambientscale > 0;
2674         qboolean dodiffuse = diffusescale > 0;
2675         qboolean dospecular = specularscale > 0;
2676         if (!doambient && !dodiffuse && !dospecular)
2677                 return;
2678         R_Mesh_ColorPointer(NULL, 0, 0);
2679         if (doambient)
2680                 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, ambientscale * r_refdef.view.colorscale);
2681         if (dodiffuse)
2682                 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2683         if (dopants)
2684         {
2685                 if (doambient)
2686                         R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, ambientscale * r_refdef.view.colorscale);
2687                 if (dodiffuse)
2688                         R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2689         }
2690         if (doshirt)
2691         {
2692                 if (doambient)
2693                         R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, ambientscale * r_refdef.view.colorscale);
2694                 if (dodiffuse)
2695                         R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2696         }
2697         if (dospecular)
2698                 R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_refdef.view.colorscale);
2699 }
2700
2701 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2702 {
2703         int renders;
2704         int i;
2705         int stop;
2706         int newfirstvertex;
2707         int newlastvertex;
2708         int newnumtriangles;
2709         int *newe;
2710         const int *e;
2711         float *c;
2712         int maxtriangles = 4096;
2713         int newelements[4096*3];
2714         R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
2715         for (renders = 0;renders < 64;renders++)
2716         {
2717                 stop = true;
2718                 newfirstvertex = 0;
2719                 newlastvertex = 0;
2720                 newnumtriangles = 0;
2721                 newe = newelements;
2722                 // due to low fillrate on the cards this vertex lighting path is
2723                 // designed for, we manually cull all triangles that do not
2724                 // contain a lit vertex
2725                 // this builds batches of triangles from multiple surfaces and
2726                 // renders them at once
2727                 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2728                 {
2729                         if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
2730                         {
2731                                 if (newnumtriangles)
2732                                 {
2733                                         newfirstvertex = min(newfirstvertex, e[0]);
2734                                         newlastvertex  = max(newlastvertex, e[0]);
2735                                 }
2736                                 else
2737                                 {
2738                                         newfirstvertex = e[0];
2739                                         newlastvertex = e[0];
2740                                 }
2741                                 newfirstvertex = min(newfirstvertex, e[1]);
2742                                 newlastvertex  = max(newlastvertex, e[1]);
2743                                 newfirstvertex = min(newfirstvertex, e[2]);
2744                                 newlastvertex  = max(newlastvertex, e[2]);
2745                                 newe[0] = e[0];
2746                                 newe[1] = e[1];
2747                                 newe[2] = e[2];
2748                                 newnumtriangles++;
2749                                 newe += 3;
2750                                 if (newnumtriangles >= maxtriangles)
2751                                 {
2752                                         R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2753                                         newnumtriangles = 0;
2754                                         newe = newelements;
2755                                         stop = false;
2756                                 }
2757                         }
2758                 }
2759                 if (newnumtriangles >= 1)
2760                 {
2761                         R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2762                         stop = false;
2763                 }
2764                 // if we couldn't find any lit triangles, exit early
2765                 if (stop)
2766                         break;
2767                 // now reduce the intensity for the next overbright pass
2768                 // we have to clamp to 0 here incase the drivers have improper
2769                 // handling of negative colors
2770                 // (some old drivers even have improper handling of >1 color)
2771                 stop = true;
2772                 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2773                 {
2774                         if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2775                         {
2776                                 c[0] = max(0, c[0] - 1);
2777                                 c[1] = max(0, c[1] - 1);
2778                                 c[2] = max(0, c[2] - 1);
2779                                 stop = false;
2780                         }
2781                         else
2782                                 VectorClear(c);
2783                 }
2784                 // another check...
2785                 if (stop)
2786                         break;
2787         }
2788 }
2789
2790 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)
2791 {
2792         // OpenGL 1.1 path (anything)
2793         float ambientcolorbase[3], diffusecolorbase[3];
2794         float ambientcolorpants[3], diffusecolorpants[3];
2795         float ambientcolorshirt[3], diffusecolorshirt[3];
2796         rmeshstate_t m;
2797         VectorScale(lightcolorbase, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorbase);
2798         VectorScale(lightcolorbase, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorbase);
2799         VectorScale(lightcolorpants, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorpants);
2800         VectorScale(lightcolorpants, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorpants);
2801         VectorScale(lightcolorshirt, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorshirt);
2802         VectorScale(lightcolorshirt, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorshirt);
2803         memset(&m, 0, sizeof(m));
2804         m.tex[0] = R_GetTexture(basetexture);
2805         m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2806         m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2807         m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2808         m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2809         if (r_textureunits.integer >= 2)
2810         {
2811                 // voodoo2 or TNT
2812                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2813                 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2814                 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2815                 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2816                 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2817                 if (r_textureunits.integer >= 3)
2818                 {
2819                         // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
2820                         m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2821                         m.texmatrix[2] = rsurface.entitytoattenuationz;
2822                         m.pointer_texcoord3f[2] = rsurface.vertex3f;
2823                         m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2824                         m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2825                 }
2826         }
2827         R_Mesh_TextureState(&m);
2828         //R_Mesh_TexBind(0, R_GetTexture(basetexture));
2829         R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
2830         if (dopants)
2831         {
2832                 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
2833                 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
2834         }
2835         if (doshirt)
2836         {
2837                 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
2838                 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
2839         }
2840 }
2841
2842 extern cvar_t gl_lightmaps;
2843 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)
2844 {
2845         float ambientscale, diffusescale, specularscale;
2846         vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
2847         rtexture_t *nmap;
2848         // calculate colors to render this texture with
2849         lightcolorbase[0] = rsurface.rtlight->currentcolor[0] * rsurface.texture->dlightcolor[0];
2850         lightcolorbase[1] = rsurface.rtlight->currentcolor[1] * rsurface.texture->dlightcolor[1];
2851         lightcolorbase[2] = rsurface.rtlight->currentcolor[2] * rsurface.texture->dlightcolor[2];
2852         ambientscale = rsurface.rtlight->ambientscale;
2853         diffusescale = rsurface.rtlight->diffusescale;
2854         specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2855         if (!r_shadow_usenormalmap.integer)
2856         {
2857                 ambientscale += 1.0f * diffusescale;
2858                 diffusescale = 0;
2859                 specularscale = 0;
2860         }
2861         if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
2862                 return;
2863         RSurf_SetupDepthAndCulling();
2864         nmap = rsurface.texture->currentskinframe->nmap;
2865         if (gl_lightmaps.integer)
2866                 nmap = r_texture_blanknormalmap;
2867         if (rsurface.texture->colormapping && !gl_lightmaps.integer)
2868         {
2869                 qboolean dopants = rsurface.texture->currentskinframe->pants != NULL && VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f);
2870                 qboolean doshirt = rsurface.texture->currentskinframe->shirt != NULL && VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f);
2871                 if (dopants)
2872                 {
2873                         lightcolorpants[0] = lightcolorbase[0] * rsurface.colormap_pantscolor[0];
2874                         lightcolorpants[1] = lightcolorbase[1] * rsurface.colormap_pantscolor[1];
2875                         lightcolorpants[2] = lightcolorbase[2] * rsurface.colormap_pantscolor[2];
2876                 }
2877                 else
2878                         VectorClear(lightcolorpants);
2879                 if (doshirt)
2880                 {
2881                         lightcolorshirt[0] = lightcolorbase[0] * rsurface.colormap_shirtcolor[0];
2882                         lightcolorshirt[1] = lightcolorbase[1] * rsurface.colormap_shirtcolor[1];
2883                         lightcolorshirt[2] = lightcolorbase[2] * rsurface.colormap_shirtcolor[2];
2884                 }
2885                 else
2886                         VectorClear(lightcolorshirt);
2887                 switch (r_shadow_rendermode)
2888                 {
2889                 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2890                         GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2891                         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);
2892                         break;
2893                 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2894                         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);
2895                         break;
2896                 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2897                         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);
2898                         break;
2899                 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2900                         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);
2901                         break;
2902                 default:
2903                         Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2904                         break;
2905                 }
2906         }
2907         else
2908         {
2909                 switch (r_shadow_rendermode)
2910                 {
2911                 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2912                         GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2913                         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);
2914                         break;
2915                 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2916                         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);
2917                         break;
2918                 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2919                         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);
2920                         break;
2921                 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2922                         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);
2923                         break;
2924                 default:
2925                         Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2926                         break;
2927                 }
2928         }
2929 }
2930
2931 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)
2932 {
2933         matrix4x4_t tempmatrix = *matrix;
2934         Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2935
2936         // if this light has been compiled before, free the associated data
2937         R_RTLight_Uncompile(rtlight);
2938
2939         // clear it completely to avoid any lingering data
2940         memset(rtlight, 0, sizeof(*rtlight));
2941
2942         // copy the properties
2943         rtlight->matrix_lighttoworld = tempmatrix;
2944         Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2945         Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2946         rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2947         VectorCopy(color, rtlight->color);
2948         rtlight->cubemapname[0] = 0;
2949         if (cubemapname && cubemapname[0])
2950                 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2951         rtlight->shadow = shadow;
2952         rtlight->corona = corona;
2953         rtlight->style = style;
2954         rtlight->isstatic = isstatic;
2955         rtlight->coronasizescale = coronasizescale;
2956         rtlight->ambientscale = ambientscale;
2957         rtlight->diffusescale = diffusescale;
2958         rtlight->specularscale = specularscale;
2959         rtlight->flags = flags;
2960
2961         // compute derived data
2962         //rtlight->cullradius = rtlight->radius;
2963         //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2964         rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2965         rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2966         rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2967         rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2968         rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2969         rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2970 }
2971
2972 // compiles rtlight geometry
2973 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2974 void R_RTLight_Compile(rtlight_t *rtlight)
2975 {
2976         int i;
2977         int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2978         int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
2979         entity_render_t *ent = r_refdef.scene.worldentity;
2980         dp_model_t *model = r_refdef.scene.worldmodel;
2981         unsigned char *data;
2982         shadowmesh_t *mesh;
2983
2984         // compile the light
2985         rtlight->compiled = true;
2986         rtlight->static_numleafs = 0;
2987         rtlight->static_numleafpvsbytes = 0;
2988         rtlight->static_leaflist = NULL;
2989         rtlight->static_leafpvs = NULL;
2990         rtlight->static_numsurfaces = 0;
2991         rtlight->static_surfacelist = NULL;
2992         rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2993         rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2994         rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2995         rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2996         rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2997         rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2998
2999         if (model && model->GetLightInfo)
3000         {
3001                 // this variable must be set for the CompileShadowVolume code
3002                 r_shadow_compilingrtlight = rtlight;
3003                 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);
3004                 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);
3005                 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3006                 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3007                 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3008                 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3009                 rtlight->static_numsurfaces = numsurfaces;
3010                 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3011                 rtlight->static_numleafs = numleafs;
3012                 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3013                 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3014                 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3015                 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3016                 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3017                 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3018                 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3019                 if (rtlight->static_numsurfaces)
3020                         memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3021                 if (rtlight->static_numleafs)
3022                         memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3023                 if (rtlight->static_numleafpvsbytes)
3024                         memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3025                 if (rtlight->static_numshadowtrispvsbytes)
3026                         memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3027                 if (rtlight->static_numlighttrispvsbytes)
3028                         memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3029                 if (model->CompileShadowVolume && rtlight->shadow)
3030                         model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3031                 // now we're done compiling the rtlight
3032                 r_shadow_compilingrtlight = NULL;
3033         }
3034
3035
3036         // use smallest available cullradius - box radius or light radius
3037         //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3038         //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3039
3040         shadowzpasstris = 0;
3041         if (rtlight->static_meshchain_shadow_zpass)
3042                 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3043                         shadowzpasstris += mesh->numtriangles;
3044
3045         shadowzfailtris = 0;
3046         if (rtlight->static_meshchain_shadow_zfail)
3047                 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3048                         shadowzfailtris += mesh->numtriangles;
3049
3050         lighttris = 0;
3051         if (rtlight->static_numlighttrispvsbytes)
3052                 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3053                         if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3054                                 lighttris++;
3055
3056         shadowtris = 0;
3057         if (rtlight->static_numlighttrispvsbytes)
3058                 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3059                         if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3060                                 shadowtris++;
3061
3062         if (developer.integer >= 10)
3063                 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);
3064 }
3065
3066 void R_RTLight_Uncompile(rtlight_t *rtlight)
3067 {
3068         if (rtlight->compiled)
3069         {
3070                 if (rtlight->static_meshchain_shadow_zpass)
3071                         Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3072                 rtlight->static_meshchain_shadow_zpass = NULL;
3073                 if (rtlight->static_meshchain_shadow_zfail)
3074                         Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3075                 rtlight->static_meshchain_shadow_zfail = NULL;
3076                 // these allocations are grouped
3077                 if (rtlight->static_surfacelist)
3078                         Mem_Free(rtlight->static_surfacelist);
3079                 rtlight->static_numleafs = 0;
3080                 rtlight->static_numleafpvsbytes = 0;
3081                 rtlight->static_leaflist = NULL;
3082                 rtlight->static_leafpvs = NULL;
3083                 rtlight->static_numsurfaces = 0;
3084                 rtlight->static_surfacelist = NULL;
3085                 rtlight->static_numshadowtrispvsbytes = 0;
3086                 rtlight->static_shadowtrispvs = NULL;
3087                 rtlight->static_numlighttrispvsbytes = 0;
3088                 rtlight->static_lighttrispvs = NULL;
3089                 rtlight->compiled = false;
3090         }
3091 }
3092
3093 void R_Shadow_UncompileWorldLights(void)
3094 {
3095         size_t lightindex;
3096         dlight_t *light;
3097         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3098         for (lightindex = 0;lightindex < range;lightindex++)
3099         {
3100                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3101                 if (!light)
3102                         continue;
3103                 R_RTLight_Uncompile(&light->rtlight);
3104         }
3105 }
3106
3107 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3108 {
3109         int i, j;
3110         mplane_t plane;
3111         // reset the count of frustum planes
3112         // see rsurface.rtlight_frustumplanes definition for how much this array
3113         // can hold
3114         rsurface.rtlight_numfrustumplanes = 0;
3115
3116         // haven't implemented a culling path for ortho rendering
3117         if (!r_refdef.view.useperspective)
3118         {
3119                 // check if the light is on screen and copy the 4 planes if it is
3120                 for (i = 0;i < 4;i++)
3121                         if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3122                                 break;
3123                 if (i == 4)
3124                         for (i = 0;i < 4;i++)
3125                                 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3126                 return;
3127         }
3128
3129 #if 1
3130         // generate a deformed frustum that includes the light origin, this is
3131         // used to cull shadow casting surfaces that can not possibly cast a
3132         // shadow onto the visible light-receiving surfaces, which can be a
3133         // performance gain
3134         //
3135         // if the light origin is onscreen the result will be 4 planes exactly
3136         // if the light origin is offscreen on only one axis the result will
3137         // be exactly 5 planes (split-side case)
3138         // if the light origin is offscreen on two axes the result will be
3139         // exactly 4 planes (stretched corner case)
3140         for (i = 0;i < 4;i++)
3141         {
3142                 // quickly reject standard frustum planes that put the light
3143                 // origin outside the frustum
3144                 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3145                         continue;
3146                 // copy the plane
3147                 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3148         }
3149         // if all the standard frustum planes were accepted, the light is onscreen
3150         // otherwise we need to generate some more planes below...
3151         if (rsurface.rtlight_numfrustumplanes < 4)
3152         {
3153                 // at least one of the stock frustum planes failed, so we need to
3154                 // create one or two custom planes to enclose the light origin
3155                 for (i = 0;i < 4;i++)
3156                 {
3157                         // create a plane using the view origin and light origin, and a
3158                         // single point from the frustum corner set
3159                         TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3160                         VectorNormalize(plane.normal);
3161                         plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3162                         // see if this plane is backwards and flip it if so
3163                         for (j = 0;j < 4;j++)
3164                                 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3165                                         break;
3166                         if (j < 4)
3167                         {
3168                                 VectorNegate(plane.normal, plane.normal);
3169                                 plane.dist *= -1;
3170                                 // flipped plane, test again to see if it is now valid
3171                                 for (j = 0;j < 4;j++)
3172                                         if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3173                                                 break;
3174                                 // if the plane is still not valid, then it is dividing the
3175                                 // frustum and has to be rejected
3176                                 if (j < 4)
3177                                         continue;
3178                         }
3179                         // we have created a valid plane, compute extra info
3180                         PlaneClassify(&plane);
3181                         // copy the plane
3182                         rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3183 #if 1
3184                         // if we've found 5 frustum planes then we have constructed a
3185                         // proper split-side case and do not need to keep searching for
3186                         // planes to enclose the light origin
3187                         if (rsurface.rtlight_numfrustumplanes == 5)
3188                                 break;
3189 #endif
3190                 }
3191         }
3192 #endif
3193
3194 #if 0
3195         for (i = 0;i < rsurface.rtlight_numfrustumplanes;i++)
3196         {
3197                 plane = rsurface.rtlight_frustumplanes[i];
3198                 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));
3199         }
3200 #endif
3201
3202 #if 0
3203         // now add the light-space box planes if the light box is rotated, as any
3204         // caster outside the oriented light box is irrelevant (even if it passed
3205         // the worldspace light box, which is axial)
3206         if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3207         {
3208                 for (i = 0;i < 6;i++)
3209                 {
3210                         vec3_t v;
3211                         VectorClear(v);
3212                         v[i >> 1] = (i & 1) ? -1 : 1;
3213                         Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3214                         VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3215                         plane.dist = VectorNormalizeLength(plane.normal);
3216                         plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3217                         rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3218                 }
3219         }
3220 #endif
3221
3222 #if 0
3223         // add the world-space reduced box planes
3224         for (i = 0;i < 6;i++)
3225         {
3226                 VectorClear(plane.normal);
3227                 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3228                 plane.dist = (i & 1) ? -rsurface.rtlight_cullmaxs[i >> 1] : rsurface.rtlight_cullmins[i >> 1];
3229                 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3230         }
3231 #endif
3232
3233 #if 0
3234         {
3235         int j, oldnum;
3236         vec3_t points[8];
3237         vec_t bestdist;
3238         // reduce all plane distances to tightly fit the rtlight cull box, which
3239         // is in worldspace
3240         VectorSet(points[0], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3241         VectorSet(points[1], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3242         VectorSet(points[2], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3243         VectorSet(points[3], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3244         VectorSet(points[4], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3245         VectorSet(points[5], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3246         VectorSet(points[6], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3247         VectorSet(points[7], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3248         oldnum = rsurface.rtlight_numfrustumplanes;
3249         rsurface.rtlight_numfrustumplanes = 0;
3250         for (j = 0;j < oldnum;j++)
3251         {
3252                 // find the nearest point on the box to this plane
3253                 bestdist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[0]);
3254                 for (i = 1;i < 8;i++)
3255                 {
3256                         dist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[i]);
3257                         if (bestdist > dist)
3258                                 bestdist = dist;
3259                 }
3260                 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);
3261                 // if the nearest point is near or behind the plane, we want this
3262                 // plane, otherwise the plane is useless as it won't cull anything
3263                 if (rsurface.rtlight_frustumplanes[j].dist < bestdist + 0.03125)
3264                 {
3265                         PlaneClassify(&rsurface.rtlight_frustumplanes[j]);
3266                         rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = rsurface.rtlight_frustumplanes[j];
3267                 }
3268         }
3269         }
3270 #endif
3271 }
3272
3273 void R_Shadow_DrawWorldShadow(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3274 {
3275         qboolean zpass;
3276         shadowmesh_t *mesh;
3277         int t, tend;
3278         int surfacelistindex;
3279         msurface_t *surface;
3280
3281         RSurf_ActiveWorldEntity();
3282         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
3283         {
3284                 if (r_refdef.scene.worldentity->model)
3285                         r_refdef.scene.worldmodel->DrawShadowMap(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
3286                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3287                 return;
3288         }
3289
3290         if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3291         {
3292                 CHECKGLERROR
3293                 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3294                 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3295                 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3296                 for (;mesh;mesh = mesh->next)
3297                 {
3298                         r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3299                         R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3300                         GL_LockArrays(0, mesh->numverts);
3301                         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3302                         {
3303                                 // increment stencil if frontface is infront of depthbuffer
3304                                 GL_CullFace(r_refdef.view.cullface_back);
3305                                 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
3306                                 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3307                                 // decrement stencil if backface is infront of depthbuffer
3308                                 GL_CullFace(r_refdef.view.cullface_front);
3309                                 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
3310                         }
3311                         else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3312                         {
3313                                 // decrement stencil if backface is behind depthbuffer
3314                                 GL_CullFace(r_refdef.view.cullface_front);
3315                                 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
3316                                 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3317                                 // increment stencil if frontface is behind depthbuffer
3318                                 GL_CullFace(r_refdef.view.cullface_back);
3319                                 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
3320                         }
3321                         R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3322                         GL_LockArrays(0, 0);
3323                 }
3324                 CHECKGLERROR
3325         }
3326         else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
3327         {
3328                 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3329                 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3330                 {
3331                         surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3332                         for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3333                                 if (CHECKPVSBIT(trispvs, t))
3334                                         shadowmarklist[numshadowmark++] = t;
3335                 }
3336                 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);
3337         }
3338         else if (numsurfaces)
3339                 r_refdef.scene.worldmodel->DrawShadowVolume(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
3340
3341         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3342 }
3343
3344 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3345 {
3346         vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3347         vec_t relativeshadowradius;
3348         RSurf_ActiveModelEntity(ent, false, false);
3349         Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3350         relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3351         relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3352         relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3353         relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3354         relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3355         relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3356         relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3357         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
3358                 ent->model->DrawShadowMap(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3359         else
3360                 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3361         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3362 }
3363
3364 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3365 {
3366         // set up properties for rendering light onto this entity
3367         RSurf_ActiveModelEntity(ent, true, true);
3368         GL_AlphaTest(false);
3369         Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3370         Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3371         Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3372         Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3373         if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
3374                 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3375 }
3376
3377 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3378 {
3379         if (!r_refdef.scene.worldmodel->DrawLight)
3380                 return;
3381
3382         // set up properties for rendering light onto this entity
3383         RSurf_ActiveWorldEntity();
3384         GL_AlphaTest(false);
3385         rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3386         Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3387         Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3388         VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3389         if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
3390                 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3391
3392         r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, trispvs);
3393
3394         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3395 }
3396
3397 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3398 {
3399         dp_model_t *model = ent->model;
3400         if (!model->DrawLight)
3401                 return;
3402
3403         R_Shadow_SetupEntityLight(ent);
3404
3405         model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3406
3407         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3408 }
3409
3410 /*
3411 {{  0,   0, 0}, "px",  true,  true,  true},
3412 {{  0,  90, 0}, "py", false,  true, false},
3413 {{  0, 180, 0}, "nx", false, false,  true},
3414 {{  0, 270, 0}, "ny",  true, false, false},
3415 {{-90, 180, 0}, "pz", false, false,  true},
3416 {{ 90, 180, 0}, "nz", false, false,  true}
3417 */
3418
3419 static const double shadowviewmat16[6][4][4] =
3420 {
3421         {
3422                 {-1,  0,  0, 0},
3423                 { 0, -1,  0, 0},
3424                 { 0,  0,  1, 0},
3425                 { 0,  0,  0, 1},
3426         },
3427         {
3428                 { 0, -1,  0, 0},
3429                 {-1,  0,  0, 0},
3430                 { 0,  0,  1, 0},
3431                 { 0,  0,  0, 1},
3432         },
3433         {
3434                 {-1,  0,  0, 0},
3435                 { 0, -1,  0, 0},
3436                 { 0,  0,  1, 0},
3437                 { 0,  0,  0, 1},
3438         },
3439         {
3440                 { 0, -1,  0, 0},
3441                 {-1,  0,  0, 0},
3442                 { 0,  0,  1, 0},
3443                 { 0,  0,  0, 1},
3444         },
3445         {
3446                 { 0,  0,  1, 0},
3447                 { 0, -1,  0, 0},
3448                 { 1,  0,  0, 0},
3449                 { 0,  0,  0, 1},
3450         },
3451         {
3452                 { 0,  0, -1, 0},
3453                 { 0, -1,  0, 0},
3454                 {-1,  0,  0, 0},
3455                 { 0,  0,  0, 1},
3456         },
3457 };
3458
3459 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
3460 {
3461         int i;
3462         float f;
3463         int numleafs, numsurfaces;
3464         int *leaflist, *surfacelist;
3465         unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs;
3466         int numlightentities;
3467         int numlightentities_noselfshadow;
3468         int numshadowentities;
3469         int numshadowentities_noselfshadow;
3470         static entity_render_t *lightentities[MAX_EDICTS];
3471         static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3472         static entity_render_t *shadowentities[MAX_EDICTS];
3473         static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3474         vec3_t nearestpoint;
3475         vec_t distance;
3476         qboolean castshadows;
3477         int lodlinear;
3478
3479         // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3480         // skip lights that are basically invisible (color 0 0 0)
3481         if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
3482                 return;
3483
3484         // loading is done before visibility checks because loading should happen
3485         // all at once at the start of a level, not when it stalls gameplay.
3486         // (especially important to benchmarks)
3487         // compile light
3488         if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
3489