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