]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - r_shadow.c
fix stencil clear
[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][0])
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.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.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", maxsize*2, maxsize*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", maxsize*2, maxsize*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", bound(1, maxsize >> r_shadow_shadowmaplod, 2048));
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.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.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.viewport.x;
1747         r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
1748         r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
1749         r_shadow_lightscissor[3] = r_refdef.view.viewport.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 = vid.height - (int)(y2 - 1.0f);
1823         ix2 = (int)(x2 + 1.0f);
1824         iy2 = vid.height - (int)(y1 + 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.viewport.x) ix1 = r_refdef.view.viewport.x;
1829         if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
1830         if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
1831         if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.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] = iy1;
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                 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
3761                 R_Shadow_ClearStencil();
3762                 if (numsurfaces)
3763                         R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3764                 for (i = 0;i < numshadowentities;i++)
3765                         R_Shadow_DrawEntityShadow(shadowentities[i]);
3766                 if (numlightentities_noselfshadow)
3767                 {
3768                         // draw lighting in the unmasked areas
3769                         R_Shadow_RenderMode_Lighting(true, false, false);
3770                         for (i = 0;i < numlightentities_noselfshadow;i++)
3771                                 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3772
3773                         // optionally draw the illuminated areas
3774                         // for performance analysis by level designers
3775                         if (r_showlighting.integer && r_refdef.view.showdebug)
3776                         {
3777                                 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
3778                                 for (i = 0;i < numlightentities_noselfshadow;i++)
3779                                         R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3780                         }
3781                 }
3782                 for (i = 0;i < numshadowentities_noselfshadow;i++)
3783                         R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3784
3785                 if (numsurfaces + numlightentities)
3786                 {
3787                         // draw lighting in the unmasked areas
3788                         R_Shadow_RenderMode_Lighting(true, false, false);
3789                         if (numsurfaces)
3790                                 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3791                         for (i = 0;i < numlightentities;i++)
3792                                 R_Shadow_DrawEntityLight(lightentities[i]);
3793                 }
3794         }
3795         else
3796         {
3797                 if (numsurfaces + numlightentities)
3798                 {
3799                         // draw lighting in the unmasked areas
3800                         R_Shadow_RenderMode_Lighting(false, false, false);
3801                         if (numsurfaces)
3802                                 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3803                         for (i = 0;i < numlightentities;i++)
3804                                 R_Shadow_DrawEntityLight(lightentities[i]);
3805                         for (i = 0;i < numlightentities_noselfshadow;i++)
3806                                 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3807                 }
3808         }
3809 }
3810
3811 void R_Shadow_DrawLightSprites(void);
3812 void R_ShadowVolumeLighting(qboolean visible)
3813 {
3814         int flag;
3815         int lnum;
3816         size_t lightindex;
3817         dlight_t *light;
3818         size_t range;
3819
3820         if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, 2048) || r_shadow_shadowmode != r_shadow_shadowmapping.integer)
3821                 R_Shadow_FreeShadowMaps();
3822
3823         if (r_editlights.integer)
3824                 R_Shadow_DrawLightSprites();
3825
3826         R_Shadow_RenderMode_Begin();
3827
3828         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3829         if (r_shadow_debuglight.integer >= 0)
3830         {
3831                 lightindex = r_shadow_debuglight.integer;
3832                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3833                 if (light && (light->flags & flag))
3834                         R_DrawRTLight(&light->rtlight, visible);
3835         }
3836         else
3837         {
3838                 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3839                 for (lightindex = 0;lightindex < range;lightindex++)
3840                 {
3841                         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3842                         if (light && (light->flags & flag))
3843                                 R_DrawRTLight(&light->rtlight, visible);
3844                 }
3845         }
3846         if (r_refdef.scene.rtdlight)
3847                 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3848                         R_DrawRTLight(r_refdef.scene.lights[lnum], visible);
3849
3850         R_Shadow_RenderMode_End();
3851 }
3852
3853 extern const float r_screenvertex3f[12];
3854 extern void R_SetupView(qboolean allowwaterclippingplane);
3855 extern void R_ResetViewRendering3D(void);
3856 extern void R_ResetViewRendering2D(void);
3857 extern cvar_t r_shadows;
3858 extern cvar_t r_shadows_darken;
3859 extern cvar_t r_shadows_drawafterrtlighting;
3860 extern cvar_t r_shadows_castfrombmodels;
3861 extern cvar_t r_shadows_throwdistance;
3862 extern cvar_t r_shadows_throwdirection;
3863 void R_DrawModelShadows(void)
3864 {
3865         int i;
3866         float relativethrowdistance;
3867         entity_render_t *ent;
3868         vec3_t relativelightorigin;
3869         vec3_t relativelightdirection;
3870         vec3_t relativeshadowmins, relativeshadowmaxs;
3871         vec3_t tmp, shadowdir;
3872
3873         if (!r_drawentities.integer || !gl_stencil)
3874                 return;
3875
3876         CHECKGLERROR
3877         R_ResetViewRendering3D();
3878         //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
3879         //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
3880         R_Shadow_RenderMode_Begin();
3881         R_Shadow_RenderMode_ActiveLight(NULL);
3882         r_shadow_lightscissor[0] = r_refdef.view.x;
3883         r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
3884         r_shadow_lightscissor[2] = r_refdef.view.width;
3885         r_shadow_lightscissor[3] = r_refdef.view.height;
3886         R_Shadow_RenderMode_StencilShadowVolumes(false);
3887
3888         // get shadow dir
3889         if (r_shadows.integer == 2)
3890         {
3891                 Math_atov(r_shadows_throwdirection.string, shadowdir);
3892                 VectorNormalize(shadowdir);
3893         }
3894
3895         R_Shadow_ClearStencil();
3896
3897         for (i = 0;i < r_refdef.scene.numentities;i++)
3898         {
3899                 ent = r_refdef.scene.entities[i];
3900
3901                 // cast shadows from anything of the map (submodels are optional)
3902                 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
3903                 {
3904                         relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
3905                         VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
3906                         VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
3907                         if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
3908                                 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
3909                         else
3910                         {
3911                                 if(ent->entitynumber != 0)
3912                                 {
3913                                         // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
3914                                         int entnum, entnum2, recursion;
3915                                         entnum = entnum2 = ent->entitynumber;
3916                                         for(recursion = 32; recursion > 0; --recursion)
3917                                         {
3918                                                 entnum2 = cl.entities[entnum].state_current.tagentity;
3919                                                 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
3920                                                         entnum = entnum2;
3921                                                 else
3922                                                         break;
3923                                         }
3924                                         if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
3925                                         {
3926                                                 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
3927                                                 // transform into modelspace of OUR entity
3928                                                 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
3929                                                 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
3930                                         }
3931                                         else
3932                                                 VectorNegate(ent->modellight_lightdir, relativelightdirection);
3933                                 }
3934                                 else
3935                                         VectorNegate(ent->modellight_lightdir, relativelightdirection);
3936                         }
3937
3938                         VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
3939                         RSurf_ActiveModelEntity(ent, false, false);
3940                         ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3941                         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3942                 }
3943         }
3944
3945         // not really the right mode, but this will disable any silly stencil features
3946         R_Shadow_RenderMode_End();
3947
3948         // set up ortho view for rendering this pass
3949         //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
3950         //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
3951         //GL_ScissorTest(true);
3952         //R_Mesh_Matrix(&identitymatrix);
3953         //R_Mesh_ResetTextureState();
3954         R_ResetViewRendering2D();
3955         R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
3956         R_Mesh_ColorPointer(NULL, 0, 0);
3957         R_SetupGenericShader(false);
3958
3959         // set up a darkening blend on shadowed areas
3960         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3961         //GL_DepthRange(0, 1);
3962         //GL_DepthTest(false);
3963         //GL_DepthMask(false);
3964         //GL_PolygonOffset(0, 0);CHECKGLERROR
3965         GL_Color(0, 0, 0, r_shadows_darken.value);
3966         //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
3967         //qglDepthFunc(GL_ALWAYS);CHECKGLERROR
3968         qglEnable(GL_STENCIL_TEST);CHECKGLERROR
3969         qglStencilMask(~0);CHECKGLERROR
3970         qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
3971         qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
3972
3973         // apply the blend to the shadowed areas
3974         R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
3975
3976         // restore the viewport
3977         R_SetViewport(&r_refdef.view.viewport);
3978
3979         // restore other state to normal
3980         //R_Shadow_RenderMode_End();
3981 }
3982
3983 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
3984 {
3985         float zdist;
3986         vec3_t centerorigin;
3987         // if it's too close, skip it
3988         if (VectorLength(rtlight->color) < (1.0f / 256.0f))
3989                 return;
3990         zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
3991         if (zdist < 32)
3992                 return;
3993         if (usequery && r_numqueries + 2 <= r_maxqueries)
3994         {
3995                 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
3996                 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
3997                 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
3998
3999                 CHECKGLERROR
4000                 // 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
4001                 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4002                 qglDepthFunc(GL_ALWAYS);
4003                 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);
4004                 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4005                 qglDepthFunc(GL_LEQUAL);
4006                 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4007                 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);
4008                 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4009                 CHECKGLERROR
4010         }
4011         rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4012 }
4013
4014 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4015 {
4016         vec3_t color;
4017         GLint allpixels = 0, visiblepixels = 0;
4018         // now we have to check the query result
4019         if (rtlight->corona_queryindex_visiblepixels)
4020         {
4021                 CHECKGLERROR
4022                 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4023                 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4024                 CHECKGLERROR
4025                 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4026                 if (visiblepixels < 1 || allpixels < 1)
4027                         return;
4028                 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4029                 cscale *= rtlight->corona_visibility;
4030         }
4031         else
4032         {
4033                 // FIXME: these traces should scan all render entities instead of cl.world
4034                 if (CL_Move(r_refdef.view.origin, vec3_origin, vec3_origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4035                         return;
4036         }
4037         VectorScale(rtlight->color, cscale, color);
4038         if (VectorLength(color) > (1.0f / 256.0f))
4039                 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);
4040 }
4041
4042 void R_DrawCoronas(void)
4043 {
4044         int i, flag;
4045         qboolean usequery;
4046         size_t lightindex;
4047         dlight_t *light;
4048         rtlight_t *rtlight;
4049         size_t range;
4050         if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4051                 return;
4052         if (r_waterstate.renderingscene)
4053                 return;
4054         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4055         R_Mesh_Matrix(&identitymatrix);
4056
4057         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4058
4059         // check occlusion of coronas
4060         // use GL_ARB_occlusion_query if available
4061         // otherwise use raytraces
4062         r_numqueries = 0;
4063         usequery = gl_support_arb_occlusion_query && r_coronas_occlusionquery.integer;
4064         if (usequery)
4065         {
4066                 GL_ColorMask(0,0,0,0);
4067                 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4068                 if (r_maxqueries < R_MAX_OCCLUSION_QUERIES)
4069                 {
4070                         i = r_maxqueries;
4071                         r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4072                         r_maxqueries = min(r_maxqueries, R_MAX_OCCLUSION_QUERIES);
4073                         CHECKGLERROR
4074                         qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4075                         CHECKGLERROR
4076                 }
4077         }
4078         for (lightindex = 0;lightindex < range;lightindex++)
4079         {
4080                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4081                 if (!light)
4082                         continue;
4083                 rtlight = &light->rtlight;
4084                 rtlight->corona_visibility = 0;
4085                 rtlight->corona_queryindex_visiblepixels = 0;
4086                 rtlight->corona_queryindex_allpixels = 0;
4087                 if (!(rtlight->flags & flag))
4088                         continue;
4089                 if (rtlight->corona <= 0)
4090                         continue;
4091                 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4092                         continue;
4093                 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4094         }
4095         for (i = 0;i < r_refdef.scene.numlights;i++)
4096         {
4097                 rtlight = r_refdef.scene.lights[i];
4098                 rtlight->corona_visibility = 0;
4099                 rtlight->corona_queryindex_visiblepixels = 0;
4100                 rtlight->corona_queryindex_allpixels = 0;
4101                 if (!(rtlight->flags & flag))
4102                         continue;
4103                 if (rtlight->corona <= 0)
4104                         continue;
4105                 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4106         }
4107         if (usequery)
4108                 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4109
4110         // now draw the coronas using the query data for intensity info
4111         for (lightindex = 0;lightindex < range;lightindex++)
4112         {
4113                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4114                 if (!light)
4115                         continue;
4116                 rtlight = &light->rtlight;
4117                 if (rtlight->corona_visibility <= 0)
4118                         continue;
4119                 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4120         }
4121         for (i = 0;i < r_refdef.scene.numlights;i++)
4122         {
4123                 rtlight = r_refdef.scene.lights[i];
4124                 if (rtlight->corona_visibility <= 0)
4125                         continue;
4126                 if (gl_flashblend.integer)
4127                         R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4128                 else
4129                         R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4130         }
4131 }
4132
4133
4134
4135 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
4136 typedef struct suffixinfo_s
4137 {
4138         char *suffix;
4139         qboolean flipx, flipy, flipdiagonal;
4140 }
4141 suffixinfo_t;
4142 static suffixinfo_t suffix[3][6] =
4143 {
4144         {
4145                 {"px",   false, false, false},
4146                 {"nx",   false, false, false},
4147                 {"py",   false, false, false},
4148                 {"ny",   false, false, false},
4149                 {"pz",   false, false, false},
4150                 {"nz",   false, false, false}
4151         },
4152         {
4153                 {"posx", false, false, false},
4154                 {"negx", false, false, false},
4155                 {"posy", false, false, false},
4156                 {"negy", false, false, false},
4157                 {"posz", false, false, false},
4158                 {"negz", false, false, false}
4159         },
4160         {
4161                 {"rt",    true, false,  true},
4162                 {"lf",   false,  true,  true},
4163                 {"ft",    true,  true, false},
4164                 {"bk",   false, false, false},
4165                 {"up",    true, false,  true},
4166                 {"dn",    true, false,  true}
4167         }
4168 };
4169
4170 static int componentorder[4] = {0, 1, 2, 3};
4171
4172 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
4173 {
4174         int i, j, cubemapsize;
4175         unsigned char *cubemappixels, *image_buffer;
4176         rtexture_t *cubemaptexture;
4177         char name[256];
4178         // must start 0 so the first loadimagepixels has no requested width/height
4179         cubemapsize = 0;
4180         cubemappixels = NULL;
4181         cubemaptexture = NULL;
4182         // keep trying different suffix groups (posx, px, rt) until one loads
4183         for (j = 0;j < 3 && !cubemappixels;j++)
4184         {
4185                 // load the 6 images in the suffix group
4186                 for (i = 0;i < 6;i++)
4187                 {
4188                         // generate an image name based on the base and and suffix
4189                         dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
4190                         // load it
4191                         if ((image_buffer = loadimagepixelsbgra(name, false, false)))
4192                         {
4193                                 // an image loaded, make sure width and height are equal
4194                                 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
4195                                 {
4196                                         // if this is the first image to load successfully, allocate the cubemap memory
4197                                         if (!cubemappixels && image_width >= 1)
4198                                         {
4199                                                 cubemapsize = image_width;
4200                                                 // note this clears to black, so unavailable sides are black
4201                                                 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
4202                                         }
4203                                         // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
4204                                         if (cubemappixels)
4205                                                 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);
4206                                 }
4207                                 else
4208                                         Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
4209                                 // free the image
4210                                 Mem_Free(image_buffer);
4211                         }
4212                 }
4213         }
4214         // if a cubemap loaded, upload it
4215         if (cubemappixels)
4216         {
4217                 if (developer_loading.integer)
4218                         Con_Printf("loading cubemap \"%s\"\n", basename);
4219
4220                 if (!r_shadow_filters_texturepool)
4221                         r_shadow_filters_texturepool = R_AllocTexturePool();
4222                 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, TEXF_PRECACHE | (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR, NULL);
4223                 Mem_Free(cubemappixels);
4224         }
4225         else
4226         {
4227                 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
4228                 if (developer_loading.integer)
4229                 {
4230                         Con_Printf("(tried tried images ");
4231                         for (j = 0;j < 3;j++)
4232                                 for (i = 0;i < 6;i++)
4233                                         Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
4234                         Con_Print(" and was unable to find any of them).\n");
4235                 }
4236         }
4237         return cubemaptexture;
4238 }
4239
4240 rtexture_t *R_Shadow_Cubemap(const char *basename)
4241 {
4242         int i;
4243         for (i = 0;i < numcubemaps;i++)
4244                 if (!strcasecmp(cubemaps[i].basename, basename))
4245                         return cubemaps[i].texture ? cubemaps[i].texture : r_texture_whitecube;
4246         if (i >= MAX_CUBEMAPS)
4247                 return r_texture_whitecube;
4248         numcubemaps++;
4249         strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
4250         cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
4251         return cubemaps[i].texture;
4252 }
4253
4254 void R_Shadow_FreeCubemaps(void)
4255 {
4256         int i;
4257         for (i = 0;i < numcubemaps;i++)
4258         {
4259                 if (developer_loading.integer)
4260                         Con_Printf("unloading cubemap \"%s\"\n", cubemaps[i].basename);
4261                 if (cubemaps[i].texture)
4262                         R_FreeTexture(cubemaps[i].texture);
4263         }
4264
4265         numcubemaps = 0;
4266         R_FreeTexturePool(&r_shadow_filters_texturepool);
4267 }
4268
4269 dlight_t *R_Shadow_NewWorldLight(void)
4270 {
4271         return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4272 }
4273
4274 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)
4275 {
4276         matrix4x4_t matrix;
4277         // validate parameters
4278         if (style < 0 || style >= MAX_LIGHTSTYLES)
4279         {
4280                 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4281                 style = 0;
4282         }
4283         if (!cubemapname)
4284                 cubemapname = "";
4285
4286         // copy to light properties
4287         VectorCopy(origin, light->origin);
4288         light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4289         light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4290         light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4291         light->color[0] = max(color[0], 0);
4292         light->color[1] = max(color[1], 0);
4293         light->color[2] = max(color[2], 0);
4294         light->radius = max(radius, 0);
4295         light->style = style;
4296         light->shadow = shadowenable;
4297         light->corona = corona;
4298         strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4299         light->coronasizescale = coronasizescale;
4300         light->ambientscale = ambientscale;
4301         light->diffusescale = diffusescale;
4302         light->specularscale = specularscale;
4303         light->flags = flags;
4304
4305         // update renderable light data
4306         Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4307         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);
4308 }
4309
4310 void R_Shadow_FreeWorldLight(dlight_t *light)
4311 {
4312         if (r_shadow_selectedlight == light)
4313                 r_shadow_selectedlight = NULL;
4314         R_RTLight_Uncompile(&light->rtlight);
4315         Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4316 }
4317
4318 void R_Shadow_ClearWorldLights(void)
4319 {
4320         size_t lightindex;
4321         dlight_t *light;
4322         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4323         for (lightindex = 0;lightindex < range;lightindex++)
4324         {
4325                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4326                 if (light)
4327                         R_Shadow_FreeWorldLight(light);
4328         }
4329         r_shadow_selectedlight = NULL;
4330         R_Shadow_FreeCubemaps();
4331 }
4332
4333 void R_Shadow_SelectLight(dlight_t *light)
4334 {
4335         if (r_shadow_selectedlight)
4336                 r_shadow_selectedlight->selected = false;
4337         r_shadow_selectedlight = light;
4338         if (r_shadow_selectedlight)
4339                 r_shadow_selectedlight->selected = true;
4340 }
4341
4342 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4343 {
4344         // this is never batched (there can be only one)
4345         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);
4346 }
4347
4348 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4349 {
4350         float intensity;
4351         float s;
4352         vec3_t spritecolor;
4353         cachepic_t *pic;
4354
4355         // this is never batched (due to the ent parameter changing every time)
4356         // so numsurfaces == 1 and surfacelist[0] == lightnumber
4357         const dlight_t *light = (dlight_t *)ent;
4358         s = EDLIGHTSPRSIZE;
4359         intensity = 0.5f;
4360         VectorScale(light->color, intensity, spritecolor);
4361         if (VectorLength(spritecolor) < 0.1732f)
4362                 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4363         if (VectorLength(spritecolor) > 1.0f)
4364                 VectorNormalize(spritecolor);
4365
4366         // draw light sprite
4367         if (light->cubemapname[0] && !light->shadow)
4368                 pic = r_editlights_sprcubemapnoshadowlight;
4369         else if (light->cubemapname[0])
4370                 pic = r_editlights_sprcubemaplight;
4371         else if (!light->shadow)
4372                 pic = r_editlights_sprnoshadowlight;
4373         else
4374                 pic = r_editlights_sprlight;
4375         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);
4376         // draw selection sprite if light is selected
4377         if (light->selected)
4378                 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);
4379         // VorteX todo: add normalmode/realtime mode light overlay sprites?
4380 }
4381
4382 void R_Shadow_DrawLightSprites(void)
4383 {
4384         size_t lightindex;
4385         dlight_t *light;
4386         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4387         for (lightindex = 0;lightindex < range;lightindex++)
4388         {
4389                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4390                 if (light)
4391                         R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4392         }
4393         R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4394 }
4395
4396 void R_Shadow_SelectLightInView(void)
4397 {
4398         float bestrating, rating, temp[3];
4399         dlight_t *best;
4400         size_t lightindex;
4401         dlight_t *light;
4402         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4403         best = NULL;
4404         bestrating = 0;
4405         for (lightindex = 0;lightindex < range;lightindex++)
4406         {
4407                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4408                 if (!light)
4409                         continue;
4410                 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4411                 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4412                 if (rating >= 0.95)
4413                 {
4414                         rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4415                         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)
4416                         {
4417                                 bestrating = rating;
4418                                 best = light;
4419                         }
4420                 }
4421         }
4422         R_Shadow_SelectLight(best);
4423 }
4424
4425 void R_Shadow_LoadWorldLights(void)
4426 {
4427         int n, a, style, shadow, flags;
4428         char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4429         float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4430         if (cl.worldmodel == NULL)
4431         {
4432                 Con_Print("No map loaded.\n");
4433                 return;
4434         }
4435         FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4436         strlcat (name, ".rtlights", sizeof (name));
4437         lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4438         if (lightsstring)
4439         {
4440                 s = lightsstring;
4441                 n = 0;
4442                 while (*s)
4443                 {
4444                         t = s;
4445                         /*
4446                         shadow = true;
4447                         for (;COM_Parse(t, true) && strcmp(
4448                         if (COM_Parse(t, true))
4449                         {
4450                                 if (com_token[0] == '!')
4451                                 {
4452                                         shadow = false;
4453                                         origin[0] = atof(com_token+1);
4454                                 }
4455                                 else
4456                                         origin[0] = atof(com_token);
4457                                 if (Com_Parse(t
4458                         }
4459                         */
4460                         t = s;
4461                         while (*s && *s != '\n' && *s != '\r')
4462                                 s++;
4463                         if (!*s)
4464                                 break;
4465                         tempchar = *s;
4466                         shadow = true;
4467                         // check for modifier flags
4468                         if (*t == '!')
4469                         {
4470                                 shadow = false;
4471                                 t++;
4472                         }
4473                         *s = 0;
4474 #if _MSC_VER >= 1400
4475 #define sscanf sscanf_s
4476 #endif
4477                         cubemapname[sizeof(cubemapname)-1] = 0;
4478 #if MAX_QPATH != 128
4479 #error update this code if MAX_QPATH changes
4480 #endif
4481                         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
4482 #if _MSC_VER >= 1400
4483 , sizeof(cubemapname)
4484 #endif
4485 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4486                         *s = tempchar;
4487                         if (a < 18)
4488                                 flags = LIGHTFLAG_REALTIMEMODE;
4489                         if (a < 17)
4490                                 specularscale = 1;
4491                         if (a < 16)
4492                                 diffusescale = 1;
4493                         if (a < 15)
4494                                 ambientscale = 0;
4495                         if (a < 14)
4496                                 coronasizescale = 0.25f;
4497                         if (a < 13)
4498                                 VectorClear(angles);
4499                         if (a < 10)
4500                                 corona = 0;
4501                         if (a < 9 || !strcmp(cubemapname, "\"\""))
4502                                 cubemapname[0] = 0;
4503                         // remove quotes on cubemapname
4504                         if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4505                         {
4506                                 size_t namelen;
4507                                 namelen = strlen(cubemapname) - 2;
4508                                 memmove(cubemapname, cubemapname + 1, namelen);
4509                                 cubemapname[namelen] = '\0';
4510                         }
4511                         if (a < 8)
4512                         {
4513                                 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);
4514                                 break;
4515                         }
4516                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4517                         if (*s == '\r')
4518                                 s++;
4519                         if (*s == '\n')
4520                                 s++;
4521                         n++;
4522                 }
4523                 if (*s)
4524                         Con_Printf("invalid rtlights file \"%s\"\n", name);
4525                 Mem_Free(lightsstring);
4526         }
4527 }
4528
4529 void R_Shadow_SaveWorldLights(void)
4530 {
4531         size_t lightindex;
4532         dlight_t *light;
4533         size_t bufchars, bufmaxchars;
4534         char *buf, *oldbuf;
4535         char name[MAX_QPATH];
4536         char line[MAX_INPUTLINE];
4537         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
4538         // I hate lines which are 3 times my screen size :( --blub
4539         if (!range)
4540                 return;
4541         if (cl.worldmodel == NULL)
4542         {
4543                 Con_Print("No map loaded.\n");
4544                 return;
4545         }
4546         FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4547         strlcat (name, ".rtlights", sizeof (name));
4548         bufchars = bufmaxchars = 0;
4549         buf = NULL;
4550         for (lightindex = 0;lightindex < range;lightindex++)
4551         {
4552                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4553                 if (!light)
4554                         continue;
4555                 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
4556                         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);
4557                 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
4558                         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]);
4559                 else
4560                         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);
4561                 if (bufchars + strlen(line) > bufmaxchars)
4562                 {
4563                         bufmaxchars = bufchars + strlen(line) + 2048;
4564                         oldbuf = buf;
4565                         buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
4566                         if (oldbuf)
4567                         {
4568                                 if (bufchars)
4569                                         memcpy(buf, oldbuf, bufchars);
4570                                 Mem_Free(oldbuf);
4571                         }
4572                 }
4573                 if (strlen(line))
4574                 {
4575                         memcpy(buf + bufchars, line, strlen(line));
4576                         bufchars += strlen(line);
4577                 }
4578         }
4579         if (bufchars)
4580                 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
4581         if (buf)
4582                 Mem_Free(buf);
4583 }
4584
4585 void R_Shadow_LoadLightsFile(void)
4586 {
4587         int n, a, style;
4588         char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
4589         float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
4590         if (cl.worldmodel == NULL)
4591         {
4592                 Con_Print("No map loaded.\n");
4593                 return;
4594         }
4595         FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4596         strlcat (name, ".lights", sizeof (name));
4597         lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4598         if (lightsstring)
4599         {
4600                 s = lightsstring;
4601                 n = 0;
4602                 while (*s)
4603                 {
4604                         t = s;
4605                         while (*s && *s != '\n' && *s != '\r')
4606                                 s++;
4607                         if (!*s)
4608                                 break;
4609                         tempchar = *s;
4610                         *s = 0;
4611                         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);
4612                         *s = tempchar;
4613                         if (a < 14)
4614                         {
4615                                 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);
4616                                 break;
4617                         }
4618                         radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
4619                         radius = bound(15, radius, 4096);
4620                         VectorScale(color, (2.0f / (8388608.0f)), color);
4621                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
4622                         if (*s == '\r')
4623                                 s++;
4624                         if (*s == '\n')
4625                                 s++;
4626                         n++;
4627                 }
4628                 if (*s)
4629                         Con_Printf("invalid lights file \"%s\"\n", name);
4630                 Mem_Free(lightsstring);
4631         }
4632 }
4633
4634 // tyrlite/hmap2 light types in the delay field
4635 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
4636
4637 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
4638 {
4639         int entnum, style, islight, skin, pflags, effects, type, n;
4640         char *entfiledata;
4641         const char *data;
4642         float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
4643         char key[256], value[MAX_INPUTLINE];
4644
4645         if (cl.worldmodel == NULL)
4646         {
4647                 Con_Print("No map loaded.\n");
4648                 return;
4649         }
4650         // try to load a .ent file first
4651         FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
4652         strlcat (key, ".ent", sizeof (key));
4653         data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
4654         // and if that is not found, fall back to the bsp file entity string
4655         if (!data)
4656                 data = cl.worldmodel->brush.entities;
4657         if (!data)
4658                 return;
4659         for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
4660         {
4661                 type = LIGHTTYPE_MINUSX;
4662                 origin[0] = origin[1] = origin[2] = 0;
4663                 originhack[0] = originhack[1] = originhack[2] = 0;
4664                 angles[0] = angles[1] = angles[2] = 0;
4665                 color[0] = color[1] = color[2] = 1;
4666                 light[0] = light[1] = light[2] = 1;light[3] = 300;
4667                 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
4668                 fadescale = 1;
4669                 lightscale = 1;
4670                 style = 0;
4671                 skin = 0;
4672                 pflags = 0;
4673                 effects = 0;
4674                 islight = false;
4675                 while (1)
4676                 {
4677                         if (!COM_ParseToken_Simple(&data, false, false))
4678                                 break; // error
4679                         if (com_token[0] == '}')
4680                                 break; // end of entity
4681                         if (com_token[0] == '_')
4682                                 strlcpy(key, com_token + 1, sizeof(key));
4683                         else
4684                                 strlcpy(key, com_token, sizeof(key));
4685                         while (key[strlen(key)-1] == ' ') // remove trailing spaces
4686                                 key[strlen(key)-1] = 0;
4687                         if (!COM_ParseToken_Simple(&data, false, false))
4688                                 break; // error
4689                         strlcpy(value, com_token, sizeof(value));
4690
4691                         // now that we have the key pair worked out...
4692                         if (!strcmp("light", key))
4693                         {
4694                                 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
4695                                 if (n == 1)
4696                                 {
4697                                         // quake
4698                                         light[0] = vec[0] * (1.0f / 256.0f);
4699                                         light[1] = vec[0] * (1.0f / 256.0f);
4700                                         light[2] = vec[0] * (1.0f / 256.0f);
4701                                         light[3] = vec[0];
4702                                 }
4703                                 else if (n == 4)
4704                                 {
4705                                         // halflife
4706                                         light[0] = vec[0] * (1.0f / 255.0f);
4707                                         light[1] = vec[1] * (1.0f / 255.0f);
4708                                         light[2] = vec[2] * (1.0f / 255.0f);
4709                                         light[3] = vec[3];
4710                                 }
4711                         }
4712                         else if (!strcmp("delay", key))
4713                                 type = atoi(value);
4714                         else if (!strcmp("origin", key))
4715                                 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
4716                         else if (!strcmp("angle", key))
4717                                 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
4718                         else if (!strcmp("angles", key))
4719                                 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
4720                         else if (!strcmp("color", key))
4721                                 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
4722                         else if (!strcmp("wait", key))
4723                                 fadescale = atof(value);
4724                         else if (!strcmp("classname", key))
4725                         {
4726                                 if (!strncmp(value, "light", 5))
4727                                 {
4728                                         islight = true;
4729                                         if (!strcmp(value, "light_fluoro"))
4730                                         {
4731                                                 originhack[0] = 0;
4732                                                 originhack[1] = 0;
4733                                                 originhack[2] = 0;
4734                                                 overridecolor[0] = 1;
4735                                                 overridecolor[1] = 1;
4736                                                 overridecolor[2] = 1;
4737                                         }
4738                                         if (!strcmp(value, "light_fluorospark"))
4739                                         {
4740                                                 originhack[0] = 0;
4741                                                 originhack[1] = 0;
4742                                                 originhack[2] = 0;
4743                                                 overridecolor[0] = 1;
4744                                                 overridecolor[1] = 1;
4745                                                 overridecolor[2] = 1;
4746                                         }
4747                                         if (!strcmp(value, "light_globe"))
4748                                         {
4749                                                 originhack[0] = 0;
4750                                                 originhack[1] = 0;
4751                                                 originhack[2] = 0;
4752                                                 overridecolor[0] = 1;
4753                                                 overridecolor[1] = 0.8;
4754                                                 overridecolor[2] = 0.4;
4755                                         }
4756                                         if (!strcmp(value, "light_flame_large_yellow"))
4757                                         {
4758                                                 originhack[0] = 0;
4759                                                 originhack[1] = 0;
4760                                                 originhack[2] = 0;
4761                                                 overridecolor[0] = 1;
4762                                                 overridecolor[1] = 0.5;
4763                                                 overridecolor[2] = 0.1;
4764                                         }
4765                                         if (!strcmp(value, "light_flame_small_yellow"))
4766                                         {
4767                                                 originhack[0] = 0;
4768                                                 originhack[1] = 0;
4769                                                 originhack[2] = 0;
4770                                                 overridecolor[0] = 1;
4771                                                 overridecolor[1] = 0.5;
4772                                                 overridecolor[2] = 0.1;
4773                                         }
4774                                         if (!strcmp(value, "light_torch_small_white"))
4775                                         {
4776                                                 originhack[0] = 0;
4777                                                 originhack[1] = 0;
4778                                                 originhack[2] = 0;
4779                                                 overridecolor[0] = 1;
4780                                                 overridecolor[1] = 0.5;
4781                                                 overridecolor[2] = 0.1;
4782                                         }
4783                                         if (!strcmp(value, "light_torch_small_walltorch"))
4784                                         {
4785                                                 originhack[0] = 0;
4786                                                 originhack[1] = 0;
4787                                                 originhack[2] = 0;
4788                                                 overridecolor[0] = 1;
4789                                                 overridecolor[1] = 0.5;
4790                                                 overridecolor[2] = 0.1;
4791                                         }
4792                                 }
4793                         }
4794                         else if (!strcmp("style", key))
4795                                 style = atoi(value);
4796                         else if (!strcmp("skin", key))
4797                                 skin = (int)atof(value);
4798                         else if (!strcmp("pflags", key))
4799                                 pflags = (int)atof(value);
4800                         else if (!strcmp("effects", key))
4801                                 effects = (int)atof(value);
4802                         else if (cl.worldmodel->type == mod_brushq3)
4803                         {
4804                                 if (!strcmp("scale", key))
4805                                         lightscale = atof(value);
4806                                 if (!strcmp("fade", key))
4807                                         fadescale = atof(value);
4808                         }
4809                 }
4810                 if (!islight)
4811                         continue;
4812                 if (lightscale <= 0)
4813                         lightscale = 1;
4814                 if (fadescale <= 0)
4815                         fadescale = 1;
4816                 if (color[0] == color[1] && color[0] == color[2])
4817                 {
4818                         color[0] *= overridecolor[0];
4819                         color[1] *= overridecolor[1];
4820                         color[2] *= overridecolor[2];
4821                 }
4822                 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
4823                 color[0] = color[0] * light[0];
4824                 color[1] = color[1] * light[1];
4825                 color[2] = color[2] * light[2];
4826                 switch (type)
4827                 {
4828                 case LIGHTTYPE_MINUSX:
4829                         break;
4830                 case LIGHTTYPE_RECIPX:
4831                         radius *= 2;
4832                         VectorScale(color, (1.0f / 16.0f), color);
4833                         break;
4834                 case LIGHTTYPE_RECIPXX:
4835                         radius *= 2;
4836                         VectorScale(color, (1.0f / 16.0f), color);
4837                         break;
4838                 default:
4839                 case LIGHTTYPE_NONE:
4840                         break;
4841                 case LIGHTTYPE_SUN:
4842                         break;
4843                 case LIGHTTYPE_MINUSXX:
4844                         break;
4845                 }
4846                 VectorAdd(origin, originhack, origin);
4847                 if (radius >= 1)
4848                         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);
4849         }
4850         if (entfiledata)
4851                 Mem_Free(entfiledata);
4852 }
4853
4854
4855 void R_Shadow_SetCursorLocationForView(void)
4856 {
4857         vec_t dist, push;
4858         vec3_t dest, endpos;
4859         trace_t trace;
4860         VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
4861         trace = CL_Move(r_refdef.view.origin, vec3_origin, vec3_origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
4862         if (trace.fraction < 1)
4863         {
4864                 dist = trace.fraction * r_editlights_cursordistance.value;
4865                 push = r_editlights_cursorpushback.value;
4866                 if (push > dist)
4867                         push = dist;
4868                 push = -push;
4869                 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
4870                 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
4871         }
4872         else
4873         {
4874                 VectorClear( endpos );
4875         }
4876         r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4877         r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4878         r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4879 }
4880
4881 void R_Shadow_UpdateWorldLightSelection(void)
4882 {
4883         if (r_editlights.integer)
4884         {
4885                 R_Shadow_SetCursorLocationForView();
4886                 R_Shadow_SelectLightInView();
4887         }
4888         else
4889                 R_Shadow_SelectLight(NULL);
4890 }
4891
4892 void R_Shadow_EditLights_Clear_f(void)
4893 {
4894         R_Shadow_ClearWorldLights();
4895 }
4896
4897 void R_Shadow_EditLights_Reload_f(void)
4898 {
4899         if (!cl.worldmodel)
4900                 return;
4901         strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
4902         R_Shadow_ClearWorldLights();
4903         R_Shadow_LoadWorldLights();
4904         if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
4905         {
4906                 R_Shadow_LoadLightsFile();
4907                 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
4908                         R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
4909         }
4910 }
4911
4912 void R_Shadow_EditLights_Save_f(void)
4913 {
4914         if (!cl.worldmodel)
4915                 return;
4916         R_Shadow_SaveWorldLights();
4917 }
4918
4919 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
4920 {
4921         R_Shadow_ClearWorldLights();
4922         R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
4923 }
4924
4925 void R_Shadow_EditLights_ImportLightsFile_f(void)
4926 {
4927         R_Shadow_ClearWorldLights();
4928         R_Shadow_LoadLightsFile();
4929 }
4930
4931 void R_Shadow_EditLights_Spawn_f(void)
4932 {
4933         vec3_t color;
4934         if (!r_editlights.integer)
4935         {
4936                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
4937                 return;
4938         }
4939         if (Cmd_Argc() != 1)
4940         {
4941                 Con_Print("r_editlights_spawn does not take parameters\n");
4942                 return;
4943         }
4944         color[0] = color[1] = color[2] = 1;
4945         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
4946 }
4947
4948 void R_Shadow_EditLights_Edit_f(void)
4949 {
4950         vec3_t origin, angles, color;
4951         vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
4952         int style, shadows, flags, normalmode, realtimemode;
4953         char cubemapname[MAX_INPUTLINE];
4954         if (!r_editlights.integer)
4955         {
4956                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
4957                 return;
4958         }
4959         if (!r_shadow_selectedlight)
4960         {
4961                 Con_Print("No selected light.\n");
4962                 return;
4963         }
4964         VectorCopy(r_shadow_selectedlight->origin, origin);
4965         VectorCopy(r_shadow_selectedlight->angles, angles);
4966         VectorCopy(r_shadow_selectedlight->color, color);
4967         radius = r_shadow_selectedlight->radius;
4968         style = r_shadow_selectedlight->style;
4969         if (r_shadow_selectedlight->cubemapname)
4970                 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
4971         else
4972                 cubemapname[0] = 0;
4973         shadows = r_shadow_selectedlight->shadow;
4974         corona = r_shadow_selectedlight->corona;
4975         coronasizescale = r_shadow_selectedlight->coronasizescale;
4976         ambientscale = r_shadow_selectedlight->ambientscale;
4977         diffusescale = r_shadow_selectedlight->diffusescale;
4978         specularscale = r_shadow_selectedlight->specularscale;
4979         flags = r_shadow_selectedlight->flags;
4980         normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
4981         realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
4982         if (!strcmp(Cmd_Argv(1), "origin"))
4983         {
4984                 if (Cmd_Argc() != 5)
4985                 {
4986                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
4987                         return;
4988                 }
4989                 origin[0] = atof(Cmd_Argv(2));
4990                 origin[1] = atof(Cmd_Argv(3));
4991                 origin[2] = atof(Cmd_Argv(4));
4992         }
4993         else if (!strcmp(Cmd_Argv(1), "originx"))
4994         {
4995                 if (Cmd_Argc() != 3)
4996                 {
4997                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4998                         return;
4999                 }
5000                 origin[0] = atof(Cmd_Argv(2));
5001         }
5002         else if (!strcmp(Cmd_Argv(1), "originy"))
5003         {
5004                 if (Cmd_Argc() != 3)
5005                 {
5006                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5007                         return;
5008                 }
5009                 origin[1] = atof(Cmd_Argv(2));
5010         }
5011         else if (!strcmp(Cmd_Argv(1), "originz"))
5012         {
5013                 if (Cmd_Argc() != 3)
5014                 {
5015                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5016                         return;
5017                 }
5018                 origin[2] = atof(Cmd_Argv(2));
5019         }
5020         else if (!strcmp(Cmd_Argv(1), "move"))
5021         {
5022                 if (Cmd_Argc() != 5)
5023                 {
5024                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5025                         return;
5026                 }
5027                 origin[0] += atof(Cmd_Argv(2));
5028                 origin[1] += atof(Cmd_Argv(3));
5029                 origin[2] += atof(Cmd_Argv(4));
5030         }
5031         else if (!strcmp(Cmd_Argv(1), "movex"))
5032         {
5033                 if (Cmd_Argc() != 3)
5034                 {
5035                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5036                         return;
5037                 }
5038                 origin[0] += atof(Cmd_Argv(2));
5039         }
5040         else if (!strcmp(Cmd_Argv(1), "movey"))
5041         {
5042                 if (Cmd_Argc() != 3)
5043                 {
5044                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5045                         return;
5046                 }
5047                 origin[1] += atof(Cmd_Argv(2));
5048         }
5049         else if (!strcmp(Cmd_Argv(1), "movez"))
5050         {
5051                 if (Cmd_Argc() != 3)
5052                 {
5053                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5054                         return;
5055                 }
5056                 origin[2] += atof(Cmd_Argv(2));
5057         }
5058         else if (!strcmp(Cmd_Argv(1), "angles"))
5059         {
5060                 if (Cmd_Argc() != 5)
5061                 {
5062                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5063                         return;
5064                 }
5065                 angles[0] = atof(Cmd_Argv(2));
5066                 angles[1] = atof(Cmd_Argv(3));
5067                 angles[2] = atof(Cmd_Argv(4));
5068         }
5069         else if (!strcmp(Cmd_Argv(1), "anglesx"))
5070         {
5071                 if (Cmd_Argc() != 3)
5072                 {
5073                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5074                         return;
5075                 }
5076                 angles[0] = atof(Cmd_Argv(2));
5077         }
5078         else if (!strcmp(Cmd_Argv(1), "anglesy"))
5079         {
5080                 if (Cmd_Argc() != 3)
5081                 {
5082                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5083                         return;
5084                 }
5085                 angles[1] = atof(Cmd_Argv(2));
5086         }
5087         else if (!strcmp(Cmd_Argv(1), "anglesz"))
5088         {
5089                 if (Cmd_Argc() != 3)
5090                 {
5091                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5092                         return;
5093                 }
5094                 angles[2] = atof(Cmd_Argv(2));
5095         }
5096         else if (!strcmp(Cmd_Argv(1), "color"))
5097         {
5098                 if (Cmd_Argc() != 5)
5099                 {
5100                         Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5101                         return;
5102                 }
5103                 color[0] = atof(Cmd_Argv(2));
5104                 color[1] = atof(Cmd_Argv(3));
5105                 color[2] = atof(Cmd_Argv(4));
5106         }
5107         else if (!strcmp(Cmd_Argv(1), "radius"))
5108         {
5109                 if (Cmd_Argc() != 3)
5110                 {
5111                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5112                         return;
5113                 }
5114                 radius = atof(Cmd_Argv(2));
5115         }
5116         else if (!strcmp(Cmd_Argv(1), "colorscale"))
5117         {
5118                 if (Cmd_Argc() == 3)
5119                 {
5120                         double scale = atof(Cmd_Argv(2));
5121                         color[0] *= scale;
5122                         color[1] *= scale;
5123                         color[2] *= scale;
5124                 }
5125                 else
5126                 {
5127                         if (Cmd_Argc() != 5)
5128                         {
5129                                 Con_Printf("usage: r_editlights_edit %s red green blue  (OR grey instead of red green blue)\n", Cmd_Argv(1));
5130                                 return;
5131                         }
5132                         color[0] *= atof(Cmd_Argv(2));
5133                         color[1] *= atof(Cmd_Argv(3));
5134                         color[2] *= atof(Cmd_Argv(4));
5135                 }
5136         }
5137         else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5138         {
5139                 if (Cmd_Argc() != 3)
5140                 {
5141                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5142                         return;
5143                 }
5144                 radius *= atof(Cmd_Argv(2));
5145         }
5146         else if (!strcmp(Cmd_Argv(1), "style"))
5147         {
5148                 if (Cmd_Argc() != 3)
5149                 {
5150                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5151                         return;
5152                 }
5153                 style = atoi(Cmd_Argv(2));
5154         }
5155         else if (!strcmp(Cmd_Argv(1), "cubemap"))
5156         {
5157                 if (Cmd_Argc() > 3)
5158                 {
5159                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5160                         return;
5161                 }
5162                 if (Cmd_Argc() == 3)
5163                         strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5164                 else
5165                         cubemapname[0] = 0;
5166         }
5167         else if (!strcmp(Cmd_Argv(1), "shadows"))
5168         {
5169                 if (Cmd_Argc() != 3)
5170                 {
5171                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5172                         return;
5173                 }
5174                 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5175         }
5176         else if (!strcmp(Cmd_Argv(1), "corona"))
5177         {
5178                 if (Cmd_Argc() != 3)
5179                 {
5180                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5181                         return;
5182                 }
5183                 corona = atof(Cmd_Argv(2));
5184         }
5185         else if (!strcmp(Cmd_Argv(1), "coronasize"))
5186         {
5187                 if (Cmd_Argc() != 3)
5188                 {
5189                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5190                         return;
5191                 }
5192                 coronasizescale = atof(Cmd_Argv(2));
5193         }
5194         else if (!strcmp(Cmd_Argv(1), "ambient"))
5195         {
5196                 if (Cmd_Argc() != 3)
5197                 {
5198                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5199                         return;
5200                 }
5201                 ambientscale = atof(Cmd_Argv(2));
5202         }
5203         else if (!strcmp(Cmd_Argv(1), "diffuse"))
5204         {
5205                 if (Cmd_Argc() != 3)
5206                 {
5207                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5208                         return;
5209                 }
5210                 diffusescale = atof(Cmd_Argv(2));
5211         }
5212         else if (!strcmp(Cmd_Argv(1), "specular"))
5213         {
5214                 if (Cmd_Argc() != 3)
5215                 {
5216                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5217                         return;
5218                 }
5219                 specularscale = atof(Cmd_Argv(2));
5220         }
5221         else if (!strcmp(Cmd_Argv(1), "normalmode"))
5222         {
5223                 if (Cmd_Argc() != 3)
5224                 {
5225                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5226                         return;
5227                 }
5228                 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5229         }
5230         else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5231         {
5232                 if (Cmd_Argc() != 3)
5233                 {
5234                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5235                         return;
5236                 }
5237                 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5238         }
5239         else
5240         {
5241                 Con_Print("usage: r_editlights_edit [property] [value]\n");
5242                 Con_Print("Selected light's properties:\n");
5243                 Con_Printf("Origin       : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5244                 Con_Printf("Angles       : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5245                 Con_Printf("Color        : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5246                 Con_Printf("Radius       : %f\n", r_shadow_selectedlight->radius);
5247                 Con_Printf("Corona       : %f\n", r_shadow_selectedlight->corona);
5248                 Con_Printf("Style        : %i\n", r_shadow_selectedlight->style);
5249                 Con_Printf("Shadows      : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5250                 Con_Printf("Cubemap      : %s\n", r_shadow_selectedlight->cubemapname);
5251                 Con_Printf("CoronaSize   : %f\n", r_shadow_selectedlight->coronasizescale);
5252                 Con_Printf("Ambient      : %f\n", r_shadow_selectedlight->ambientscale);
5253                 Con_Printf("Diffuse      : %f\n", r_shadow_selectedlight->diffusescale);
5254                 Con_Printf("Specular     : %f\n", r_shadow_selectedlight->specularscale);
5255                 Con_Printf("NormalMode   : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5256                 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5257                 return;
5258         }
5259         flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5260         R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5261 }
5262
5263 void R_Shadow_EditLights_EditAll_f(void)
5264 {
5265         size_t lightindex;
5266         dlight_t *light;
5267         size_t range;
5268
5269         if (!r_editlights.integer)
5270         {
5271                 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5272                 return;
5273         }
5274
5275         // EditLights doesn't seem to have a "remove" command or something so:
5276         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5277         for (lightindex = 0;lightindex < range;lightindex++)
5278         {
5279                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5280                 if (!light)
5281                         continue;
5282                 R_Shadow_SelectLight(light);
5283                 R_Shadow_EditLights_Edit_f();
5284         }
5285 }
5286
5287 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5288 {
5289         int lightnumber, lightcount;
5290         size_t lightindex, range;
5291         dlight_t *light;
5292         float x, y;
5293         char temp[256];
5294         if (!r_editlights.integer)
5295                 return;
5296         x = vid_conwidth.value - 240;
5297         y = 5;
5298         DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5299         lightnumber = -1;
5300         lightcount = 0;
5301         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5302         for (lightindex = 0;lightindex < range;lightindex++)
5303         {
5304                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5305                 if (!light)
5306                         continue;
5307                 if (light == r_shadow_selectedlight)
5308                         lightnumber = lightindex;
5309                 lightcount++;
5310         }
5311         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;
5312         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;
5313         y += 8;
5314         if (r_shadow_selectedlight == NULL)
5315                 return;
5316         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;
5317         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;
5318         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;
5319         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;
5320         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;
5321         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;
5322         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;
5323         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;
5324         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;
5325         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;
5326         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;
5327         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;
5328         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;
5329         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;
5330         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;
5331 }
5332
5333 void R_Shadow_EditLights_ToggleShadow_f(void)
5334 {
5335         if (!r_editlights.integer)
5336         {
5337                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
5338                 return;
5339         }
5340         if (!r_shadow_selectedlight)
5341         {
5342                 Con_Print("No selected light.\n");
5343                 return;
5344         }
5345         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);
5346 }
5347
5348 void R_Shadow_EditLights_ToggleCorona_f(void)
5349 {
5350         if (!r_editlights.integer)
5351         {
5352                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
5353                 return;
5354         }
5355         if (!r_shadow_selectedlight)
5356         {
5357                 Con_Print("No selected light.\n");
5358                 return;
5359         }
5360         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);
5361 }
5362
5363 void R_Shadow_EditLights_Remove_f(void)
5364 {
5365         if (!r_editlights.integer)
5366         {
5367                 Con_Print("Cannot remove light when not in editing mode.  Set r_editlights to 1.\n");
5368                 return;
5369         }
5370         if (!r_shadow_selectedlight)
5371         {
5372                 Con_Print("No selected light.\n");
5373                 return;
5374         }
5375         R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5376         r_shadow_selectedlight = NULL;
5377 }
5378
5379 void R_Shadow_EditLights_Help_f(void)
5380 {
5381         Con_Print(
5382 "Documentation on r_editlights system:\n"
5383 "Settings:\n"
5384 "r_editlights : enable/disable editing mode\n"
5385 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5386 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5387 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5388 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5389 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5390 "Commands:\n"
5391 "r_editlights_help : this help\n"
5392 "r_editlights_clear : remove all lights\n"
5393 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5394 "r_editlights_save : save to .rtlights file\n"
5395 "r_editlights_spawn : create a light with default settings\n"
5396 "r_editlights_edit command : edit selected light - more documentation below\n"
5397 "r_editlights_remove : remove selected light\n"
5398 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5399 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5400 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5401 "Edit commands:\n"
5402 "origin x y z : set light location\n"
5403 "originx x: set x component of light location\n"
5404 "originy y: set y component of light location\n"
5405 "originz z: set z component of light location\n"
5406 "move x y z : adjust light location\n"
5407 "movex x: adjust x component of light location\n"
5408 "movey y: adjust y component of light location\n"
5409 "movez z: adjust z component of light location\n"
5410 "angles x y z : set light angles\n"
5411 "anglesx x: set x component of light angles\n"
5412 "anglesy y: set y component of light angles\n"
5413 "anglesz z: set z component of light angles\n"
5414 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5415 "radius radius : set radius (size) of light\n"
5416 "colorscale grey : multiply color of light (1 does nothing)\n"
5417 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5418 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5419 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5420 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5421 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5422 "shadows 1/0 : turn on/off shadows\n"
5423 "corona n : set corona intensity\n"
5424 "coronasize n : set corona size (0-1)\n"
5425 "ambient n : set ambient intensity (0-1)\n"
5426 "diffuse n : set diffuse intensity (0-1)\n"
5427 "specular n : set specular intensity (0-1)\n"
5428 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5429 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5430 "<nothing> : print light properties to console\n"
5431         );
5432 }
5433
5434 void R_Shadow_EditLights_CopyInfo_f(void)
5435 {
5436         if (!r_editlights.integer)
5437         {
5438                 Con_Print("Cannot copy light info when not in editing mode.  Set r_editlights to 1.\n");
5439                 return;
5440         }
5441         if (!r_shadow_selectedlight)
5442         {
5443                 Con_Print("No selected light.\n");
5444                 return;
5445         }
5446         VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5447         VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5448         r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5449         r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5450         if (r_shadow_selectedlight->cubemapname)
5451                 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5452         else
5453                 r_shadow_bufferlight.cubemapname[0] = 0;
5454         r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5455         r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5456         r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5457         r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5458         r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5459         r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5460         r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5461 }
5462
5463 void R_Shadow_EditLights_PasteInfo_f(void)
5464 {
5465         if (!r_editlights.integer)
5466         {
5467                 Con_Print("Cannot paste light info when not in editing mode.  Set r_editlights to 1.\n");
5468                 return;
5469         }
5470         if (!r_shadow_selectedlight)
5471         {
5472                 Con_Print("No selected light.\n");
5473                 return;
5474         }
5475         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);
5476 }
5477
5478 void R_Shadow_EditLights_Init(void)
5479 {
5480         Cvar_RegisterVariable(&r_editlights);
5481         Cvar_RegisterVariable(&r_editlights_cursordistance);
5482         Cvar_RegisterVariable(&r_editlights_cursorpushback);
5483         Cvar_RegisterVariable(&r_editlights_cursorpushoff);
5484         Cvar_RegisterVariable(&r_editlights_cursorgrid);
5485         Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
5486         Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
5487         Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
5488         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)");
5489         Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
5490         Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
5491         Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
5492         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)");
5493         Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
5494         Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
5495         Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
5496         Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
5497         Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
5498         Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
5499         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)");
5500 }
5501
5502
5503
5504 /*
5505 =============================================================================
5506
5507 LIGHT SAMPLING
5508
5509 =============================================================================
5510 */
5511
5512 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
5513 {
5514         VectorClear(diffusecolor);
5515         VectorClear(diffusenormal);
5516
5517         if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
5518         {
5519                 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient * (2.0f / 128.0f);
5520                 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
5521         }
5522         else
5523                 VectorSet(ambientcolor, 1, 1, 1);
5524
5525         if (dynamic)
5526         {
5527                 int i;
5528                 float f, v[3];
5529                 rtlight_t *light;
5530                 for (i = 0;i < r_refdef.scene.numlights;i++)
5531                 {
5532                         light = r_refdef.scene.lights[i];
5533                         Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
5534                         f = 1 - VectorLength2(v);
5535                         if (f > 0 && CL_Move(p, vec3_origin, vec3_origin, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
5536                                 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);
5537                 }
5538         }
5539 }