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