]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - r_shadow.c
removed CL_UpdateEntities call in CSQC rendering code
[xonotic/darkplaces.git] / r_shadow.c
1
2 /*
3 Terminology: Stencil Shadow Volume (sometimes called Stencil Shadows)
4 An extrusion of the lit faces, beginning at the original geometry and ending
5 further from the light source than the original geometry (presumably at least
6 as far as the light's radius, if the light has a radius at all), capped at
7 both front and back to avoid any problems (extrusion from dark faces also
8 works but has a different set of problems)
9
10 This is normally rendered using Carmack's Reverse technique, in which
11 backfaces behind zbuffer (zfail) increment the stencil, and frontfaces behind
12 zbuffer (zfail) decrement the stencil, the result is a stencil value of zero
13 where shadows did not intersect the visible geometry, suitable as a stencil
14 mask for rendering lighting everywhere but shadow.
15
16 In our case to hopefully avoid the Creative Labs patent, we draw the backfaces
17 as decrement and the frontfaces as increment, and we redefine the DepthFunc to
18 GL_LESS (the patent uses GL_GEQUAL) which causes zfail when behind surfaces
19 and zpass when infront (the patent draws where zpass with a GL_GEQUAL test),
20 additionally we clear stencil to 128 to avoid the need for the unclamped
21 incr/decr extension (not related to patent).
22
23 Patent warning:
24 This algorithm may be covered by Creative's patent (US Patent #6384822),
25 however that patent is quite specific about increment on backfaces and
26 decrement on frontfaces where zpass with GL_GEQUAL depth test, which is
27 opposite this implementation and partially opposite Carmack's Reverse paper
28 (which uses GL_LESS, but increments on backfaces and decrements on frontfaces).
29
30
31
32 Terminology: Stencil Light Volume (sometimes called Light Volumes)
33 Similar to a Stencil Shadow Volume, but inverted; rather than containing the
34 areas in shadow it contains the areas in light, this can only be built
35 quickly for certain limited cases (such as portal visibility from a point),
36 but is quite useful for some effects (sunlight coming from sky polygons is
37 one possible example, translucent occluders is another example).
38
39
40
41 Terminology: Optimized Stencil Shadow Volume
42 A Stencil Shadow Volume that has been processed sufficiently to ensure it has
43 no duplicate coverage of areas (no need to shadow an area twice), often this
44 greatly improves performance but is an operation too costly to use on moving
45 lights (however completely optimal Stencil Light Volumes can be constructed
46 in some ideal cases).
47
48
49
50 Terminology: Per Pixel Lighting (sometimes abbreviated PPL)
51 Per pixel evaluation of lighting equations, at a bare minimum this involves
52 DOT3 shading of diffuse lighting (per pixel dotproduct of negated incidence
53 vector and surface normal, using a texture of the surface bumps, called a
54 NormalMap) if supported by hardware; in our case there is support for cards
55 which are incapable of DOT3, the quality is quite poor however.  Additionally
56 it is desirable to have specular evaluation per pixel, per vertex
57 normalization of specular halfangle vectors causes noticable distortion but
58 is unavoidable on hardware without GL_ARB_fragment_program or
59 GL_ARB_fragment_shader.
60
61
62
63 Terminology: Normalization CubeMap
64 A cubemap containing normalized dot3-encoded (vectors of length 1 or less
65 encoded as RGB colors) for any possible direction, this technique allows per
66 pixel calculation of incidence vector for per pixel lighting purposes, which
67 would not otherwise be possible per pixel without GL_ARB_fragment_program or
68 GL_ARB_fragment_shader.
69
70
71
72 Terminology: 2D+1D Attenuation Texturing
73 A very crude approximation of light attenuation with distance which results
74 in cylindrical light shapes which fade vertically as a streak (some games
75 such as Doom3 allow this to be rotated to be less noticable in specific
76 cases), the technique is simply modulating lighting by two 2D textures (which
77 can be the same) on different axes of projection (XY and Z, typically), this
78 is the second best technique available without 3D Attenuation Texturing,
79 GL_ARB_fragment_program or GL_ARB_fragment_shader technology.
80
81
82
83 Terminology: 2D+1D Inverse Attenuation Texturing
84 A clever method described in papers on the Abducted engine, this has a squared
85 distance texture (bright on the outside, black in the middle), which is used
86 twice using GL_ADD blending, the result of this is used in an inverse modulate
87 (GL_ONE_MINUS_DST_ALPHA, GL_ZERO) to implement the equation
88 lighting*=(1-((X*X+Y*Y)+(Z*Z))) which is spherical (unlike 2D+1D attenuation
89 texturing).
90
91
92
93 Terminology: 3D Attenuation Texturing
94 A slightly crude approximation of light attenuation with distance, its flaws
95 are limited radius and resolution (performance tradeoffs).
96
97
98
99 Terminology: 3D Attenuation-Normalization Texturing
100 A 3D Attenuation Texture merged with a Normalization CubeMap, by making the
101 vectors shorter the lighting becomes darker, a very effective optimization of
102 diffuse lighting if 3D Attenuation Textures are already used.
103
104
105
106 Terminology: Light Cubemap Filtering
107 A technique for modeling non-uniform light distribution according to
108 direction, for example a lantern may use a cubemap to describe the light
109 emission pattern of the cage around the lantern (as well as soot buildup
110 discoloring the light in certain areas), often also used for softened grate
111 shadows and light shining through a stained glass window (done crudely by
112 texturing the lighting with a cubemap), another good example would be a disco
113 light.  This technique is used heavily in many games (Doom3 does not support
114 this however).
115
116
117
118 Terminology: Light Projection Filtering
119 A technique for modeling shadowing of light passing through translucent
120 surfaces, allowing stained glass windows and other effects to be done more
121 elegantly than possible with Light Cubemap Filtering by applying an occluder
122 texture to the lighting combined with a stencil light volume to limit the lit
123 area, this technique is used by Doom3 for spotlights and flashlights, among
124 other things, this can also be used more generally to render light passing
125 through multiple translucent occluders in a scene (using a light volume to
126 describe the area beyond the occluder, and thus mask off rendering of all
127 other areas).
128
129
130
131 Terminology: Doom3 Lighting
132 A combination of Stencil Shadow Volume, Per Pixel Lighting, Normalization
133 CubeMap, 2D+1D Attenuation Texturing, and Light Projection Filtering, as
134 demonstrated by the game Doom3.
135 */
136
137 #include "quakedef.h"
138 #include "r_shadow.h"
139 #include "cl_collision.h"
140 #include "portals.h"
141 #include "image.h"
142
143 extern void R_Shadow_EditLights_Init(void);
144
145 typedef enum r_shadow_rendermode_e
146 {
147         R_SHADOW_RENDERMODE_NONE,
148         R_SHADOW_RENDERMODE_STENCIL,
149         R_SHADOW_RENDERMODE_SEPARATESTENCIL,
150         R_SHADOW_RENDERMODE_STENCILTWOSIDE,
151         R_SHADOW_RENDERMODE_LIGHT_VERTEX,
152         R_SHADOW_RENDERMODE_LIGHT_DOT3,
153         R_SHADOW_RENDERMODE_LIGHT_GLSL,
154         R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
155         R_SHADOW_RENDERMODE_VISIBLELIGHTING,
156 }
157 r_shadow_rendermode_t;
158
159 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
160 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
161 r_shadow_rendermode_t r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_NONE;
162
163 int maxshadowtriangles;
164 int *shadowelements;
165
166 int maxshadowvertices;
167 float *shadowvertex3f;
168
169 int maxshadowmark;
170 int numshadowmark;
171 int *shadowmark;
172 int *shadowmarklist;
173 int shadowmarkcount;
174
175 int maxvertexupdate;
176 int *vertexupdate;
177 int *vertexremap;
178 int vertexupdatenum;
179
180 int r_shadow_buffer_numleafpvsbytes;
181 unsigned char *r_shadow_buffer_leafpvs;
182 int *r_shadow_buffer_leaflist;
183
184 int r_shadow_buffer_numsurfacepvsbytes;
185 unsigned char *r_shadow_buffer_surfacepvs;
186 int *r_shadow_buffer_surfacelist;
187
188 // current light's cull box (copied out of an rtlight or calculated by GetLightInfo)
189 vec3_t r_shadow_rtlight_cullmins;
190 vec3_t r_shadow_rtlight_cullmaxs;
191
192 rtexturepool_t *r_shadow_texturepool;
193 rtexture_t *r_shadow_attenuation2dtexture;
194 rtexture_t *r_shadow_attenuation3dtexture;
195
196 // lights are reloaded when this changes
197 char r_shadow_mapname[MAX_QPATH];
198
199 // used only for light filters (cubemaps)
200 rtexturepool_t *r_shadow_filters_texturepool;
201
202 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"};
203 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"};
204 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
205 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)"};
206 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"};
207 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "2", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
208 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
209 cvar_t r_shadow_lightattenuationpower = {0, "r_shadow_lightattenuationpower", "0.5", "changes attenuation texture generation (does not affect r_glsl lighting)"};
210 cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1", "changes attenuation texture generation (does not affect r_glsl lighting)"};
211 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
212 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"};
213 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000", "how far to cast shadows"};
214 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)"};
215 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
216 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
217 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
218 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)"};
219 cvar_t r_shadow_realtime_world_dlightshadows = {CVAR_SAVE, "r_shadow_realtime_world_dlightshadows", "1", "enables shadows from dynamic lights when using full world lighting"};
220 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"};
221 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
222 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
223 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"};
224 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation"};
225 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)"};
226 cvar_t r_shadow_shadow_polygonfactor = {0, "r_shadow_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
227 cvar_t r_shadow_shadow_polygonoffset = {0, "r_shadow_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)"};
228 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)"};
229 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatetencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
230 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
231 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
232 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
233 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
234 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
235 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
236 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
237
238 float r_shadow_attenpower, r_shadow_attenscale;
239
240 rtlight_t *r_shadow_compilingrtlight;
241 dlight_t *r_shadow_worldlightchain;
242 dlight_t *r_shadow_selectedlight;
243 dlight_t r_shadow_bufferlight;
244 vec3_t r_editlights_cursorlocation;
245
246 extern int con_vislines;
247
248 typedef struct cubemapinfo_s
249 {
250         char basename[64];
251         rtexture_t *texture;
252 }
253 cubemapinfo_t;
254
255 #define MAX_CUBEMAPS 256
256 static int numcubemaps;
257 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
258
259 void R_Shadow_UncompileWorldLights(void);
260 void R_Shadow_ClearWorldLights(void);
261 void R_Shadow_SaveWorldLights(void);
262 void R_Shadow_LoadWorldLights(void);
263 void R_Shadow_LoadLightsFile(void);
264 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
265 void R_Shadow_EditLights_Reload_f(void);
266 void R_Shadow_ValidateCvars(void);
267 static void R_Shadow_MakeTextures(void);
268 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light);
269
270 void r_shadow_start(void)
271 {
272         // allocate vertex processing arrays
273         numcubemaps = 0;
274         r_shadow_attenuation2dtexture = NULL;
275         r_shadow_attenuation3dtexture = NULL;
276         r_shadow_texturepool = NULL;
277         r_shadow_filters_texturepool = NULL;
278         R_Shadow_ValidateCvars();
279         R_Shadow_MakeTextures();
280         maxshadowtriangles = 0;
281         shadowelements = NULL;
282         maxshadowvertices = 0;
283         shadowvertex3f = NULL;
284         maxvertexupdate = 0;
285         vertexupdate = NULL;
286         vertexremap = NULL;
287         vertexupdatenum = 0;
288         maxshadowmark = 0;
289         numshadowmark = 0;
290         shadowmark = NULL;
291         shadowmarklist = NULL;
292         shadowmarkcount = 0;
293         r_shadow_buffer_numleafpvsbytes = 0;
294         r_shadow_buffer_leafpvs = NULL;
295         r_shadow_buffer_leaflist = NULL;
296         r_shadow_buffer_numsurfacepvsbytes = 0;
297         r_shadow_buffer_surfacepvs = NULL;
298         r_shadow_buffer_surfacelist = NULL;
299 }
300
301 void r_shadow_shutdown(void)
302 {
303         R_Shadow_UncompileWorldLights();
304         numcubemaps = 0;
305         r_shadow_attenuation2dtexture = NULL;
306         r_shadow_attenuation3dtexture = NULL;
307         R_FreeTexturePool(&r_shadow_texturepool);
308         R_FreeTexturePool(&r_shadow_filters_texturepool);
309         maxshadowtriangles = 0;
310         if (shadowelements)
311                 Mem_Free(shadowelements);
312         shadowelements = NULL;
313         if (shadowvertex3f)
314                 Mem_Free(shadowvertex3f);
315         shadowvertex3f = NULL;
316         maxvertexupdate = 0;
317         if (vertexupdate)
318                 Mem_Free(vertexupdate);
319         vertexupdate = NULL;
320         if (vertexremap)
321                 Mem_Free(vertexremap);
322         vertexremap = NULL;
323         vertexupdatenum = 0;
324         maxshadowmark = 0;
325         numshadowmark = 0;
326         if (shadowmark)
327                 Mem_Free(shadowmark);
328         shadowmark = NULL;
329         if (shadowmarklist)
330                 Mem_Free(shadowmarklist);
331         shadowmarklist = NULL;
332         shadowmarkcount = 0;
333         r_shadow_buffer_numleafpvsbytes = 0;
334         if (r_shadow_buffer_leafpvs)
335                 Mem_Free(r_shadow_buffer_leafpvs);
336         r_shadow_buffer_leafpvs = NULL;
337         if (r_shadow_buffer_leaflist)
338                 Mem_Free(r_shadow_buffer_leaflist);
339         r_shadow_buffer_leaflist = NULL;
340         r_shadow_buffer_numsurfacepvsbytes = 0;
341         if (r_shadow_buffer_surfacepvs)
342                 Mem_Free(r_shadow_buffer_surfacepvs);
343         r_shadow_buffer_surfacepvs = NULL;
344         if (r_shadow_buffer_surfacelist)
345                 Mem_Free(r_shadow_buffer_surfacelist);
346         r_shadow_buffer_surfacelist = NULL;
347 }
348
349 void r_shadow_newmap(void)
350 {
351 }
352
353 void R_Shadow_Help_f(void)
354 {
355         Con_Printf(
356 "Documentation on r_shadow system:\n"
357 "Settings:\n"
358 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
359 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
360 "r_shadow_debuglight : render only this light number (-1 = all)\n"
361 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
362 "r_shadow_gloss2intensity : brightness of forced gloss\n"
363 "r_shadow_glossintensity : brightness of textured gloss\n"
364 "r_shadow_lightattenuationpower : used to generate attenuation texture\n"
365 "r_shadow_lightattenuationscale : used to generate attenuation texture\n"
366 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
367 "r_shadow_portallight : use portal visibility for static light precomputation\n"
368 "r_shadow_projectdistance : shadow volume projection distance\n"
369 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
370 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
371 "r_shadow_realtime_world : use high quality world lighting mode\n"
372 "r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n"
373 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
374 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
375 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
376 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
377 "r_shadow_scissor : use scissor optimization\n"
378 "r_shadow_shadow_polygonfactor : nudge shadow volumes closer/further\n"
379 "r_shadow_shadow_polygonoffset : nudge shadow volumes closer/further\n"
380 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
381 "r_showlighting : useful for performance testing; bright = slow!\n"
382 "r_showshadowvolumes : useful for performance testing; bright = slow!\n"
383 "Commands:\n"
384 "r_shadow_help : this help\n"
385         );
386 }
387
388 void R_Shadow_Init(void)
389 {
390         Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
391         Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
392         Cvar_RegisterVariable(&r_shadow_debuglight);
393         Cvar_RegisterVariable(&r_shadow_gloss);
394         Cvar_RegisterVariable(&r_shadow_gloss2intensity);
395         Cvar_RegisterVariable(&r_shadow_glossintensity);
396         Cvar_RegisterVariable(&r_shadow_glossexponent);
397         Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
398         Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
399         Cvar_RegisterVariable(&r_shadow_lightintensityscale);
400         Cvar_RegisterVariable(&r_shadow_portallight);
401         Cvar_RegisterVariable(&r_shadow_projectdistance);
402         Cvar_RegisterVariable(&r_shadow_frontsidecasting);
403         Cvar_RegisterVariable(&r_shadow_realtime_dlight);
404         Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
405         Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
406         Cvar_RegisterVariable(&r_shadow_realtime_world);
407         Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows);
408         Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
409         Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
410         Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
411         Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
412         Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
413         Cvar_RegisterVariable(&r_shadow_scissor);
414         Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor);
415         Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset);
416         Cvar_RegisterVariable(&r_shadow_texture3d);
417         Cvar_RegisterVariable(&gl_ext_separatestencil);
418         Cvar_RegisterVariable(&gl_ext_stenciltwoside);
419         if (gamemode == GAME_TENEBRAE)
420         {
421                 Cvar_SetValue("r_shadow_gloss", 2);
422                 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
423         }
424         Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f, "prints documentation on console commands and variables used by realtime lighting and shadowing system");
425         R_Shadow_EditLights_Init();
426         r_shadow_worldlightchain = NULL;
427         maxshadowtriangles = 0;
428         shadowelements = NULL;
429         maxshadowvertices = 0;
430         shadowvertex3f = NULL;
431         maxvertexupdate = 0;
432         vertexupdate = NULL;
433         vertexremap = NULL;
434         vertexupdatenum = 0;
435         maxshadowmark = 0;
436         numshadowmark = 0;
437         shadowmark = NULL;
438         shadowmarklist = NULL;
439         shadowmarkcount = 0;
440         r_shadow_buffer_numleafpvsbytes = 0;
441         r_shadow_buffer_leafpvs = NULL;
442         r_shadow_buffer_leaflist = NULL;
443         r_shadow_buffer_numsurfacepvsbytes = 0;
444         r_shadow_buffer_surfacepvs = NULL;
445         r_shadow_buffer_surfacelist = NULL;
446         R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
447 }
448
449 matrix4x4_t matrix_attenuationxyz =
450 {
451         {
452                 {0.5, 0.0, 0.0, 0.5},
453                 {0.0, 0.5, 0.0, 0.5},
454                 {0.0, 0.0, 0.5, 0.5},
455                 {0.0, 0.0, 0.0, 1.0}
456         }
457 };
458
459 matrix4x4_t matrix_attenuationz =
460 {
461         {
462                 {0.0, 0.0, 0.5, 0.5},
463                 {0.0, 0.0, 0.0, 0.5},
464                 {0.0, 0.0, 0.0, 0.5},
465                 {0.0, 0.0, 0.0, 1.0}
466         }
467 };
468
469 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles)
470 {
471         // make sure shadowelements is big enough for this volume
472         if (maxshadowtriangles < numtriangles)
473         {
474                 maxshadowtriangles = numtriangles;
475                 if (shadowelements)
476                         Mem_Free(shadowelements);
477                 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[24]));
478         }
479         // make sure shadowvertex3f is big enough for this volume
480         if (maxshadowvertices < numvertices)
481         {
482                 maxshadowvertices = numvertices;
483                 if (shadowvertex3f)
484                         Mem_Free(shadowvertex3f);
485                 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[6]));
486         }
487 }
488
489 static void R_Shadow_EnlargeLeafSurfaceBuffer(int numleafs, int numsurfaces)
490 {
491         int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
492         int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
493         if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
494         {
495                 if (r_shadow_buffer_leafpvs)
496                         Mem_Free(r_shadow_buffer_leafpvs);
497                 if (r_shadow_buffer_leaflist)
498                         Mem_Free(r_shadow_buffer_leaflist);
499                 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
500                 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
501                 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
502         }
503         if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
504         {
505                 if (r_shadow_buffer_surfacepvs)
506                         Mem_Free(r_shadow_buffer_surfacepvs);
507                 if (r_shadow_buffer_surfacelist)
508                         Mem_Free(r_shadow_buffer_surfacelist);
509                 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
510                 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
511                 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
512         }
513 }
514
515 void R_Shadow_PrepareShadowMark(int numtris)
516 {
517         // make sure shadowmark is big enough for this volume
518         if (maxshadowmark < numtris)
519         {
520                 maxshadowmark = numtris;
521                 if (shadowmark)
522                         Mem_Free(shadowmark);
523                 if (shadowmarklist)
524                         Mem_Free(shadowmarklist);
525                 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
526                 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
527                 shadowmarkcount = 0;
528         }
529         shadowmarkcount++;
530         // if shadowmarkcount wrapped we clear the array and adjust accordingly
531         if (shadowmarkcount == 0)
532         {
533                 shadowmarkcount = 1;
534                 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
535         }
536         numshadowmark = 0;
537 }
538
539 int R_Shadow_ConstructShadowVolume(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)
540 {
541         int i, j;
542         int outtriangles = 0, outvertices = 0;
543         const int *element;
544         const float *vertex;
545         float ratio, direction[3], projectvector[3];
546
547         if (projectdirection)
548                 VectorScale(projectdirection, projectdistance, projectvector);
549         else
550                 VectorClear(projectvector);
551
552         if (maxvertexupdate < innumvertices)
553         {
554                 maxvertexupdate = innumvertices;
555                 if (vertexupdate)
556                         Mem_Free(vertexupdate);
557                 if (vertexremap)
558                         Mem_Free(vertexremap);
559                 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
560                 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
561                 vertexupdatenum = 0;
562         }
563         vertexupdatenum++;
564         if (vertexupdatenum == 0)
565         {
566                 vertexupdatenum = 1;
567                 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
568                 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
569         }
570
571         for (i = 0;i < numshadowmarktris;i++)
572                 shadowmark[shadowmarktris[i]] = shadowmarkcount;
573
574         // create the vertices
575         if (projectdirection)
576         {
577                 for (i = 0;i < numshadowmarktris;i++)
578                 {
579                         element = inelement3i + shadowmarktris[i] * 3;
580                         for (j = 0;j < 3;j++)
581                         {
582                                 if (vertexupdate[element[j]] != vertexupdatenum)
583                                 {
584                                         vertexupdate[element[j]] = vertexupdatenum;
585                                         vertexremap[element[j]] = outvertices;
586                                         vertex = invertex3f + element[j] * 3;
587                                         // project one copy of the vertex according to projectvector
588                                         VectorCopy(vertex, outvertex3f);
589                                         VectorAdd(vertex, projectvector, (outvertex3f + 3));
590                                         outvertex3f += 6;
591                                         outvertices += 2;
592                                 }
593                         }
594                 }
595         }
596         else
597         {
598                 for (i = 0;i < numshadowmarktris;i++)
599                 {
600                         element = inelement3i + shadowmarktris[i] * 3;
601                         for (j = 0;j < 3;j++)
602                         {
603                                 if (vertexupdate[element[j]] != vertexupdatenum)
604                                 {
605                                         vertexupdate[element[j]] = vertexupdatenum;
606                                         vertexremap[element[j]] = outvertices;
607                                         vertex = invertex3f + element[j] * 3;
608                                         // project one copy of the vertex to the sphere radius of the light
609                                         // (FIXME: would projecting it to the light box be better?)
610                                         VectorSubtract(vertex, projectorigin, direction);
611                                         ratio = projectdistance / VectorLength(direction);
612                                         VectorCopy(vertex, outvertex3f);
613                                         VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
614                                         outvertex3f += 6;
615                                         outvertices += 2;
616                                 }
617                         }
618                 }
619         }
620
621         if (r_shadow_frontsidecasting.integer)
622         {
623                 for (i = 0;i < numshadowmarktris;i++)
624                 {
625                         int remappedelement[3];
626                         int markindex;
627                         const int *neighbortriangle;
628
629                         markindex = shadowmarktris[i] * 3;
630                         element = inelement3i + markindex;
631                         neighbortriangle = inneighbor3i + markindex;
632                         // output the front and back triangles
633                         outelement3i[0] = vertexremap[element[0]];
634                         outelement3i[1] = vertexremap[element[1]];
635                         outelement3i[2] = vertexremap[element[2]];
636                         outelement3i[3] = vertexremap[element[2]] + 1;
637                         outelement3i[4] = vertexremap[element[1]] + 1;
638                         outelement3i[5] = vertexremap[element[0]] + 1;
639
640                         outelement3i += 6;
641                         outtriangles += 2;
642                         // output the sides (facing outward from this triangle)
643                         if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
644                         {
645                                 remappedelement[0] = vertexremap[element[0]];
646                                 remappedelement[1] = vertexremap[element[1]];
647                                 outelement3i[0] = remappedelement[1];
648                                 outelement3i[1] = remappedelement[0];
649                                 outelement3i[2] = remappedelement[0] + 1;
650                                 outelement3i[3] = remappedelement[1];
651                                 outelement3i[4] = remappedelement[0] + 1;
652                                 outelement3i[5] = remappedelement[1] + 1;
653
654                                 outelement3i += 6;
655                                 outtriangles += 2;
656                         }
657                         if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
658                         {
659                                 remappedelement[1] = vertexremap[element[1]];
660                                 remappedelement[2] = vertexremap[element[2]];
661                                 outelement3i[0] = remappedelement[2];
662                                 outelement3i[1] = remappedelement[1];
663                                 outelement3i[2] = remappedelement[1] + 1;
664                                 outelement3i[3] = remappedelement[2];
665                                 outelement3i[4] = remappedelement[1] + 1;
666                                 outelement3i[5] = remappedelement[2] + 1;
667
668                                 outelement3i += 6;
669                                 outtriangles += 2;
670                         }
671                         if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
672                         {
673                                 remappedelement[0] = vertexremap[element[0]];
674                                 remappedelement[2] = vertexremap[element[2]];
675                                 outelement3i[0] = remappedelement[0];
676                                 outelement3i[1] = remappedelement[2];
677                                 outelement3i[2] = remappedelement[2] + 1;
678                                 outelement3i[3] = remappedelement[0];
679                                 outelement3i[4] = remappedelement[2] + 1;
680                                 outelement3i[5] = remappedelement[0] + 1;
681
682                                 outelement3i += 6;
683                                 outtriangles += 2;
684                         }
685                 }
686         }
687         else
688         {
689                 for (i = 0;i < numshadowmarktris;i++)
690                 {
691                         int remappedelement[3];
692                         int markindex;
693                         const int *neighbortriangle;
694
695                         markindex = shadowmarktris[i] * 3;
696                         element = inelement3i + markindex;
697                         neighbortriangle = inneighbor3i + markindex;
698                         // output the front and back triangles
699                         outelement3i[0] = vertexremap[element[2]];
700                         outelement3i[1] = vertexremap[element[1]];
701                         outelement3i[2] = vertexremap[element[0]];
702                         outelement3i[3] = vertexremap[element[0]] + 1;
703                         outelement3i[4] = vertexremap[element[1]] + 1;
704                         outelement3i[5] = vertexremap[element[2]] + 1;
705
706                         outelement3i += 6;
707                         outtriangles += 2;
708                         // output the sides (facing outward from this triangle)
709                         if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
710                         {
711                                 remappedelement[0] = vertexremap[element[0]];
712                                 remappedelement[1] = vertexremap[element[1]];
713                                 outelement3i[0] = remappedelement[0];
714                                 outelement3i[1] = remappedelement[1];
715                                 outelement3i[2] = remappedelement[1] + 1;
716                                 outelement3i[3] = remappedelement[0];
717                                 outelement3i[4] = remappedelement[1] + 1;
718                                 outelement3i[5] = remappedelement[0] + 1;
719
720                                 outelement3i += 6;
721                                 outtriangles += 2;
722                         }
723                         if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
724                         {
725                                 remappedelement[1] = vertexremap[element[1]];
726                                 remappedelement[2] = vertexremap[element[2]];
727                                 outelement3i[0] = remappedelement[1];
728                                 outelement3i[1] = remappedelement[2];
729                                 outelement3i[2] = remappedelement[2] + 1;
730                                 outelement3i[3] = remappedelement[1];
731                                 outelement3i[4] = remappedelement[2] + 1;
732                                 outelement3i[5] = remappedelement[1] + 1;
733
734                                 outelement3i += 6;
735                                 outtriangles += 2;
736                         }
737                         if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
738                         {
739                                 remappedelement[0] = vertexremap[element[0]];
740                                 remappedelement[2] = vertexremap[element[2]];
741                                 outelement3i[0] = remappedelement[2];
742                                 outelement3i[1] = remappedelement[0];
743                                 outelement3i[2] = remappedelement[0] + 1;
744                                 outelement3i[3] = remappedelement[2];
745                                 outelement3i[4] = remappedelement[0] + 1;
746                                 outelement3i[5] = remappedelement[2] + 1;
747
748                                 outelement3i += 6;
749                                 outtriangles += 2;
750                         }
751                 }
752         }
753         if (outnumvertices)
754                 *outnumvertices = outvertices;
755         return outtriangles;
756 }
757
758 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)
759 {
760         int tris, outverts;
761         if (projectdistance < 0.1)
762         {
763                 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
764                 return;
765         }
766         if (!numverts || !nummarktris)
767                 return;
768         // make sure shadowelements is big enough for this volume
769         if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
770                 R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
771         tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
772         r_refdef.stats.lights_dynamicshadowtriangles += tris;
773         R_Shadow_RenderVolume(outverts, tris, shadowvertex3f, shadowelements);
774 }
775
776 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)
777 {
778         int t, tend;
779         const int *e;
780         const float *v[3];
781         float normal[3];
782         if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
783                 return;
784         tend = firsttriangle + numtris;
785         if (surfacemins[0] >= lightmins[0] && surfacemaxs[0] <= lightmaxs[0]
786          && surfacemins[1] >= lightmins[1] && surfacemaxs[1] <= lightmaxs[1]
787          && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2])
788         {
789                 // surface box entirely inside light box, no box cull
790                 if (projectdirection)
791                 {
792                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
793                         {
794                                 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
795                                 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
796                                         shadowmarklist[numshadowmark++] = t;
797                         }
798                 }
799                 else
800                 {
801                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
802                                 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
803                                         shadowmarklist[numshadowmark++] = t;
804                 }
805         }
806         else
807         {
808                 // surface box not entirely inside light box, cull each triangle
809                 if (projectdirection)
810                 {
811                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
812                         {
813                                 v[0] = invertex3f + e[0] * 3;
814                                 v[1] = invertex3f + e[1] * 3;
815                                 v[2] = invertex3f + e[2] * 3;
816                                 TriangleNormal(v[0], v[1], v[2], normal);
817                                 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
818                                  && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
819                                  && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
820                                  && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
821                                  && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
822                                  && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
823                                  && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
824                                         shadowmarklist[numshadowmark++] = t;
825                         }
826                 }
827                 else
828                 {
829                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
830                         {
831                                 v[0] = invertex3f + e[0] * 3;
832                                 v[1] = invertex3f + e[1] * 3;
833                                 v[2] = invertex3f + e[2] * 3;
834                                 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
835                                  && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
836                                  && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
837                                  && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
838                                  && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
839                                  && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
840                                  && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
841                                         shadowmarklist[numshadowmark++] = t;
842                         }
843                 }
844         }
845 }
846
847 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
848 {
849         if (r_shadow_compilingrtlight)
850         {
851                 // if we're compiling an rtlight, capture the mesh
852                 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
853                 return;
854         }
855         r_refdef.stats.lights_shadowtriangles += numtriangles;
856         CHECKGLERROR
857         R_Mesh_VertexPointer(vertex3f);
858         GL_LockArrays(0, numvertices);
859         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
860         {
861                 // decrement stencil if backface is behind depthbuffer
862                 GL_CullFace(GL_BACK); // quake is backwards, this culls front faces
863                 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
864                 R_Mesh_Draw(0, numvertices, numtriangles, element3i);
865                 // increment stencil if frontface is behind depthbuffer
866                 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
867                 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
868         }
869         R_Mesh_Draw(0, numvertices, numtriangles, element3i);
870         GL_LockArrays(0, 0);
871         CHECKGLERROR
872 }
873
874 static void R_Shadow_MakeTextures(void)
875 {
876         int x, y, z, d;
877         float v[3], intensity;
878         unsigned char *data;
879         R_FreeTexturePool(&r_shadow_texturepool);
880         r_shadow_texturepool = R_AllocTexturePool();
881         r_shadow_attenpower = r_shadow_lightattenuationpower.value;
882         r_shadow_attenscale = r_shadow_lightattenuationscale.value;
883 #define ATTEN2DSIZE 64
884 #define ATTEN3DSIZE 32
885         data = (unsigned char *)Mem_Alloc(tempmempool, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4));
886         for (y = 0;y < ATTEN2DSIZE;y++)
887         {
888                 for (x = 0;x < ATTEN2DSIZE;x++)
889                 {
890                         v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
891                         v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
892                         v[2] = 0;
893                         intensity = 1.0f - sqrt(DotProduct(v, v));
894                         if (intensity > 0)
895                                 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
896                         d = (int)bound(0, intensity, 255);
897                         data[(y*ATTEN2DSIZE+x)*4+0] = d;
898                         data[(y*ATTEN2DSIZE+x)*4+1] = d;
899                         data[(y*ATTEN2DSIZE+x)*4+2] = d;
900                         data[(y*ATTEN2DSIZE+x)*4+3] = d;
901                 }
902         }
903         r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
904         if (r_shadow_texture3d.integer && gl_texture3d)
905         {
906                 for (z = 0;z < ATTEN3DSIZE;z++)
907                 {
908                         for (y = 0;y < ATTEN3DSIZE;y++)
909                         {
910                                 for (x = 0;x < ATTEN3DSIZE;x++)
911                                 {
912                                         v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
913                                         v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
914                                         v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
915                                         intensity = 1.0f - sqrt(DotProduct(v, v));
916                                         if (intensity > 0)
917                                                 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
918                                         d = (int)bound(0, intensity, 255);
919                                         data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
920                                         data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
921                                         data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
922                                         data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
923                                 }
924                         }
925                 }
926                 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
927         }
928         Mem_Free(data);
929 }
930
931 void R_Shadow_ValidateCvars(void)
932 {
933         if (r_shadow_texture3d.integer && !gl_texture3d)
934                 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
935         if (gl_ext_separatestencil.integer && !gl_support_separatestencil)
936                 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
937         if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
938                 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
939 }
940
941 // light currently being rendered
942 rtlight_t *r_shadow_rtlight;
943
944 // this is the location of the light in entity space
945 vec3_t r_shadow_entitylightorigin;
946 // this transforms entity coordinates to light filter cubemap coordinates
947 // (also often used for other purposes)
948 matrix4x4_t r_shadow_entitytolight;
949 // based on entitytolight this transforms -1 to +1 to 0 to 1 for purposes
950 // of attenuation texturing in full 3D (Z result often ignored)
951 matrix4x4_t r_shadow_entitytoattenuationxyz;
952 // this transforms only the Z to S, and T is always 0.5
953 matrix4x4_t r_shadow_entitytoattenuationz;
954
955 void R_Shadow_RenderMode_Begin(void)
956 {
957         R_Shadow_ValidateCvars();
958
959         if (!r_shadow_attenuation2dtexture
960          || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
961          || r_shadow_lightattenuationpower.value != r_shadow_attenpower
962          || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
963                 R_Shadow_MakeTextures();
964
965         CHECKGLERROR
966         R_Mesh_ColorPointer(NULL);
967         R_Mesh_ResetTextureState();
968         GL_BlendFunc(GL_ONE, GL_ZERO);
969         GL_DepthTest(true);
970         GL_DepthMask(false);
971         GL_Color(0, 0, 0, 1);
972         GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
973
974         r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
975
976         if (gl_ext_separatestencil.integer)
977                 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
978         else if (gl_ext_stenciltwoside.integer)
979                 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
980         else
981                 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
982
983         if (r_glsl.integer && gl_support_fragment_shader)
984                 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
985         else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
986                 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
987         else
988                 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
989 }
990
991 void R_Shadow_RenderMode_ActiveLight(rtlight_t *rtlight)
992 {
993         r_shadow_rtlight = rtlight;
994 }
995
996 void R_Shadow_RenderMode_Reset(void)
997 {
998         CHECKGLERROR
999         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1000         {
1001                 qglUseProgramObjectARB(0);CHECKGLERROR
1002         }
1003         else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
1004         {
1005                 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1006         }
1007         R_Mesh_ColorPointer(NULL);
1008         R_Mesh_ResetTextureState();
1009         GL_DepthTest(true);
1010         GL_DepthMask(false);
1011         qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1012         qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1013         qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1014         qglStencilMask(~0);CHECKGLERROR
1015         qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1016         qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1017         GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
1018         GL_Color(1, 1, 1, 1);
1019         GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
1020         GL_BlendFunc(GL_ONE, GL_ZERO);
1021 }
1022
1023 void R_Shadow_RenderMode_StencilShadowVolumes(void)
1024 {
1025         CHECKGLERROR
1026         R_Shadow_RenderMode_Reset();
1027         GL_ColorMask(0, 0, 0, 0);
1028         qglPolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1029         qglDepthFunc(GL_LESS);CHECKGLERROR
1030         qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1031         r_shadow_rendermode = r_shadow_shadowingrendermode;
1032         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SEPARATESTENCIL)
1033         {
1034                 GL_CullFace(GL_NONE);
1035                 qglStencilOpSeparate(GL_BACK, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR // quake is backwards, this is front faces
1036                 qglStencilOpSeparate(GL_FRONT, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR // quake is backwards, this is back faces
1037         }
1038         else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCILTWOSIDE)
1039         {
1040                 GL_CullFace(GL_NONE);
1041                 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1042                 qglActiveStencilFaceEXT(GL_BACK);CHECKGLERROR // quake is backwards, this is front faces
1043                 qglStencilMask(~0);CHECKGLERROR
1044                 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1045                 qglActiveStencilFaceEXT(GL_FRONT);CHECKGLERROR // quake is backwards, this is back faces
1046                 qglStencilMask(~0);CHECKGLERROR
1047                 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1048         }
1049         GL_Clear(GL_STENCIL_BUFFER_BIT);
1050         r_refdef.stats.lights_clears++;
1051 }
1052
1053 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent)
1054 {
1055         CHECKGLERROR
1056         R_Shadow_RenderMode_Reset();
1057         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1058         if (!transparent)
1059         {
1060                 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1061         }
1062         if (stenciltest)
1063         {
1064                 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1065                 // only draw light where this geometry was already rendered AND the
1066                 // stencil is 128 (values other than this mean shadow)
1067                 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1068         }
1069         r_shadow_rendermode = r_shadow_lightingrendermode;
1070         // do global setup needed for the chosen lighting mode
1071         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1072         {
1073                 R_Mesh_TexBind(0, R_GetTexture(r_texture_blanknormalmap)); // normal
1074                 R_Mesh_TexBind(1, R_GetTexture(r_texture_white)); // diffuse
1075                 R_Mesh_TexBind(2, R_GetTexture(r_texture_white)); // gloss
1076                 R_Mesh_TexBindCubeMap(3, R_GetTexture(r_shadow_rtlight->currentcubemap)); // light filter
1077                 R_Mesh_TexBind(4, R_GetTexture(r_texture_fogattenuation)); // fog
1078                 R_Mesh_TexBind(5, R_GetTexture(r_texture_white)); // pants
1079                 R_Mesh_TexBind(6, R_GetTexture(r_texture_white)); // shirt
1080                 R_Mesh_TexBind(7, R_GetTexture(r_texture_white)); // lightmap
1081                 R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap)); // deluxemap
1082                 R_Mesh_TexBind(9, R_GetTexture(r_texture_black)); // glow
1083                 //R_Mesh_TexMatrix(3, r_shadow_entitytolight); // light filter matrix
1084                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1085                 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 0);
1086                 CHECKGLERROR
1087         }
1088 }
1089
1090 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
1091 {
1092         CHECKGLERROR
1093         R_Shadow_RenderMode_Reset();
1094         GL_BlendFunc(GL_ONE, GL_ONE);
1095         GL_DepthTest(r_showshadowvolumes.integer < 2);
1096         GL_Color(0.0, 0.0125 * r_view.colorscale, 0.1 * r_view.colorscale, 1);
1097         qglPolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1098         GL_CullFace(GL_NONE);
1099         r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
1100 }
1101
1102 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
1103 {
1104         CHECKGLERROR
1105         R_Shadow_RenderMode_Reset();
1106         GL_BlendFunc(GL_ONE, GL_ONE);
1107         GL_DepthTest(r_showlighting.integer < 2);
1108         GL_Color(0.1 * r_view.colorscale, 0.0125 * r_view.colorscale, 0, 1);
1109         if (!transparent)
1110         {
1111                 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1112         }
1113         if (stenciltest)
1114         {
1115                 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1116                 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1117         }
1118         r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
1119 }
1120
1121 void R_Shadow_RenderMode_End(void)
1122 {
1123         CHECKGLERROR
1124         R_Shadow_RenderMode_Reset();
1125         R_Shadow_RenderMode_ActiveLight(NULL);
1126         GL_DepthMask(true);
1127         GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
1128         r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1129 }
1130
1131 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1132 {
1133         int i, ix1, iy1, ix2, iy2;
1134         float x1, y1, x2, y2;
1135         vec4_t v, v2;
1136         rmesh_t mesh;
1137         mplane_t planes[11];
1138         float vertex3f[256*3];
1139
1140         // if view is inside the light box, just say yes it's visible
1141         if (BoxesOverlap(r_view.origin, r_view.origin, mins, maxs))
1142         {
1143                 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
1144                 return false;
1145         }
1146
1147         // create a temporary brush describing the area the light can affect in worldspace
1148         VectorNegate(r_view.frustum[0].normal, planes[ 0].normal);planes[ 0].dist = -r_view.frustum[0].dist;
1149         VectorNegate(r_view.frustum[1].normal, planes[ 1].normal);planes[ 1].dist = -r_view.frustum[1].dist;
1150         VectorNegate(r_view.frustum[2].normal, planes[ 2].normal);planes[ 2].dist = -r_view.frustum[2].dist;
1151         VectorNegate(r_view.frustum[3].normal, planes[ 3].normal);planes[ 3].dist = -r_view.frustum[3].dist;
1152         VectorNegate(r_view.frustum[4].normal, planes[ 4].normal);planes[ 4].dist = -r_view.frustum[4].dist;
1153         VectorSet   (planes[ 5].normal,  1, 0, 0);         planes[ 5].dist =  maxs[0];
1154         VectorSet   (planes[ 6].normal, -1, 0, 0);         planes[ 6].dist = -mins[0];
1155         VectorSet   (planes[ 7].normal, 0,  1, 0);         planes[ 7].dist =  maxs[1];
1156         VectorSet   (planes[ 8].normal, 0, -1, 0);         planes[ 8].dist = -mins[1];
1157         VectorSet   (planes[ 9].normal, 0, 0,  1);         planes[ 9].dist =  maxs[2];
1158         VectorSet   (planes[10].normal, 0, 0, -1);         planes[10].dist = -mins[2];
1159
1160         // turn the brush into a mesh
1161         memset(&mesh, 0, sizeof(rmesh_t));
1162         mesh.maxvertices = 256;
1163         mesh.vertex3f = vertex3f;
1164         mesh.epsilon2 = (1.0f / (32.0f * 32.0f));
1165         R_Mesh_AddBrushMeshFromPlanes(&mesh, 11, planes);
1166
1167         // if that mesh is empty, the light is not visible at all
1168         if (!mesh.numvertices)
1169                 return true;
1170
1171         if (!r_shadow_scissor.integer)
1172                 return false;
1173
1174         // if that mesh is not empty, check what area of the screen it covers
1175         x1 = y1 = x2 = y2 = 0;
1176         v[3] = 1.0f;
1177         //Con_Printf("%i vertices to transform...\n", mesh.numvertices);
1178         for (i = 0;i < mesh.numvertices;i++)
1179         {
1180                 VectorCopy(mesh.vertex3f + i * 3, v);
1181                 GL_TransformToScreen(v, v2);
1182                 //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]);
1183                 if (i)
1184                 {
1185                         if (x1 > v2[0]) x1 = v2[0];
1186                         if (x2 < v2[0]) x2 = v2[0];
1187                         if (y1 > v2[1]) y1 = v2[1];
1188                         if (y2 < v2[1]) y2 = v2[1];
1189                 }
1190                 else
1191                 {
1192                         x1 = x2 = v2[0];
1193                         y1 = y2 = v2[1];
1194                 }
1195         }
1196
1197         // now convert the scissor rectangle to integer screen coordinates
1198         ix1 = (int)(x1 - 1.0f);
1199         iy1 = (int)(y1 - 1.0f);
1200         ix2 = (int)(x2 + 1.0f);
1201         iy2 = (int)(y2 + 1.0f);
1202         //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1203
1204         // clamp it to the screen
1205         if (ix1 < r_view.x) ix1 = r_view.x;
1206         if (iy1 < r_view.y) iy1 = r_view.y;
1207         if (ix2 > r_view.x + r_view.width) ix2 = r_view.x + r_view.width;
1208         if (iy2 > r_view.y + r_view.height) iy2 = r_view.y + r_view.height;
1209
1210         // if it is inside out, it's not visible
1211         if (ix2 <= ix1 || iy2 <= iy1)
1212                 return true;
1213
1214         // the light area is visible, set up the scissor rectangle
1215         GL_Scissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1216         //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);CHECKGLERROR
1217         //qglEnable(GL_SCISSOR_TEST);CHECKGLERROR
1218         r_refdef.stats.lights_scissored++;
1219         return false;
1220 }
1221
1222 static void R_Shadow_RenderSurfacesLighting_Light_Vertex_Shading(const msurface_t *surface, const float *diffusecolor, const float *ambientcolor)
1223 {
1224         int numverts = surface->num_vertices;
1225         float *vertex3f = rsurface_vertex3f + 3 * surface->num_firstvertex;
1226         float *normal3f = rsurface_normal3f + 3 * surface->num_firstvertex;
1227         float *color4f = rsurface_array_color4f + 4 * surface->num_firstvertex;
1228         float dist, dot, distintensity, shadeintensity, v[3], n[3];
1229         if (r_textureunits.integer >= 3)
1230         {
1231                 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1232                 {
1233                         Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1234                         Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1235                         if ((dot = DotProduct(n, v)) < 0)
1236                         {
1237                                 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1238                                 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]);
1239                                 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]);
1240                                 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]);
1241                                 if (r_refdef.fogenabled)
1242                                 {
1243                                         float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
1244                                         VectorScale(color4f, f, color4f);
1245                                 }
1246                         }
1247                         else
1248                                 VectorClear(color4f);
1249                         color4f[3] = 1;
1250                 }
1251         }
1252         else if (r_textureunits.integer >= 2)
1253         {
1254                 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1255                 {
1256                         Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1257                         if ((dist = fabs(v[2])) < 1)
1258                         {
1259                                 distintensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1260                                 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1261                                 if ((dot = DotProduct(n, v)) < 0)
1262                                 {
1263                                         shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1264                                         color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1265                                         color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1266                                         color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1267                                 }
1268                                 else
1269                                 {
1270                                         color4f[0] = ambientcolor[0] * distintensity;
1271                                         color4f[1] = ambientcolor[1] * distintensity;
1272                                         color4f[2] = ambientcolor[2] * distintensity;
1273                                 }
1274                                 if (r_refdef.fogenabled)
1275                                 {
1276                                         float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
1277                                         VectorScale(color4f, f, color4f);
1278                                 }
1279                         }
1280                         else
1281                                 VectorClear(color4f);
1282                         color4f[3] = 1;
1283                 }
1284         }
1285         else
1286         {
1287                 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1288                 {
1289                         Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v);
1290                         if ((dist = DotProduct(v, v)) < 1)
1291                         {
1292                                 dist = sqrt(dist);
1293                                 distintensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1294                                 Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n);
1295                                 if ((dot = DotProduct(n, v)) < 0)
1296                                 {
1297                                         shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1298                                         color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1299                                         color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1300                                         color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1301                                 }
1302                                 else
1303                                 {
1304                                         color4f[0] = ambientcolor[0] * distintensity;
1305                                         color4f[1] = ambientcolor[1] * distintensity;
1306                                         color4f[2] = ambientcolor[2] * distintensity;
1307                                 }
1308                                 if (r_refdef.fogenabled)
1309                                 {
1310                                         float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
1311                                         VectorScale(color4f, f, color4f);
1312                                 }
1313                         }
1314                         else
1315                                 VectorClear(color4f);
1316                         color4f[3] = 1;
1317                 }
1318         }
1319 }
1320
1321 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1322
1323 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int numsurfaces, msurface_t **surfacelist)
1324 {
1325         int surfacelistindex;
1326         for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1327         {
1328                 const msurface_t *surface = surfacelist[surfacelistindex];
1329                 int i;
1330                 float *out3f = rsurface_array_texcoord3f + 3 * surface->num_firstvertex;
1331                 const float *vertex3f = rsurface_vertex3f + 3 * surface->num_firstvertex;
1332                 const float *svector3f = rsurface_svector3f + 3 * surface->num_firstvertex;
1333                 const float *tvector3f = rsurface_tvector3f + 3 * surface->num_firstvertex;
1334                 const float *normal3f = rsurface_normal3f + 3 * surface->num_firstvertex;
1335                 float lightdir[3];
1336                 for (i = 0;i < surface->num_vertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1337                 {
1338                         VectorSubtract(r_shadow_entitylightorigin, vertex3f, lightdir);
1339                         // the cubemap normalizes this for us
1340                         out3f[0] = DotProduct(svector3f, lightdir);
1341                         out3f[1] = DotProduct(tvector3f, lightdir);
1342                         out3f[2] = DotProduct(normal3f, lightdir);
1343                 }
1344         }
1345 }
1346
1347 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int numsurfaces, msurface_t **surfacelist)
1348 {
1349         int surfacelistindex;
1350         for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1351         {
1352                 const msurface_t *surface = surfacelist[surfacelistindex];
1353                 int i;
1354                 float *out3f = rsurface_array_texcoord3f + 3 * surface->num_firstvertex;
1355                 const float *vertex3f = rsurface_vertex3f + 3 * surface->num_firstvertex;
1356                 const float *svector3f = rsurface_svector3f + 3 * surface->num_firstvertex;
1357                 const float *tvector3f = rsurface_tvector3f + 3 * surface->num_firstvertex;
1358                 const float *normal3f = rsurface_normal3f + 3 * surface->num_firstvertex;
1359                 float lightdir[3], eyedir[3], halfdir[3];
1360                 for (i = 0;i < surface->num_vertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1361                 {
1362                         VectorSubtract(r_shadow_entitylightorigin, vertex3f, lightdir);
1363                         VectorNormalize(lightdir);
1364                         VectorSubtract(rsurface_modelorg, vertex3f, eyedir);
1365                         VectorNormalize(eyedir);
1366                         VectorAdd(lightdir, eyedir, halfdir);
1367                         // the cubemap normalizes this for us
1368                         out3f[0] = DotProduct(svector3f, halfdir);
1369                         out3f[1] = DotProduct(tvector3f, halfdir);
1370                         out3f[2] = DotProduct(normal3f, halfdir);
1371                 }
1372         }
1373 }
1374
1375 static void R_Shadow_RenderSurfacesLighting_VisibleLighting(int numsurfaces, msurface_t **surfacelist, 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 specularscale, qboolean dopants, qboolean doshirt)
1376 {
1377         // used to display how many times a surface is lit for level design purposes
1378         GL_Color(0.1 * r_view.colorscale, 0.025 * r_view.colorscale, 0, 1);
1379         R_Mesh_ColorPointer(NULL);
1380         R_Mesh_ResetTextureState();
1381         RSurf_PrepareVerticesForBatch(false, false, numsurfaces, surfacelist);
1382         RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1383         GL_LockArrays(0, 0);
1384 }
1385
1386 static void R_Shadow_RenderSurfacesLighting_Light_GLSL(int numsurfaces, msurface_t **surfacelist, 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 specularscale, qboolean dopants, qboolean doshirt)
1387 {
1388         // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
1389         RSurf_PrepareVerticesForBatch(true, true, numsurfaces, surfacelist);
1390         R_SetupSurfaceShader(lightcolorbase, false);
1391         R_Mesh_TexCoordPointer(0, 2, rsurface_model->surfmesh.data_texcoordtexture2f);
1392         R_Mesh_TexCoordPointer(1, 3, rsurface_svector3f);
1393         R_Mesh_TexCoordPointer(2, 3, rsurface_tvector3f);
1394         R_Mesh_TexCoordPointer(3, 3, rsurface_normal3f);
1395         if (rsurface_texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1396         {
1397                 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1398         }
1399         RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1400         GL_LockArrays(0, 0);
1401         if (rsurface_texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1402         {
1403                 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1404         }
1405 }
1406
1407 static void R_Shadow_RenderSurfacesLighting_Light_Dot3_Finalize(int numsurfaces, msurface_t **surfacelist, float r, float g, float b)
1408 {
1409         // shared final code for all the dot3 layers
1410         int renders;
1411         GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 0);
1412         for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
1413         {
1414                 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
1415                 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1416                 GL_LockArrays(0, 0);
1417         }
1418 }
1419
1420 static void R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, rtexture_t *basetexture, float colorscale)
1421 {
1422         rmeshstate_t m;
1423         // colorscale accounts for how much we multiply the brightness
1424         // during combine.
1425         //
1426         // mult is how many times the final pass of the lighting will be
1427         // performed to get more brightness than otherwise possible.
1428         //
1429         // Limit mult to 64 for sanity sake.
1430         GL_Color(1,1,1,1);
1431         if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
1432         {
1433                 // 3 3D combine path (Geforce3, Radeon 8500)
1434                 memset(&m, 0, sizeof(m));
1435                 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1436                 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1437                 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1438                 m.tex[1] = R_GetTexture(basetexture);
1439                 m.pointer_texcoord[1] = rsurface_model->surfmesh.data_texcoordtexture2f;
1440                 m.texmatrix[1] = rsurface_texture->currenttexmatrix;
1441                 m.texcubemap[2] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1442                 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1443                 m.texmatrix[2] = r_shadow_entitytolight;
1444                 GL_BlendFunc(GL_ONE, GL_ONE);
1445         }
1446         else if (r_shadow_texture3d.integer && r_shadow_rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
1447         {
1448                 // 2 3D combine path (Geforce3, original Radeon)
1449                 memset(&m, 0, sizeof(m));
1450                 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1451                 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1452                 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1453                 m.tex[1] = R_GetTexture(basetexture);
1454                 m.pointer_texcoord[1] = rsurface_model->surfmesh.data_texcoordtexture2f;
1455                 m.texmatrix[1] = rsurface_texture->currenttexmatrix;
1456                 GL_BlendFunc(GL_ONE, GL_ONE);
1457         }
1458         else if (r_textureunits.integer >= 4 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1459         {
1460                 // 4 2D combine path (Geforce3, Radeon 8500)
1461                 memset(&m, 0, sizeof(m));
1462                 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1463                 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1464                 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1465                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1466                 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1467                 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1468                 m.tex[2] = R_GetTexture(basetexture);
1469                 m.pointer_texcoord[2] = rsurface_model->surfmesh.data_texcoordtexture2f;
1470                 m.texmatrix[2] = rsurface_texture->currenttexmatrix;
1471                 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1472                 {
1473                         m.texcubemap[3] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1474                         m.pointer_texcoord3f[3] = rsurface_vertex3f;
1475                         m.texmatrix[3] = r_shadow_entitytolight;
1476                 }
1477                 GL_BlendFunc(GL_ONE, GL_ONE);
1478         }
1479         else if (r_textureunits.integer >= 3 && r_shadow_rtlight->currentcubemap == r_texture_whitecube)
1480         {
1481                 // 3 2D combine path (Geforce3, original Radeon)
1482                 memset(&m, 0, sizeof(m));
1483                 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1484                 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1485                 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1486                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1487                 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1488                 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1489                 m.tex[2] = R_GetTexture(basetexture);
1490                 m.pointer_texcoord[2] = rsurface_model->surfmesh.data_texcoordtexture2f;
1491                 m.texmatrix[2] = rsurface_texture->currenttexmatrix;
1492                 GL_BlendFunc(GL_ONE, GL_ONE);
1493         }
1494         else
1495         {
1496                 // 2/2/2 2D combine path (any dot3 card)
1497                 memset(&m, 0, sizeof(m));
1498                 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1499                 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1500                 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1501                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1502                 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1503                 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1504                 R_Mesh_TextureState(&m);
1505                 GL_ColorMask(0,0,0,1);
1506                 GL_BlendFunc(GL_ONE, GL_ZERO);
1507                 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1508                 GL_LockArrays(0, 0);
1509
1510                 // second pass
1511                 memset(&m, 0, sizeof(m));
1512                 m.tex[0] = R_GetTexture(basetexture);
1513                 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1514                 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1515                 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1516                 {
1517                         m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1518                         m.pointer_texcoord3f[1] = rsurface_vertex3f;
1519                         m.texmatrix[1] = r_shadow_entitytolight;
1520                 }
1521                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1522         }
1523         // this final code is shared
1524         R_Mesh_TextureState(&m);
1525         R_Shadow_RenderSurfacesLighting_Light_Dot3_Finalize(numsurfaces, surfacelist, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1526 }
1527
1528 static void R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, rtexture_t *basetexture, rtexture_t *normalmaptexture, float colorscale)
1529 {
1530         rmeshstate_t m;
1531         // colorscale accounts for how much we multiply the brightness
1532         // during combine.
1533         //
1534         // mult is how many times the final pass of the lighting will be
1535         // performed to get more brightness than otherwise possible.
1536         //
1537         // Limit mult to 64 for sanity sake.
1538         GL_Color(1,1,1,1);
1539         // generate normalization cubemap texcoords
1540         R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(numsurfaces, surfacelist);
1541         if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1542         {
1543                 // 3/2 3D combine path (Geforce3, Radeon 8500)
1544                 memset(&m, 0, sizeof(m));
1545                 m.tex[0] = R_GetTexture(normalmaptexture);
1546                 m.texcombinergb[0] = GL_REPLACE;
1547                 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1548                 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1549                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1550                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1551                 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1552                 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1553                 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1554                 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
1555                 R_Mesh_TextureState(&m);
1556                 GL_ColorMask(0,0,0,1);
1557                 GL_BlendFunc(GL_ONE, GL_ZERO);
1558                 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1559                 GL_LockArrays(0, 0);
1560
1561                 // second pass
1562                 memset(&m, 0, sizeof(m));
1563                 m.tex[0] = R_GetTexture(basetexture);
1564                 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1565                 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1566                 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1567                 {
1568                         m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1569                         m.pointer_texcoord3f[1] = rsurface_vertex3f;
1570                         m.texmatrix[1] = r_shadow_entitytolight;
1571                 }
1572                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1573         }
1574         else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1575         {
1576                 // 1/2/2 3D combine path (original Radeon)
1577                 memset(&m, 0, sizeof(m));
1578                 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1579                 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1580                 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1581                 R_Mesh_TextureState(&m);
1582                 GL_ColorMask(0,0,0,1);
1583                 GL_BlendFunc(GL_ONE, GL_ZERO);
1584                 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1585                 GL_LockArrays(0, 0);
1586
1587                 // second pass
1588                 memset(&m, 0, sizeof(m));
1589                 m.tex[0] = R_GetTexture(normalmaptexture);
1590                 m.texcombinergb[0] = GL_REPLACE;
1591                 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1592                 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1593                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1594                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1595                 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1596                 R_Mesh_TextureState(&m);
1597                 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1598                 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1599                 GL_LockArrays(0, 0);
1600
1601                 // second pass
1602                 memset(&m, 0, sizeof(m));
1603                 m.tex[0] = R_GetTexture(basetexture);
1604                 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1605                 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1606                 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1607                 {
1608                         m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1609                         m.pointer_texcoord3f[1] = rsurface_vertex3f;
1610                         m.texmatrix[1] = r_shadow_entitytolight;
1611                 }
1612                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1613         }
1614         else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap == r_texture_whitecube)
1615         {
1616                 // 2/2 3D combine path (original Radeon)
1617                 memset(&m, 0, sizeof(m));
1618                 m.tex[0] = R_GetTexture(normalmaptexture);
1619                 m.texcombinergb[0] = GL_REPLACE;
1620                 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1621                 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1622                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1623                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1624                 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1625                 R_Mesh_TextureState(&m);
1626                 GL_ColorMask(0,0,0,1);
1627                 GL_BlendFunc(GL_ONE, GL_ZERO);
1628                 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1629                 GL_LockArrays(0, 0);
1630
1631                 // second pass
1632                 memset(&m, 0, sizeof(m));
1633                 m.tex[0] = R_GetTexture(basetexture);
1634                 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1635                 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1636                 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1637                 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1638                 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
1639                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1640         }
1641         else if (r_textureunits.integer >= 4)
1642         {
1643                 // 4/2 2D combine path (Geforce3, Radeon 8500)
1644                 memset(&m, 0, sizeof(m));
1645                 m.tex[0] = R_GetTexture(normalmaptexture);
1646                 m.texcombinergb[0] = GL_REPLACE;
1647                 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1648                 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1649                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1650                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1651                 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1652                 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1653                 m.pointer_texcoord3f[2] = rsurface_vertex3f;
1654                 m.texmatrix[2] = r_shadow_entitytoattenuationxyz;
1655                 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1656                 m.pointer_texcoord3f[3] = rsurface_vertex3f;
1657                 m.texmatrix[3] = r_shadow_entitytoattenuationz;
1658                 R_Mesh_TextureState(&m);
1659                 GL_ColorMask(0,0,0,1);
1660                 GL_BlendFunc(GL_ONE, GL_ZERO);
1661                 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1662                 GL_LockArrays(0, 0);
1663
1664                 // second pass
1665                 memset(&m, 0, sizeof(m));
1666                 m.tex[0] = R_GetTexture(basetexture);
1667                 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1668                 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1669                 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1670                 {
1671                         m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1672                         m.pointer_texcoord3f[1] = rsurface_vertex3f;
1673                         m.texmatrix[1] = r_shadow_entitytolight;
1674                 }
1675                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1676         }
1677         else
1678         {
1679                 // 2/2/2 2D combine path (any dot3 card)
1680                 memset(&m, 0, sizeof(m));
1681                 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1682                 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1683                 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1684                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1685                 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1686                 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1687                 R_Mesh_TextureState(&m);
1688                 GL_ColorMask(0,0,0,1);
1689                 GL_BlendFunc(GL_ONE, GL_ZERO);
1690                 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1691                 GL_LockArrays(0, 0);
1692
1693                 // second pass
1694                 memset(&m, 0, sizeof(m));
1695                 m.tex[0] = R_GetTexture(normalmaptexture);
1696                 m.texcombinergb[0] = GL_REPLACE;
1697                 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1698                 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1699                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1700                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1701                 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1702                 R_Mesh_TextureState(&m);
1703                 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1704                 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1705                 GL_LockArrays(0, 0);
1706
1707                 // second pass
1708                 memset(&m, 0, sizeof(m));
1709                 m.tex[0] = R_GetTexture(basetexture);
1710                 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1711                 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1712                 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1713                 {
1714                         m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1715                         m.pointer_texcoord3f[1] = rsurface_vertex3f;
1716                         m.texmatrix[1] = r_shadow_entitytolight;
1717                 }
1718                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1719         }
1720         // this final code is shared
1721         R_Mesh_TextureState(&m);
1722         R_Shadow_RenderSurfacesLighting_Light_Dot3_Finalize(numsurfaces, surfacelist, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1723 }
1724
1725 static void R_Shadow_RenderSurfacesLighting_Light_Dot3_SpecularPass(int numsurfaces, msurface_t **surfacelist, const vec3_t lightcolorbase, rtexture_t *glosstexture, rtexture_t *normalmaptexture, float colorscale)
1726 {
1727         float glossexponent;
1728         rmeshstate_t m;
1729         // FIXME: detect blendsquare!
1730         //if (!gl_support_blendsquare)
1731         //      return;
1732         GL_Color(1,1,1,1);
1733         // generate normalization cubemap texcoords
1734         R_Shadow_GenTexCoords_Specular_NormalCubeMap(numsurfaces, surfacelist);
1735         if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1736         {
1737                 // 2/0/0/1/2 3D combine blendsquare path
1738                 memset(&m, 0, sizeof(m));
1739                 m.tex[0] = R_GetTexture(normalmaptexture);
1740                 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1741                 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1742                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1743                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1744                 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1745                 R_Mesh_TextureState(&m);
1746                 GL_ColorMask(0,0,0,1);
1747                 // this squares the result
1748                 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1749                 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1750                 GL_LockArrays(0, 0);
1751
1752                 // second and third pass
1753                 R_Mesh_ResetTextureState();
1754                 // square alpha in framebuffer a few times to make it shiny
1755                 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1756                 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
1757                         RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1758                 GL_LockArrays(0, 0);
1759
1760                 // fourth pass
1761                 memset(&m, 0, sizeof(m));
1762                 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1763                 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1764                 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1765                 R_Mesh_TextureState(&m);
1766                 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1767                 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1768                 GL_LockArrays(0, 0);
1769
1770                 // fifth pass
1771                 memset(&m, 0, sizeof(m));
1772                 m.tex[0] = R_GetTexture(glosstexture);
1773                 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1774                 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1775                 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1776                 {
1777                         m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1778                         m.pointer_texcoord3f[1] = rsurface_vertex3f;
1779                         m.texmatrix[1] = r_shadow_entitytolight;
1780                 }
1781                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1782         }
1783         else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && r_shadow_rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
1784         {
1785                 // 2/0/0/2 3D combine blendsquare path
1786                 memset(&m, 0, sizeof(m));
1787                 m.tex[0] = R_GetTexture(normalmaptexture);
1788                 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1789                 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1790                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1791                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1792                 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1793                 R_Mesh_TextureState(&m);
1794                 GL_ColorMask(0,0,0,1);
1795                 // this squares the result
1796                 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1797                 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1798                 GL_LockArrays(0, 0);
1799
1800                 // second and third pass
1801                 R_Mesh_ResetTextureState();
1802                 // square alpha in framebuffer a few times to make it shiny
1803                 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1804                 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
1805                         RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1806                 GL_LockArrays(0, 0);
1807
1808                 // fourth pass
1809                 memset(&m, 0, sizeof(m));
1810                 m.tex[0] = R_GetTexture(glosstexture);
1811                 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1812                 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1813                 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1814                 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1815                 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
1816                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1817         }
1818         else
1819         {
1820                 // 2/0/0/2/2 2D combine blendsquare path
1821                 memset(&m, 0, sizeof(m));
1822                 m.tex[0] = R_GetTexture(normalmaptexture);
1823                 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1824                 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1825                 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
1826                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1827                 m.pointer_texcoord3f[1] = rsurface_array_texcoord3f;
1828                 R_Mesh_TextureState(&m);
1829                 GL_ColorMask(0,0,0,1);
1830                 // this squares the result
1831                 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1832                 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1833                 GL_LockArrays(0, 0);
1834
1835                 // second and third pass
1836                 R_Mesh_ResetTextureState();
1837                 // square alpha in framebuffer a few times to make it shiny
1838                 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1839                 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
1840                         RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1841                 GL_LockArrays(0, 0);
1842
1843                 // fourth pass
1844                 memset(&m, 0, sizeof(m));
1845                 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1846                 m.pointer_texcoord3f[0] = rsurface_vertex3f;
1847                 m.texmatrix[0] = r_shadow_entitytoattenuationxyz;
1848                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1849                 m.pointer_texcoord3f[1] = rsurface_vertex3f;
1850                 m.texmatrix[1] = r_shadow_entitytoattenuationz;
1851                 R_Mesh_TextureState(&m);
1852                 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1853                 RSurf_DrawBatch_Simple(numsurfaces, surfacelist);
1854                 GL_LockArrays(0, 0);
1855
1856                 // fifth pass
1857                 memset(&m, 0, sizeof(m));
1858                 m.tex[0] = R_GetTexture(glosstexture);
1859                 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
1860                 m.texmatrix[0] = rsurface_texture->currenttexmatrix;
1861                 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
1862                 {
1863                         m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap);
1864                         m.pointer_texcoord3f[1] = rsurface_vertex3f;
1865                         m.texmatrix[1] = r_shadow_entitytolight;
1866                 }
1867                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1868         }
1869         // this final code is shared
1870         R_Mesh_TextureState(&m);
1871         R_Shadow_RenderSurfacesLighting_Light_Dot3_Finalize(numsurfaces, surfacelist, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
1872 }
1873
1874 static void R_Shadow_RenderSurfacesLighting_Light_Dot3(int numsurfaces, msurface_t **surfacelist, 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 specularscale, qboolean dopants, qboolean doshirt)
1875 {
1876         // ARB path (any Geforce, any Radeon)
1877         qboolean doambient = r_shadow_rtlight->ambientscale > 0;
1878         qboolean dodiffuse = r_shadow_rtlight->diffusescale > 0;
1879         qboolean dospecular = specularscale > 0;
1880         if (!doambient && !dodiffuse && !dospecular)
1881                 return;
1882         RSurf_PrepareVerticesForBatch(true, true, numsurfaces, surfacelist);
1883         R_Mesh_ColorPointer(NULL);
1884         if (doambient)
1885                 R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(numsurfaces, surfacelist, lightcolorbase, basetexture, r_shadow_rtlight->ambientscale * r_view.colorscale);
1886         if (dodiffuse)
1887                 R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(numsurfaces, surfacelist, lightcolorbase, basetexture, normalmaptexture, r_shadow_rtlight->diffusescale * r_view.colorscale);
1888         if (dopants)
1889         {
1890                 if (doambient)
1891                         R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(numsurfaces, surfacelist, lightcolorpants, pantstexture, r_shadow_rtlight->ambientscale * r_view.colorscale);
1892                 if (dodiffuse)
1893                         R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(numsurfaces, surfacelist, lightcolorpants, pantstexture, normalmaptexture, r_shadow_rtlight->diffusescale * r_view.colorscale);
1894         }
1895         if (doshirt)
1896         {
1897                 if (doambient)
1898                         R_Shadow_RenderSurfacesLighting_Light_Dot3_AmbientPass(numsurfaces, surfacelist, lightcolorshirt, shirttexture, r_shadow_rtlight->ambientscale * r_view.colorscale);
1899                 if (dodiffuse)
1900                         R_Shadow_RenderSurfacesLighting_Light_Dot3_DiffusePass(numsurfaces, surfacelist, lightcolorshirt, shirttexture, normalmaptexture, r_shadow_rtlight->diffusescale * r_view.colorscale);
1901         }
1902         if (dospecular)
1903                 R_Shadow_RenderSurfacesLighting_Light_Dot3_SpecularPass(numsurfaces, surfacelist, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_view.colorscale);
1904 }
1905
1906 void R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(const model_t *model, int numsurfaces, msurface_t **surfacelist, vec3_t diffusecolor2, vec3_t ambientcolor2)
1907 {
1908         int surfacelistindex;
1909         int renders;
1910         for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1911         {
1912                 const msurface_t *surface = surfacelist[surfacelistindex];
1913                 R_Shadow_RenderSurfacesLighting_Light_Vertex_Shading(surface, diffusecolor2, ambientcolor2);
1914         }
1915         for (renders = 0;renders < 64;renders++)
1916         {
1917                 const int *e;
1918                 int stop;
1919                 int firstvertex;
1920                 int lastvertex;
1921                 int newnumtriangles;
1922                 int *newe;
1923                 int newelements[3072];
1924                 stop = true;
1925                 firstvertex = 0;
1926                 lastvertex = 0;
1927                 newnumtriangles = 0;
1928                 newe = newelements;
1929                 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1930                 {
1931                         const msurface_t *surface = surfacelist[surfacelistindex];
1932                         const int *elements = rsurface_model->surfmesh.data_element3i + surface->num_firsttriangle * 3;
1933                         int i;
1934                         // due to low fillrate on the cards this vertex lighting path is
1935                         // designed for, we manually cull all triangles that do not
1936                         // contain a lit vertex
1937                         // this builds batches of triangles from multiple surfaces and
1938                         // renders them at once
1939                         for (i = 0, e = elements;i < surface->num_triangles;i++, e += 3)
1940                         {
1941                                 if (VectorLength2(rsurface_array_color4f + e[0] * 4) + VectorLength2(rsurface_array_color4f + e[1] * 4) + VectorLength2(rsurface_array_color4f + e[2] * 4) >= 0.01)
1942                                 {
1943                                         if (newnumtriangles)
1944                                         {
1945                                                 firstvertex = min(firstvertex, e[0]);
1946                                                 lastvertex = max(lastvertex, e[0]);
1947                                         }
1948                                         else
1949                                         {
1950                                                 firstvertex = e[0];
1951                                                 lastvertex = e[0];
1952                                         }
1953                                         firstvertex = min(firstvertex, e[1]);
1954                                         lastvertex = max(lastvertex, e[1]);
1955                                         firstvertex = min(firstvertex, e[2]);
1956                                         lastvertex = max(lastvertex, e[2]);
1957                                         newe[0] = e[0];
1958                                         newe[1] = e[1];
1959                                         newe[2] = e[2];
1960                                         newnumtriangles++;
1961                                         newe += 3;
1962                                         if (newnumtriangles >= 1024)
1963                                         {
1964                                                 GL_LockArrays(firstvertex, lastvertex - firstvertex + 1);
1965                                                 R_Mesh_Draw(firstvertex, lastvertex - firstvertex + 1, newnumtriangles, newelements);
1966                                                 newnumtriangles = 0;
1967                                                 newe = newelements;
1968                                                 stop = false;
1969                                         }
1970                                 }
1971                         }
1972                 }
1973                 if (newnumtriangles >= 1)
1974                 {
1975                         GL_LockArrays(firstvertex, lastvertex - firstvertex + 1);
1976                         R_Mesh_Draw(firstvertex, lastvertex - firstvertex + 1, newnumtriangles, newelements);
1977                         stop = false;
1978                 }
1979                 GL_LockArrays(0, 0);
1980                 // if we couldn't find any lit triangles, exit early
1981                 if (stop)
1982                         break;
1983                 // now reduce the intensity for the next overbright pass
1984                 // we have to clamp to 0 here incase the drivers have improper
1985                 // handling of negative colors
1986                 // (some old drivers even have improper handling of >1 color)
1987                 stop = true;
1988                 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1989                 {
1990                         int i;
1991                         float *c;
1992                         const msurface_t *surface = surfacelist[surfacelistindex];
1993                         for (i = 0, c = rsurface_array_color4f + 4 * surface->num_firstvertex;i < surface->num_vertices;i++, c += 4)
1994                         {
1995                                 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
1996                                 {
1997                                         c[0] = max(0, c[0] - 1);
1998                                         c[1] = max(0, c[1] - 1);
1999                                         c[2] = max(0, c[2] - 1);
2000                                         stop = false;
2001                                 }
2002                                 else
2003                                         VectorClear(c);
2004                         }
2005                 }
2006                 // another check...
2007                 if (stop)
2008                         break;
2009         }
2010 }
2011
2012 static void R_Shadow_RenderSurfacesLighting_Light_Vertex(int numsurfaces, msurface_t **surfacelist, 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 specularscale, qboolean dopants, qboolean doshirt)
2013 {
2014         // OpenGL 1.1 path (anything)
2015         model_t *model = rsurface_entity->model;
2016         float ambientcolorbase[3], diffusecolorbase[3];
2017         float ambientcolorpants[3], diffusecolorpants[3];
2018         float ambientcolorshirt[3], diffusecolorshirt[3];
2019         rmeshstate_t m;
2020         VectorScale(lightcolorbase, r_shadow_rtlight->ambientscale * 2 * r_view.colorscale, ambientcolorbase);
2021         VectorScale(lightcolorbase, r_shadow_rtlight->diffusescale * 2 * r_view.colorscale, diffusecolorbase);
2022         VectorScale(lightcolorpants, r_shadow_rtlight->ambientscale * 2 * r_view.colorscale, ambientcolorpants);
2023         VectorScale(lightcolorpants, r_shadow_rtlight->diffusescale * 2 * r_view.colorscale, diffusecolorpants);
2024         VectorScale(lightcolorshirt, r_shadow_rtlight->ambientscale * 2 * r_view.colorscale, ambientcolorshirt);
2025         VectorScale(lightcolorshirt, r_shadow_rtlight->diffusescale * 2 * r_view.colorscale, diffusecolorshirt);
2026         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2027         R_Mesh_ColorPointer(rsurface_array_color4f);
2028         memset(&m, 0, sizeof(m));
2029         m.tex[0] = R_GetTexture(basetexture);
2030         m.texmatrix[0] = rsurface_texture->currenttexmatrix;
2031         m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
2032         if (r_textureunits.integer >= 2)
2033         {
2034                 // voodoo2 or TNT
2035                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2036                 m.texmatrix[1] = r_shadow_entitytoattenuationxyz;
2037                 m.pointer_texcoord3f[1] = rsurface_vertex3f;
2038                 if (r_textureunits.integer >= 3)
2039                 {
2040                         // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
2041                         m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2042                         m.texmatrix[2] = r_shadow_entitytoattenuationz;
2043                         m.pointer_texcoord3f[2] = rsurface_vertex3f;
2044                 }
2045         }
2046         R_Mesh_TextureState(&m);
2047         RSurf_PrepareVerticesForBatch(true, false, numsurfaces, surfacelist);
2048         R_Mesh_TexBind(0, R_GetTexture(basetexture));
2049         R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(model, numsurfaces, surfacelist, diffusecolorbase, ambientcolorbase);
2050         if (dopants)
2051         {
2052                 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
2053                 R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(model, numsurfaces, surfacelist, diffusecolorpants, ambientcolorpants);
2054         }
2055         if (doshirt)
2056         {
2057                 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
2058                 R_Shadow_RenderSurfacesLighting_Light_Vertex_Pass(model, numsurfaces, surfacelist, diffusecolorshirt, ambientcolorshirt);
2059         }
2060 }
2061
2062 void R_Shadow_RenderSurfacesLighting(int numsurfaces, msurface_t **surfacelist)
2063 {
2064         // FIXME: support MATERIALFLAG_NODEPTHTEST
2065         vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
2066         // calculate colors to render this texture with
2067         lightcolorbase[0] = r_shadow_rtlight->currentcolor[0] * rsurface_entity->colormod[0] * rsurface_texture->currentalpha;
2068         lightcolorbase[1] = r_shadow_rtlight->currentcolor[1] * rsurface_entity->colormod[1] * rsurface_texture->currentalpha;
2069         lightcolorbase[2] = r_shadow_rtlight->currentcolor[2] * rsurface_entity->colormod[2] * rsurface_texture->currentalpha;
2070         if ((r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorbase) + (r_shadow_rtlight->specularscale * rsurface_texture->specularscale) * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
2071                 return;
2072         GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
2073         GL_CullFace(((rsurface_texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) || (rsurface_entity->flags & RENDER_NOCULLFACE)) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
2074         if (rsurface_texture->colormapping)
2075         {
2076                 qboolean dopants = rsurface_texture->currentskinframe->pants != NULL && VectorLength2(rsurface_entity->colormap_pantscolor) >= (1.0f / 1048576.0f);
2077                 qboolean doshirt = rsurface_texture->currentskinframe->shirt != NULL && VectorLength2(rsurface_entity->colormap_shirtcolor) >= (1.0f / 1048576.0f);
2078                 if (dopants)
2079                 {
2080                         lightcolorpants[0] = lightcolorbase[0] * rsurface_entity->colormap_pantscolor[0];
2081                         lightcolorpants[1] = lightcolorbase[1] * rsurface_entity->colormap_pantscolor[1];
2082                         lightcolorpants[2] = lightcolorbase[2] * rsurface_entity->colormap_pantscolor[2];
2083                 }
2084                 else
2085                         VectorClear(lightcolorpants);
2086                 if (doshirt)
2087                 {
2088                         lightcolorshirt[0] = lightcolorbase[0] * rsurface_entity->colormap_shirtcolor[0];
2089                         lightcolorshirt[1] = lightcolorbase[1] * rsurface_entity->colormap_shirtcolor[1];
2090                         lightcolorshirt[2] = lightcolorbase[2] * rsurface_entity->colormap_shirtcolor[2];
2091                 }
2092                 else
2093                         VectorClear(lightcolorshirt);
2094                 switch (r_shadow_rendermode)
2095                 {
2096                 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2097                         GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2098                         R_Shadow_RenderSurfacesLighting_VisibleLighting(numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->currentskinframe->pants, rsurface_texture->currentskinframe->shirt, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, dopants, doshirt);
2099                         break;
2100                 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2101                         R_Shadow_RenderSurfacesLighting_Light_GLSL(numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->currentskinframe->pants, rsurface_texture->currentskinframe->shirt, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, dopants, doshirt);
2102                         break;
2103                 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2104                         R_Shadow_RenderSurfacesLighting_Light_Dot3(numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->currentskinframe->pants, rsurface_texture->currentskinframe->shirt, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, dopants, doshirt);
2105                         break;
2106                 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2107                         R_Shadow_RenderSurfacesLighting_Light_Vertex(numsurfaces, surfacelist, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->currentskinframe->pants, rsurface_texture->currentskinframe->shirt, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, dopants, doshirt);
2108                         break;
2109                 default:
2110                         Con_Printf("R_Shadow_RenderSurfacesLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2111                         break;
2112                 }
2113         }
2114         else
2115         {
2116                 switch (r_shadow_rendermode)
2117                 {
2118                 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2119                         GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2120                         R_Shadow_RenderSurfacesLighting_VisibleLighting(numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, false, false);
2121                         break;
2122                 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2123                         R_Shadow_RenderSurfacesLighting_Light_GLSL(numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, false, false);
2124                         break;
2125                 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2126                         R_Shadow_RenderSurfacesLighting_Light_Dot3(numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, false, false);
2127                         break;
2128                 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2129                         R_Shadow_RenderSurfacesLighting_Light_Vertex(numsurfaces, surfacelist, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, false, false);
2130                         break;
2131                 default:
2132                         Con_Printf("R_Shadow_RenderSurfacesLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2133                         break;
2134                 }
2135         }
2136 }
2137
2138 void R_RTLight_Update(rtlight_t *rtlight, int isstatic, matrix4x4_t *matrix, vec3_t color, int style, const char *cubemapname, qboolean shadow, vec_t corona, vec_t coronasizescale, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int flags)
2139 {
2140         // if this light has been compiled before, free the associated data
2141         R_RTLight_Uncompile(rtlight);
2142
2143         // clear it completely to avoid any lingering data
2144         memset(rtlight, 0, sizeof(*rtlight));
2145
2146         // copy the properties
2147         Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, matrix);
2148         Matrix4x4_OriginFromMatrix(matrix, rtlight->shadoworigin);
2149         rtlight->radius = Matrix4x4_ScaleFromMatrix(matrix);
2150         VectorCopy(color, rtlight->color);
2151         rtlight->cubemapname[0] = 0;
2152         if (cubemapname && cubemapname[0])
2153                 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2154         rtlight->shadow = shadow;
2155         rtlight->corona = corona;
2156         rtlight->style = style;
2157         rtlight->isstatic = isstatic;
2158         rtlight->coronasizescale = coronasizescale;
2159         rtlight->ambientscale = ambientscale;
2160         rtlight->diffusescale = diffusescale;
2161         rtlight->specularscale = specularscale;
2162         rtlight->flags = flags;
2163
2164         // compute derived data
2165         //rtlight->cullradius = rtlight->radius;
2166         //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2167         rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2168         rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2169         rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2170         rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2171         rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2172         rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2173 }
2174
2175 // compiles rtlight geometry
2176 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2177 void R_RTLight_Compile(rtlight_t *rtlight)
2178 {
2179         int shadowmeshes, shadowtris, numleafs, numleafpvsbytes, numsurfaces;
2180         entity_render_t *ent = r_refdef.worldentity;
2181         model_t *model = r_refdef.worldmodel;
2182         unsigned char *data;
2183
2184         // compile the light
2185         rtlight->compiled = true;
2186         rtlight->static_numleafs = 0;
2187         rtlight->static_numleafpvsbytes = 0;
2188         rtlight->static_leaflist = NULL;
2189         rtlight->static_leafpvs = NULL;
2190         rtlight->static_numsurfaces = 0;
2191         rtlight->static_surfacelist = NULL;
2192         rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2193         rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2194         rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2195         rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2196         rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2197         rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2198
2199         if (model && model->GetLightInfo)
2200         {
2201                 // this variable must be set for the CompileShadowVolume code
2202                 r_shadow_compilingrtlight = rtlight;
2203                 R_Shadow_EnlargeLeafSurfaceBuffer(model->brush.num_leafs, model->num_surfaces);
2204                 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);
2205                 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2206                 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numleafs + numleafpvsbytes + sizeof(int) * numsurfaces);
2207                 rtlight->static_numleafs = numleafs;
2208                 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2209                 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2210                 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2211                 rtlight->static_numsurfaces = numsurfaces;
2212                 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2213                 if (numleafs)
2214                         memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2215                 if (numleafpvsbytes)
2216                         memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2217                 if (numsurfaces)
2218                         memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2219                 if (model->CompileShadowVolume && rtlight->shadow)
2220                         model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2221                 // now we're done compiling the rtlight
2222                 r_shadow_compilingrtlight = NULL;
2223         }
2224
2225
2226         // use smallest available cullradius - box radius or light radius
2227         //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2228         //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2229
2230         shadowmeshes = 0;
2231         shadowtris = 0;
2232         if (rtlight->static_meshchain_shadow)
2233         {
2234                 shadowmesh_t *mesh;
2235                 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2236                 {
2237                         shadowmeshes++;
2238                         shadowtris += mesh->numtriangles;
2239                 }
2240         }
2241
2242         if (developer.integer >= 10)
2243                 Con_Printf("static light built: %f %f %f : %f %f %f box, %i shadow volume triangles (in %i meshes)\n", rtlight->cullmins[0], rtlight->cullmins[1], rtlight->cullmins[2], rtlight->cullmaxs[0], rtlight->cullmaxs[1], rtlight->cullmaxs[2], shadowtris, shadowmeshes);
2244 }
2245
2246 void R_RTLight_Uncompile(rtlight_t *rtlight)
2247 {
2248         if (rtlight->compiled)
2249         {
2250                 if (rtlight->static_meshchain_shadow)
2251                         Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2252                 rtlight->static_meshchain_shadow = NULL;
2253                 // these allocations are grouped
2254                 if (rtlight->static_leaflist)
2255                         Mem_Free(rtlight->static_leaflist);
2256                 rtlight->static_numleafs = 0;
2257                 rtlight->static_numleafpvsbytes = 0;
2258                 rtlight->static_leaflist = NULL;
2259                 rtlight->static_leafpvs = NULL;
2260                 rtlight->static_numsurfaces = 0;
2261                 rtlight->static_surfacelist = NULL;
2262                 rtlight->compiled = false;
2263         }
2264 }
2265
2266 void R_Shadow_UncompileWorldLights(void)
2267 {
2268         dlight_t *light;
2269         for (light = r_shadow_worldlightchain;light;light = light->next)
2270                 R_RTLight_Uncompile(&light->rtlight);
2271 }
2272
2273 void R_Shadow_DrawEntityShadow(entity_render_t *ent, int numsurfaces, int *surfacelist)
2274 {
2275         model_t *model = ent->model;
2276         vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
2277         vec_t relativeshadowradius;
2278         if (ent == r_refdef.worldentity)
2279         {
2280                 if (r_shadow_rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
2281                 {
2282                         shadowmesh_t *mesh;
2283                         R_Mesh_Matrix(&ent->matrix);
2284                         CHECKGLERROR
2285                         for (mesh = r_shadow_rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2286                         {
2287                                 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
2288                                 R_Mesh_VertexPointer(mesh->vertex3f);
2289                                 GL_LockArrays(0, mesh->numverts);
2290                                 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL)
2291                                 {
2292                                         // decrement stencil if backface is behind depthbuffer
2293                                         GL_CullFace(GL_BACK); // quake is backwards, this culls front faces
2294                                         qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2295                                         R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2296                                         // increment stencil if frontface is behind depthbuffer
2297                                         GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
2298                                         qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2299                                 }
2300                                 R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i);
2301                                 GL_LockArrays(0, 0);
2302                         }
2303                         CHECKGLERROR
2304                 }
2305                 else if (numsurfaces)
2306                 {
2307                         R_Mesh_Matrix(&ent->matrix);
2308                         model->DrawShadowVolume(ent, r_shadow_rtlight->shadoworigin, NULL, r_shadow_rtlight->radius, numsurfaces, surfacelist, r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs);
2309                 }
2310         }
2311         else
2312         {
2313                 Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, relativeshadoworigin);
2314                 relativeshadowradius = r_shadow_rtlight->radius / ent->scale;
2315                 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
2316                 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
2317                 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
2318                 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
2319                 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
2320                 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
2321                 R_Mesh_Matrix(&ent->matrix);
2322                 model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, model->nummodelsurfaces, model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2323         }
2324 }
2325
2326 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
2327 {
2328         // set up properties for rendering light onto this entity
2329         RSurf_ActiveEntity(ent, true, true);
2330         Matrix4x4_Concat(&r_shadow_entitytolight, &r_shadow_rtlight->matrix_worldtolight, &ent->matrix);
2331         Matrix4x4_Concat(&r_shadow_entitytoattenuationxyz, &matrix_attenuationxyz, &r_shadow_entitytolight);
2332         Matrix4x4_Concat(&r_shadow_entitytoattenuationz, &matrix_attenuationz, &r_shadow_entitytolight);
2333         Matrix4x4_Transform(&ent->inversematrix, r_shadow_rtlight->shadoworigin, r_shadow_entitylightorigin);
2334         if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2335                 R_Mesh_TexMatrix(3, &r_shadow_entitytolight);
2336 }
2337
2338 void R_Shadow_DrawEntityLight(entity_render_t *ent, int numsurfaces, int *surfacelist)
2339 {
2340         model_t *model = ent->model;
2341         if (!model->DrawLight)
2342                 return;
2343         R_Shadow_SetupEntityLight(ent);
2344         if (ent == r_refdef.worldentity)
2345                 model->DrawLight(ent, numsurfaces, surfacelist);
2346         else
2347                 model->DrawLight(ent, model->nummodelsurfaces, model->surfacelist);
2348 }
2349
2350 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
2351 {
2352         int i, usestencil;
2353         float f;
2354         int numleafs, numsurfaces;
2355         int *leaflist, *surfacelist;
2356         unsigned char *leafpvs;
2357         int numlightentities;
2358         int numshadowentities;
2359         entity_render_t *lightentities[MAX_EDICTS];
2360         entity_render_t *shadowentities[MAX_EDICTS];
2361
2362         // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
2363         // skip lights that are basically invisible (color 0 0 0)
2364         if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
2365                 return;
2366
2367         // loading is done before visibility checks because loading should happen
2368         // all at once at the start of a level, not when it stalls gameplay.
2369         // (especially important to benchmarks)
2370         // compile light
2371         if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
2372                 R_RTLight_Compile(rtlight);
2373         // load cubemap
2374         rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
2375
2376         // look up the light style value at this time
2377         f = (rtlight->style >= 0 ? r_refdef.lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value;
2378         VectorScale(rtlight->color, f, rtlight->currentcolor);
2379         /*
2380         if (rtlight->selected)
2381         {
2382                 f = 2 + sin(realtime * M_PI * 4.0);
2383                 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
2384         }
2385         */
2386
2387         // if lightstyle is currently off, don't draw the light
2388         if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
2389                 return;
2390
2391         // if the light box is offscreen, skip it
2392         if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2393                 return;
2394
2395         VectorCopy(rtlight->cullmins, r_shadow_rtlight_cullmins);
2396         VectorCopy(rtlight->cullmaxs, r_shadow_rtlight_cullmaxs);
2397
2398         if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
2399         {
2400                 // compiled light, world available and can receive realtime lighting
2401                 // retrieve leaf information
2402                 numleafs = rtlight->static_numleafs;
2403                 leaflist = rtlight->static_leaflist;
2404                 leafpvs = rtlight->static_leafpvs;
2405                 numsurfaces = rtlight->static_numsurfaces;
2406                 surfacelist = rtlight->static_surfacelist;
2407         }
2408         else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2409         {
2410                 // dynamic light, world available and can receive realtime lighting
2411                 // calculate lit surfaces and leafs
2412                 R_Shadow_EnlargeLeafSurfaceBuffer(r_refdef.worldmodel->brush.num_leafs, r_refdef.worldmodel->num_surfaces);
2413                 r_refdef.worldmodel->GetLightInfo(r_refdef.worldentity, rtlight->shadoworigin, rtlight->radius, r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs, r_shadow_buffer_leaflist, r_shadow_buffer_leafpvs, &numleafs, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces);
2414                 leaflist = r_shadow_buffer_leaflist;
2415                 leafpvs = r_shadow_buffer_leafpvs;
2416                 surfacelist = r_shadow_buffer_surfacelist;
2417                 // if the reduced leaf bounds are offscreen, skip it
2418                 if (R_CullBox(r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs))
2419                         return;
2420         }
2421         else
2422         {
2423                 // no world
2424                 numleafs = 0;
2425                 leaflist = NULL;
2426                 leafpvs = NULL;
2427                 numsurfaces = 0;
2428                 surfacelist = NULL;
2429         }
2430         // check if light is illuminating any visible leafs
2431         if (numleafs)
2432         {
2433                 for (i = 0;i < numleafs;i++)
2434                         if (r_viewcache.world_leafvisible[leaflist[i]])
2435                                 break;
2436                 if (i == numleafs)
2437                         return;
2438         }
2439         // set up a scissor rectangle for this light
2440         if (R_Shadow_ScissorForBBox(r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs))
2441                 return;
2442
2443         // make a list of lit entities and shadow casting entities
2444         numlightentities = 0;
2445         numshadowentities = 0;
2446         // don't count the world unless some surfaces are actually lit
2447         if (numsurfaces)
2448         {
2449                 lightentities[numlightentities++] = r_refdef.worldentity;
2450                 shadowentities[numshadowentities++] = r_refdef.worldentity;
2451         }
2452         // add dynamic entities that are lit by the light
2453         if (r_drawentities.integer)
2454         {
2455                 for (i = 0;i < r_refdef.numentities;i++)
2456                 {
2457                         model_t *model;
2458                         entity_render_t *ent = r_refdef.entities[i];
2459                         if (BoxesOverlap(ent->mins, ent->maxs, r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs)
2460                          && (model = ent->model)
2461                          && !(ent->flags & RENDER_TRANSPARENT)
2462                          && (r_refdef.worldmodel == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS == NULL || r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs)))
2463                         {
2464                                 // about the VectorDistance2 - light emitting entities should not cast their own shadow
2465                                 vec3_t org;
2466                                 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
2467                                 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
2468                                         shadowentities[numshadowentities++] = ent;
2469                                 if (r_viewcache.entityvisible[i] && (ent->flags & RENDER_LIGHT) && model->DrawLight)
2470                                         lightentities[numlightentities++] = ent;
2471                         }
2472                 }
2473         }
2474
2475         // return if there's nothing at all to light
2476         if (!numlightentities)
2477                 return;
2478
2479         // don't let sound skip if going slow
2480         if (r_refdef.extraupdate)
2481                 S_ExtraUpdate ();
2482
2483         // make this the active rtlight for rendering purposes
2484         R_Shadow_RenderMode_ActiveLight(rtlight);
2485         // count this light in the r_speeds
2486         r_refdef.stats.lights++;
2487
2488         usestencil = false;
2489         if (numshadowentities && rtlight->shadow && (rtlight->isstatic ? r_refdef.rtworldshadows : r_refdef.rtdlightshadows))
2490         {
2491                 // draw stencil shadow volumes to mask off pixels that are in shadow
2492                 // so that they won't receive lighting
2493                 if (gl_stencil)
2494                 {
2495                         usestencil = true;
2496                         R_Shadow_RenderMode_StencilShadowVolumes();
2497                         for (i = 0;i < numshadowentities;i++)
2498                                 R_Shadow_DrawEntityShadow(shadowentities[i], numsurfaces, surfacelist);
2499                 }
2500
2501                 // optionally draw visible shape of the shadow volumes
2502                 // for performance analysis by level designers
2503                 if (r_showshadowvolumes.integer)
2504                 {
2505                         R_Shadow_RenderMode_VisibleShadowVolumes();
2506                         for (i = 0;i < numshadowentities;i++)
2507                                 R_Shadow_DrawEntityShadow(shadowentities[i], numsurfaces, surfacelist);
2508                 }
2509         }
2510
2511         if (numlightentities)
2512         {
2513                 // draw lighting in the unmasked areas
2514                 R_Shadow_RenderMode_Lighting(usestencil, false);
2515                 for (i = 0;i < numlightentities;i++)
2516                         R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
2517
2518                 // optionally draw the illuminated areas
2519                 // for performance analysis by level designers
2520                 if (r_showlighting.integer)
2521                 {
2522                         R_Shadow_RenderMode_VisibleLighting(usestencil && !r_showdisabledepthtest.integer, false);
2523                         for (i = 0;i < numlightentities;i++)
2524                                 R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist);
2525                 }
2526         }
2527 }
2528
2529 void R_ShadowVolumeLighting(qboolean visible)
2530 {
2531         int lnum, flag;
2532         dlight_t *light;
2533
2534         if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2535                 R_Shadow_EditLights_Reload_f();
2536
2537         R_Shadow_RenderMode_Begin();
2538
2539         flag = r_refdef.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2540         if (r_shadow_debuglight.integer >= 0)
2541         {
2542                 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2543                         if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
2544                                 R_DrawRTLight(&light->rtlight, visible);
2545         }
2546         else
2547                 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2548                         if (light->flags & flag)
2549                                 R_DrawRTLight(&light->rtlight, visible);
2550         if (r_refdef.rtdlight)
2551                 for (lnum = 0;lnum < r_refdef.numlights;lnum++)
2552                         R_DrawRTLight(&r_refdef.lights[lnum], visible);
2553
2554         R_Shadow_RenderMode_End();
2555 }
2556
2557 extern void R_SetupView(const matrix4x4_t *matrix);
2558 extern cvar_t r_shadows_throwdistance;
2559 void R_DrawModelShadows(void)
2560 {
2561         int i;
2562         float relativethrowdistance;
2563         entity_render_t *ent;
2564         vec3_t relativelightorigin;
2565         vec3_t relativelightdirection;
2566         vec3_t relativeshadowmins, relativeshadowmaxs;
2567         float vertex3f[12];
2568
2569         if (!r_drawentities.integer || !gl_stencil)
2570                 return;
2571
2572         CHECKGLERROR
2573         GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
2574
2575         r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2576
2577         if (gl_ext_separatestencil.integer)
2578                 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
2579         else if (gl_ext_stenciltwoside.integer)
2580                 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
2581         else
2582                 r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
2583
2584         R_Shadow_RenderMode_StencilShadowVolumes();
2585
2586         for (i = 0;i < r_refdef.numentities;i++)
2587         {
2588                 ent = r_refdef.entities[i];
2589                 // cast shadows from anything that is not a submodel of the map
2590                 if (ent->model && ent->model->DrawShadowVolume != NULL && !ent->model->brush.submodel && (ent->flags & RENDER_SHADOW))
2591                 {
2592                         relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
2593                         VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
2594                         VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
2595                         VectorNegate(ent->modellight_lightdir, relativelightdirection);
2596                         VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
2597                         R_Mesh_Matrix(&ent->matrix);
2598                         ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
2599                 }
2600         }
2601
2602         // not really the right mode, but this will disable any silly stencil features
2603         R_Shadow_RenderMode_VisibleLighting(true, true);
2604
2605         // vertex coordinates for a quad that covers the screen exactly
2606         vertex3f[0] = 0;vertex3f[1] = 0;vertex3f[2] = 0;
2607         vertex3f[3] = 1;vertex3f[4] = 0;vertex3f[5] = 0;
2608         vertex3f[6] = 1;vertex3f[7] = 1;vertex3f[8] = 0;
2609         vertex3f[9] = 0;vertex3f[10] = 1;vertex3f[11] = 0;
2610
2611         // set up ortho view for rendering this pass
2612         GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
2613         GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
2614         GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
2615         GL_ScissorTest(true);
2616         R_Mesh_Matrix(&identitymatrix);
2617         R_Mesh_ResetTextureState();
2618         R_Mesh_VertexPointer(vertex3f);
2619         R_Mesh_ColorPointer(NULL);
2620
2621         // set up a 50% darkening blend on shadowed areas
2622         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2623         GL_DepthTest(false);
2624         GL_DepthMask(false);
2625         qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
2626         GL_Color(0, 0, 0, 0.5);
2627         GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
2628         qglDepthFunc(GL_ALWAYS);CHECKGLERROR
2629         qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2630         qglStencilMask(~0);CHECKGLERROR
2631         qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
2632         qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
2633
2634         // apply the blend to the shadowed areas
2635         R_Mesh_Draw(0, 4, 2, polygonelements);
2636
2637         // restoring the perspective view is done by R_RenderScene
2638         //R_SetupView(&r_view.matrix);
2639
2640         // restore other state to normal
2641         R_Shadow_RenderMode_End();
2642 }
2643
2644
2645 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2646 typedef struct suffixinfo_s
2647 {
2648         char *suffix;
2649         qboolean flipx, flipy, flipdiagonal;
2650 }
2651 suffixinfo_t;
2652 static suffixinfo_t suffix[3][6] =
2653 {
2654         {
2655                 {"px",   false, false, false},
2656                 {"nx",   false, false, false},
2657                 {"py",   false, false, false},
2658                 {"ny",   false, false, false},
2659                 {"pz",   false, false, false},
2660                 {"nz",   false, false, false}
2661         },
2662         {
2663                 {"posx", false, false, false},
2664                 {"negx", false, false, false},
2665                 {"posy", false, false, false},
2666                 {"negy", false, false, false},
2667                 {"posz", false, false, false},
2668                 {"negz", false, false, false}
2669         },
2670         {
2671                 {"rt",    true, false,  true},
2672                 {"lf",   false,  true,  true},
2673                 {"ft",    true,  true, false},
2674                 {"bk",   false, false, false},
2675                 {"up",    true, false,  true},
2676                 {"dn",    true, false,  true}
2677         }
2678 };
2679
2680 static int componentorder[4] = {0, 1, 2, 3};
2681
2682 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2683 {
2684         int i, j, cubemapsize;
2685         unsigned char *cubemappixels, *image_rgba;
2686         rtexture_t *cubemaptexture;
2687         char name[256];
2688         // must start 0 so the first loadimagepixels has no requested width/height
2689         cubemapsize = 0;
2690         cubemappixels = NULL;
2691         cubemaptexture = NULL;
2692         // keep trying different suffix groups (posx, px, rt) until one loads
2693         for (j = 0;j < 3 && !cubemappixels;j++)
2694         {
2695                 // load the 6 images in the suffix group
2696                 for (i = 0;i < 6;i++)
2697                 {
2698                         // generate an image name based on the base and and suffix
2699                         dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2700                         // load it
2701                         if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2702                         {
2703                                 // an image loaded, make sure width and height are equal
2704                                 if (image_width == image_height)
2705                                 {
2706                                         // if this is the first image to load successfully, allocate the cubemap memory
2707                                         if (!cubemappixels && image_width >= 1)
2708                                         {
2709                                                 cubemapsize = image_width;
2710                                                 // note this clears to black, so unavailable sides are black
2711                                                 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2712                                         }
2713                                         // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2714                                         if (cubemappixels)
2715                                                 Image_CopyMux(cubemappixels+i*cubemapsize*cubemapsize*4, image_rgba, cubemapsize, cubemapsize, suffix[j][i].flipx, suffix[j][i].flipy, suffix[j][i].flipdiagonal, 4, 4, componentorder);
2716                                 }
2717                                 else
2718                                         Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2719                                 // free the image
2720                                 Mem_Free(image_rgba);
2721                         }
2722                 }
2723         }
2724         // if a cubemap loaded, upload it
2725         if (cubemappixels)
2726         {
2727                 if (!r_shadow_filters_texturepool)
2728                         r_shadow_filters_texturepool = R_AllocTexturePool();
2729                 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
2730                 Mem_Free(cubemappixels);
2731         }
2732         else
2733         {
2734                 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
2735                 for (j = 0;j < 3;j++)
2736                         for (i = 0;i < 6;i++)
2737                                 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2738                 Con_Print(" and was unable to find any of them.\n");
2739         }
2740         return cubemaptexture;
2741 }
2742
2743 rtexture_t *R_Shadow_Cubemap(const char *basename)
2744 {
2745         int i;
2746         for (i = 0;i < numcubemaps;i++)
2747                 if (!strcasecmp(cubemaps[i].basename, basename))
2748                         return cubemaps[i].texture;
2749         if (i >= MAX_CUBEMAPS)
2750                 return r_texture_whitecube;
2751         numcubemaps++;
2752         strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
2753         cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
2754         if (!cubemaps[i].texture)
2755                 cubemaps[i].texture = r_texture_whitecube;
2756         return cubemaps[i].texture;
2757 }
2758
2759 void R_Shadow_FreeCubemaps(void)
2760 {
2761         numcubemaps = 0;
2762         R_FreeTexturePool(&r_shadow_filters_texturepool);
2763 }
2764
2765 dlight_t *R_Shadow_NewWorldLight(void)
2766 {
2767         dlight_t *light;
2768         light = (dlight_t *)Mem_Alloc(r_main_mempool, sizeof(dlight_t));
2769         light->next = r_shadow_worldlightchain;
2770         r_shadow_worldlightchain = light;
2771         return light;
2772 }
2773
2774 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)
2775 {
2776         matrix4x4_t matrix;
2777         // validate parameters
2778         if (style < 0 || style >= MAX_LIGHTSTYLES)
2779         {
2780                 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
2781                 style = 0;
2782         }
2783         if (!cubemapname)
2784                 cubemapname = "";
2785
2786         // copy to light properties
2787         VectorCopy(origin, light->origin);
2788         light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
2789         light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
2790         light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
2791         light->color[0] = max(color[0], 0);
2792         light->color[1] = max(color[1], 0);
2793         light->color[2] = max(color[2], 0);
2794         light->radius = max(radius, 0);
2795         light->style = style;
2796         light->shadow = shadowenable;
2797         light->corona = corona;
2798         strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
2799         light->coronasizescale = coronasizescale;
2800         light->ambientscale = ambientscale;
2801         light->diffusescale = diffusescale;
2802         light->specularscale = specularscale;
2803         light->flags = flags;
2804
2805         // update renderable light data
2806         Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
2807         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);
2808 }
2809
2810 void R_Shadow_FreeWorldLight(dlight_t *light)
2811 {
2812         dlight_t **lightpointer;
2813         R_RTLight_Uncompile(&light->rtlight);
2814         for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
2815         if (*lightpointer != light)
2816                 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain");
2817         *lightpointer = light->next;
2818         Mem_Free(light);
2819 }
2820
2821 void R_Shadow_ClearWorldLights(void)
2822 {
2823         while (r_shadow_worldlightchain)
2824                 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
2825         r_shadow_selectedlight = NULL;
2826         R_Shadow_FreeCubemaps();
2827 }
2828
2829 void R_Shadow_SelectLight(dlight_t *light)
2830 {
2831         if (r_shadow_selectedlight)
2832                 r_shadow_selectedlight->selected = false;
2833         r_shadow_selectedlight = light;
2834         if (r_shadow_selectedlight)
2835                 r_shadow_selectedlight->selected = true;
2836 }
2837
2838 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2839 {
2840         // this is never batched (there can be only one)
2841         float scale = r_editlights_cursorgrid.value * 0.5f;
2842         R_DrawSprite(GL_SRC_ALPHA, GL_ONE, r_crosshairs[1]->tex, NULL, false, r_editlights_cursorlocation, r_view.right, r_view.up, scale, -scale, -scale, scale, 1, 1, 1, 0.5f);
2843 }
2844
2845 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2846 {
2847         // this is never batched (due to the ent parameter changing every time)
2848         // so numsurfaces == 1 and surfacelist[0] == lightnumber
2849         float intensity;
2850         const dlight_t *light = (dlight_t *)ent;
2851         intensity = 0.5;
2852         if (light->selected)
2853                 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
2854         if (!light->shadow)
2855                 intensity *= 0.5f;
2856         R_DrawSprite(GL_SRC_ALPHA, GL_ONE, r_crosshairs[surfacelist[0]]->tex, NULL, false, light->origin, r_view.right, r_view.up, 8, -8, -8, 8, intensity, intensity, intensity, 0.5);
2857 }
2858
2859 void R_Shadow_DrawLightSprites(void)
2860 {
2861         int i;
2862         dlight_t *light;
2863
2864         for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
2865                 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 1+(i % 5), &light->rtlight);
2866         R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
2867 }
2868
2869 void R_Shadow_SelectLightInView(void)
2870 {
2871         float bestrating, rating, temp[3];
2872         dlight_t *best, *light;
2873         best = NULL;
2874         bestrating = 0;
2875         for (light = r_shadow_worldlightchain;light;light = light->next)
2876         {
2877                 VectorSubtract(light->origin, r_view.origin, temp);
2878                 rating = (DotProduct(temp, r_view.forward) / sqrt(DotProduct(temp, temp)));
2879                 if (rating >= 0.95)
2880                 {
2881                         rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
2882                         if (bestrating < rating && CL_TraceBox(light->origin, vec3_origin, vec3_origin, r_view.origin, true, NULL, SUPERCONTENTS_SOLID, false).fraction == 1.0f)
2883                         {
2884                                 bestrating = rating;
2885                                 best = light;
2886                         }
2887                 }
2888         }
2889         R_Shadow_SelectLight(best);
2890 }
2891
2892 void R_Shadow_LoadWorldLights(void)
2893 {
2894         int n, a, style, shadow, flags;
2895         char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
2896         float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
2897         if (r_refdef.worldmodel == NULL)
2898         {
2899                 Con_Print("No map loaded.\n");
2900                 return;
2901         }
2902         FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
2903         strlcat (name, ".rtlights", sizeof (name));
2904         lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
2905         if (lightsstring)
2906         {
2907                 s = lightsstring;
2908                 n = 0;
2909                 while (*s)
2910                 {
2911                         t = s;
2912                         /*
2913                         shadow = true;
2914                         for (;COM_Parse(t, true) && strcmp(
2915                         if (COM_Parse(t, true))
2916                         {
2917                                 if (com_token[0] == '!')
2918                                 {
2919                                         shadow = false;
2920                                         origin[0] = atof(com_token+1);
2921                                 }
2922                                 else
2923                                         origin[0] = atof(com_token);
2924                                 if (Com_Parse(t
2925                         }
2926                         */
2927                         t = s;
2928                         while (*s && *s != '\n' && *s != '\r')
2929                                 s++;
2930                         if (!*s)
2931                                 break;
2932                         tempchar = *s;
2933                         shadow = true;
2934                         // check for modifier flags
2935                         if (*t == '!')
2936                         {
2937                                 shadow = false;
2938                                 t++;
2939                         }
2940                         *s = 0;
2941                         a = sscanf(t, "%f %f %f %f %f %f %f %d %s %f %f %f %f %f %f %f %f %i", &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);
2942                         *s = tempchar;
2943                         if (a < 18)
2944                                 flags = LIGHTFLAG_REALTIMEMODE;
2945                         if (a < 17)
2946                                 specularscale = 1;
2947                         if (a < 16)
2948                                 diffusescale = 1;
2949                         if (a < 15)
2950                                 ambientscale = 0;
2951                         if (a < 14)
2952                                 coronasizescale = 0.25f;
2953                         if (a < 13)
2954                                 VectorClear(angles);
2955                         if (a < 10)
2956                                 corona = 0;
2957                         if (a < 9 || !strcmp(cubemapname, "\"\""))
2958                                 cubemapname[0] = 0;
2959                         // remove quotes on cubemapname
2960                         if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
2961                         {
2962                                 size_t namelen;
2963                                 namelen = strlen(cubemapname) - 2;
2964                                 memmove(cubemapname, cubemapname + 1, namelen);
2965                                 cubemapname[namelen] = '\0';
2966                         }
2967                         if (a < 8)
2968                         {
2969                                 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);
2970                                 break;
2971                         }
2972                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
2973                         if (*s == '\r')
2974                                 s++;
2975                         if (*s == '\n')
2976                                 s++;
2977                         n++;
2978                 }
2979                 if (*s)
2980                         Con_Printf("invalid rtlights file \"%s\"\n", name);
2981                 Mem_Free(lightsstring);
2982         }
2983 }
2984
2985 void R_Shadow_SaveWorldLights(void)
2986 {
2987         dlight_t *light;
2988         size_t bufchars, bufmaxchars;
2989         char *buf, *oldbuf;
2990         char name[MAX_QPATH];
2991         char line[MAX_INPUTLINE];
2992         if (!r_shadow_worldlightchain)
2993                 return;
2994         if (r_refdef.worldmodel == NULL)
2995         {
2996                 Con_Print("No map loaded.\n");
2997                 return;
2998         }
2999         FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3000         strlcat (name, ".rtlights", sizeof (name));
3001         bufchars = bufmaxchars = 0;
3002         buf = NULL;
3003         for (light = r_shadow_worldlightchain;light;light = light->next)
3004         {
3005                 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
3006                         sprintf(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);
3007                 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
3008                         sprintf(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]);
3009                 else
3010                         sprintf(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);
3011                 if (bufchars + strlen(line) > bufmaxchars)
3012                 {
3013                         bufmaxchars = bufchars + strlen(line) + 2048;
3014                         oldbuf = buf;
3015                         buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
3016                         if (oldbuf)
3017                         {
3018                                 if (bufchars)
3019                                         memcpy(buf, oldbuf, bufchars);
3020                                 Mem_Free(oldbuf);
3021                         }
3022                 }
3023                 if (strlen(line))
3024                 {
3025                         memcpy(buf + bufchars, line, strlen(line));
3026                         bufchars += strlen(line);
3027                 }
3028         }
3029         if (bufchars)
3030                 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
3031         if (buf)
3032                 Mem_Free(buf);
3033 }
3034
3035 void R_Shadow_LoadLightsFile(void)
3036 {
3037         int n, a, style;
3038         char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
3039         float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
3040         if (r_refdef.worldmodel == NULL)
3041         {
3042                 Con_Print("No map loaded.\n");
3043                 return;
3044         }
3045         FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
3046         strlcat (name, ".lights", sizeof (name));
3047         lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
3048         if (lightsstring)
3049         {
3050                 s = lightsstring;
3051                 n = 0;
3052                 while (*s)
3053                 {
3054                         t = s;
3055                         while (*s && *s != '\n' && *s != '\r')
3056                                 s++;
3057                         if (!*s)
3058                                 break;
3059                         tempchar = *s;
3060                         *s = 0;
3061                         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);
3062                         *s = tempchar;
3063                         if (a < 14)
3064                         {
3065                                 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);
3066                                 break;
3067                         }
3068                         radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
3069                         radius = bound(15, radius, 4096);
3070                         VectorScale(color, (2.0f / (8388608.0f)), color);
3071                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3072                         if (*s == '\r')
3073                                 s++;
3074                         if (*s == '\n')
3075                                 s++;
3076                         n++;
3077                 }
3078                 if (*s)
3079                         Con_Printf("invalid lights file \"%s\"\n", name);
3080                 Mem_Free(lightsstring);
3081         }
3082 }
3083
3084 // tyrlite/hmap2 light types in the delay field
3085 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
3086
3087 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
3088 {
3089         int entnum, style, islight, skin, pflags, effects, type, n;
3090         char *entfiledata;
3091         const char *data;
3092         float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
3093         char key[256], value[MAX_INPUTLINE];
3094
3095         if (r_refdef.worldmodel == NULL)
3096         {
3097                 Con_Print("No map loaded.\n");
3098                 return;
3099         }
3100         // try to load a .ent file first
3101         FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3102         strlcat (key, ".ent", sizeof (key));
3103         data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
3104         // and if that is not found, fall back to the bsp file entity string
3105         if (!data)
3106                 data = r_refdef.worldmodel->brush.entities;
3107         if (!data)
3108                 return;
3109         for (entnum = 0;COM_ParseTokenConsole(&data) && com_token[0] == '{';entnum++)
3110         {
3111                 type = LIGHTTYPE_MINUSX;
3112                 origin[0] = origin[1] = origin[2] = 0;
3113                 originhack[0] = originhack[1] = originhack[2] = 0;
3114                 angles[0] = angles[1] = angles[2] = 0;
3115                 color[0] = color[1] = color[2] = 1;
3116                 light[0] = light[1] = light[2] = 1;light[3] = 300;
3117                 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3118                 fadescale = 1;
3119                 lightscale = 1;
3120                 style = 0;
3121                 skin = 0;
3122                 pflags = 0;
3123                 effects = 0;
3124                 islight = false;
3125                 while (1)
3126                 {
3127                         if (!COM_ParseTokenConsole(&data))
3128                                 break; // error
3129                         if (com_token[0] == '}')
3130                                 break; // end of entity
3131                         if (com_token[0] == '_')
3132                                 strlcpy(key, com_token + 1, sizeof(key));
3133                         else
3134                                 strlcpy(key, com_token, sizeof(key));
3135                         while (key[strlen(key)-1] == ' ') // remove trailing spaces
3136                                 key[strlen(key)-1] = 0;
3137                         if (!COM_ParseTokenConsole(&data))
3138                                 break; // error
3139                         strlcpy(value, com_token, sizeof(value));
3140
3141                         // now that we have the key pair worked out...
3142                         if (!strcmp("light", key))
3143                         {
3144                                 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3145                                 if (n == 1)
3146                                 {
3147                                         // quake
3148                                         light[0] = vec[0] * (1.0f / 256.0f);
3149                                         light[1] = vec[0] * (1.0f / 256.0f);
3150                                         light[2] = vec[0] * (1.0f / 256.0f);
3151                                         light[3] = vec[0];
3152                                 }
3153                                 else if (n == 4)
3154                                 {
3155                                         // halflife
3156                                         light[0] = vec[0] * (1.0f / 255.0f);
3157                                         light[1] = vec[1] * (1.0f / 255.0f);
3158                                         light[2] = vec[2] * (1.0f / 255.0f);
3159                                         light[3] = vec[3];
3160                                 }
3161                         }
3162                         else if (!strcmp("delay", key))
3163                                 type = atoi(value);
3164                         else if (!strcmp("origin", key))
3165                                 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3166                         else if (!strcmp("angle", key))
3167                                 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3168                         else if (!strcmp("angles", key))
3169                                 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3170                         else if (!strcmp("color", key))
3171                                 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3172                         else if (!strcmp("wait", key))
3173                                 fadescale = atof(value);
3174                         else if (!strcmp("classname", key))
3175                         {
3176                                 if (!strncmp(value, "light", 5))
3177                                 {
3178                                         islight = true;
3179                                         if (!strcmp(value, "light_fluoro"))
3180                                         {
3181                                                 originhack[0] = 0;
3182                                                 originhack[1] = 0;
3183                                                 originhack[2] = 0;
3184                                                 overridecolor[0] = 1;
3185                                                 overridecolor[1] = 1;
3186                                                 overridecolor[2] = 1;
3187                                         }
3188                                         if (!strcmp(value, "light_fluorospark"))
3189                                         {
3190                                                 originhack[0] = 0;
3191                                                 originhack[1] = 0;
3192                                                 originhack[2] = 0;
3193                                                 overridecolor[0] = 1;
3194                                                 overridecolor[1] = 1;
3195                                                 overridecolor[2] = 1;
3196                                         }
3197                                         if (!strcmp(value, "light_globe"))
3198                                         {
3199                                                 originhack[0] = 0;
3200                                                 originhack[1] = 0;
3201                                                 originhack[2] = 0;
3202                                                 overridecolor[0] = 1;
3203                                                 overridecolor[1] = 0.8;
3204                                                 overridecolor[2] = 0.4;
3205                                         }
3206                                         if (!strcmp(value, "light_flame_large_yellow"))
3207                                         {
3208                                                 originhack[0] = 0;
3209                                                 originhack[1] = 0;
3210                                                 originhack[2] = 0;
3211                                                 overridecolor[0] = 1;
3212                                                 overridecolor[1] = 0.5;
3213                                                 overridecolor[2] = 0.1;
3214                                         }
3215                                         if (!strcmp(value, "light_flame_small_yellow"))
3216                                         {
3217                                                 originhack[0] = 0;
3218                                                 originhack[1] = 0;
3219                                                 originhack[2] = 0;
3220                                                 overridecolor[0] = 1;
3221                                                 overridecolor[1] = 0.5;
3222                                                 overridecolor[2] = 0.1;
3223                                         }
3224                                         if (!strcmp(value, "light_torch_small_white"))
3225                                         {
3226                                                 originhack[0] = 0;
3227                                                 originhack[1] = 0;
3228                                                 originhack[2] = 0;
3229                                                 overridecolor[0] = 1;
3230                                                 overridecolor[1] = 0.5;
3231                                                 overridecolor[2] = 0.1;
3232                                         }
3233                                         if (!strcmp(value, "light_torch_small_walltorch"))
3234                                         {
3235                                                 originhack[0] = 0;
3236                                                 originhack[1] = 0;
3237                                                 originhack[2] = 0;
3238                                                 overridecolor[0] = 1;
3239                                                 overridecolor[1] = 0.5;
3240                                                 overridecolor[2] = 0.1;
3241                                         }
3242                                 }
3243                         }
3244                         else if (!strcmp("style", key))
3245                                 style = atoi(value);
3246                         else if (!strcmp("skin", key))
3247                                 skin = (int)atof(value);
3248                         else if (!strcmp("pflags", key))
3249                                 pflags = (int)atof(value);
3250                         else if (!strcmp("effects", key))
3251                                 effects = (int)atof(value);
3252                         else if (r_refdef.worldmodel->type == mod_brushq3)
3253                         {
3254                                 if (!strcmp("scale", key))
3255                                         lightscale = atof(value);
3256                                 if (!strcmp("fade", key))
3257                                         fadescale = atof(value);
3258                         }
3259                 }
3260                 if (!islight)
3261                         continue;
3262                 if (lightscale <= 0)
3263                         lightscale = 1;
3264                 if (fadescale <= 0)
3265                         fadescale = 1;
3266                 if (color[0] == color[1] && color[0] == color[2])
3267                 {
3268                         color[0] *= overridecolor[0];
3269                         color[1] *= overridecolor[1];
3270                         color[2] *= overridecolor[2];
3271                 }
3272                 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3273                 color[0] = color[0] * light[0];
3274                 color[1] = color[1] * light[1];
3275                 color[2] = color[2] * light[2];
3276                 switch (type)
3277                 {
3278                 case LIGHTTYPE_MINUSX:
3279                         break;
3280                 case LIGHTTYPE_RECIPX:
3281                         radius *= 2;
3282                         VectorScale(color, (1.0f / 16.0f), color);
3283                         break;
3284                 case LIGHTTYPE_RECIPXX:
3285                         radius *= 2;
3286                         VectorScale(color, (1.0f / 16.0f), color);
3287                         break;
3288                 default:
3289                 case LIGHTTYPE_NONE:
3290                         break;
3291                 case LIGHTTYPE_SUN:
3292                         break;
3293                 case LIGHTTYPE_MINUSXX:
3294                         break;
3295                 }
3296                 VectorAdd(origin, originhack, origin);
3297                 if (radius >= 1)
3298                         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);
3299         }
3300         if (entfiledata)
3301                 Mem_Free(entfiledata);
3302 }
3303
3304
3305 void R_Shadow_SetCursorLocationForView(void)
3306 {
3307         vec_t dist, push;
3308         vec3_t dest, endpos;
3309         trace_t trace;
3310         VectorMA(r_view.origin, r_editlights_cursordistance.value, r_view.forward, dest);
3311         trace = CL_TraceBox(r_view.origin, vec3_origin, vec3_origin, dest, true, NULL, SUPERCONTENTS_SOLID, false);
3312         if (trace.fraction < 1)
3313         {
3314                 dist = trace.fraction * r_editlights_cursordistance.value;
3315                 push = r_editlights_cursorpushback.value;
3316                 if (push > dist)
3317                         push = dist;
3318                 push = -push;
3319                 VectorMA(trace.endpos, push, r_view.forward, endpos);
3320                 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
3321         }
3322         else
3323         {
3324                 VectorClear( endpos );
3325         }
3326         r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3327         r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3328         r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3329 }
3330
3331 void R_Shadow_UpdateWorldLightSelection(void)
3332 {
3333         if (r_editlights.integer)
3334         {
3335                 R_Shadow_SetCursorLocationForView();
3336                 R_Shadow_SelectLightInView();
3337                 R_Shadow_DrawLightSprites();
3338         }
3339         else
3340                 R_Shadow_SelectLight(NULL);
3341 }
3342
3343 void R_Shadow_EditLights_Clear_f(void)
3344 {
3345         R_Shadow_ClearWorldLights();
3346 }
3347
3348 void R_Shadow_EditLights_Reload_f(void)
3349 {
3350         if (!r_refdef.worldmodel)
3351                 return;
3352         strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3353         R_Shadow_ClearWorldLights();
3354         R_Shadow_LoadWorldLights();
3355         if (r_shadow_worldlightchain == NULL)
3356         {
3357                 R_Shadow_LoadLightsFile();
3358                 if (r_shadow_worldlightchain == NULL)
3359                         R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3360         }
3361 }
3362
3363 void R_Shadow_EditLights_Save_f(void)
3364 {
3365         if (!r_refdef.worldmodel)
3366                 return;
3367         R_Shadow_SaveWorldLights();
3368 }
3369
3370 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3371 {
3372         R_Shadow_ClearWorldLights();
3373         R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3374 }
3375
3376 void R_Shadow_EditLights_ImportLightsFile_f(void)
3377 {
3378         R_Shadow_ClearWorldLights();
3379         R_Shadow_LoadLightsFile();
3380 }
3381
3382 void R_Shadow_EditLights_Spawn_f(void)
3383 {
3384         vec3_t color;
3385         if (!r_editlights.integer)
3386         {
3387                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
3388                 return;
3389         }
3390         if (Cmd_Argc() != 1)
3391         {
3392                 Con_Print("r_editlights_spawn does not take parameters\n");
3393                 return;
3394         }
3395         color[0] = color[1] = color[2] = 1;
3396         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3397 }
3398
3399 void R_Shadow_EditLights_Edit_f(void)
3400 {
3401         vec3_t origin, angles, color;
3402         vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3403         int style, shadows, flags, normalmode, realtimemode;
3404         char cubemapname[MAX_INPUTLINE];
3405         if (!r_editlights.integer)
3406         {
3407                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
3408                 return;
3409         }
3410         if (!r_shadow_selectedlight)
3411         {
3412                 Con_Print("No selected light.\n");
3413                 return;
3414         }
3415         VectorCopy(r_shadow_selectedlight->origin, origin);
3416         VectorCopy(r_shadow_selectedlight->angles, angles);
3417         VectorCopy(r_shadow_selectedlight->color, color);
3418         radius = r_shadow_selectedlight->radius;
3419         style = r_shadow_selectedlight->style;
3420         if (r_shadow_selectedlight->cubemapname)
3421                 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
3422         else
3423                 cubemapname[0] = 0;
3424         shadows = r_shadow_selectedlight->shadow;
3425         corona = r_shadow_selectedlight->corona;
3426         coronasizescale = r_shadow_selectedlight->coronasizescale;
3427         ambientscale = r_shadow_selectedlight->ambientscale;
3428         diffusescale = r_shadow_selectedlight->diffusescale;
3429         specularscale = r_shadow_selectedlight->specularscale;
3430         flags = r_shadow_selectedlight->flags;
3431         normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3432         realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3433         if (!strcmp(Cmd_Argv(1), "origin"))
3434         {
3435                 if (Cmd_Argc() != 5)
3436                 {
3437                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3438                         return;
3439                 }
3440                 origin[0] = atof(Cmd_Argv(2));
3441                 origin[1] = atof(Cmd_Argv(3));
3442                 origin[2] = atof(Cmd_Argv(4));
3443         }
3444         else if (!strcmp(Cmd_Argv(1), "originx"))
3445         {
3446                 if (Cmd_Argc() != 3)
3447                 {
3448                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3449                         return;
3450                 }
3451                 origin[0] = atof(Cmd_Argv(2));
3452         }
3453         else if (!strcmp(Cmd_Argv(1), "originy"))
3454         {
3455                 if (Cmd_Argc() != 3)
3456                 {
3457                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3458                         return;
3459                 }
3460                 origin[1] = atof(Cmd_Argv(2));
3461         }
3462         else if (!strcmp(Cmd_Argv(1), "originz"))
3463         {
3464                 if (Cmd_Argc() != 3)
3465                 {
3466                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3467                         return;
3468                 }
3469                 origin[2] = atof(Cmd_Argv(2));
3470         }
3471         else if (!strcmp(Cmd_Argv(1), "move"))
3472         {
3473                 if (Cmd_Argc() != 5)
3474                 {
3475                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3476                         return;
3477                 }
3478                 origin[0] += atof(Cmd_Argv(2));
3479                 origin[1] += atof(Cmd_Argv(3));
3480                 origin[2] += atof(Cmd_Argv(4));
3481         }
3482         else if (!strcmp(Cmd_Argv(1), "movex"))
3483         {
3484                 if (Cmd_Argc() != 3)
3485                 {
3486                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3487                         return;
3488                 }
3489                 origin[0] += atof(Cmd_Argv(2));
3490         }
3491         else if (!strcmp(Cmd_Argv(1), "movey"))
3492         {
3493                 if (Cmd_Argc() != 3)
3494                 {
3495                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3496                         return;
3497                 }
3498                 origin[1] += atof(Cmd_Argv(2));
3499         }
3500         else if (!strcmp(Cmd_Argv(1), "movez"))
3501         {
3502                 if (Cmd_Argc() != 3)
3503                 {
3504                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3505                         return;
3506                 }
3507                 origin[2] += atof(Cmd_Argv(2));
3508         }
3509         else if (!strcmp(Cmd_Argv(1), "angles"))
3510         {
3511                 if (Cmd_Argc() != 5)
3512                 {
3513                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3514                         return;
3515                 }
3516                 angles[0] = atof(Cmd_Argv(2));
3517                 angles[1] = atof(Cmd_Argv(3));
3518                 angles[2] = atof(Cmd_Argv(4));
3519         }
3520         else if (!strcmp(Cmd_Argv(1), "anglesx"))
3521         {
3522                 if (Cmd_Argc() != 3)
3523                 {
3524                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3525                         return;
3526                 }
3527                 angles[0] = atof(Cmd_Argv(2));
3528         }
3529         else if (!strcmp(Cmd_Argv(1), "anglesy"))
3530         {
3531                 if (Cmd_Argc() != 3)
3532                 {
3533                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3534                         return;
3535                 }
3536                 angles[1] = atof(Cmd_Argv(2));
3537         }
3538         else if (!strcmp(Cmd_Argv(1), "anglesz"))
3539         {
3540                 if (Cmd_Argc() != 3)
3541                 {
3542                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3543                         return;
3544                 }
3545                 angles[2] = atof(Cmd_Argv(2));
3546         }
3547         else if (!strcmp(Cmd_Argv(1), "color"))
3548         {
3549                 if (Cmd_Argc() != 5)
3550                 {
3551                         Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3552                         return;
3553                 }
3554                 color[0] = atof(Cmd_Argv(2));
3555                 color[1] = atof(Cmd_Argv(3));
3556                 color[2] = atof(Cmd_Argv(4));
3557         }
3558         else if (!strcmp(Cmd_Argv(1), "radius"))
3559         {
3560                 if (Cmd_Argc() != 3)
3561                 {
3562                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3563                         return;
3564                 }
3565                 radius = atof(Cmd_Argv(2));
3566         }
3567         else if (!strcmp(Cmd_Argv(1), "colorscale"))
3568         {
3569                 if (Cmd_Argc() == 3)
3570                 {
3571                         double scale = atof(Cmd_Argv(2));
3572                         color[0] *= scale;
3573                         color[1] *= scale;
3574                         color[2] *= scale;
3575                 }
3576                 else
3577                 {
3578                         if (Cmd_Argc() != 5)
3579                         {
3580                                 Con_Printf("usage: r_editlights_edit %s red green blue  (OR grey instead of red green blue)\n", Cmd_Argv(1));
3581                                 return;
3582                         }
3583                         color[0] *= atof(Cmd_Argv(2));
3584                         color[1] *= atof(Cmd_Argv(3));
3585                         color[2] *= atof(Cmd_Argv(4));
3586                 }
3587         }
3588         else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
3589         {
3590                 if (Cmd_Argc() != 3)
3591                 {
3592                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3593                         return;
3594                 }
3595                 radius *= atof(Cmd_Argv(2));
3596         }
3597         else if (!strcmp(Cmd_Argv(1), "style"))
3598         {
3599                 if (Cmd_Argc() != 3)
3600                 {
3601                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3602                         return;
3603                 }
3604                 style = atoi(Cmd_Argv(2));
3605         }
3606         else if (!strcmp(Cmd_Argv(1), "cubemap"))
3607         {
3608                 if (Cmd_Argc() > 3)
3609                 {
3610                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3611                         return;
3612                 }
3613                 if (Cmd_Argc() == 3)
3614                         strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
3615                 else
3616                         cubemapname[0] = 0;
3617         }
3618         else if (!strcmp(Cmd_Argv(1), "shadows"))
3619         {
3620                 if (Cmd_Argc() != 3)
3621                 {
3622                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3623                         return;
3624                 }
3625                 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3626         }
3627         else if (!strcmp(Cmd_Argv(1), "corona"))
3628         {
3629                 if (Cmd_Argc() != 3)
3630                 {
3631                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3632                         return;
3633                 }
3634                 corona = atof(Cmd_Argv(2));
3635         }
3636         else if (!strcmp(Cmd_Argv(1), "coronasize"))
3637         {
3638                 if (Cmd_Argc() != 3)
3639                 {
3640                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3641                         return;
3642                 }
3643                 coronasizescale = atof(Cmd_Argv(2));
3644         }
3645         else if (!strcmp(Cmd_Argv(1), "ambient"))
3646         {
3647                 if (Cmd_Argc() != 3)
3648                 {
3649                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3650                         return;
3651                 }
3652                 ambientscale = atof(Cmd_Argv(2));
3653         }
3654         else if (!strcmp(Cmd_Argv(1), "diffuse"))
3655         {
3656                 if (Cmd_Argc() != 3)
3657                 {
3658                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3659                         return;
3660                 }
3661                 diffusescale = atof(Cmd_Argv(2));
3662         }
3663         else if (!strcmp(Cmd_Argv(1), "specular"))
3664         {
3665                 if (Cmd_Argc() != 3)
3666                 {
3667                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3668                         return;
3669                 }
3670                 specularscale = atof(Cmd_Argv(2));
3671         }
3672         else if (!strcmp(Cmd_Argv(1), "normalmode"))
3673         {
3674                 if (Cmd_Argc() != 3)
3675                 {
3676                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3677                         return;
3678                 }
3679                 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3680         }
3681         else if (!strcmp(Cmd_Argv(1), "realtimemode"))
3682         {
3683                 if (Cmd_Argc() != 3)
3684                 {
3685                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3686                         return;
3687                 }
3688                 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3689         }
3690         else
3691         {
3692                 Con_Print("usage: r_editlights_edit [property] [value]\n");
3693                 Con_Print("Selected light's properties:\n");
3694                 Con_Printf("Origin       : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3695                 Con_Printf("Angles       : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3696                 Con_Printf("Color        : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3697                 Con_Printf("Radius       : %f\n", r_shadow_selectedlight->radius);
3698                 Con_Printf("Corona       : %f\n", r_shadow_selectedlight->corona);
3699                 Con_Printf("Style        : %i\n", r_shadow_selectedlight->style);
3700                 Con_Printf("Shadows      : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3701                 Con_Printf("Cubemap      : %s\n", r_shadow_selectedlight->cubemapname);
3702                 Con_Printf("CoronaSize   : %f\n", r_shadow_selectedlight->coronasizescale);
3703                 Con_Printf("Ambient      : %f\n", r_shadow_selectedlight->ambientscale);
3704                 Con_Printf("Diffuse      : %f\n", r_shadow_selectedlight->diffusescale);
3705                 Con_Printf("Specular     : %f\n", r_shadow_selectedlight->specularscale);
3706                 Con_Printf("NormalMode   : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
3707                 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
3708                 return;
3709         }
3710         flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
3711         R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3712 }
3713
3714 void R_Shadow_EditLights_EditAll_f(void)
3715 {
3716         dlight_t *light;
3717
3718         if (!r_editlights.integer)
3719         {
3720                 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
3721                 return;
3722         }
3723
3724         for (light = r_shadow_worldlightchain;light;light = light->next)
3725         {
3726                 R_Shadow_SelectLight(light);
3727                 R_Shadow_EditLights_Edit_f();
3728         }
3729 }
3730
3731 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3732 {
3733         int lightnumber, lightcount;
3734         dlight_t *light;
3735         float x, y;
3736         char temp[256];
3737         if (!r_editlights.integer)
3738                 return;
3739         x = 0;
3740         y = con_vislines;
3741         lightnumber = -1;
3742         lightcount = 0;
3743         for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
3744                 if (light == r_shadow_selectedlight)
3745                         lightnumber = lightcount;
3746         sprintf(temp, "Cursor  %f %f %f  Total Lights %i", r_editlights_cursorlocation[0], r_editlights_cursorlocation[1], r_editlights_cursorlocation[2], lightcount);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3747         if (r_shadow_selectedlight == NULL)
3748                 return;
3749         sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3750         sprintf(temp, "Origin       : %f %f %f\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);y += 8;
3751         sprintf(temp, "Angles       : %f %f %f\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);y += 8;
3752         sprintf(temp, "Color        : %f %f %f\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);y += 8;
3753         sprintf(temp, "Radius       : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3754         sprintf(temp, "Corona       : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3755         sprintf(temp, "Style        : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3756         sprintf(temp, "Shadows      : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3757         sprintf(temp, "Cubemap      : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3758         sprintf(temp, "CoronaSize   : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3759         sprintf(temp, "Ambient      : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3760         sprintf(temp, "Diffuse      : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3761         sprintf(temp, "Specular     : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3762         sprintf(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);y += 8;
3763         sprintf(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);y += 8;
3764 }
3765
3766 void R_Shadow_EditLights_ToggleShadow_f(void)
3767 {
3768         if (!r_editlights.integer)
3769         {
3770                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
3771                 return;
3772         }
3773         if (!r_shadow_selectedlight)
3774         {
3775                 Con_Print("No selected light.\n");
3776                 return;
3777         }
3778         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);
3779 }
3780
3781 void R_Shadow_EditLights_ToggleCorona_f(void)
3782 {
3783         if (!r_editlights.integer)
3784         {
3785                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
3786                 return;
3787         }
3788         if (!r_shadow_selectedlight)
3789         {
3790                 Con_Print("No selected light.\n");
3791                 return;
3792         }
3793         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);
3794 }
3795
3796 void R_Shadow_EditLights_Remove_f(void)
3797 {
3798         if (!r_editlights.integer)
3799         {
3800                 Con_Print("Cannot remove light when not in editing mode.  Set r_editlights to 1.\n");
3801                 return;
3802         }
3803         if (!r_shadow_selectedlight)
3804         {
3805                 Con_Print("No selected light.\n");
3806                 return;
3807         }
3808         R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3809         r_shadow_selectedlight = NULL;
3810 }
3811
3812 void R_Shadow_EditLights_Help_f(void)
3813 {
3814         Con_Print(
3815 "Documentation on r_editlights system:\n"
3816 "Settings:\n"
3817 "r_editlights : enable/disable editing mode\n"
3818 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
3819 "r_editlights_cursorpushback : push back cursor this far from surface\n"
3820 "r_editlights_cursorpushoff : push cursor off surface this far\n"
3821 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
3822 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
3823 "Commands:\n"
3824 "r_editlights_help : this help\n"
3825 "r_editlights_clear : remove all lights\n"
3826 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
3827 "r_editlights_save : save to .rtlights file\n"
3828 "r_editlights_spawn : create a light with default settings\n"
3829 "r_editlights_edit command : edit selected light - more documentation below\n"
3830 "r_editlights_remove : remove selected light\n"
3831 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
3832 "r_editlights_importlightentitiesfrommap : reload light entities\n"
3833 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
3834 "Edit commands:\n"
3835 "origin x y z : set light location\n"
3836 "originx x: set x component of light location\n"
3837 "originy y: set y component of light location\n"
3838 "originz z: set z component of light location\n"
3839 "move x y z : adjust light location\n"
3840 "movex x: adjust x component of light location\n"
3841 "movey y: adjust y component of light location\n"
3842 "movez z: adjust z component of light location\n"
3843 "angles x y z : set light angles\n"
3844 "anglesx x: set x component of light angles\n"
3845 "anglesy y: set y component of light angles\n"
3846 "anglesz z: set z component of light angles\n"
3847 "color r g b : set color of light (can be brighter than 1 1 1)\n"
3848 "radius radius : set radius (size) of light\n"
3849 "colorscale grey : multiply color of light (1 does nothing)\n"
3850 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
3851 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
3852 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
3853 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
3854 "cubemap basename : set filter cubemap of light (not yet supported)\n"
3855 "shadows 1/0 : turn on/off shadows\n"
3856 "corona n : set corona intensity\n"
3857 "coronasize n : set corona size (0-1)\n"
3858 "ambient n : set ambient intensity (0-1)\n"
3859 "diffuse n : set diffuse intensity (0-1)\n"
3860 "specular n : set specular intensity (0-1)\n"
3861 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
3862 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
3863 "<nothing> : print light properties to console\n"
3864         );
3865 }
3866
3867 void R_Shadow_EditLights_CopyInfo_f(void)
3868 {
3869         if (!r_editlights.integer)
3870         {
3871                 Con_Print("Cannot copy light info when not in editing mode.  Set r_editlights to 1.\n");
3872                 return;
3873         }
3874         if (!r_shadow_selectedlight)
3875         {
3876                 Con_Print("No selected light.\n");
3877                 return;
3878         }
3879         VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
3880         VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
3881         r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
3882         r_shadow_bufferlight.style = r_shadow_selectedlight->style;
3883         if (r_shadow_selectedlight->cubemapname)
3884                 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
3885         else
3886                 r_shadow_bufferlight.cubemapname[0] = 0;
3887         r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
3888         r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
3889         r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
3890         r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
3891         r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
3892         r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
3893         r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
3894 }
3895
3896 void R_Shadow_EditLights_PasteInfo_f(void)
3897 {
3898         if (!r_editlights.integer)
3899         {
3900                 Con_Print("Cannot paste light info when not in editing mode.  Set r_editlights to 1.\n");
3901                 return;
3902         }
3903         if (!r_shadow_selectedlight)
3904         {
3905                 Con_Print("No selected light.\n");
3906                 return;
3907         }
3908         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);
3909 }
3910
3911 void R_Shadow_EditLights_Init(void)
3912 {
3913         Cvar_RegisterVariable(&r_editlights);
3914         Cvar_RegisterVariable(&r_editlights_cursordistance);
3915         Cvar_RegisterVariable(&r_editlights_cursorpushback);
3916         Cvar_RegisterVariable(&r_editlights_cursorpushoff);
3917         Cvar_RegisterVariable(&r_editlights_cursorgrid);
3918         Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
3919         Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
3920         Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
3921         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)");
3922         Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
3923         Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
3924         Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
3925         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)");
3926         Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
3927         Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
3928         Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
3929         Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
3930         Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
3931         Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
3932         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)");
3933 }
3934