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