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