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