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