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