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