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