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