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