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