]> icculus.org git repositories - divverent/darkplaces.git/blob - r_shadow.c
stub out face culling for shadowmapping temporarily
[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 0
1704         if(r_shadow_shadowmode >= 1 && r_shadow_shadowmode <= 2)
1705         {
1706                 static qboolean cullback[6] = { true, false, true, false, false, true };
1707                 GL_CullFace(cullback[side] ? r_refdef.view.cullface_back :  r_refdef.view.cullface_front);
1708         }
1709         else if(r_shadow_shadowmode == 3)
1710                 GL_CullFace(r_refdef.view.cullface_back);
1711 #else
1712         GL_CullFace(GL_NONE);
1713 #endif
1714         GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
1715         GL_DepthMask(true);
1716         GL_DepthTest(true);
1717         qglClearDepth(1);CHECKGLERROR
1718         CHECKGLERROR
1719         if (clear)
1720                 qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |  GL_STENCIL_BUFFER_BIT);
1721         CHECKGLERROR
1722 }
1723
1724 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
1725 {
1726         CHECKGLERROR
1727         R_Shadow_RenderMode_Reset();
1728         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1729         if (!transparent)
1730         {
1731                 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1732         }
1733         if (stenciltest)
1734         {
1735                 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1736                 // only draw light where this geometry was already rendered AND the
1737                 // stencil is 128 (values other than this mean shadow)
1738                 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1739         }
1740         r_shadow_rendermode = r_shadow_lightingrendermode;
1741         // do global setup needed for the chosen lighting mode
1742         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1743         {
1744                 R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap)); // light filter
1745                 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
1746                 CHECKGLERROR
1747                 if (shadowmapping)
1748                 {
1749                         if (r_shadow_shadowmode == 1)
1750                         {
1751                                 r_shadow_usingshadowmap2d = true;
1752                                 R_Mesh_TexBind(GL20TU_SHADOWMAP2D, R_GetTexture(r_shadow_shadowmap2dtexture));
1753                                 CHECKGLERROR
1754                         }
1755                         else if (r_shadow_shadowmode == 2)
1756                         {
1757                                 r_shadow_usingshadowmaprect = true;
1758                                 R_Mesh_TexBindRectangle(GL20TU_SHADOWMAPRECT, R_GetTexture(r_shadow_shadowmaprectangletexture));
1759                                 CHECKGLERROR
1760                         }
1761                         else if (r_shadow_shadowmode == 3)
1762                         {
1763                                 r_shadow_usingshadowmapcube = true;
1764                                 R_Mesh_TexBindCubeMap(GL20TU_SHADOWMAPCUBE, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]));
1765                                 CHECKGLERROR
1766                         }
1767
1768                         if (r_shadow_shadowmapvsdct && (r_shadow_usingshadowmap2d || r_shadow_usingshadowmaprect))
1769                         {
1770                                 R_Mesh_TexBindCubeMap(GL20TU_CUBEPROJECTION, R_GetTexture(r_shadow_shadowmapvsdcttexture));
1771                                 CHECKGLERROR
1772                         }
1773                 }
1774         }
1775         else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_VERTEX)
1776                 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
1777         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1778         CHECKGLERROR
1779 }
1780
1781 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
1782 {
1783         CHECKGLERROR
1784         R_Shadow_RenderMode_Reset();
1785         GL_BlendFunc(GL_ONE, GL_ONE);
1786         GL_DepthRange(0, 1);
1787         GL_DepthTest(r_showshadowvolumes.integer < 2);
1788         GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
1789         GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1790         GL_CullFace(GL_NONE);
1791         r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
1792 }
1793
1794 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
1795 {
1796         CHECKGLERROR
1797         R_Shadow_RenderMode_Reset();
1798         GL_BlendFunc(GL_ONE, GL_ONE);
1799         GL_DepthRange(0, 1);
1800         GL_DepthTest(r_showlighting.integer < 2);
1801         GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
1802         if (!transparent)
1803         {
1804                 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1805         }
1806         if (stenciltest)
1807         {
1808                 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1809                 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1810         }
1811         r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
1812 }
1813
1814 void R_Shadow_RenderMode_End(void)
1815 {
1816         CHECKGLERROR
1817         R_Shadow_RenderMode_Reset();
1818         R_Shadow_RenderMode_ActiveLight(NULL);
1819         GL_DepthMask(true);
1820         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1821         r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1822 }
1823
1824 int bboxedges[12][2] =
1825 {
1826         // top
1827         {0, 1}, // +X
1828         {0, 2}, // +Y
1829         {1, 3}, // Y, +X
1830         {2, 3}, // X, +Y
1831         // bottom
1832         {4, 5}, // +X
1833         {4, 6}, // +Y
1834         {5, 7}, // Y, +X
1835         {6, 7}, // X, +Y
1836         // verticals
1837         {0, 4}, // +Z
1838         {1, 5}, // X, +Z
1839         {2, 6}, // Y, +Z
1840         {3, 7}, // XY, +Z
1841 };
1842
1843 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1844 {
1845         int i, ix1, iy1, ix2, iy2;
1846         float x1, y1, x2, y2;
1847         vec4_t v, v2;
1848         float vertex[20][3];
1849         int j, k;
1850         vec4_t plane4f;
1851         int numvertices;
1852         float corner[8][4];
1853         float dist[8];
1854         int sign[8];
1855         float f;
1856
1857         r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
1858         r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
1859         r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
1860         r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
1861
1862         if (!r_shadow_scissor.integer)
1863                 return false;
1864
1865         // if view is inside the light box, just say yes it's visible
1866         if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
1867                 return false;
1868
1869         x1 = y1 = x2 = y2 = 0;
1870
1871         // transform all corners that are infront of the nearclip plane
1872         VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
1873         plane4f[3] = r_refdef.view.frustum[4].dist;
1874         numvertices = 0;
1875         for (i = 0;i < 8;i++)
1876         {
1877                 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
1878                 dist[i] = DotProduct4(corner[i], plane4f);
1879                 sign[i] = dist[i] > 0;
1880                 if (!sign[i])
1881                 {
1882                         VectorCopy(corner[i], vertex[numvertices]);
1883                         numvertices++;
1884                 }
1885         }
1886         // if some points are behind the nearclip, add clipped edge points to make
1887         // sure that the scissor boundary is complete
1888         if (numvertices > 0 && numvertices < 8)
1889         {
1890                 // add clipped edge points
1891                 for (i = 0;i < 12;i++)
1892                 {
1893                         j = bboxedges[i][0];
1894                         k = bboxedges[i][1];
1895                         if (sign[j] != sign[k])
1896                         {
1897                                 f = dist[j] / (dist[j] - dist[k]);
1898                                 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
1899                                 numvertices++;
1900                         }
1901                 }
1902         }
1903
1904         // if we have no points to check, the light is behind the view plane
1905         if (!numvertices)
1906                 return true;
1907
1908         // if we have some points to transform, check what screen area is covered
1909         x1 = y1 = x2 = y2 = 0;
1910         v[3] = 1.0f;
1911         //Con_Printf("%i vertices to transform...\n", numvertices);
1912         for (i = 0;i < numvertices;i++)
1913         {
1914                 VectorCopy(vertex[i], v);
1915                 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
1916                 //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]);
1917                 if (i)
1918                 {
1919                         if (x1 > v2[0]) x1 = v2[0];
1920                         if (x2 < v2[0]) x2 = v2[0];
1921                         if (y1 > v2[1]) y1 = v2[1];
1922                         if (y2 < v2[1]) y2 = v2[1];
1923                 }
1924                 else
1925                 {
1926                         x1 = x2 = v2[0];
1927                         y1 = y2 = v2[1];
1928                 }
1929         }
1930
1931         // now convert the scissor rectangle to integer screen coordinates
1932         ix1 = (int)(x1 - 1.0f);
1933         iy1 = vid.height - (int)(y2 - 1.0f);
1934         ix2 = (int)(x2 + 1.0f);
1935         iy2 = vid.height - (int)(y1 + 1.0f);
1936         //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1937
1938         // clamp it to the screen
1939         if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
1940         if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
1941         if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
1942         if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
1943
1944         // if it is inside out, it's not visible
1945         if (ix2 <= ix1 || iy2 <= iy1)
1946                 return true;
1947
1948         // the light area is visible, set up the scissor rectangle
1949         r_shadow_lightscissor[0] = ix1;
1950         r_shadow_lightscissor[1] = iy1;
1951         r_shadow_lightscissor[2] = ix2 - ix1;
1952         r_shadow_lightscissor[3] = iy2 - iy1;
1953
1954         r_refdef.stats.lights_scissored++;
1955         return false;
1956 }
1957
1958 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
1959 {
1960         float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1961         float *normal3f = rsurface.normal3f + 3 * firstvertex;
1962         float *color4f = rsurface.array_color4f + 4 * firstvertex;
1963         float dist, dot, distintensity, shadeintensity, v[3], n[3];
1964         if (r_textureunits.integer >= 3)
1965         {
1966                 if (VectorLength2(diffusecolor) > 0)
1967                 {
1968                         for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1969                         {
1970                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1971                                 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1972                                 if ((dot = DotProduct(n, v)) < 0)
1973                                 {
1974                                         shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1975                                         VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
1976                                 }
1977                                 else
1978                                         VectorCopy(ambientcolor, color4f);
1979                                 if (r_refdef.fogenabled)
1980                                 {
1981                                         float f;
1982                                         f = FogPoint_Model(vertex3f);
1983                                         VectorScale(color4f, f, color4f);
1984                                 }
1985                                 color4f[3] = 1;
1986                         }
1987                 }
1988                 else
1989                 {
1990                         for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1991                         {
1992                                 VectorCopy(ambientcolor, color4f);
1993                                 if (r_refdef.fogenabled)
1994                                 {
1995                                         float f;
1996                                         Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1997                                         f = FogPoint_Model(vertex3f);
1998                                         VectorScale(color4f, f, color4f);
1999                                 }
2000                                 color4f[3] = 1;
2001                         }
2002                 }
2003         }
2004         else if (r_textureunits.integer >= 2)
2005         {
2006                 if (VectorLength2(diffusecolor) > 0)
2007                 {
2008                         for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2009                         {
2010                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2011                                 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2012                                 {
2013                                         Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2014                                         if ((dot = DotProduct(n, v)) < 0)
2015                                         {
2016                                                 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2017                                                 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2018                                                 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2019                                                 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2020                                         }
2021                                         else
2022                                         {
2023                                                 color4f[0] = ambientcolor[0] * distintensity;
2024                                                 color4f[1] = ambientcolor[1] * distintensity;
2025                                                 color4f[2] = ambientcolor[2] * distintensity;
2026                                         }
2027                                         if (r_refdef.fogenabled)
2028                                         {
2029                                                 float f;
2030                                                 f = FogPoint_Model(vertex3f);
2031                                                 VectorScale(color4f, f, color4f);
2032                                         }
2033                                 }
2034                                 else
2035                                         VectorClear(color4f);
2036                                 color4f[3] = 1;
2037                         }
2038                 }
2039                 else
2040                 {
2041                         for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2042                         {
2043                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2044                                 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2045                                 {
2046                                         color4f[0] = ambientcolor[0] * distintensity;
2047                                         color4f[1] = ambientcolor[1] * distintensity;
2048                                         color4f[2] = ambientcolor[2] * distintensity;
2049                                         if (r_refdef.fogenabled)
2050                                         {
2051                                                 float f;
2052                                                 f = FogPoint_Model(vertex3f);
2053                                                 VectorScale(color4f, f, color4f);
2054                                         }
2055                                 }
2056                                 else
2057                                         VectorClear(color4f);
2058                                 color4f[3] = 1;
2059                         }
2060                 }
2061         }
2062         else
2063         {
2064                 if (VectorLength2(diffusecolor) > 0)
2065                 {
2066                         for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2067                         {
2068                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2069                                 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2070                                 {
2071                                         distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2072                                         Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2073                                         if ((dot = DotProduct(n, v)) < 0)
2074                                         {
2075                                                 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2076                                                 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2077                                                 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2078                                                 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2079                                         }
2080                                         else
2081                                         {
2082                                                 color4f[0] = ambientcolor[0] * distintensity;
2083                                                 color4f[1] = ambientcolor[1] * distintensity;
2084                                                 color4f[2] = ambientcolor[2] * distintensity;
2085                                         }
2086                                         if (r_refdef.fogenabled)
2087                                         {
2088                                                 float f;
2089                                                 f = FogPoint_Model(vertex3f);
2090                                                 VectorScale(color4f, f, color4f);
2091                                         }
2092                                 }
2093                                 else
2094                                         VectorClear(color4f);
2095                                 color4f[3] = 1;
2096                         }
2097                 }
2098                 else
2099                 {
2100                         for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2101                         {
2102                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2103                                 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2104                                 {
2105                                         distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2106                                         color4f[0] = ambientcolor[0] * distintensity;
2107                                         color4f[1] = ambientcolor[1] * distintensity;
2108                                         color4f[2] = ambientcolor[2] * distintensity;
2109                                         if (r_refdef.fogenabled)
2110                                         {
2111                                                 float f;
2112                                                 f = FogPoint_Model(vertex3f);
2113                                                 VectorScale(color4f, f, color4f);
2114                                         }
2115                                 }
2116                                 else
2117                                         VectorClear(color4f);
2118                                 color4f[3] = 1;
2119                         }
2120                 }
2121         }
2122 }
2123
2124 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
2125
2126 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2127 {
2128         int i;
2129         float       *out3f     = rsurface.array_texcoord3f + 3 * firstvertex;
2130         const float *vertex3f  = rsurface.vertex3f         + 3 * firstvertex;
2131         const float *svector3f = rsurface.svector3f        + 3 * firstvertex;
2132         const float *tvector3f = rsurface.tvector3f        + 3 * firstvertex;
2133         const float *normal3f  = rsurface.normal3f         + 3 * firstvertex;
2134         float lightdir[3];
2135         for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2136         {
2137                 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2138                 // the cubemap normalizes this for us
2139                 out3f[0] = DotProduct(svector3f, lightdir);
2140                 out3f[1] = DotProduct(tvector3f, lightdir);
2141                 out3f[2] = DotProduct(normal3f, lightdir);
2142         }
2143 }
2144
2145 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2146 {
2147         int i;
2148         float       *out3f     = rsurface.array_texcoord3f + 3 * firstvertex;
2149         const float *vertex3f  = rsurface.vertex3f         + 3 * firstvertex;
2150         const float *svector3f = rsurface.svector3f        + 3 * firstvertex;
2151         const float *tvector3f = rsurface.tvector3f        + 3 * firstvertex;
2152         const float *normal3f  = rsurface.normal3f         + 3 * firstvertex;
2153         float lightdir[3], eyedir[3], halfdir[3];
2154         for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2155         {
2156                 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2157                 VectorNormalize(lightdir);
2158                 VectorSubtract(rsurface.modelorg, vertex3f, eyedir);
2159                 VectorNormalize(eyedir);
2160                 VectorAdd(lightdir, eyedir, halfdir);
2161                 // the cubemap normalizes this for us
2162                 out3f[0] = DotProduct(svector3f, halfdir);
2163                 out3f[1] = DotProduct(tvector3f, halfdir);
2164                 out3f[2] = DotProduct(normal3f, halfdir);
2165         }
2166 }
2167
2168 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)
2169 {
2170         // used to display how many times a surface is lit for level design purposes
2171         R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2172 }
2173
2174 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)
2175 {
2176         // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2177         R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
2178         if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND))
2179                 R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
2180         else
2181                 R_Mesh_ColorPointer(NULL, 0, 0);
2182         R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2183         R_Mesh_TexMatrix(1, &rsurface.texture->currentbackgroundtexmatrix);
2184         R_Mesh_TexBind(GL20TU_NORMAL, R_GetTexture(rsurface.texture->currentskinframe->nmap));
2185         R_Mesh_TexBind(GL20TU_COLOR, R_GetTexture(rsurface.texture->basetexture));
2186         R_Mesh_TexBind(GL20TU_GLOSS, R_GetTexture(rsurface.texture->glosstexture));
2187         if (rsurface.texture->backgroundcurrentskinframe)
2188         {
2189                 R_Mesh_TexBind(GL20TU_SECONDARY_NORMAL, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->nmap));
2190                 R_Mesh_TexBind(GL20TU_SECONDARY_COLOR, R_GetTexture(rsurface.texture->backgroundbasetexture));
2191                 R_Mesh_TexBind(GL20TU_SECONDARY_GLOSS, R_GetTexture(rsurface.texture->backgroundglosstexture));
2192                 R_Mesh_TexBind(GL20TU_SECONDARY_GLOW, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->glow));
2193         }
2194         //R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap));
2195         R_Mesh_TexBind(GL20TU_FOGMASK, R_GetTexture(r_texture_fogattenuation));
2196         if(rsurface.texture->colormapping)
2197         {
2198                 R_Mesh_TexBind(GL20TU_PANTS, R_GetTexture(rsurface.texture->currentskinframe->pants));
2199                 R_Mesh_TexBind(GL20TU_SHIRT, R_GetTexture(rsurface.texture->currentskinframe->shirt));
2200         }
2201         R_Mesh_TexBind(GL20TU_ATTENUATION, R_GetTexture(r_shadow_attenuationgradienttexture));
2202         R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
2203         R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
2204         R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
2205         R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
2206         if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2207         {
2208                 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2209         }
2210         R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2211         if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2212         {
2213                 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2214         }
2215 }
2216
2217 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)
2218 {
2219         // shared final code for all the dot3 layers
2220         int renders;
2221         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2222         for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
2223         {
2224                 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
2225                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2226         }
2227 }
2228
2229 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)
2230 {
2231         rmeshstate_t m;
2232         // colorscale accounts for how much we multiply the brightness
2233         // during combine.
2234         //
2235         // mult is how many times the final pass of the lighting will be
2236         // performed to get more brightness than otherwise possible.
2237         //
2238         // Limit mult to 64 for sanity sake.
2239         GL_Color(1,1,1,1);
2240         if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
2241         {
2242                 // 3 3D combine path (Geforce3, Radeon 8500)
2243                 memset(&m, 0, sizeof(m));
2244                 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2245                 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2246                 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2247                 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2248                 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2249                 m.tex[1] = R_GetTexture(basetexture);
2250                 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2251                 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2252                 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2253                 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2254                 m.texcubemap[2] = R_GetTexture(rsurface.rtlight->currentcubemap);
2255                 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2256                 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2257                 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2258                 m.texmatrix[2] = rsurface.entitytolight;
2259                 GL_BlendFunc(GL_ONE, GL_ONE);
2260         }
2261         else if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
2262         {
2263                 // 2 3D combine path (Geforce3, original Radeon)
2264                 memset(&m, 0, sizeof(m));
2265                 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2266                 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2267                 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2268                 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2269                 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2270                 m.tex[1] = R_GetTexture(basetexture);
2271                 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2272                 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2273                 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2274                 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2275                 GL_BlendFunc(GL_ONE, GL_ONE);
2276         }
2277         else if (r_textureunits.integer >= 4 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2278         {
2279                 // 4 2D combine path (Geforce3, Radeon 8500)
2280                 memset(&m, 0, sizeof(m));
2281                 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2282                 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2283                 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2284                 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2285                 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2286                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2287                 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2288                 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2289                 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2290                 m.texmatrix[1] = rsurface.entitytoattenuationz;
2291                 m.tex[2] = R_GetTexture(basetexture);
2292                 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2293                 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2294                 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2295                 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2296                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2297                 {
2298                         m.texcubemap[3] = R_GetTexture(rsurface.rtlight->currentcubemap);
2299                         m.pointer_texcoord3f[3] = rsurface.vertex3f;
2300                         m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2301                         m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2302                         m.texmatrix[3] = rsurface.entitytolight;
2303                 }
2304                 GL_BlendFunc(GL_ONE, GL_ONE);
2305         }
2306         else if (r_textureunits.integer >= 3 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2307         {
2308                 // 3 2D combine path (Geforce3, original Radeon)
2309                 memset(&m, 0, sizeof(m));
2310                 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2311                 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2312                 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2313                 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2314                 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2315                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2316                 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2317                 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2318                 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2319                 m.texmatrix[1] = rsurface.entitytoattenuationz;
2320                 m.tex[2] = R_GetTexture(basetexture);
2321                 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2322                 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2323                 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2324                 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2325                 GL_BlendFunc(GL_ONE, GL_ONE);
2326         }
2327         else
2328         {
2329                 // 2/2/2 2D combine path (any dot3 card)
2330                 memset(&m, 0, sizeof(m));
2331                 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2332                 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2333                 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2334                 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2335                 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2336                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2337                 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2338                 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2339                 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2340                 m.texmatrix[1] = rsurface.entitytoattenuationz;
2341                 R_Mesh_TextureState(&m);
2342                 GL_ColorMask(0,0,0,1);
2343                 GL_BlendFunc(GL_ONE, GL_ZERO);
2344                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2345
2346                 // second pass
2347                 memset(&m, 0, sizeof(m));
2348                 m.tex[0] = R_GetTexture(basetexture);
2349                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2350                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2351                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2352                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2353                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2354                 {
2355                         m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2356                         m.pointer_texcoord3f[1] = rsurface.vertex3f;
2357                         m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2358                         m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2359                         m.texmatrix[1] = rsurface.entitytolight;
2360                 }
2361                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2362         }
2363         // this final code is shared
2364         R_Mesh_TextureState(&m);
2365         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);
2366 }
2367
2368 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)
2369 {
2370         rmeshstate_t m;
2371         // colorscale accounts for how much we multiply the brightness
2372         // during combine.
2373         //
2374         // mult is how many times the final pass of the lighting will be
2375         // performed to get more brightness than otherwise possible.
2376         //
2377         // Limit mult to 64 for sanity sake.
2378         GL_Color(1,1,1,1);
2379         // generate normalization cubemap texcoords
2380         R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2381         if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
2382         {
2383                 // 3/2 3D combine path (Geforce3, Radeon 8500)
2384                 memset(&m, 0, sizeof(m));
2385                 m.tex[0] = R_GetTexture(normalmaptexture);
2386                 m.texcombinergb[0] = GL_REPLACE;
2387                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2388                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2389                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2390                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2391                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2392                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2393                 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2394                 m.pointer_texcoord_bufferobject[1] = 0;
2395                 m.pointer_texcoord_bufferoffset[1] = 0;
2396                 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
2397                 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2398                 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2399                 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2400                 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2401                 R_Mesh_TextureState(&m);
2402                 GL_ColorMask(0,0,0,1);
2403                 GL_BlendFunc(GL_ONE, GL_ZERO);
2404                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2405
2406                 // second pass
2407                 memset(&m, 0, sizeof(m));
2408                 m.tex[0] = R_GetTexture(basetexture);
2409                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2410                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2411                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2412                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2413                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2414                 {
2415                         m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2416                         m.pointer_texcoord3f[1] = rsurface.vertex3f;
2417                         m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2418                         m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2419                         m.texmatrix[1] = rsurface.entitytolight;
2420                 }
2421                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2422         }
2423         else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2424         {
2425                 // 1/2/2 3D combine path (original Radeon)
2426                 memset(&m, 0, sizeof(m));
2427                 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2428                 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2429                 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2430                 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2431                 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2432                 R_Mesh_TextureState(&m);
2433                 GL_ColorMask(0,0,0,1);
2434                 GL_BlendFunc(GL_ONE, GL_ZERO);
2435                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2436
2437                 // second pass
2438                 memset(&m, 0, sizeof(m));
2439                 m.tex[0] = R_GetTexture(normalmaptexture);
2440                 m.texcombinergb[0] = GL_REPLACE;
2441                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2442                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2443                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2444                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2445                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2446                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2447                 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2448                 m.pointer_texcoord_bufferobject[1] = 0;
2449                 m.pointer_texcoord_bufferoffset[1] = 0;
2450                 R_Mesh_TextureState(&m);
2451                 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2452                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2453
2454                 // second pass
2455                 memset(&m, 0, sizeof(m));
2456                 m.tex[0] = R_GetTexture(basetexture);
2457                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2458                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2459                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2460                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2461                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2462                 {
2463                         m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2464                         m.pointer_texcoord3f[1] = rsurface.vertex3f;
2465                         m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2466                         m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2467                         m.texmatrix[1] = rsurface.entitytolight;
2468                 }
2469                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2470         }
2471         else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2472         {
2473                 // 2/2 3D combine path (original Radeon)
2474                 memset(&m, 0, sizeof(m));
2475                 m.tex[0] = R_GetTexture(normalmaptexture);
2476                 m.texcombinergb[0] = GL_REPLACE;
2477                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2478                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2479                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2480                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2481                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2482                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2483                 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2484                 m.pointer_texcoord_bufferobject[1] = 0;
2485                 m.pointer_texcoord_bufferoffset[1] = 0;
2486                 R_Mesh_TextureState(&m);
2487                 GL_ColorMask(0,0,0,1);
2488                 GL_BlendFunc(GL_ONE, GL_ZERO);
2489                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2490
2491                 // second pass
2492                 memset(&m, 0, sizeof(m));
2493                 m.tex[0] = R_GetTexture(basetexture);
2494                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2495                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2496                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2497                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2498                 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2499                 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2500                 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2501                 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2502                 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2503                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2504         }
2505         else if (r_textureunits.integer >= 4)
2506         {
2507                 // 4/2 2D combine path (Geforce3, Radeon 8500)
2508                 memset(&m, 0, sizeof(m));
2509                 m.tex[0] = R_GetTexture(normalmaptexture);
2510                 m.texcombinergb[0] = GL_REPLACE;
2511                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2512                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2513                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2514                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2515                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2516                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2517                 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2518                 m.pointer_texcoord_bufferobject[1] = 0;
2519                 m.pointer_texcoord_bufferoffset[1] = 0;
2520                 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2521                 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2522                 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2523                 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2524                 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2525                 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2526                 m.pointer_texcoord3f[3] = rsurface.vertex3f;
2527                 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2528                 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2529                 m.texmatrix[3] = rsurface.entitytoattenuationz;
2530                 R_Mesh_TextureState(&m);
2531                 GL_ColorMask(0,0,0,1);
2532                 GL_BlendFunc(GL_ONE, GL_ZERO);
2533                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2534
2535                 // second pass
2536                 memset(&m, 0, sizeof(m));
2537                 m.tex[0] = R_GetTexture(basetexture);
2538                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2539                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2540                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2541                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2542                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2543                 {
2544                         m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2545                         m.pointer_texcoord3f[1] = rsurface.vertex3f;
2546                         m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2547                         m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2548                         m.texmatrix[1] = rsurface.entitytolight;
2549                 }
2550                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2551         }
2552         else
2553         {
2554                 // 2/2/2 2D combine path (any dot3 card)
2555                 memset(&m, 0, sizeof(m));
2556                 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2557                 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2558                 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2559                 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2560                 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2561                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2562                 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2563                 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2564                 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2565                 m.texmatrix[1] = rsurface.entitytoattenuationz;
2566                 R_Mesh_TextureState(&m);
2567                 GL_ColorMask(0,0,0,1);
2568                 GL_BlendFunc(GL_ONE, GL_ZERO);
2569                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2570
2571                 // second pass
2572                 memset(&m, 0, sizeof(m));
2573                 m.tex[0] = R_GetTexture(normalmaptexture);
2574                 m.texcombinergb[0] = GL_REPLACE;
2575                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2576                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2577                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2578                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2579                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2580                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2581                 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2582                 m.pointer_texcoord_bufferobject[1] = 0;
2583                 m.pointer_texcoord_bufferoffset[1] = 0;
2584                 R_Mesh_TextureState(&m);
2585                 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2586                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2587
2588                 // second pass
2589                 memset(&m, 0, sizeof(m));
2590                 m.tex[0] = R_GetTexture(basetexture);
2591                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2592                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2593                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2594                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2595                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2596                 {
2597                         m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2598                         m.pointer_texcoord3f[1] = rsurface.vertex3f;
2599                         m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2600                         m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2601                         m.texmatrix[1] = rsurface.entitytolight;
2602                 }
2603                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2604         }
2605         // this final code is shared
2606         R_Mesh_TextureState(&m);
2607         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);
2608 }
2609
2610 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)
2611 {
2612         float glossexponent;
2613         rmeshstate_t m;
2614         // FIXME: detect blendsquare!
2615         //if (!gl_support_blendsquare)
2616         //      return;
2617         GL_Color(1,1,1,1);
2618         // generate normalization cubemap texcoords
2619         R_Shadow_GenTexCoords_Specular_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2620         if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2621         {
2622                 // 2/0/0/1/2 3D combine blendsquare path
2623                 memset(&m, 0, sizeof(m));
2624                 m.tex[0] = R_GetTexture(normalmaptexture);
2625                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2626                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2627                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2628                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2629                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2630                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2631                 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2632                 m.pointer_texcoord_bufferobject[1] = 0;
2633                 m.pointer_texcoord_bufferoffset[1] = 0;
2634                 R_Mesh_TextureState(&m);
2635                 GL_ColorMask(0,0,0,1);
2636                 // this squares the result
2637                 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2638                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2639
2640                 // second and third pass
2641                 R_Mesh_ResetTextureState();
2642                 // square alpha in framebuffer a few times to make it shiny
2643                 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2644                 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2645                         R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2646
2647                 // fourth pass
2648                 memset(&m, 0, sizeof(m));
2649                 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2650                 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2651                 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2652                 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2653                 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2654                 R_Mesh_TextureState(&m);
2655                 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2656                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2657
2658                 // fifth pass
2659                 memset(&m, 0, sizeof(m));
2660                 m.tex[0] = R_GetTexture(glosstexture);
2661                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2662                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2663                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2664                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2665                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2666                 {
2667                         m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2668                         m.pointer_texcoord3f[1] = rsurface.vertex3f;
2669                         m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2670                         m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2671                         m.texmatrix[1] = rsurface.entitytolight;
2672                 }
2673                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2674         }
2675         else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
2676         {
2677                 // 2/0/0/2 3D combine blendsquare path
2678                 memset(&m, 0, sizeof(m));
2679                 m.tex[0] = R_GetTexture(normalmaptexture);
2680                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2681                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2682                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2683                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2684                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2685                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2686                 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2687                 m.pointer_texcoord_bufferobject[1] = 0;
2688                 m.pointer_texcoord_bufferoffset[1] = 0;
2689                 R_Mesh_TextureState(&m);
2690                 GL_ColorMask(0,0,0,1);
2691                 // this squares the result
2692                 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2693                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2694
2695                 // second and third pass
2696                 R_Mesh_ResetTextureState();
2697                 // square alpha in framebuffer a few times to make it shiny
2698                 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2699                 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2700                         R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2701
2702                 // fourth pass
2703                 memset(&m, 0, sizeof(m));
2704                 m.tex[0] = R_GetTexture(glosstexture);
2705                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2706                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2707                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2708                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2709                 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2710                 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2711                 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2712                 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2713                 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2714                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2715         }
2716         else
2717         {
2718                 // 2/0/0/2/2 2D combine blendsquare path
2719                 memset(&m, 0, sizeof(m));
2720                 m.tex[0] = R_GetTexture(normalmaptexture);
2721                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2722                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2723                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2724                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2725                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2726                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2727                 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2728                 m.pointer_texcoord_bufferobject[1] = 0;
2729                 m.pointer_texcoord_bufferoffset[1] = 0;
2730                 R_Mesh_TextureState(&m);
2731                 GL_ColorMask(0,0,0,1);
2732                 // this squares the result
2733                 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2734                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2735
2736                 // second and third pass
2737                 R_Mesh_ResetTextureState();
2738                 // square alpha in framebuffer a few times to make it shiny
2739                 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2740                 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2741                         R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2742
2743                 // fourth pass
2744                 memset(&m, 0, sizeof(m));
2745                 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2746                 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2747                 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2748                 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2749                 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2750                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2751                 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2752                 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2753                 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2754                 m.texmatrix[1] = rsurface.entitytoattenuationz;
2755                 R_Mesh_TextureState(&m);
2756                 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2757                 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2758
2759                 // fifth pass
2760                 memset(&m, 0, sizeof(m));
2761                 m.tex[0] = R_GetTexture(glosstexture);
2762                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2763                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2764                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2765                 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2766                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2767                 {
2768                         m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2769                         m.pointer_texcoord3f[1] = rsurface.vertex3f;
2770                         m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2771                         m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2772                         m.texmatrix[1] = rsurface.entitytolight;
2773                 }
2774                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2775         }
2776         // this final code is shared
2777         R_Mesh_TextureState(&m);
2778         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);
2779 }
2780
2781 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)
2782 {
2783         // ARB path (any Geforce, any Radeon)
2784         qboolean doambient = ambientscale > 0;
2785         qboolean dodiffuse = diffusescale > 0;
2786         qboolean dospecular = specularscale > 0;
2787         if (!doambient && !dodiffuse && !dospecular)
2788                 return;
2789         R_Mesh_ColorPointer(NULL, 0, 0);
2790         if (doambient)
2791                 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, ambientscale * r_refdef.view.colorscale);
2792         if (dodiffuse)
2793                 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2794         if (dopants)
2795         {
2796                 if (doambient)
2797                         R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, ambientscale * r_refdef.view.colorscale);
2798                 if (dodiffuse)
2799                         R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2800         }
2801         if (doshirt)
2802         {
2803                 if (doambient)
2804                         R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, ambientscale * r_refdef.view.colorscale);
2805                 if (dodiffuse)
2806                         R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2807         }
2808         if (dospecular)
2809                 R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_refdef.view.colorscale);
2810 }
2811
2812 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2813 {
2814         int renders;
2815         int i;
2816         int stop;
2817         int newfirstvertex;
2818         int newlastvertex;
2819         int newnumtriangles;
2820         int *newe;
2821         const int *e;
2822         float *c;
2823         int maxtriangles = 4096;
2824         int newelements[4096*3];
2825         R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
2826         for (renders = 0;renders < 64;renders++)
2827         {
2828                 stop = true;
2829                 newfirstvertex = 0;
2830                 newlastvertex = 0;
2831                 newnumtriangles = 0;
2832                 newe = newelements;
2833                 // due to low fillrate on the cards this vertex lighting path is
2834                 // designed for, we manually cull all triangles that do not
2835                 // contain a lit vertex
2836                 // this builds batches of triangles from multiple surfaces and
2837                 // renders them at once
2838                 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2839                 {
2840                         if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
2841                         {
2842                                 if (newnumtriangles)
2843                                 {
2844                                         newfirstvertex = min(newfirstvertex, e[0]);
2845                                         newlastvertex  = max(newlastvertex, e[0]);
2846                                 }
2847                                 else
2848                                 {
2849                                         newfirstvertex = e[0];
2850                                         newlastvertex = e[0];
2851                                 }
2852                                 newfirstvertex = min(newfirstvertex, e[1]);
2853                                 newlastvertex  = max(newlastvertex, e[1]);
2854                                 newfirstvertex = min(newfirstvertex, e[2]);
2855                                 newlastvertex  = max(newlastvertex, e[2]);
2856                                 newe[0] = e[0];
2857                                 newe[1] = e[1];
2858                                 newe[2] = e[2];
2859                                 newnumtriangles++;
2860                                 newe += 3;
2861                                 if (newnumtriangles >= maxtriangles)
2862                                 {
2863                                         R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2864                                         newnumtriangles = 0;
2865                                         newe = newelements;
2866                                         stop = false;
2867                                 }
2868                         }
2869                 }
2870                 if (newnumtriangles >= 1)
2871                 {
2872                         R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2873                         stop = false;
2874                 }
2875                 // if we couldn't find any lit triangles, exit early
2876                 if (stop)
2877                         break;
2878                 // now reduce the intensity for the next overbright pass
2879                 // we have to clamp to 0 here incase the drivers have improper
2880                 // handling of negative colors
2881                 // (some old drivers even have improper handling of >1 color)
2882                 stop = true;
2883                 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2884                 {
2885                         if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2886                         {
2887                                 c[0] = max(0, c[0] - 1);
2888                                 c[1] = max(0, c[1] - 1);
2889                                 c[2] = max(0, c[2] - 1);
2890                                 stop = false;
2891                         }
2892                         else
2893                                 VectorClear(c);
2894                 }
2895                 // another check...
2896                 if (stop)
2897                         break;
2898         }
2899 }
2900
2901 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)
2902 {
2903         // OpenGL 1.1 path (anything)
2904         float ambientcolorbase[3], diffusecolorbase[3];
2905         float ambientcolorpants[3], diffusecolorpants[3];
2906         float ambientcolorshirt[3], diffusecolorshirt[3];
2907         rmeshstate_t m;
2908         VectorScale(lightcolorbase, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorbase);
2909         VectorScale(lightcolorbase, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorbase);
2910         VectorScale(lightcolorpants, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorpants);
2911         VectorScale(lightcolorpants, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorpants);
2912         VectorScale(lightcolorshirt, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorshirt);
2913         VectorScale(lightcolorshirt, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorshirt);
2914         memset(&m, 0, sizeof(m));
2915         m.tex[0] = R_GetTexture(basetexture);
2916         m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2917         m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2918         m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2919         m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2920         if (r_textureunits.integer >= 2)
2921         {
2922                 // voodoo2 or TNT
2923                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2924                 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2925                 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2926                 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2927                 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2928                 if (r_textureunits.integer >= 3)
2929                 {
2930                         // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
2931                         m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2932                         m.texmatrix[2] = rsurface.entitytoattenuationz;
2933                         m.pointer_texcoord3f[2] = rsurface.vertex3f;
2934                         m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2935                         m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2936                 }
2937         }
2938         R_Mesh_TextureState(&m);
2939         //R_Mesh_TexBind(0, R_GetTexture(basetexture));
2940         R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
2941         if (dopants)
2942         {
2943                 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
2944                 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
2945         }
2946         if (doshirt)
2947         {
2948                 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
2949                 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
2950         }
2951 }
2952
2953 extern cvar_t gl_lightmaps;
2954 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)
2955 {
2956         float ambientscale, diffusescale, specularscale;
2957         vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
2958         rtexture_t *nmap;
2959         // calculate colors to render this texture with
2960         lightcolorbase[0] = rsurface.rtlight->currentcolor[0] * rsurface.texture->dlightcolor[0];
2961         lightcolorbase[1] = rsurface.rtlight->currentcolor[1] * rsurface.texture->dlightcolor[1];
2962         lightcolorbase[2] = rsurface.rtlight->currentcolor[2] * rsurface.texture->dlightcolor[2];
2963         ambientscale = rsurface.rtlight->ambientscale;
2964         diffusescale = rsurface.rtlight->diffusescale;
2965         specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2966         if (!r_shadow_usenormalmap.integer)
2967         {
2968                 ambientscale += 1.0f * diffusescale;
2969                 diffusescale = 0;
2970                 specularscale = 0;
2971         }
2972         if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
2973                 return;
2974         RSurf_SetupDepthAndCulling();
2975         nmap = rsurface.texture->currentskinframe->nmap;
2976         if (gl_lightmaps.integer)
2977                 nmap = r_texture_blanknormalmap;
2978         if (rsurface.texture->colormapping && !gl_lightmaps.integer)
2979         {
2980                 qboolean dopants = rsurface.texture->currentskinframe->pants != NULL && VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f);
2981                 qboolean doshirt = rsurface.texture->currentskinframe->shirt != NULL && VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f);
2982                 if (dopants)
2983                 {
2984                         lightcolorpants[0] = lightcolorbase[0] * rsurface.colormap_pantscolor[0];
2985                         lightcolorpants[1] = lightcolorbase[1] * rsurface.colormap_pantscolor[1];
2986                         lightcolorpants[2] = lightcolorbase[2] * rsurface.colormap_pantscolor[2];
2987                 }
2988                 else
2989                         VectorClear(lightcolorpants);
2990                 if (doshirt)
2991                 {
2992                         lightcolorshirt[0] = lightcolorbase[0] * rsurface.colormap_shirtcolor[0];
2993                         lightcolorshirt[1] = lightcolorbase[1] * rsurface.colormap_shirtcolor[1];
2994                         lightcolorshirt[2] = lightcolorbase[2] * rsurface.colormap_shirtcolor[2];
2995                 }
2996                 else
2997                         VectorClear(lightcolorshirt);
2998                 switch (r_shadow_rendermode)
2999                 {
3000                 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3001                         GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3002                         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);
3003                         break;
3004                 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3005                         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);
3006                         break;
3007                 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
3008                         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);
3009                         break;
3010                 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3011                         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);
3012                         break;
3013                 default:
3014                         Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3015                         break;
3016                 }
3017         }
3018         else
3019         {
3020                 switch (r_shadow_rendermode)
3021                 {
3022                 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3023                         GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3024                         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);
3025                         break;
3026                 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3027                         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);
3028                         break;
3029                 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
3030                         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);
3031                         break;
3032                 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3033                         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);
3034                         break;
3035                 default:
3036                         Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3037                         break;
3038                 }
3039         }
3040 }
3041
3042 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)
3043 {
3044         matrix4x4_t tempmatrix = *matrix;
3045         Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
3046
3047         // if this light has been compiled before, free the associated data
3048         R_RTLight_Uncompile(rtlight);
3049
3050         // clear it completely to avoid any lingering data
3051         memset(rtlight, 0, sizeof(*rtlight));
3052
3053         // copy the properties
3054         rtlight->matrix_lighttoworld = tempmatrix;
3055         Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3056         Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3057         rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3058         VectorCopy(color, rtlight->color);
3059         rtlight->cubemapname[0] = 0;
3060         if (cubemapname && cubemapname[0])
3061                 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3062         rtlight->shadow = shadow;
3063         rtlight->corona = corona;
3064         rtlight->style = style;
3065         rtlight->isstatic = isstatic;
3066         rtlight->coronasizescale = coronasizescale;
3067         rtlight->ambientscale = ambientscale;
3068         rtlight->diffusescale = diffusescale;
3069         rtlight->specularscale = specularscale;
3070         rtlight->flags = flags;
3071
3072         // compute derived data
3073         //rtlight->cullradius = rtlight->radius;
3074         //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3075         rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3076         rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3077         rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3078         rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3079         rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3080         rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3081 }
3082
3083 // compiles rtlight geometry
3084 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3085 void R_RTLight_Compile(rtlight_t *rtlight)
3086 {
3087         int i;
3088         int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3089         int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
3090         entity_render_t *ent = r_refdef.scene.worldentity;
3091         dp_model_t *model = r_refdef.scene.worldmodel;
3092         unsigned char *data;
3093         shadowmesh_t *mesh;
3094
3095         // compile the light
3096         rtlight->compiled = true;
3097         rtlight->static_numleafs = 0;
3098         rtlight->static_numleafpvsbytes = 0;
3099         rtlight->static_leaflist = NULL;
3100         rtlight->static_leafpvs = NULL;
3101         rtlight->static_numsurfaces = 0;
3102         rtlight->static_surfacelist = NULL;
3103         rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3104         rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3105         rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3106         rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3107         rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3108         rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3109
3110         if (model && model->GetLightInfo)
3111         {
3112                 // this variable must be set for the CompileShadowVolume code
3113                 r_shadow_compilingrtlight = rtlight;
3114                 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);
3115                 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);
3116                 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3117                 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3118                 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3119                 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3120                 rtlight->static_numsurfaces = numsurfaces;
3121                 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3122                 rtlight->static_numleafs = numleafs;
3123                 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3124                 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3125                 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3126                 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3127                 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3128                 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3129                 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3130                 if (rtlight->static_numsurfaces)
3131                         memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3132                 if (rtlight->static_numleafs)
3133                         memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3134                 if (rtlight->static_numleafpvsbytes)
3135                         memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3136                 if (rtlight->static_numshadowtrispvsbytes)
3137                         memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3138                 if (rtlight->static_numlighttrispvsbytes)
3139                         memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3140                 if (model->CompileShadowVolume && rtlight->shadow)
3141                         model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3142                 // now we're done compiling the rtlight
3143                 r_shadow_compilingrtlight = NULL;
3144         }
3145
3146
3147         // use smallest available cullradius - box radius or light radius
3148         //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3149         //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3150
3151         shadowzpasstris = 0;
3152         if (rtlight->static_meshchain_shadow_zpass)
3153                 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3154                         shadowzpasstris += mesh->numtriangles;
3155
3156         shadowzfailtris = 0;
3157         if (rtlight->static_meshchain_shadow_zfail)
3158                 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3159                         shadowzfailtris += mesh->numtriangles;
3160
3161         lighttris = 0;
3162         if (rtlight->static_numlighttrispvsbytes)
3163                 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3164                         if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3165                                 lighttris++;
3166
3167         shadowtris = 0;
3168         if (rtlight->static_numlighttrispvsbytes)
3169                 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3170                         if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3171                                 shadowtris++;
3172
3173         if (developer.integer >= 10)
3174                 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);
3175 }
3176
3177 void R_RTLight_Uncompile(rtlight_t *rtlight)
3178 {
3179         if (rtlight->compiled)
3180         {
3181                 if (rtlight->static_meshchain_shadow_zpass)
3182                         Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3183                 rtlight->static_meshchain_shadow_zpass = NULL;
3184                 if (rtlight->static_meshchain_shadow_zfail)
3185                         Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3186                 rtlight->static_meshchain_shadow_zfail = NULL;
3187                 // these allocations are grouped
3188                 if (rtlight->static_surfacelist)
3189                         Mem_Free(rtlight->static_surfacelist);
3190                 rtlight->static_numleafs = 0;
3191                 rtlight->static_numleafpvsbytes = 0;
3192                 rtlight->static_leaflist = NULL;
3193                 rtlight->static_leafpvs = NULL;
3194                 rtlight->static_numsurfaces = 0;
3195                 rtlight->static_surfacelist = NULL;
3196                 rtlight->static_numshadowtrispvsbytes = 0;
3197                 rtlight->static_shadowtrispvs = NULL;
3198                 rtlight->static_numlighttrispvsbytes = 0;
3199                 rtlight->static_lighttrispvs = NULL;
3200                 rtlight->compiled = false;
3201         }
3202 }
3203
3204 void R_Shadow_UncompileWorldLights(void)
3205 {
3206         size_t lightindex;
3207         dlight_t *light;
3208         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3209         for (lightindex = 0;lightindex < range;lightindex++)
3210         {
3211                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3212                 if (!light)
3213                         continue;
3214                 R_RTLight_Uncompile(&light->rtlight);
3215         }
3216 }
3217
3218 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3219 {
3220         int i, j;
3221         mplane_t plane;
3222         // reset the count of frustum planes
3223         // see rsurface.rtlight_frustumplanes definition for how much this array
3224         // can hold
3225         rsurface.rtlight_numfrustumplanes = 0;
3226
3227         // haven't implemented a culling path for ortho rendering
3228         if (!r_refdef.view.useperspective)
3229         {
3230                 // check if the light is on screen and copy the 4 planes if it is
3231                 for (i = 0;i < 4;i++)
3232                         if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3233                                 break;
3234                 if (i == 4)
3235                         for (i = 0;i < 4;i++)
3236                                 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3237                 return;
3238         }
3239
3240 #if 1
3241         // generate a deformed frustum that includes the light origin, this is
3242         // used to cull shadow casting surfaces that can not possibly cast a
3243         // shadow onto the visible light-receiving surfaces, which can be a
3244         // performance gain
3245         //
3246         // if the light origin is onscreen the result will be 4 planes exactly
3247         // if the light origin is offscreen on only one axis the result will
3248         // be exactly 5 planes (split-side case)
3249         // if the light origin is offscreen on two axes the result will be
3250         // exactly 4 planes (stretched corner case)
3251         for (i = 0;i < 4;i++)
3252         {
3253                 // quickly reject standard frustum planes that put the light
3254                 // origin outside the frustum
3255                 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3256                         continue;
3257                 // copy the plane
3258                 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3259         }
3260         // if all the standard frustum planes were accepted, the light is onscreen
3261         // otherwise we need to generate some more planes below...
3262         if (rsurface.rtlight_numfrustumplanes < 4)
3263         {
3264                 // at least one of the stock frustum planes failed, so we need to
3265                 // create one or two custom planes to enclose the light origin
3266                 for (i = 0;i < 4;i++)
3267                 {
3268                         // create a plane using the view origin and light origin, and a
3269                         // single point from the frustum corner set
3270                         TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3271                         VectorNormalize(plane.normal);
3272                         plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3273                         // see if this plane is backwards and flip it if so
3274                         for (j = 0;j < 4;j++)
3275                                 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3276                                         break;
3277                         if (j < 4)
3278                         {
3279                                 VectorNegate(plane.normal, plane.normal);
3280                                 plane.dist *= -1;
3281                                 // flipped plane, test again to see if it is now valid
3282                                 for (j = 0;j < 4;j++)
3283                                         if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3284                                                 break;
3285                                 // if the plane is still not valid, then it is dividing the
3286                                 // frustum and has to be rejected
3287                                 if (j < 4)
3288                                         continue;
3289                         }
3290                         // we have created a valid plane, compute extra info
3291                         PlaneClassify(&plane);
3292                         // copy the plane
3293                         rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3294 #if 1
3295                         // if we've found 5 frustum planes then we have constructed a
3296                         // proper split-side case and do not need to keep searching for
3297                         // planes to enclose the light origin
3298                         if (rsurface.rtlight_numfrustumplanes == 5)
3299                                 break;
3300 #endif
3301                 }
3302         }
3303 #endif
3304
3305 #if 0
3306         for (i = 0;i < rsurface.rtlight_numfrustumplanes;i++)
3307         {
3308                 plane = rsurface.rtlight_frustumplanes[i];
3309                 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));
3310         }
3311 #endif
3312
3313 #if 0
3314         // now add the light-space box planes if the light box is rotated, as any
3315         // caster outside the oriented light box is irrelevant (even if it passed
3316         // the worldspace light box, which is axial)
3317         if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3318         {
3319                 for (i = 0;i < 6;i++)
3320                 {
3321                         vec3_t v;
3322                         VectorClear(v);
3323                         v[i >> 1] = (i & 1) ? -1 : 1;
3324                         Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3325                         VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3326                         plane.dist = VectorNormalizeLength(plane.normal);
3327                         plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3328                         rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3329                 }
3330         }
3331 #endif
3332
3333 #if 0
3334         // add the world-space reduced box planes
3335         for (i = 0;i < 6;i++)
3336         {
3337                 VectorClear(plane.normal);
3338                 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3339                 plane.dist = (i & 1) ? -rsurface.rtlight_cullmaxs[i >> 1] : rsurface.rtlight_cullmins[i >> 1];
3340                 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3341         }
3342 #endif
3343
3344 #if 0
3345         {
3346         int j, oldnum;
3347         vec3_t points[8];
3348         vec_t bestdist;
3349         // reduce all plane distances to tightly fit the rtlight cull box, which
3350         // is in worldspace
3351         VectorSet(points[0], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3352         VectorSet(points[1], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3353         VectorSet(points[2], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3354         VectorSet(points[3], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3355         VectorSet(points[4], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3356         VectorSet(points[5], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3357         VectorSet(points[6], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3358         VectorSet(points[7], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3359         oldnum = rsurface.rtlight_numfrustumplanes;
3360         rsurface.rtlight_numfrustumplanes = 0;
3361         for (j = 0;j < oldnum;j++)
3362         {
3363                 // find the nearest point on the box to this plane
3364                 bestdist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[0]);
3365                 for (i = 1;i < 8;i++)
3366                 {
3367                         dist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[i]);
3368                         if (bestdist > dist)
3369                                 bestdist = dist;
3370                 }
3371                 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);
3372                 // if the nearest point is near or behind the plane, we want this
3373                 // plane, otherwise the plane is useless as it won't cull anything
3374                 if (rsurface.rtlight_frustumplanes[j].dist < bestdist + 0.03125)
3375                 {
3376                         PlaneClassify(&rsurface.rtlight_frustumplanes[j]);
3377                         rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = rsurface.rtlight_frustumplanes[j];
3378                 }
3379         }
3380         }
3381 #endif
3382 }
3383
3384 void R_Shadow_DrawWorldShadow(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3385 {
3386         qboolean zpass;
3387         shadowmesh_t *mesh;
3388         int t, tend;
3389         int surfacelistindex;
3390         msurface_t *surface;
3391
3392         RSurf_ActiveWorldEntity();
3393         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
3394         {
3395                 if (r_refdef.scene.worldentity->model)
3396                         r_refdef.scene.worldmodel->DrawShadowMap(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
3397                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3398                 return;
3399         }
3400
3401         if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3402         {
3403                 CHECKGLERROR
3404                 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3405                 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3406                 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3407                 for (;mesh;mesh = mesh->next)
3408                 {
3409                         r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3410                         R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3411                         GL_LockArrays(0, mesh->numverts);
3412                         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3413                         {
3414                                 // increment stencil if frontface is infront of depthbuffer
3415                                 GL_CullFace(r_refdef.view.cullface_back);
3416                                 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
3417                                 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3418                                 // decrement stencil if backface is infront of depthbuffer
3419                                 GL_CullFace(r_refdef.view.cullface_front);
3420                                 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
3421                         }
3422                         else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3423                         {
3424                                 // decrement stencil if backface is behind depthbuffer
3425                                 GL_CullFace(r_refdef.view.cullface_front);
3426                                 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
3427                                 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3428                                 // increment stencil if frontface is behind depthbuffer
3429                                 GL_CullFace(r_refdef.view.cullface_back);
3430                                 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
3431                         }
3432                         R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3433                         GL_LockArrays(0, 0);
3434                 }
3435                 CHECKGLERROR
3436         }
3437         else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
3438         {
3439                 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3440                 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3441                 {
3442                         surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3443                         for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3444                                 if (CHECKPVSBIT(trispvs, t))
3445                                         shadowmarklist[numshadowmark++] = t;
3446                 }
3447                 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);
3448         }
3449         else if (numsurfaces)
3450                 r_refdef.scene.worldmodel->DrawShadowVolume(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
3451
3452         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3453 }
3454
3455 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3456 {
3457         vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3458         vec_t relativeshadowradius;
3459         RSurf_ActiveModelEntity(ent, false, false);
3460         Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3461         relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3462         relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3463         relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3464         relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3465         relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3466         relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3467         relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3468         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
3469                 ent->model->DrawShadowMap(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3470         else
3471                 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3472         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3473 }
3474
3475 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3476 {
3477         // set up properties for rendering light onto this entity
3478         RSurf_ActiveModelEntity(ent, true, true);
3479         GL_AlphaTest(false);
3480         Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3481         Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3482         Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3483         Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3484         if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
3485                 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3486 }
3487
3488 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3489 {
3490         if (!r_refdef.scene.worldmodel->DrawLight)
3491                 return;
3492
3493         // set up properties for rendering light onto this entity
3494         RSurf_ActiveWorldEntity();
3495         GL_AlphaTest(false);
3496         rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3497         Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3498         Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3499         VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3500         if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
3501                 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3502
3503         r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, trispvs);
3504
3505         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3506 }
3507
3508 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3509 {
3510         dp_model_t *model = ent->model;
3511         if (!model->DrawLight)
3512                 return;
3513
3514         R_Shadow_SetupEntityLight(ent);
3515
3516         model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3517
3518         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3519 }
3520
3521 /*
3522 {{  0,   0, 0}, "px",  true,  true,  true},
3523 {{  0,  90, 0}, "py", false,  true, false},
3524 {{  0, 180, 0}, "nx", false, false,  true},
3525 {{  0, 270, 0}, "ny",  true, false, false},
3526 {{-90, 180, 0}, "pz", false, false,  true},
3527 {{ 90, 180, 0}, "nz", false, false,  true}
3528 */
3529
3530 static const double shadowviewmat16[6][4][4] =
3531 {
3532         {
3533                 {-1,  0,  0, 0},
3534                 { 0, -1,  0, 0},
3535                 { 0,  0,  1, 0},
3536                 { 0,  0,  0, 1},
3537         },
3538         {
3539                 { 0, -1,  0, 0},
3540                 {-1,  0,  0, 0},
3541                 { 0,  0,  1, 0},
3542                 { 0,  0,  0, 1},
3543         },
3544         {
3545                 {-1,  0,  0, 0},
3546                 { 0, -1,  0, 0},
3547                 { 0,  0,  1, 0},
3548                 { 0,  0,  0, 1},
3549         },
3550         {
3551                 { 0, -1,  0, 0},
3552                 {-1,  0,  0, 0},
3553                 { 0,  0,  1, 0},
3554                 { 0,  0,  0, 1},
3555         },
3556         {
3557                 { 0,  0,  1, 0},
3558                 { 0, -1,  0, 0},
3559                 { 1,  0,  0, 0},
3560                 { 0,  0,  0, 1},
3561         },
3562         {
3563                 { 0,  0, -1, 0},
3564                 { 0, -1,  0, 0},
3565                 {-1,  0,  0, 0},
3566                 { 0,  0,  0, 1},
3567         },
3568 };
3569
3570 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
3571 {
3572         int i;
3573         float f;
3574         int numleafs, numsurfaces;
3575         int *leaflist, *surfacelist;
3576         unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs;
3577         int numlightentities;
3578         int numlightentities_noselfshadow;
3579         int numshadowentities;
3580         int numshadowentities_noselfshadow;
3581         static entity_render_t *lightentities[MAX_EDICTS];
3582         static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3583         static entity_render_t *shadowentities[MAX_EDICTS];
3584         static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3585         vec3_t nearestpoint;
3586         vec_t distance;
3587         qboolean castshadows;
3588         int lodlinear;
3589
3590         // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3591         // skip lights that are basically invisible (color 0 0 0)
3592         if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
3593                 return;
3594
3595         // loading is done before visibility checks because loading should happen
3596         // all at once at the start of a level, not when it stalls gameplay.
3597         // (especially important to benchmarks)
3598         // compile light
3599         if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
3600                 R_RTLight_Compile(rtlight);
3601         // load cubemap
3602         rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
3603
3604         // look up the light style value at this time
3605         f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3606         VectorScale(rtlight->color, f, rtlight->currentcolor);
3607         /*
3608         if (rtlight->selected)
3609         {
3610                 f = 2 + sin(realtime * M_PI * 4.0);
3611                 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3612         }
3613         */
3614
3615         // if lightstyle is currently off, don't draw the light
3616         if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3617                 return;
3618
3619         // if the light box is offscreen, skip it
3620         if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3621                 return;
3622
3623         VectorCopy(rtlight->cullmins, rsurface.rtlight_cullmins);
3624         VectorCopy(rtlight->cullmaxs, rsurface.rtlight_cullmaxs);
3625
3626         if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3627         {
3628                 // compiled light, world available and can receive realtime lighting
3629                 // retrieve leaf information
3630                 numleafs = rtlight->static_numleafs;
3631                 leaflist = rtlight->static_leaflist;
3632                 leafpvs = rtlight->static_leafpvs;
3633                 numsurfaces = rtlight->static_numsurfaces;
3634                 surfacelist = rtlight->static_surfacelist;
3635                 shadowtrispvs = rtlight->static_shadowtrispvs;
3636                 lighttrispvs = rtlight->static_lighttrispvs;
3637         }
3638         else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3639         {
3640                 // dynamic light, world available and can receive realtime lighting
3641                 // calculate lit surfaces and leafs
3642                 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);
3643                 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);
3644                 leaflist = r_shadow_buffer_leaflist;
3645                 leafpvs = r_shadow_buffer_leafpvs;
3646                 surfacelist = r_shadow_buffer_surfacelist;
3647                 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3648                 lighttrispvs = r_shadow_buffer_lighttrispvs;
3649                 // if the reduced leaf bounds are offscreen, skip it
3650                 if (R_CullBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3651                         return;
3652         }
3653         else
3654         {
3655                 // no world
3656                 numleafs = 0;
3657                 leaflist = NULL;
3658                 leafpvs = NULL;
3659                 numsurfaces = 0;
3660                 surfacelist = NULL;
3661                 shadowtrispvs = NULL;
3662                 lighttrispvs = NULL;
3663         }
3664         // check if light is illuminating any visible leafs
3665         if (numleafs)
3666         {
3667                 for (i = 0;i < numleafs;i++)
3668                         if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3669                                 break;
3670                 if (i == numleafs)
3671                         return;
3672         }
3673         // set up a scissor rectangle for this light
3674         if (R_Shadow_ScissorForBBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3675                 return;
3676
3677         R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3678
3679         // make a list of lit entities and shadow casting entities
3680         numlightentities = 0;
3681         numlightentities_noselfshadow = 0;
3682         numshadowentities = 0;
3683         numshadowentities_noselfshadow = 0;
3684         // add dynamic entities that are lit by the light
3685         if (r_drawentities.integer)
3686         {
3687                 for (i = 0;i < r_refdef.scene.numentities;i++)
3688                 {
3689                         dp_model_t *model;
3690                         entity_render_t *ent = r_refdef.scene.entities[i];
3691                         vec3_t org;
3692                         if (!BoxesOverlap(ent->mins, ent->maxs, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3693                                 continue;
3694                         // skip the object entirely if it is not within the valid
3695                         // shadow-casting region (which includes the lit region)
3696                         if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rsurface.rtlight_numfrustumplanes, rsurface.rtlight_frustumplanes))
3697                                 continue;
3698                         if (!(model = ent->model))
3699                                 continue;
3700                         if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3701                         {
3702                                 // this entity wants to receive light, is visible, and is
3703                                 // inside the light box
3704                                 // TODO: check if the surfaces in the model can receive light
3705                                 // so now check if it's in a leaf seen by the light
3706                                 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))
3707                                         continue;
3708                                 if (ent->flags & RENDER_NOSELFSHADOW)
3709                                         lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3710                                 else
3711                                         lightentities[numlightentities++] = ent;
3712                                 // since it is lit, it probably also casts a shadow...
3713                                 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3714                                 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3715                                 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3716                                 {
3717                                         // note: exterior models without the RENDER_NOSELFSHADOW
3718                                         // flag still create a RENDER_NOSELFSHADOW shadow but
3719                                         // are lit normally, this means that they are
3720                                         // self-shadowing but do not shadow other
3721                                         // RENDER_NOSELFSHADOW entities such as the gun
3722                                         // (very weird, but keeps the player shadow off the gun)
3723                                         if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3724                                                 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3725                                         else
3726                                                 shadowentities[numshadowentities++] = ent;
3727                                 }
3728                         }
3729                         else if (ent->flags & RENDER_SHADOW)
3730                         {
3731                                 // this entity is not receiving light, but may still need to
3732                                 // cast a shadow...
3733                                 // TODO: check if the surfaces in the model can cast shadow
3734                                 // now check if it is in a leaf seen by the light
3735                                 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))
3736                                         continue;
3737                                 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3738                                 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3739                                 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3740                                 {
3741                                         if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3742                                                 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3743                                         else
3744                                                 shadowentities[numshadowentities++] = ent;
3745                                 }
3746                         }
3747                 }
3748         }
3749
3750         // return if there's nothing at all to light
3751         if (!numlightentities && !numsurfaces)
3752                 return;
3753
3754         // don't let sound skip if going slow
3755         if (r_refdef.scene.extraupdate)
3756                 S_ExtraUpdate ();
3757
3758         // make this the active rtlight for rendering purposes
3759         R_Shadow_RenderMode_ActiveLight(rtlight);
3760         // count this light in the r_speeds
3761         r_refdef.stats.lights++;
3762
3763         if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3764         {
3765                 // optionally draw visible shape of the shadow volumes
3766                 // for performance analysis by level designers
3767                 R_Shadow_RenderMode_VisibleShadowVolumes();
3768                 if (numsurfaces)
3769                         R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3770                 for (i = 0;i < numshadowentities;i++)
3771                         R_Shadow_DrawEntityShadow(shadowentities[i]);
3772                 for (i = 0;i < numshadowentities_noselfshadow;i++)
3773                         R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3774         }
3775
3776         if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3777         {
3778                 // optionally draw the illuminated areas
3779                 // for performance analysis by level designers
3780                 R_Shadow_RenderMode_VisibleLighting(false, false);
3781                 if (numsurfaces)
3782                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3783                 for (i = 0;i < numlightentities;i++)
3784                         R_Shadow_DrawEntityLight(lightentities[i]);
3785                 for (i = 0;i < numlightentities_noselfshadow;i++)
3786                         R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3787         }
3788
3789         castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3790
3791         nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3792         nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3793         nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3794         distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3795         lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3796         lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapping_maxsize.integer);
3797
3798         if (castshadows && r_shadow_shadowmode >= 1 && r_shadow_shadowmode <= 3 && r_glsl.integer && gl_support_fragment_shader)
3799         {
3800                 int side;
3801                 int size;
3802
3803                 r_shadow_shadowmaplod = 0;
3804                 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
3805                         if ((r_shadow_shadowmapping_maxsize.integer >> i) > lodlinear)
3806                                 r_shadow_shadowmaplod = i;
3807
3808                 size = r_shadow_shadowmode == 3 ? r_shadow_shadowmapping_maxsize.integer >> r_shadow_shadowmaplod : lodlinear;
3809                 size = bound(1, size, 2048);
3810
3811                 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
3812
3813                 // render shadow casters into 6 sided depth texture
3814                 for (side = 0;side < 6;side++)
3815                 {
3816                         R_Shadow_RenderMode_ShadowMap(side, true, size);
3817                         if (numsurfaces)
3818                                 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3819                         for (i = 0;i < numshadowentities;i++)
3820                                 R_Shadow_DrawEntityShadow(shadowentities[i]);
3821                 }
3822
3823                 if (numlightentities_noselfshadow)
3824                 {
3825                         // render lighting using the depth texture as shadowmap
3826                         // draw lighting in the unmasked areas
3827                         R_Shadow_RenderMode_Lighting(false, false, true);
3828                         for (i = 0;i < numlightentities_noselfshadow;i++)
3829                                 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3830                 }
3831
3832                 // render shadow casters into 6 sided depth texture
3833                 for (side = 0;side < 6;side++)
3834                 {
3835                         R_Shadow_RenderMode_ShadowMap(side, false, size);
3836                         for (i = 0;i < numshadowentities_noselfshadow;i++)
3837                                 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3838                 }
3839
3840                 // render lighting using the depth texture as shadowmap
3841                 // draw lighting in the unmasked areas
3842                 R_Shadow_RenderMode_Lighting(false, false, true);
3843                 // draw lighting in the unmasked areas
3844                 if (numsurfaces)
3845                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3846                 for (i = 0;i < numlightentities;i++)
3847                         R_Shadow_DrawEntityLight(lightentities[i]);
3848         }
3849         else if (castshadows && gl_stencil)
3850         {
3851                 // draw stencil shadow volumes to mask off pixels that are in shadow
3852                 // so that they won't receive lighting
3853                 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
3854                 R_Shadow_ClearStencil();
3855                 if (numsurfaces)
3856                         R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3857                 for (i = 0;i < numshadowentities;i++)
3858                         R_Shadow_DrawEntityShadow(shadowentities[i]);
3859                 if (numlightentities_noselfshadow)
3860                 {
3861                         // draw lighting in the unmasked areas
3862                         R_Shadow_RenderMode_Lighting(true, false, false);
3863                         for (i = 0;i < numlightentities_noselfshadow;i++)
3864                                 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3865
3866                         // optionally draw the illuminated areas
3867                         // for performance analysis by level designers
3868                         if (r_showlighting.integer && r_refdef.view.showdebug)
3869                         {
3870                                 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
3871                                 for (i = 0;i < numlightentities_noselfshadow;i++)
3872                                         R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3873                         }
3874                 }
3875                 for (i = 0;i < numshadowentities_noselfshadow;i++)
3876                         R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3877
3878                 if (numsurfaces + numlightentities)
3879                 {
3880                         // draw lighting in the unmasked areas
3881                         R_Shadow_RenderMode_Lighting(true, false, false);
3882                         if (numsurfaces)
3883                                 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3884                         for (i = 0;i < numlightentities;i++)
3885                                 R_Shadow_DrawEntityLight(lightentities[i]);
3886                 }
3887         }
3888         else
3889         {
3890                 if (numsurfaces + numlightentities)
3891                 {
3892                         // draw lighting in the unmasked areas
3893                         R_Shadow_RenderMode_Lighting(false, false, false);
3894                         if (numsurfaces)
3895                                 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3896                         for (i = 0;i < numlightentities;i++)
3897                                 R_Shadow_DrawEntityLight(lightentities[i]);
3898                         for (i = 0;i < numlightentities_noselfshadow;i++)
3899                                 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3900                 }
3901         }
3902 }
3903
3904 void R_Shadow_DrawLightSprites(void);
3905 void R_ShadowVolumeLighting(qboolean visible)
3906 {
3907         int flag;
3908         int lnum;
3909         size_t lightindex;
3910         dlight_t *light;
3911         size_t range;
3912
3913         if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, 2048) || 
3914                 (r_shadow_shadowmode != 0) != (r_shadow_shadowmapping.integer != 0) || 
3915                 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0) || 
3916                 r_shadow_shadowmaptexturetype != r_shadow_shadowmapping_texturetype.integer ||
3917                 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer || 
3918                 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
3919                 R_Shadow_FreeShadowMaps();
3920
3921         if (r_editlights.integer)
3922                 R_Shadow_DrawLightSprites();
3923
3924         R_Shadow_RenderMode_Begin();
3925
3926         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3927         if (r_shadow_debuglight.integer >= 0)
3928         {
3929                 lightindex = r_shadow_debuglight.integer;
3930                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3931                 if (light && (light->flags & flag))
3932                         R_DrawRTLight(&light->rtlight, visible);
3933         }
3934         else
3935         {
3936                 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3937                 for (lightindex = 0;lightindex < range;lightindex++)
3938                 {
3939                         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3940                         if (light && (light->flags & flag))
3941                                 R_DrawRTLight(&light->rtlight, visible);
3942                 }
3943         }
3944         if (r_refdef.scene.rtdlight)
3945                 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3946                         R_DrawRTLight(r_refdef.scene.lights[lnum], visible);
3947
3948         R_Shadow_RenderMode_End();
3949 }
3950
3951 extern const float r_screenvertex3f[12];
3952 extern void R_SetupView(qboolean allowwaterclippingplane);
3953 extern void R_ResetViewRendering3D(void);
3954 extern void R_ResetViewRendering2D(void);
3955 extern cvar_t r_shadows;
3956 extern cvar_t r_shadows_darken;
3957 extern cvar_t r_shadows_drawafterrtlighting;
3958 extern cvar_t r_shadows_castfrombmodels;
3959 extern cvar_t r_shadows_throwdistance;
3960 extern cvar_t r_shadows_throwdirection;
3961 void R_DrawModelShadows(void)
3962 {
3963         int i;
3964         float relativethrowdistance;
3965         entity_render_t *ent;
3966         vec3_t relativelightorigin;
3967         vec3_t relativelightdirection;
3968         vec3_t relativeshadowmins, relativeshadowmaxs;
3969         vec3_t tmp, shadowdir;
3970
3971         if (!r_drawentities.integer || !gl_stencil)
3972                 return;
3973
3974         CHECKGLERROR
3975         R_ResetViewRendering3D();
3976         //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
3977         //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
3978         R_Shadow_RenderMode_Begin();
3979         R_Shadow_RenderMode_ActiveLight(NULL);
3980         r_shadow_lightscissor[0] = r_refdef.view.x;
3981         r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
3982         r_shadow_lightscissor[2] = r_refdef.view.width;
3983         r_shadow_lightscissor[3] = r_refdef.view.height;
3984         R_Shadow_RenderMode_StencilShadowVolumes(false);
3985
3986         // get shadow dir
3987         if (r_shadows.integer == 2)
3988         {
3989                 Math_atov(r_shadows_throwdirection.string, shadowdir);
3990                 VectorNormalize(shadowdir);
3991         }
3992
3993         R_Shadow_ClearStencil();
3994
3995         for (i = 0;i < r_refdef.scene.numentities;i++)
3996         {
3997                 ent = r_refdef.scene.entities[i];
3998
3999                 // cast shadows from anything of the map (submodels are optional)
4000                 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4001                 {
4002                         relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4003                         VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4004                         VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4005                         if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4006                                 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4007                         else
4008                         {
4009                                 if(ent->entitynumber != 0)
4010                                 {
4011                                         // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4012                                         int entnum, entnum2, recursion;
4013                                         entnum = entnum2 = ent->entitynumber;
4014                                         for(recursion = 32; recursion > 0; --recursion)
4015                                         {
4016                                                 entnum2 = cl.entities[entnum].state_current.tagentity;
4017                                                 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4018                                                         entnum = entnum2;
4019                                                 else
4020                                                         break;
4021                                         }
4022                                         if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4023                                         {
4024                                                 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4025                                                 // transform into modelspace of OUR entity
4026                                                 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4027                                                 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4028                                         }
4029                                         else
4030                                                 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4031                                 }
4032                                 else
4033                                         VectorNegate(ent->modellight_lightdir, relativelightdirection);
4034                         }
4035
4036                         VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4037                         RSurf_ActiveModelEntity(ent, false, false);
4038                         ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4039                         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4040                 }
4041         }
4042
4043         // not really the right mode, but this will disable any silly stencil features
4044         R_Shadow_RenderMode_End();
4045
4046         // set up ortho view for rendering this pass
4047         //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4048         //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4049         //GL_ScissorTest(true);
4050         //R_Mesh_Matrix(&identitymatrix);
4051         //R_Mesh_ResetTextureState();
4052         R_ResetViewRendering2D();
4053         R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
4054         R_Mesh_ColorPointer(NULL, 0, 0);
4055         R_SetupGenericShader(false);
4056
4057         // set up a darkening blend on shadowed areas
4058         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4059         //GL_DepthRange(0, 1);
4060         //GL_DepthTest(false);
4061         //GL_DepthMask(false);
4062         //GL_PolygonOffset(0, 0);CHECKGLERROR
4063         GL_Color(0, 0, 0, r_shadows_darken.value);
4064         //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4065         //qglDepthFunc(GL_ALWAYS);CHECKGLERROR
4066         qglEnable(GL_STENCIL_TEST);CHECKGLERROR
4067         qglStencilMask(~0);CHECKGLERROR
4068         qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
4069         qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
4070
4071         // apply the blend to the shadowed areas
4072         R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
4073
4074         // restore the viewport
4075         R_SetViewport(&r_refdef.view.viewport);
4076
4077         // restore other state to normal
4078         //R_Shadow_RenderMode_End();
4079 }
4080
4081 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4082 {
4083         float zdist;
4084         vec3_t centerorigin;
4085         // if it's too close, skip it
4086         if (VectorLength(rtlight->color) < (1.0f / 256.0f))
4087                 return;
4088         zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4089         if (zdist < 32)
4090                 return;
4091         if (usequery && r_numqueries + 2 <= r_maxqueries)
4092         {
4093                 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4094                 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4095                 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4096
4097                 CHECKGLERROR
4098                 // 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
4099                 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4100                 qglDepthFunc(GL_ALWAYS);
4101                 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);
4102                 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4103                 qglDepthFunc(GL_LEQUAL);
4104                 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4105                 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);
4106                 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4107                 CHECKGLERROR
4108         }
4109         rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4110 }
4111
4112 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4113 {
4114         vec3_t color;
4115         GLint allpixels = 0, visiblepixels = 0;
4116         // now we have to check the query result
4117         if (rtlight->corona_queryindex_visiblepixels)
4118         {
4119                 CHECKGLERROR
4120                 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4121                 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4122                 CHECKGLERROR
4123                 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4124                 if (visiblepixels < 1 || allpixels < 1)
4125                         return;
4126                 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4127                 cscale *= rtlight->corona_visibility;
4128         }
4129         else
4130         {
4131                 // FIXME: these traces should scan all render entities instead of cl.world
4132                 if (CL_Move(r_refdef.view.origin, vec3_origin, vec3_origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4133                         return;
4134         }
4135         VectorScale(rtlight->color, cscale, color);
4136         if (VectorLength(color) > (1.0f / 256.0f))
4137                 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);
4138 }
4139
4140 void R_DrawCoronas(void)
4141 {
4142         int i, flag;
4143         qboolean usequery;
4144         size_t lightindex;
4145         dlight_t *light;
4146         rtlight_t *rtlight;
4147         size_t range;
4148         if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4149                 return;
4150         if (r_waterstate.renderingscene)
4151                 return;
4152         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4153         R_Mesh_Matrix(&identitymatrix);
4154
4155         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4156
4157         // check occlusion of coronas
4158         // use GL_ARB_occlusion_query if available
4159         // otherwise use raytraces
4160         r_numqueries = 0;
4161         usequery = gl_support_arb_occlusion_query && r_coronas_occlusionquery.integer;
4162         if (usequery)
4163         {
4164                 GL_ColorMask(0,0,0,0);
4165                 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4166                 if (r_maxqueries < R_MAX_OCCLUSION_QUERIES)
4167                 {
4168                         i = r_maxqueries;
4169                         r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4170                         r_maxqueries = min(r_maxqueries, R_MAX_OCCLUSION_QUERIES);
4171                         CHECKGLERROR
4172                         qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4173                         CHECKGLERROR
4174                 }
4175         }
4176         for (lightindex = 0;lightindex < range;lightindex++)
4177         {
4178                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4179                 if (!light)
4180                         continue;
4181                 rtlight = &light->rtlight;
4182                 rtlight->corona_visibility = 0;
4183                 rtlight->corona_queryindex_visiblepixels = 0;
4184                 rtlight->corona_queryindex_allpixels = 0;
4185                 if (!(rtlight->flags & flag))
4186                         continue;
4187                 if (rtlight->corona <= 0)
4188                         continue;
4189                 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4190                         continue;
4191                 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4192         }
4193         for (i = 0;i < r_refdef.scene.numlights;i++)
4194         {
4195                 rtlight = r_refdef.scene.lights[i];
4196                 rtlight->corona_visibility = 0;
4197                 rtlight->corona_queryindex_visiblepixels = 0;
4198                 rtlight->corona_queryindex_allpixels = 0;
4199                 if (!(rtlight->flags & flag))
4200                         continue;
4201                 if (rtlight->corona <= 0)
4202                         continue;
4203                 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4204         }
4205         if (usequery)
4206                 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4207
4208         // now draw the coronas using the query data for intensity info
4209         for (lightindex = 0;lightindex < range;lightindex++)
4210         {
4211                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4212                 if (!light)
4213                         continue;
4214                 rtlight = &light->rtlight;
4215                 if (rtlight->corona_visibility <= 0)
4216                         continue;
4217                 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4218         }
4219         for (i = 0;i < r_refdef.scene.numlights;i++)
4220         {
4221                 rtlight = r_refdef.scene.lights[i];
4222                 if (rtlight->corona_visibility <= 0)
4223                         continue;
4224                 if (gl_flashblend.integer)
4225                         R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4226                 else
4227                         R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4228         }
4229 }
4230
4231
4232
4233 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
4234 typedef struct suffixinfo_s
4235 {
4236         char *suffix;
4237         qboolean flipx, flipy, flipdiagonal;
4238 }
4239 suffixinfo_t;
4240 static suffixinfo_t suffix[3][6] =
4241 {
4242         {
4243                 {"px",   false, false, false},
4244                 {"nx",   false, false, false},
4245                 {"py",   false, false, false},
4246                 {"ny",   false, false, false},
4247                 {"pz",   false, false, false},
4248                 {"nz",   false, false, false}
4249         },
4250         {
4251                 {"posx", false, false, false},
4252                 {"negx", false, false, false},
4253                 {"posy", false, false, false},
4254                 {"negy", false, false, false},
4255                 {"posz", false, false, false},
4256                 {"negz", false, false, false}
4257         },
4258         {
4259                 {"rt",    true, false,  true},
4260                 {"lf",   false,  true,  true},
4261                 {"ft",    true,  true, false},
4262                 {"bk",   false, false, false},
4263                 {"up",    true, false,  true},
4264                 {"dn",    true, false,  true}
4265         }
4266 };
4267
4268 static int componentorder[4] = {0, 1, 2, 3};
4269
4270 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
4271 {
4272         int i, j, cubemapsize;
4273         unsigned char *cubemappixels, *image_buffer;
4274         rtexture_t *cubemaptexture;
4275         char name[256];
4276         // must start 0 so the first loadimagepixels has no requested width/height
4277         cubemapsize = 0;
4278         cubemappixels = NULL;
4279         cubemaptexture = NULL;
4280         // keep trying different suffix groups (posx, px, rt) until one loads
4281         for (j = 0;j < 3 && !cubemappixels;j++)
4282         {
4283                 // load the 6 images in the suffix group
4284                 for (i = 0;i < 6;i++)
4285                 {
4286                         // generate an image name based on the base and and suffix
4287                         dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
4288                         // load it
4289                         if ((image_buffer = loadimagepixelsbgra(name, false, false)))
4290                         {
4291                                 // an image loaded, make sure width and height are equal
4292                                 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
4293                                 {
4294                                         // if this is the first image to load successfully, allocate the cubemap memory
4295                                         if (!cubemappixels && image_width >= 1)
4296                                         {
4297                                                 cubemapsize = image_width;
4298                                                 // note this clears to black, so unavailable sides are black
4299                                                 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
4300                                         }
4301                                         // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
4302                                         if (cubemappixels)
4303                                                 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);
4304                                 }
4305                                 else
4306                                         Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
4307                                 // free the image
4308                                 Mem_Free(image_buffer);
4309                         }
4310                 }
4311         }
4312         // if a cubemap loaded, upload it
4313         if (cubemappixels)
4314         {
4315                 if (developer_loading.integer)
4316                         Con_Printf("loading cubemap \"%s\"\n", basename);
4317
4318                 if (!r_shadow_filters_texturepool)
4319                         r_shadow_filters_texturepool = R_AllocTexturePool();
4320                 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, TEXF_PRECACHE | (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR, NULL);
4321                 Mem_Free(cubemappixels);
4322         }
4323         else
4324         {
4325                 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
4326                 if (developer_loading.integer)
4327                 {
4328                         Con_Printf("(tried tried images ");
4329                         for (j = 0;j < 3;j++)
4330                                 for (i = 0;i < 6;i++)
4331                                         Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
4332                         Con_Print(" and was unable to find any of them).\n");
4333                 }
4334         }
4335         return cubemaptexture;
4336 }
4337
4338 rtexture_t *R_Shadow_Cubemap(const char *basename)
4339 {
4340         int i;
4341         for (i = 0;i < numcubemaps;i++)
4342                 if (!strcasecmp(cubemaps[i].basename, basename))
4343                         return cubemaps[i].texture ? cubemaps[i].texture : r_texture_whitecube;
4344         if (i >= MAX_CUBEMAPS)
4345                 return r_texture_whitecube;
4346         numcubemaps++;
4347         strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
4348         cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
4349         return cubemaps[i].texture;
4350 }
4351
4352 void R_Shadow_FreeCubemaps(void)
4353 {
4354         int i;
4355         for (i = 0;i < numcubemaps;i++)
4356         {
4357                 if (developer_loading.integer)
4358                         Con_Printf("unloading cubemap \"%s\"\n", cubemaps[i].basename);
4359                 if (cubemaps[i].texture)
4360                         R_FreeTexture(cubemaps[i].texture);
4361         }
4362
4363         numcubemaps = 0;
4364         R_FreeTexturePool(&r_shadow_filters_texturepool);
4365 }
4366
4367 dlight_t *R_Shadow_NewWorldLight(void)
4368 {
4369         return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4370 }
4371
4372 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)
4373 {
4374         matrix4x4_t matrix;
4375         // validate parameters
4376         if (style < 0 || style >= MAX_LIGHTSTYLES)
4377         {
4378                 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4379                 style = 0;
4380         }
4381         if (!cubemapname)
4382                 cubemapname = "";
4383
4384         // copy to light properties
4385         VectorCopy(origin, light->origin);
4386         light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4387         light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4388         light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4389         light->color[0] = max(color[0], 0);
4390         light->color[1] = max(color[1], 0);
4391         light->color[2] = max(color[2], 0);
4392         light->radius = max(radius, 0);
4393         light->style = style;
4394         light->shadow = shadowenable;
4395         light->corona = corona;
4396         strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4397         light->coronasizescale = coronasizescale;
4398         light->ambientscale = ambientscale;
4399         light->diffusescale = diffusescale;
4400         light->specularscale = specularscale;
4401         light->flags = flags;
4402
4403         // update renderable light data
4404         Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4405         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);
4406 }
4407
4408 void R_Shadow_FreeWorldLight(dlight_t *light)
4409 {
4410         if (r_shadow_selectedlight == light)
4411                 r_shadow_selectedlight = NULL;
4412         R_RTLight_Uncompile(&light->rtlight);
4413         Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4414 }
4415
4416 void R_Shadow_ClearWorldLights(void)
4417 {
4418         size_t lightindex;
4419         dlight_t *light;
4420         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4421         for (lightindex = 0;lightindex < range;lightindex++)
4422         {
4423                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4424                 if (light)
4425                         R_Shadow_FreeWorldLight(light);
4426         }
4427         r_shadow_selectedlight = NULL;
4428         R_Shadow_FreeCubemaps();
4429 }
4430
4431 void R_Shadow_SelectLight(dlight_t *light)
4432 {
4433         if (r_shadow_selectedlight)
4434                 r_shadow_selectedlight->selected = false;
4435         r_shadow_selectedlight = light;
4436         if (r_shadow_selectedlight)
4437                 r_shadow_selectedlight->selected = true;
4438 }
4439
4440 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4441 {
4442         // this is never batched (there can be only one)
4443         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);
4444 }
4445
4446 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4447 {
4448         float intensity;
4449         float s;
4450         vec3_t spritecolor;
4451         cachepic_t *pic;
4452
4453         // this is never batched (due to the ent parameter changing every time)
4454         // so numsurfaces == 1 and surfacelist[0] == lightnumber
4455         const dlight_t *light = (dlight_t *)ent;
4456         s = EDLIGHTSPRSIZE;
4457         intensity = 0.5f;
4458         VectorScale(light->color, intensity, spritecolor);
4459         if (VectorLength(spritecolor) < 0.1732f)
4460                 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4461         if (VectorLength(spritecolor) > 1.0f)
4462                 VectorNormalize(spritecolor);
4463
4464         // draw light sprite
4465         if (light->cubemapname[0] && !light->shadow)
4466                 pic = r_editlights_sprcubemapnoshadowlight;
4467         else if (light->cubemapname[0])
4468                 pic = r_editlights_sprcubemaplight;
4469         else if (!light->shadow)
4470                 pic = r_editlights_sprnoshadowlight;
4471         else
4472                 pic = r_editlights_sprlight;
4473         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);
4474         // draw selection sprite if light is selected
4475         if (light->selected)
4476                 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);
4477         // VorteX todo: add normalmode/realtime mode light overlay sprites?
4478 }
4479
4480 void R_Shadow_DrawLightSprites(void)
4481 {
4482         size_t lightindex;
4483         dlight_t *light;
4484         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4485         for (lightindex = 0;lightindex < range;lightindex++)
4486         {
4487                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4488                 if (light)
4489                         R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4490         }
4491         R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4492 }
4493
4494 void R_Shadow_SelectLightInView(void)
4495 {
4496         float bestrating, rating, temp[3];
4497         dlight_t *best;
4498         size_t lightindex;
4499         dlight_t *light;
4500         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4501         best = NULL;
4502         bestrating = 0;
4503         for (lightindex = 0;lightindex < range;lightindex++)
4504         {
4505                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4506                 if (!light)
4507                         continue;
4508                 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4509                 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4510                 if (rating >= 0.95)
4511                 {
4512                         rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4513                         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)
4514                         {
4515                                 bestrating = rating;
4516                                 best = light;
4517                         }
4518                 }
4519         }
4520         R_Shadow_SelectLight(best);
4521 }
4522
4523 void R_Shadow_LoadWorldLights(void)
4524 {
4525         int n, a, style, shadow, flags;
4526         char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4527         float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4528         if (cl.worldmodel == NULL)
4529         {
4530                 Con_Print("No map loaded.\n");
4531                 return;
4532         }
4533         FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4534         strlcat (name, ".rtlights", sizeof (name));
4535         lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4536         if (lightsstring)
4537         {
4538                 s = lightsstring;
4539                 n = 0;
4540                 while (*s)
4541                 {
4542                         t = s;
4543                         /*
4544                         shadow = true;
4545                         for (;COM_Parse(t, true) && strcmp(
4546                         if (COM_Parse(t, true))
4547                         {
4548                                 if (com_token[0] == '!')
4549                                 {
4550                                         shadow = false;
4551                                         origin[0] = atof(com_token+1);
4552                                 }
4553                                 else
4554                                         origin[0] = atof(com_token);
4555                                 if (Com_Parse(t
4556                         }
4557                         */
4558                         t = s;
4559                         while (*s && *s != '\n' && *s != '\r')
4560                                 s++;
4561                         if (!*s)
4562                                 break;
4563                         tempchar = *s;
4564                         shadow = true;
4565                         // check for modifier flags
4566                         if (*t == '!')
4567                         {
4568                                 shadow = false;
4569                                 t++;
4570                         }
4571                         *s = 0;
4572 #if _MSC_VER >= 1400
4573 #define sscanf sscanf_s
4574 #endif
4575                         cubemapname[sizeof(cubemapname)-1] = 0;
4576 #if MAX_QPATH != 128
4577 #error update this code if MAX_QPATH changes
4578 #endif
4579                         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
4580 #if _MSC_VER >= 1400
4581 , sizeof(cubemapname)
4582 #endif
4583 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4584                         *s = tempchar;
4585                         if (a < 18)
4586                                 flags = LIGHTFLAG_REALTIMEMODE;
4587                         if (a < 17)
4588                                 specularscale = 1;
4589                         if (a < 16)
4590                                 diffusescale = 1;
4591                         if (a < 15)
4592                                 ambientscale = 0;
4593                         if (a < 14)
4594                                 coronasizescale = 0.25f;
4595                         if (a < 13)
4596                                 VectorClear(angles);
4597                         if (a < 10)
4598                                 corona = 0;
4599                         if (a < 9 || !strcmp(cubemapname, "\"\""))
4600                                 cubemapname[0] = 0;
4601                         // remove quotes on cubemapname
4602                         if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4603                         {
4604                                 size_t namelen;
4605                                 namelen = strlen(cubemapname) - 2;
4606                                 memmove(cubemapname, cubemapname + 1, namelen);
4607                                 cubemapname[namelen] = '\0';
4608                         }
4609                         if (a < 8)
4610                         {
4611                                 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);
4612                                 break;
4613                         }
4614                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4615                         if (*s == '\r')
4616                                 s++;
4617                         if (*s == '\n')
4618                                 s++;
4619                         n++;
4620                 }
4621                 if (*s)
4622                         Con_Printf("invalid rtlights file \"%s\"\n", name);
4623                 Mem_Free(lightsstring);
4624         }
4625 }
4626
4627 void R_Shadow_SaveWorldLights(void)
4628 {
4629         size_t lightindex;
4630         dlight_t *light;
4631         size_t bufchars, bufmaxchars;
4632         char *buf, *oldbuf;
4633         char name[MAX_QPATH];
4634         char line[MAX_INPUTLINE];
4635         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
4636         // I hate lines which are 3 times my screen size :( --blub
4637         if (!range)
4638                 return;
4639         if (cl.worldmodel == NULL)
4640         {
4641                 Con_Print("No map loaded.\n");
4642                 return;
4643         }
4644         FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4645         strlcat (name, ".rtlights", sizeof (name));
4646         bufchars = bufmaxchars = 0;
4647         buf = NULL;
4648         for (lightindex = 0;lightindex < range;lightindex++)
4649         {
4650                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4651                 if (!light)
4652                         continue;
4653                 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
4654                         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);
4655                 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
4656                         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]);
4657                 else
4658                         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);
4659                 if (bufchars + strlen(line) > bufmaxchars)
4660                 {
4661                         bufmaxchars = bufchars + strlen(line) + 2048;
4662                         oldbuf = buf;
4663                         buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
4664                         if (oldbuf)
4665                         {
4666                                 if (bufchars)
4667                                         memcpy(buf, oldbuf, bufchars);
4668                                 Mem_Free(oldbuf);
4669                         }
4670                 }
4671                 if (strlen(line))
4672                 {
4673                         memcpy(buf + bufchars, line, strlen(line));
4674                         bufchars += strlen(line);
4675                 }
4676         }
4677         if (bufchars)
4678                 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
4679         if (buf)
4680                 Mem_Free(buf);
4681 }
4682
4683 void R_Shadow_LoadLightsFile(void)
4684 {
4685         int n, a, style;
4686         char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
4687         float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
4688         if (cl.worldmodel == NULL)
4689         {
4690                 Con_Print("No map loaded.\n");
4691                 return;
4692         }
4693         FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4694         strlcat (name, ".lights", sizeof (name));
4695         lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4696         if (lightsstring)
4697         {
4698                 s = lightsstring;
4699                 n = 0;
4700                 while (*s)
4701                 {
4702                         t = s;
4703                         while (*s && *s != '\n' && *s != '\r')
4704                                 s++;
4705                         if (!*s)
4706                                 break;
4707                         tempchar = *s;
4708                         *s = 0;
4709                         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);
4710                         *s = tempchar;
4711                         if (a < 14)
4712                         {
4713                                 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);
4714                                 break;
4715                         }
4716                         radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
4717                         radius = bound(15, radius, 4096);
4718                         VectorScale(color, (2.0f / (8388608.0f)), color);
4719                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
4720                         if (*s == '\r')
4721                                 s++;
4722                         if (*s == '\n')
4723                                 s++;
4724                         n++;
4725                 }
4726                 if (*s)
4727                         Con_Printf("invalid lights file \"%s\"\n", name);
4728                 Mem_Free(lightsstring);
4729         }
4730 }
4731
4732 // tyrlite/hmap2 light types in the delay field
4733 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
4734
4735 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
4736 {
4737         int entnum, style, islight, skin, pflags, effects, type, n;
4738         char *entfiledata;
4739         const char *data;
4740         float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
4741         char key[256], value[MAX_INPUTLINE];
4742
4743         if (cl.worldmodel == NULL)
4744         {
4745                 Con_Print("No map loaded.\n");
4746                 return;
4747         }
4748         // try to load a .ent file first
4749         FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
4750         strlcat (key, ".ent", sizeof (key));
4751         data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
4752         // and if that is not found, fall back to the bsp file entity string
4753         if (!data)
4754                 data = cl.worldmodel->brush.entities;
4755         if (!data)
4756                 return;
4757         for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
4758         {
4759                 type = LIGHTTYPE_MINUSX;
4760                 origin[0] = origin[1] = origin[2] = 0;
4761                 originhack[0] = originhack[1] = originhack[2] = 0;
4762                 angles[0] = angles[1] = angles[2] = 0;
4763                 color[0] = color[1] = color[2] = 1;
4764                 light[0] = light[1] = light[2] = 1;light[3] = 300;
4765                 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
4766                 fadescale = 1;
4767                 lightscale = 1;
4768                 style = 0;
4769                 skin = 0;
4770                 pflags = 0;
4771                 effects = 0;
4772                 islight = false;
4773                 while (1)
4774                 {
4775                         if (!COM_ParseToken_Simple(&data, false, false))
4776                                 break; // error
4777                         if (com_token[0] == '}')
4778                                 break; // end of entity
4779                         if (com_token[0] == '_')
4780                                 strlcpy(key, com_token + 1, sizeof(key));
4781                         else
4782                                 strlcpy(key, com_token, sizeof(key));
4783                         while (key[strlen(key)-1] == ' ') // remove trailing spaces
4784                                 key[strlen(key)-1] = 0;
4785                         if (!COM_ParseToken_Simple(&data, false, false))
4786                                 break; // error
4787                         strlcpy(value, com_token, sizeof(value));
4788
4789                         // now that we have the key pair worked out...
4790                         if (!strcmp("light", key))
4791                         {
4792                                 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
4793                                 if (n == 1)
4794                                 {
4795                                         // quake
4796                                         light[0] = vec[0] * (1.0f / 256.0f);
4797                                         light[1] = vec[0] * (1.0f / 256.0f);
4798                                         light[2] = vec[0] * (1.0f / 256.0f);
4799                                         light[3] = vec[0];
4800                                 }
4801                                 else if (n == 4)
4802                                 {
4803                                         // halflife
4804                                         light[0] = vec[0] * (1.0f / 255.0f);
4805                                         light[1] = vec[1] * (1.0f / 255.0f);
4806                                         light[2] = vec[2] * (1.0f / 255.0f);
4807                                         light[3] = vec[3];
4808                                 }
4809                         }
4810                         else if (!strcmp("delay", key))
4811                                 type = atoi(value);
4812                         else if (!strcmp("origin", key))
4813                                 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
4814                         else if (!strcmp("angle", key))
4815                                 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
4816                         else if (!strcmp("angles", key))
4817                                 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
4818                         else if (!strcmp("color", key))
4819                                 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
4820                         else if (!strcmp("wait", key))
4821                                 fadescale = atof(value);
4822                         else if (!strcmp("classname", key))
4823                         {
4824                                 if (!strncmp(value, "light", 5))
4825                                 {
4826                                         islight = true;
4827                                         if (!strcmp(value, "light_fluoro"))
4828                                         {
4829                                                 originhack[0] = 0;
4830                                                 originhack[1] = 0;
4831                                                 originhack[2] = 0;
4832                                                 overridecolor[0] = 1;
4833                                                 overridecolor[1] = 1;
4834                                                 overridecolor[2] = 1;
4835                                         }
4836                                         if (!strcmp(value, "light_fluorospark"))
4837                                         {
4838                                                 originhack[0] = 0;
4839                                                 originhack[1] = 0;
4840                                                 originhack[2] = 0;
4841                                                 overridecolor[0] = 1;
4842                                                 overridecolor[1] = 1;
4843                                                 overridecolor[2] = 1;
4844                                         }
4845                                         if (!strcmp(value, "light_globe"))
4846                                         {
4847                                                 originhack[0] = 0;
4848                                                 originhack[1] = 0;
4849                                                 originhack[2] = 0;
4850                                                 overridecolor[0] = 1;
4851                                                 overridecolor[1] = 0.8;
4852                                                 overridecolor[2] = 0.4;
4853                                         }
4854                                         if (!strcmp(value, "light_flame_large_yellow"))
4855                                         {
4856                                                 originhack[0] = 0;
4857                                                 originhack[1] = 0;
4858                                                 originhack[2] = 0;
4859                                                 overridecolor[0] = 1;
4860                                                 overridecolor[1] = 0.5;
4861                                                 overridecolor[2] = 0.1;
4862                                         }
4863                                         if (!strcmp(value, "light_flame_small_yellow"))
4864                                         {
4865                                                 originhack[0] = 0;
4866                                                 originhack[1] = 0;
4867                                                 originhack[2] = 0;
4868                                                 overridecolor[0] = 1;
4869                                                 overridecolor[1] = 0.5;
4870                                                 overridecolor[2] = 0.1;
4871                                         }
4872                                         if (!strcmp(value, "light_torch_small_white"))
4873                                         {
4874                                                 originhack[0] = 0;
4875                                                 originhack[1] = 0;
4876                                                 originhack[2] = 0;
4877                                                 overridecolor[0] = 1;
4878                                                 overridecolor[1] = 0.5;
4879                                                 overridecolor[2] = 0.1;
4880                                         }
4881                                         if (!strcmp(value, "light_torch_small_walltorch"))
4882                                         {
4883                                                 originhack[0] = 0;
4884                                                 originhack[1] = 0;
4885                                                 originhack[2] = 0;
4886                                                 overridecolor[0] = 1;
4887                                                 overridecolor[1] = 0.5;
4888                                                 overridecolor[2] = 0.1;
4889                                         }
4890                                 }
4891                         }
4892                         else if (!strcmp("style", key))
4893                                 style = atoi(value);
4894                         else if (!strcmp("skin", key))
4895                                 skin = (int)atof(value);
4896                         else if (!strcmp("pflags", key))
4897                                 pflags = (int)atof(value);
4898                         else if (!strcmp("effects", key))
4899                                 effects = (int)atof(value);
4900                         else if (cl.worldmodel->type == mod_brushq3)
4901                         {
4902                                 if (!strcmp("scale", key))
4903                                         lightscale = atof(value);
4904                                 if (!strcmp("fade", key))
4905                                         fadescale = atof(value);
4906                         }
4907                 }
4908                 if (!islight)
4909                         continue;
4910                 if (lightscale <= 0)
4911                         lightscale = 1;
4912                 if (fadescale <= 0)
4913                         fadescale = 1;
4914                 if (color[0] == color[1] && color[0] == color[2])
4915                 {
4916                         color[0] *= overridecolor[0];
4917                         color[1] *= overridecolor[1];
4918                         color[2] *= overridecolor[2];
4919                 }
4920                 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
4921                 color[0] = color[0] * light[0];
4922                 color[1] = color[1] * light[1];
4923                 color[2] = color[2] * light[2];
4924                 switch (type)
4925                 {
4926                 case LIGHTTYPE_MINUSX:
4927                         break;
4928                 case LIGHTTYPE_RECIPX:
4929                         radius *= 2;
4930                         VectorScale(color, (1.0f / 16.0f), color);
4931                         break;
4932                 case LIGHTTYPE_RECIPXX:
4933                         radius *= 2;
4934                         VectorScale(color, (1.0f / 16.0f), color);
4935                         break;
4936                 default:
4937                 case LIGHTTYPE_NONE:
4938                         break;
4939                 case LIGHTTYPE_SUN:
4940                         break;
4941                 case LIGHTTYPE_MINUSXX:
4942                         break;
4943                 }
4944                 VectorAdd(origin, originhack, origin);
4945                 if (radius >= 1)
4946                         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);
4947         }
4948         if (entfiledata)
4949                 Mem_Free(entfiledata);
4950 }
4951
4952
4953 void R_Shadow_SetCursorLocationForView(void)
4954 {
4955         vec_t dist, push;
4956         vec3_t dest, endpos;
4957         trace_t trace;
4958         VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
4959         trace = CL_Move(r_refdef.view.origin, vec3_origin, vec3_origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
4960         if (trace.fraction < 1)
4961         {
4962                 dist = trace.fraction * r_editlights_cursordistance.value;
4963                 push = r_editlights_cursorpushback.value;
4964                 if (push > dist)
4965                         push = dist;
4966                 push = -push;
4967                 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
4968                 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
4969         }
4970         else
4971         {
4972                 VectorClear( endpos );
4973         }
4974         r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4975         r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4976         r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4977 }
4978
4979 void R_Shadow_UpdateWorldLightSelection(void)
4980 {
4981         if (r_editlights.integer)
4982         {
4983                 R_Shadow_SetCursorLocationForView();
4984                 R_Shadow_SelectLightInView();
4985         }
4986         else
4987                 R_Shadow_SelectLight(NULL);
4988 }
4989
4990 void R_Shadow_EditLights_Clear_f(void)
4991 {
4992         R_Shadow_ClearWorldLights();
4993 }
4994
4995 void R_Shadow_EditLights_Reload_f(void)
4996 {
4997         if (!cl.worldmodel)
4998                 return;
4999         strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
5000         R_Shadow_ClearWorldLights();
5001         R_Shadow_LoadWorldLights();
5002         if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5003         {
5004                 R_Shadow_LoadLightsFile();
5005                 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5006                         R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5007         }
5008 }
5009
5010 void R_Shadow_EditLights_Save_f(void)
5011 {
5012         if (!cl.worldmodel)
5013                 return;
5014         R_Shadow_SaveWorldLights();
5015 }
5016
5017 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5018 {
5019         R_Shadow_ClearWorldLights();
5020         R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5021 }
5022
5023 void R_Shadow_EditLights_ImportLightsFile_f(void)
5024 {
5025         R_Shadow_ClearWorldLights();
5026         R_Shadow_LoadLightsFile();
5027 }
5028
5029 void R_Shadow_EditLights_Spawn_f(void)
5030 {
5031         vec3_t color;
5032         if (!r_editlights.integer)
5033         {
5034                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
5035                 return;
5036         }
5037         if (Cmd_Argc() != 1)
5038         {
5039                 Con_Print("r_editlights_spawn does not take parameters\n");
5040                 return;
5041         }
5042         color[0] = color[1] = color[2] = 1;
5043         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5044 }
5045
5046 void R_Shadow_EditLights_Edit_f(void)
5047 {
5048         vec3_t origin, angles, color;
5049         vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5050         int style, shadows, flags, normalmode, realtimemode;
5051         char cubemapname[MAX_INPUTLINE];
5052         if (!r_editlights.integer)
5053         {
5054                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
5055                 return;
5056         }
5057         if (!r_shadow_selectedlight)
5058         {
5059                 Con_Print("No selected light.\n");
5060                 return;
5061         }
5062         VectorCopy(r_shadow_selectedlight->origin, origin);
5063         VectorCopy(r_shadow_selectedlight->angles, angles);
5064         VectorCopy(r_shadow_selectedlight->color, color);
5065         radius = r_shadow_selectedlight->radius;
5066         style = r_shadow_selectedlight->style;
5067         if (r_shadow_selectedlight->cubemapname)
5068                 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5069         else
5070                 cubemapname[0] = 0;
5071         shadows = r_shadow_selectedlight->shadow;
5072         corona = r_shadow_selectedlight->corona;
5073         coronasizescale = r_shadow_selectedlight->coronasizescale;
5074         ambientscale = r_shadow_selectedlight->ambientscale;
5075         diffusescale = r_shadow_selectedlight->diffusescale;
5076         specularscale = r_shadow_selectedlight->specularscale;
5077         flags = r_shadow_selectedlight->flags;
5078         normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5079         realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5080         if (!strcmp(Cmd_Argv(1), "origin"))
5081         {
5082                 if (Cmd_Argc() != 5)
5083                 {
5084                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5085                         return;
5086                 }
5087                 origin[0] = atof(Cmd_Argv(2));
5088                 origin[1] = atof(Cmd_Argv(3));
5089                 origin[2] = atof(Cmd_Argv(4));
5090         }
5091         else if (!strcmp(Cmd_Argv(1), "originx"))
5092         {
5093                 if (Cmd_Argc() != 3)
5094                 {
5095                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5096                         return;
5097                 }
5098                 origin[0] = atof(Cmd_Argv(2));
5099         }
5100         else if (!strcmp(Cmd_Argv(1), "originy"))
5101         {
5102                 if (Cmd_Argc() != 3)
5103                 {
5104                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5105                         return;
5106                 }
5107                 origin[1] = atof(Cmd_Argv(2));
5108         }
5109         else if (!strcmp(Cmd_Argv(1), "originz"))
5110         {
5111                 if (Cmd_Argc() != 3)
5112                 {
5113                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5114                         return;
5115                 }
5116                 origin[2] = atof(Cmd_Argv(2));
5117         }
5118         else if (!strcmp(Cmd_Argv(1), "move"))
5119         {
5120                 if (Cmd_Argc() != 5)
5121                 {
5122                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5123                         return;
5124                 }
5125                 origin[0] += atof(Cmd_Argv(2));
5126                 origin[1] += atof(Cmd_Argv(3));
5127                 origin[2] += atof(Cmd_Argv(4));
5128         }
5129         else if (!strcmp(Cmd_Argv(1), "movex"))
5130         {
5131                 if (Cmd_Argc() != 3)
5132                 {
5133                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5134                         return;
5135                 }
5136                 origin[0] += atof(Cmd_Argv(2));
5137         }
5138         else if (!strcmp(Cmd_Argv(1), "movey"))
5139         {
5140                 if (Cmd_Argc() != 3)
5141                 {
5142                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5143                         return;
5144                 }
5145                 origin[1] += atof(Cmd_Argv(2));
5146         }
5147         else if (!strcmp(Cmd_Argv(1), "movez"))
5148         {
5149                 if (Cmd_Argc() != 3)
5150                 {
5151                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5152                         return;
5153                 }
5154                 origin[2] += atof(Cmd_Argv(2));
5155         }
5156         else if (!strcmp(Cmd_Argv(1), "angles"))
5157         {
5158                 if (Cmd_Argc() != 5)
5159                 {
5160                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5161                         return;
5162                 }
5163                 angles[0] = atof(Cmd_Argv(2));
5164                 angles[1] = atof(Cmd_Argv(3));
5165                 angles[2] = atof(Cmd_Argv(4));
5166         }
5167         else if (!strcmp(Cmd_Argv(1), "anglesx"))
5168         {
5169                 if (Cmd_Argc() != 3)
5170                 {
5171                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5172                         return;
5173                 }
5174                 angles[0] = atof(Cmd_Argv(2));
5175         }
5176         else if (!strcmp(Cmd_Argv(1), "anglesy"))
5177         {
5178                 if (Cmd_Argc() != 3)
5179                 {
5180                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5181                         return;
5182                 }
5183                 angles[1] = atof(Cmd_Argv(2));
5184         }
5185         else if (!strcmp(Cmd_Argv(1), "anglesz"))
5186         {
5187                 if (Cmd_Argc() != 3)
5188                 {
5189                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5190                         return;
5191                 }
5192                 angles[2] = atof(Cmd_Argv(2));
5193         }
5194         else if (!strcmp(Cmd_Argv(1), "color"))
5195         {
5196                 if (Cmd_Argc() != 5)
5197                 {
5198                         Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5199                         return;
5200                 }
5201                 color[0] = atof(Cmd_Argv(2));
5202                 color[1] = atof(Cmd_Argv(3));
5203                 color[2] = atof(Cmd_Argv(4));
5204         }
5205         else if (!strcmp(Cmd_Argv(1), "radius"))
5206         {
5207                 if (Cmd_Argc() != 3)
5208                 {
5209                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5210                         return;
5211                 }
5212                 radius = atof(Cmd_Argv(2));
5213         }
5214         else if (!strcmp(Cmd_Argv(1), "colorscale"))
5215         {
5216                 if (Cmd_Argc() == 3)
5217                 {
5218                         double scale = atof(Cmd_Argv(2));
5219                         color[0] *= scale;
5220                         color[1] *= scale;
5221                         color[2] *= scale;
5222                 }
5223                 else
5224                 {
5225                         if (Cmd_Argc() != 5)
5226                         {
5227                                 Con_Printf("usage: r_editlights_edit %s red green blue  (OR grey instead of red green blue)\n", Cmd_Argv(1));
5228                                 return;
5229                         }
5230                         color[0] *= atof(Cmd_Argv(2));
5231                         color[1] *= atof(Cmd_Argv(3));
5232                         color[2] *= atof(Cmd_Argv(4));
5233                 }
5234         }
5235         else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5236         {
5237                 if (Cmd_Argc() != 3)
5238                 {
5239                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5240                         return;
5241                 }
5242                 radius *= atof(Cmd_Argv(2));
5243         }
5244         else if (!strcmp(Cmd_Argv(1), "style"))
5245         {
5246                 if (Cmd_Argc() != 3)
5247                 {
5248                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5249                         return;
5250                 }
5251                 style = atoi(Cmd_Argv(2));
5252         }
5253         else if (!strcmp(Cmd_Argv(1), "cubemap"))
5254         {
5255                 if (Cmd_Argc() > 3)
5256                 {
5257                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5258                         return;
5259                 }
5260                 if (Cmd_Argc() == 3)
5261                         strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5262                 else
5263                         cubemapname[0] = 0;
5264         }
5265         else if (!strcmp(Cmd_Argv(1), "shadows"))
5266         {
5267                 if (Cmd_Argc() != 3)
5268                 {
5269                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5270                         return;
5271                 }
5272                 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5273         }
5274         else if (!strcmp(Cmd_Argv(1), "corona"))
5275         {
5276                 if (Cmd_Argc() != 3)
5277                 {
5278                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5279                         return;
5280                 }
5281                 corona = atof(Cmd_Argv(2));
5282         }
5283         else if (!strcmp(Cmd_Argv(1), "coronasize"))
5284         {
5285                 if (Cmd_Argc() != 3)
5286                 {
5287                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5288                         return;
5289                 }
5290                 coronasizescale = atof(Cmd_Argv(2));
5291         }
5292         else if (!strcmp(Cmd_Argv(1), "ambient"))
5293         {
5294                 if (Cmd_Argc() != 3)
5295                 {
5296                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5297                         return;
5298                 }
5299                 ambientscale = atof(Cmd_Argv(2));
5300         }
5301         else if (!strcmp(Cmd_Argv(1), "diffuse"))
5302         {
5303                 if (Cmd_Argc() != 3)
5304                 {
5305                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5306                         return;
5307                 }
5308                 diffusescale = atof(Cmd_Argv(2));
5309         }
5310         else if (!strcmp(Cmd_Argv(1), "specular"))
5311         {
5312                 if (Cmd_Argc() != 3)
5313                 {
5314                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5315                         return;
5316                 }
5317                 specularscale = atof(Cmd_Argv(2));
5318         }
5319         else if (!strcmp(Cmd_Argv(1), "normalmode"))
5320         {
5321                 if (Cmd_Argc() != 3)
5322                 {
5323                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5324                         return;
5325                 }
5326                 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5327         }
5328         else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5329         {
5330                 if (Cmd_Argc() != 3)
5331                 {
5332                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5333                         return;
5334                 }
5335                 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5336         }
5337         else
5338         {
5339                 Con_Print("usage: r_editlights_edit [property] [value]\n");
5340                 Con_Print("Selected light's properties:\n");
5341                 Con_Printf("Origin       : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5342                 Con_Printf("Angles       : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5343                 Con_Printf("Color        : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5344                 Con_Printf("Radius       : %f\n", r_shadow_selectedlight->radius);
5345                 Con_Printf("Corona       : %f\n", r_shadow_selectedlight->corona);
5346                 Con_Printf("Style        : %i\n", r_shadow_selectedlight->style);
5347                 Con_Printf("Shadows      : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5348                 Con_Printf("Cubemap      : %s\n", r_shadow_selectedlight->cubemapname);
5349                 Con_Printf("CoronaSize   : %f\n", r_shadow_selectedlight->coronasizescale);
5350                 Con_Printf("Ambient      : %f\n", r_shadow_selectedlight->ambientscale);
5351                 Con_Printf("Diffuse      : %f\n", r_shadow_selectedlight->diffusescale);
5352                 Con_Printf("Specular     : %f\n", r_shadow_selectedlight->specularscale);
5353                 Con_Printf("NormalMode   : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5354                 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5355                 return;
5356         }
5357         flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5358         R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5359 }
5360
5361 void R_Shadow_EditLights_EditAll_f(void)
5362 {
5363         size_t lightindex;
5364         dlight_t *light;
5365         size_t range;
5366
5367         if (!r_editlights.integer)
5368         {
5369                 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5370                 return;
5371         }
5372
5373         // EditLights doesn't seem to have a "remove" command or something so:
5374         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5375         for (lightindex = 0;lightindex < range;lightindex++)
5376         {
5377                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5378                 if (!light)
5379                         continue;
5380                 R_Shadow_SelectLight(light);
5381                 R_Shadow_EditLights_Edit_f();
5382         }
5383 }
5384
5385 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5386 {
5387         int lightnumber, lightcount;
5388         size_t lightindex, range;
5389         dlight_t *light;
5390         float x, y;
5391         char temp[256];
5392         if (!r_editlights.integer)
5393                 return;
5394         x = vid_conwidth.value - 240;
5395         y = 5;
5396         DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5397         lightnumber = -1;
5398         lightcount = 0;
5399         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5400         for (lightindex = 0;lightindex < range;lightindex++)
5401         {
5402                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5403                 if (!light)
5404                         continue;
5405                 if (light == r_shadow_selectedlight)
5406                         lightnumber = lightindex;
5407                 lightcount++;
5408         }
5409         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;
5410         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;
5411         y += 8;
5412         if (r_shadow_selectedlight == NULL)
5413                 return;
5414         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;
5415         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;
5416         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;
5417         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;
5418         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;
5419         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;
5420         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;
5421         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;
5422         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;
5423         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;
5424         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;
5425         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;
5426         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;
5427         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;
5428         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;
5429 }
5430
5431 void R_Shadow_EditLights_ToggleShadow_f(void)
5432 {
5433         if (!r_editlights.integer)
5434         {
5435                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
5436                 return;
5437         }
5438         if (!r_shadow_selectedlight)
5439         {
5440                 Con_Print("No selected light.\n");
5441                 return;
5442         }
5443         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);
5444 }
5445
5446 void R_Shadow_EditLights_ToggleCorona_f(void)
5447 {
5448         if (!r_editlights.integer)
5449         {
5450                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
5451                 return;
5452         }
5453         if (!r_shadow_selectedlight)
5454         {
5455                 Con_Print("No selected light.\n");
5456                 return;
5457         }
5458         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);
5459 }
5460
5461 void R_Shadow_EditLights_Remove_f(void)
5462 {
5463         if (!r_editlights.integer)
5464         {
5465                 Con_Print("Cannot remove light when not in editing mode.  Set r_editlights to 1.\n");
5466                 return;
5467         }
5468         if (!r_shadow_selectedlight)
5469         {
5470                 Con_Print("No selected light.\n");
5471                 return;
5472         }
5473         R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5474         r_shadow_selectedlight = NULL;
5475 }
5476
5477 void R_Shadow_EditLights_Help_f(void)
5478 {
5479         Con_Print(
5480 "Documentation on r_editlights system:\n"
5481 "Settings:\n"
5482 "r_editlights : enable/disable editing mode\n"
5483 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5484 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5485 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5486 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5487 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5488 "Commands:\n"
5489 "r_editlights_help : this help\n"
5490 "r_editlights_clear : remove all lights\n"
5491 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5492 "r_editlights_save : save to .rtlights file\n"
5493 "r_editlights_spawn : create a light with default settings\n"
5494 "r_editlights_edit command : edit selected light - more documentation below\n"
5495 "r_editlights_remove : remove selected light\n"
5496 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5497 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5498 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5499 "Edit commands:\n"
5500 "origin x y z : set light location\n"
5501 "originx x: set x component of light location\n"
5502 "originy y: set y component of light location\n"
5503 "originz z: set z component of light location\n"
5504 "move x y z : adjust light location\n"
5505 "movex x: adjust x component of light location\n"
5506 "movey y: adjust y component of light location\n"
5507 "movez z: adjust z component of light location\n"
5508 "angles x y z : set light angles\n"
5509 "anglesx x: set x component of light angles\n"
5510 "anglesy y: set y component of light angles\n"
5511 "anglesz z: set z component of light angles\n"
5512 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5513 "radius radius : set radius (size) of light\n"
5514 "colorscale grey : multiply color of light (1 does nothing)\n"
5515 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5516 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5517 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5518 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5519 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5520 "shadows 1/0 : turn on/off shadows\n"
5521 "corona n : set corona intensity\n"
5522 "coronasize n : set corona size (0-1)\n"
5523 "ambient n : set ambient intensity (0-1)\n"
5524 "diffuse n : set diffuse intensity (0-1)\n"
5525 "specular n : set specular intensity (0-1)\n"
5526 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5527 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5528 "<nothing> : print light properties to console\n"
5529         );
5530 }
5531
5532 void R_Shadow_EditLights_CopyInfo_f(void)
5533 {
5534         if (!r_editlights.integer)
5535         {
5536                 Con_Print("Cannot copy light info when not in editing mode.  Set r_editlights to 1.\n");
5537                 return;
5538         }
5539         if (!r_shadow_selectedlight)
5540         {
5541                 Con_Print("No selected light.\n");
5542                 return;
5543         }
5544         VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5545         VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5546         r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5547         r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5548         if (r_shadow_selectedlight->cubemapname)
5549                 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5550         else
5551                 r_shadow_bufferlight.cubemapname[0] = 0;
5552         r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5553         r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5554         r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5555         r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5556         r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5557         r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5558         r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5559 }
5560
5561 void R_Shadow_EditLights_PasteInfo_f(void)
5562 {
5563         if (!r_editlights.integer)
5564         {
5565                 Con_Print("Cannot paste light info when not in editing mode.  Set r_editlights to 1.\n");
5566                 return;
5567         }
5568         if (!r_shadow_selectedlight)
5569         {
5570                 Con_Print("No selected light.\n");
5571                 return;
5572         }
5573         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);
5574 }
5575
5576 void R_Shadow_EditLights_Init(void)
5577 {
5578         Cvar_RegisterVariable(&r_editlights);
5579         Cvar_RegisterVariable(&r_editlights_cursordistance);
5580         Cvar_RegisterVariable(&r_editlights_cursorpushback);
5581         Cvar_RegisterVariable(&r_editlights_cursorpushoff);
5582         Cvar_RegisterVariable(&r_editlights_cursorgrid);
5583         Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
5584         Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
5585         Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
5586         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)");
5587         Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
5588         Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
5589         Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
5590         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)");
5591         Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
5592         Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
5593         Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
5594         Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
5595         Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
5596         Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
5597         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)");
5598 }
5599
5600
5601
5602 /*
5603 =============================================================================
5604
5605 LIGHT SAMPLING
5606
5607 =============================================================================
5608 */
5609
5610 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
5611 {
5612         VectorClear(diffusecolor);
5613         VectorClear(diffusenormal);
5614
5615         if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
5616         {
5617                 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient * (2.0f / 128.0f);
5618                 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
5619         }
5620         else
5621                 VectorSet(ambientcolor, 1, 1, 1);
5622
5623         if (dynamic)
5624         {
5625                 int i;
5626                 float f, v[3];
5627                 rtlight_t *light;
5628                 for (i = 0;i < r_refdef.scene.numlights;i++)
5629                 {
5630                         light = r_refdef.scene.lights[i];
5631                         Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
5632                         f = 1 - VectorLength2(v);
5633                         if (f > 0 && CL_Move(p, vec3_origin, vec3_origin, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
5634                                 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);
5635                 }
5636         }
5637 }