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