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