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