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