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