]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - r_shadow.c
added Bloom effect (r_bloom* cvars)
[xonotic/darkplaces.git] / r_shadow.c
1
2 /*
3 Terminology: Stencil Shadow Volume (sometimes called Stencil Shadows)
4 An extrusion of the lit faces, beginning at the original geometry and ending
5 further from the light source than the original geometry (presumably at least
6 as far as the light's radius, if the light has a radius at all), capped at
7 both front and back to avoid any problems (extrusion from dark faces also
8 works but has a different set of problems)
9
10 This is 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                         }
1402                         else if (r_shadow_texture3d.integer && !lightcubemap && r_textureunits.integer >= 2)
1403                         {
1404                                 // 2 3D combine path (Geforce3, original Radeon)
1405                                 memset(&m, 0, sizeof(m));
1406                                 m.pointer_vertex = vertex3f;
1407                                 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1408 #ifdef USETEXMATRIX
1409                                 m.pointer_texcoord3f[0] = vertex3f;
1410                                 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1411 #else
1412                                 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1413                                 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1414 #endif
1415                                 m.tex[1] = R_GetTexture(basetexture);
1416                                 m.pointer_texcoord[1] = texcoord2f;
1417                         }
1418                         else if (r_textureunits.integer >= 4 && lightcubemap)
1419                         {
1420                                 // 4 2D combine path (Geforce3, Radeon 8500)
1421                                 memset(&m, 0, sizeof(m));
1422                                 m.pointer_vertex = vertex3f;
1423                                 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1424 #ifdef USETEXMATRIX
1425                                 m.pointer_texcoord3f[0] = vertex3f;
1426                                 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1427 #else
1428                                 m.pointer_texcoord[0] = varray_texcoord2f[0];
1429                                 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1430 #endif
1431                                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1432 #ifdef USETEXMATRIX
1433                                 m.pointer_texcoord3f[1] = vertex3f;
1434                                 m.texmatrix[1] = *matrix_modeltoattenuationz;
1435 #else
1436                                 m.pointer_texcoord[1] = varray_texcoord2f[1];
1437                                 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1438 #endif
1439                                 m.tex[2] = R_GetTexture(basetexture);
1440                                 m.pointer_texcoord[2] = texcoord2f;
1441                                 if (lightcubemap)
1442                                 {
1443                                         m.texcubemap[3] = R_GetTexture(lightcubemap);
1444 #ifdef USETEXMATRIX
1445                                         m.pointer_texcoord3f[3] = vertex3f;
1446                                         m.texmatrix[3] = *matrix_modeltolight;
1447 #else
1448                                         m.pointer_texcoord3f[3] = varray_texcoord3f[3];
1449                                         R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[3], numverts, vertex3f, matrix_modeltolight);
1450 #endif
1451                                 }
1452                         }
1453                         else if (r_textureunits.integer >= 3 && !lightcubemap)
1454                         {
1455                                 // 3 2D combine path (Geforce3, original Radeon)
1456                                 memset(&m, 0, sizeof(m));
1457                                 m.pointer_vertex = vertex3f;
1458                                 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1459 #ifdef USETEXMATRIX
1460                                 m.pointer_texcoord3f[0] = vertex3f;
1461                                 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1462 #else
1463                                 m.pointer_texcoord[0] = varray_texcoord2f[0];
1464                                 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1465 #endif
1466                                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1467 #ifdef USETEXMATRIX
1468                                 m.pointer_texcoord3f[1] = vertex3f;
1469                                 m.texmatrix[1] = *matrix_modeltoattenuationz;
1470 #else
1471                                 m.pointer_texcoord[1] = varray_texcoord2f[1];
1472                                 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1473 #endif
1474                                 m.tex[2] = R_GetTexture(basetexture);
1475                                 m.pointer_texcoord[2] = texcoord2f;
1476                         }
1477                         else
1478                         {
1479                                 // 2/2/2 2D combine path (any dot3 card)
1480                                 memset(&m, 0, sizeof(m));
1481                                 m.pointer_vertex = vertex3f;
1482                                 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1483 #ifdef USETEXMATRIX
1484                                 m.pointer_texcoord3f[0] = vertex3f;
1485                                 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1486 #else
1487                                 m.pointer_texcoord[0] = varray_texcoord2f[0];
1488                                 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1489 #endif
1490                                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1491 #ifdef USETEXMATRIX
1492                                 m.pointer_texcoord3f[1] = vertex3f;
1493                                 m.texmatrix[1] = *matrix_modeltoattenuationz;
1494 #else
1495                                 m.pointer_texcoord[1] = varray_texcoord2f[1];
1496                                 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1497 #endif
1498                                 R_Mesh_State(&m);
1499                                 GL_ColorMask(0,0,0,1);
1500                                 GL_BlendFunc(GL_ONE, GL_ZERO);
1501                                 GL_LockArrays(0, numverts);
1502                                 R_Mesh_Draw(numverts, numtriangles, elements);
1503                                 GL_LockArrays(0, 0);
1504                                 c_rt_lightmeshes++;
1505                                 c_rt_lighttris += numtriangles;
1506         
1507                                 memset(&m, 0, sizeof(m));
1508                                 m.pointer_vertex = vertex3f;
1509                                 m.tex[0] = R_GetTexture(basetexture);
1510                                 m.pointer_texcoord[0] = texcoord2f;
1511                                 if (lightcubemap)
1512                                 {
1513                                         m.texcubemap[1] = R_GetTexture(lightcubemap);
1514 #ifdef USETEXMATRIX
1515                                         m.pointer_texcoord3f[1] = vertex3f;
1516                                         m.texmatrix[1] = *matrix_modeltolight;
1517 #else
1518                                         m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1519                                         R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1520 #endif
1521                                 }
1522                         }
1523                         // this final code is shared
1524                         R_Mesh_State(&m);
1525                         GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1526                         GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1527                         VectorScale(lightcolor, colorscale, color2);
1528                         GL_LockArrays(0, numverts);
1529                         for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1530                         {
1531                                 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1532                                 R_Mesh_Draw(numverts, numtriangles, elements);
1533                                 c_rt_lightmeshes++;
1534                                 c_rt_lighttris += numtriangles;
1535                         }
1536                         GL_LockArrays(0, 0);
1537                 }
1538                 if (diffusescale)
1539                 {
1540                         GL_Color(1,1,1,1);
1541                         colorscale = r_shadow_lightintensityscale.value * diffusescale;
1542                         // colorscale accounts for how much we multiply the brightness
1543                         // during combine.
1544                         //
1545                         // mult is how many times the final pass of the lighting will be
1546                         // performed to get more brightness than otherwise possible.
1547                         //
1548                         // Limit mult to 64 for sanity sake.
1549                         if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1550                         {
1551                                 // 3/2 3D combine path (Geforce3, Radeon 8500)
1552                                 memset(&m, 0, sizeof(m));
1553                                 m.pointer_vertex = vertex3f;
1554                                 m.tex[0] = R_GetTexture(bumptexture);
1555                                 m.texcombinergb[0] = GL_REPLACE;
1556                                 m.pointer_texcoord[0] = texcoord2f;
1557                                 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1558                                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1559                                 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1560                                 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1561                                 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1562 #ifdef USETEXMATRIX
1563                                 m.pointer_texcoord3f[2] = vertex3f;
1564                                 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
1565 #else
1566                                 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1567                                 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1568 #endif
1569                                 R_Mesh_State(&m);
1570                                 GL_ColorMask(0,0,0,1);
1571                                 GL_BlendFunc(GL_ONE, GL_ZERO);
1572                                 GL_LockArrays(0, numverts);
1573                                 R_Mesh_Draw(numverts, numtriangles, elements);
1574                                 GL_LockArrays(0, 0);
1575                                 c_rt_lightmeshes++;
1576                                 c_rt_lighttris += numtriangles;
1577         
1578                                 memset(&m, 0, sizeof(m));
1579                                 m.pointer_vertex = vertex3f;
1580                                 m.tex[0] = R_GetTexture(basetexture);
1581                                 m.pointer_texcoord[0] = texcoord2f;
1582                                 if (lightcubemap)
1583                                 {
1584                                         m.texcubemap[1] = R_GetTexture(lightcubemap);
1585 #ifdef USETEXMATRIX
1586                                         m.pointer_texcoord3f[1] = vertex3f;
1587                                         m.texmatrix[1] = *matrix_modeltolight;
1588 #else
1589                                         m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1590                                         R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1591 #endif
1592                                 }
1593                         }
1594                         else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap)
1595                         {
1596                                 // 1/2/2 3D combine path (original Radeon)
1597                                 memset(&m, 0, sizeof(m));
1598                                 m.pointer_vertex = vertex3f;
1599                                 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1600 #ifdef USETEXMATRIX
1601                                 m.pointer_texcoord3f[0] = vertex3f;
1602                                 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1603 #else
1604                                 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1605                                 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1606 #endif
1607                                 R_Mesh_State(&m);
1608                                 GL_ColorMask(0,0,0,1);
1609                                 GL_BlendFunc(GL_ONE, GL_ZERO);
1610                                 GL_LockArrays(0, numverts);
1611                                 R_Mesh_Draw(numverts, numtriangles, elements);
1612                                 GL_LockArrays(0, 0);
1613                                 c_rt_lightmeshes++;
1614                                 c_rt_lighttris += numtriangles;
1615         
1616                                 memset(&m, 0, sizeof(m));
1617                                 m.pointer_vertex = vertex3f;
1618                                 m.tex[0] = R_GetTexture(bumptexture);
1619                                 m.texcombinergb[0] = GL_REPLACE;
1620                                 m.pointer_texcoord[0] = texcoord2f;
1621                                 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1622                                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1623                                 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1624                                 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1625                                 R_Mesh_State(&m);
1626                                 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1627                                 GL_LockArrays(0, numverts);
1628                                 R_Mesh_Draw(numverts, numtriangles, elements);
1629                                 GL_LockArrays(0, 0);
1630                                 c_rt_lightmeshes++;
1631                                 c_rt_lighttris += numtriangles;
1632         
1633                                 memset(&m, 0, sizeof(m));
1634                                 m.pointer_vertex = vertex3f;
1635                                 m.tex[0] = R_GetTexture(basetexture);
1636                                 m.pointer_texcoord[0] = texcoord2f;
1637                                 if (lightcubemap)
1638                                 {
1639                                         m.texcubemap[1] = R_GetTexture(lightcubemap);
1640 #ifdef USETEXMATRIX
1641                                         m.pointer_texcoord3f[1] = vertex3f;
1642                                         m.texmatrix[1] = *matrix_modeltolight;
1643 #else
1644                                         m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1645                                         R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1646 #endif
1647                                 }
1648                         }
1649                         else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap)
1650                         {
1651                                 // 2/2 3D combine path (original Radeon)
1652                                 memset(&m, 0, sizeof(m));
1653                                 m.pointer_vertex = vertex3f;
1654                                 m.tex[0] = R_GetTexture(bumptexture);
1655                                 m.texcombinergb[0] = GL_REPLACE;
1656                                 m.pointer_texcoord[0] = texcoord2f;
1657                                 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1658                                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1659                                 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1660                                 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1661                                 R_Mesh_State(&m);
1662                                 GL_ColorMask(0,0,0,1);
1663                                 GL_BlendFunc(GL_ONE, GL_ZERO);
1664                                 GL_LockArrays(0, numverts);
1665                                 R_Mesh_Draw(numverts, numtriangles, elements);
1666                                 GL_LockArrays(0, 0);
1667                                 c_rt_lightmeshes++;
1668                                 c_rt_lighttris += numtriangles;
1669         
1670                                 memset(&m, 0, sizeof(m));
1671                                 m.pointer_vertex = vertex3f;
1672                                 m.tex[0] = R_GetTexture(basetexture);
1673                                 m.pointer_texcoord[0] = texcoord2f;
1674                                 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1675 #ifdef USETEXMATRIX
1676                                 m.pointer_texcoord3f[1] = vertex3f;
1677                                 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1678 #else
1679                                 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1680                                 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1681 #endif
1682                         }
1683                         else if (r_textureunits.integer >= 4)
1684                         {
1685                                 // 4/2 2D combine path (Geforce3, Radeon 8500)
1686                                 memset(&m, 0, sizeof(m));
1687                                 m.pointer_vertex = vertex3f;
1688                                 m.tex[0] = R_GetTexture(bumptexture);
1689                                 m.texcombinergb[0] = GL_REPLACE;
1690                                 m.pointer_texcoord[0] = texcoord2f;
1691                                 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1692                                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1693                                 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1694                                 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1695                                 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1696 #ifdef USETEXMATRIX
1697                                 m.pointer_texcoord3f[2] = vertex3f;
1698                                 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
1699 #else
1700                                 m.pointer_texcoord[2] = varray_texcoord2f[2];
1701                                 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1702 #endif
1703                                 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1704 #ifdef USETEXMATRIX
1705                                 m.pointer_texcoord3f[3] = vertex3f;
1706                                 m.texmatrix[3] = *matrix_modeltoattenuationz;
1707 #else
1708                                 m.pointer_texcoord[3] = varray_texcoord2f[3];
1709                                 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[3], numverts, vertex3f, matrix_modeltoattenuationz);
1710 #endif
1711                                 R_Mesh_State(&m);
1712                                 GL_ColorMask(0,0,0,1);
1713                                 GL_BlendFunc(GL_ONE, GL_ZERO);
1714                                 GL_LockArrays(0, numverts);
1715                                 R_Mesh_Draw(numverts, numtriangles, elements);
1716                                 GL_LockArrays(0, 0);
1717                                 c_rt_lightmeshes++;
1718                                 c_rt_lighttris += numtriangles;
1719         
1720                                 memset(&m, 0, sizeof(m));
1721                                 m.pointer_vertex = vertex3f;
1722                                 m.tex[0] = R_GetTexture(basetexture);
1723                                 m.pointer_texcoord[0] = texcoord2f;
1724                                 if (lightcubemap)
1725                                 {
1726                                         m.texcubemap[1] = R_GetTexture(lightcubemap);
1727 #ifdef USETEXMATRIX
1728                                         m.pointer_texcoord3f[1] = vertex3f;
1729                                         m.texmatrix[1] = *matrix_modeltolight;
1730 #else
1731                                         m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1732                                         R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1733 #endif
1734                                 }
1735                         }
1736                         else
1737                         {
1738                                 // 2/2/2 2D combine path (any dot3 card)
1739                                 memset(&m, 0, sizeof(m));
1740                                 m.pointer_vertex = vertex3f;
1741                                 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1742 #ifdef USETEXMATRIX
1743                                 m.pointer_texcoord3f[0] = vertex3f;
1744                                 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1745 #else
1746                                 m.pointer_texcoord[0] = varray_texcoord2f[0];
1747                                 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1748 #endif
1749                                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1750 #ifdef USETEXMATRIX
1751                                 m.pointer_texcoord3f[1] = vertex3f;
1752                                 m.texmatrix[1] = *matrix_modeltoattenuationz;
1753 #else
1754                                 m.pointer_texcoord[1] = varray_texcoord2f[1];
1755                                 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1756 #endif
1757                                 R_Mesh_State(&m);
1758                                 GL_ColorMask(0,0,0,1);
1759                                 GL_BlendFunc(GL_ONE, GL_ZERO);
1760                                 GL_LockArrays(0, numverts);
1761                                 R_Mesh_Draw(numverts, numtriangles, elements);
1762                                 GL_LockArrays(0, 0);
1763                                 c_rt_lightmeshes++;
1764                                 c_rt_lighttris += numtriangles;
1765         
1766                                 memset(&m, 0, sizeof(m));
1767                                 m.pointer_vertex = vertex3f;
1768                                 m.tex[0] = R_GetTexture(bumptexture);
1769                                 m.texcombinergb[0] = GL_REPLACE;
1770                                 m.pointer_texcoord[0] = texcoord2f;
1771                                 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1772                                 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1773                                 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1774                                 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1775                                 R_Mesh_State(&m);
1776                                 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1777                                 GL_LockArrays(0, numverts);
1778                                 R_Mesh_Draw(numverts, numtriangles, elements);
1779                                 GL_LockArrays(0, 0);
1780                                 c_rt_lightmeshes++;
1781                                 c_rt_lighttris += numtriangles;
1782         
1783                                 memset(&m, 0, sizeof(m));
1784                                 m.pointer_vertex = vertex3f;
1785                                 m.tex[0] = R_GetTexture(basetexture);
1786                                 m.pointer_texcoord[0] = texcoord2f;
1787                                 if (lightcubemap)
1788                                 {
1789                                         m.texcubemap[1] = R_GetTexture(lightcubemap);
1790 #ifdef USETEXMATRIX
1791                                         m.pointer_texcoord3f[1] = vertex3f;
1792                                         m.texmatrix[1] = *matrix_modeltolight;
1793 #else
1794                                         m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1795                                         R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1796 #endif
1797                                 }
1798                         }
1799                         // this final code is shared
1800                         R_Mesh_State(&m);
1801                         GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
1802                         GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1803                         VectorScale(lightcolor, colorscale, color2);
1804                         GL_LockArrays(0, numverts);
1805                         for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1806                         {
1807                                 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1808                                 R_Mesh_Draw(numverts, numtriangles, elements);
1809                                 c_rt_lightmeshes++;
1810                                 c_rt_lighttris += numtriangles;
1811                         }
1812                         GL_LockArrays(0, 0);
1813                 }
1814                 if (specularscale && (r_shadow_gloss.integer >= 2 || (r_shadow_gloss.integer >= 1 && glosstexture != r_shadow_blankglosstexture)))
1815                 {
1816                         // FIXME: detect blendsquare!
1817                         //if (gl_support_blendsquare)
1818                         {
1819                                 colorscale = r_shadow_lightintensityscale.value * r_shadow_glossintensity.value * specularscale;
1820                                 if (glosstexture == r_shadow_blankglosstexture)
1821                                         colorscale *= r_shadow_gloss2intensity.value;
1822                                 GL_Color(1,1,1,1);
1823                                 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1824                                 {
1825                                         // 2/0/0/1/2 3D combine blendsquare path
1826                                         memset(&m, 0, sizeof(m));
1827                                         m.pointer_vertex = vertex3f;
1828                                         m.tex[0] = R_GetTexture(bumptexture);
1829                                         m.pointer_texcoord[0] = texcoord2f;
1830                                         m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1831                                         m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1832                                         m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1833                                         R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1834                                         R_Mesh_State(&m);
1835                                         GL_ColorMask(0,0,0,1);
1836                                         // this squares the result
1837                                         GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1838                                         GL_LockArrays(0, numverts);
1839                                         R_Mesh_Draw(numverts, numtriangles, elements);
1840                                         GL_LockArrays(0, 0);
1841                                         c_rt_lightmeshes++;
1842                                         c_rt_lighttris += numtriangles;
1843                 
1844                                         memset(&m, 0, sizeof(m));
1845                                         m.pointer_vertex = vertex3f;
1846                                         R_Mesh_State(&m);
1847                                         GL_LockArrays(0, numverts);
1848                                         // square alpha in framebuffer a few times to make it shiny
1849                                         GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1850                                         // these comments are a test run through this math for intensity 0.5
1851                                         // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1852                                         // 0.25 * 0.25 = 0.0625 (this is another pass)
1853                                         // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1854                                         R_Mesh_Draw(numverts, numtriangles, elements);
1855                                         c_rt_lightmeshes++;
1856                                         c_rt_lighttris += numtriangles;
1857                                         R_Mesh_Draw(numverts, numtriangles, elements);
1858                                         c_rt_lightmeshes++;
1859                                         c_rt_lighttris += numtriangles;
1860                                         GL_LockArrays(0, 0);
1861                 
1862                                         memset(&m, 0, sizeof(m));
1863                                         m.pointer_vertex = vertex3f;
1864                                         m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1865 #ifdef USETEXMATRIX
1866                                         m.pointer_texcoord3f[0] = vertex3f;
1867                                         m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1868 #else
1869                                         m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1870                                         R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1871 #endif
1872                                         R_Mesh_State(&m);
1873                                         GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1874                                         GL_LockArrays(0, numverts);
1875                                         R_Mesh_Draw(numverts, numtriangles, elements);
1876                                         GL_LockArrays(0, 0);
1877                                         c_rt_lightmeshes++;
1878                                         c_rt_lighttris += numtriangles;
1879                 
1880                                         memset(&m, 0, sizeof(m));
1881                                         m.pointer_vertex = vertex3f;
1882                                         m.tex[0] = R_GetTexture(glosstexture);
1883                                         m.pointer_texcoord[0] = texcoord2f;
1884                                         if (lightcubemap)
1885                                         {
1886                                                 m.texcubemap[1] = R_GetTexture(lightcubemap);
1887 #ifdef USETEXMATRIX
1888                                                 m.pointer_texcoord3f[1] = vertex3f;
1889                                                 m.texmatrix[1] = *matrix_modeltolight;
1890 #else
1891                                                 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1892                                                 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1893 #endif
1894                                         }
1895                                 }
1896                                 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1897                                 {
1898                                         // 2/0/0/2 3D combine blendsquare path
1899                                         memset(&m, 0, sizeof(m));
1900                                         m.pointer_vertex = vertex3f;
1901                                         m.tex[0] = R_GetTexture(bumptexture);
1902                                         m.pointer_texcoord[0] = texcoord2f;
1903                                         m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1904                                         m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1905                                         m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1906                                         R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1907                                         R_Mesh_State(&m);
1908                                         GL_ColorMask(0,0,0,1);
1909                                         // this squares the result
1910                                         GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1911                                         GL_LockArrays(0, numverts);
1912                                         R_Mesh_Draw(numverts, numtriangles, elements);
1913                                         GL_LockArrays(0, 0);
1914                                         c_rt_lightmeshes++;
1915                                         c_rt_lighttris += numtriangles;
1916                 
1917                                         memset(&m, 0, sizeof(m));
1918                                         m.pointer_vertex = vertex3f;
1919                                         R_Mesh_State(&m);
1920                                         GL_LockArrays(0, numverts);
1921                                         // square alpha in framebuffer a few times to make it shiny
1922                                         GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1923                                         // these comments are a test run through this math for intensity 0.5
1924                                         // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1925                                         // 0.25 * 0.25 = 0.0625 (this is another pass)
1926                                         // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1927                                         R_Mesh_Draw(numverts, numtriangles, elements);
1928                                         c_rt_lightmeshes++;
1929                                         c_rt_lighttris += numtriangles;
1930                                         R_Mesh_Draw(numverts, numtriangles, elements);
1931                                         c_rt_lightmeshes++;
1932                                         c_rt_lighttris += numtriangles;
1933                                         GL_LockArrays(0, 0);
1934                 
1935                                         memset(&m, 0, sizeof(m));
1936                                         m.pointer_vertex = vertex3f;
1937                                         m.tex[0] = R_GetTexture(glosstexture);
1938                                         m.pointer_texcoord[0] = texcoord2f;
1939                                         m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1940 #ifdef USETEXMATRIX
1941                                         m.pointer_texcoord3f[1] = vertex3f;
1942                                         m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1943 #else
1944                                         m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1945                                         R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1946 #endif
1947                                 }
1948                                 else
1949                                 {
1950                                         // 2/0/0/2/2 2D combine blendsquare path
1951                                         memset(&m, 0, sizeof(m));
1952                                         m.pointer_vertex = vertex3f;
1953                                         m.tex[0] = R_GetTexture(bumptexture);
1954                                         m.pointer_texcoord[0] = texcoord2f;
1955                                         m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1956                                         m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1957                                         m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1958                                         R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1959                                         R_Mesh_State(&m);
1960                                         GL_ColorMask(0,0,0,1);
1961                                         // this squares the result
1962                                         GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1963                                         GL_LockArrays(0, numverts);
1964                                         R_Mesh_Draw(numverts, numtriangles, elements);
1965                                         GL_LockArrays(0, 0);
1966                                         c_rt_lightmeshes++;
1967                                         c_rt_lighttris += numtriangles;
1968                 
1969                                         memset(&m, 0, sizeof(m));
1970                                         m.pointer_vertex = vertex3f;
1971                                         R_Mesh_State(&m);
1972                                         GL_LockArrays(0, numverts);
1973                                         // square alpha in framebuffer a few times to make it shiny
1974                                         GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1975                                         // these comments are a test run through this math for intensity 0.5
1976                                         // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1977                                         // 0.25 * 0.25 = 0.0625 (this is another pass)
1978                                         // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1979                                         R_Mesh_Draw(numverts, numtriangles, elements);
1980                                         c_rt_lightmeshes++;
1981                                         c_rt_lighttris += numtriangles;
1982                                         R_Mesh_Draw(numverts, numtriangles, elements);
1983                                         c_rt_lightmeshes++;
1984                                         c_rt_lighttris += numtriangles;
1985                                         GL_LockArrays(0, 0);
1986                 
1987                                         memset(&m, 0, sizeof(m));
1988                                         m.pointer_vertex = vertex3f;
1989                                         m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1990 #ifdef USETEXMATRIX
1991                                         m.pointer_texcoord3f[0] = vertex3f;
1992                                         m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1993 #else
1994                                         m.pointer_texcoord[0] = varray_texcoord2f[0];
1995                                         R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1996 #endif
1997                                         m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1998 #ifdef USETEXMATRIX
1999                                         m.pointer_texcoord3f[1] = vertex3f;
2000                                         m.texmatrix[1] = *matrix_modeltoattenuationz;
2001 #else
2002                                         m.pointer_texcoord[1] = varray_texcoord2f[1];
2003                                         R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
2004 #endif
2005                                         R_Mesh_State(&m);
2006                                         GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2007                                         GL_LockArrays(0, numverts);
2008                                         R_Mesh_Draw(numverts, numtriangles, elements);
2009                                         GL_LockArrays(0, 0);
2010                                         c_rt_lightmeshes++;
2011                                         c_rt_lighttris += numtriangles;
2012                 
2013                                         memset(&m, 0, sizeof(m));
2014                                         m.pointer_vertex = vertex3f;
2015                                         m.tex[0] = R_GetTexture(glosstexture);
2016                                         m.pointer_texcoord[0] = texcoord2f;
2017                                         if (lightcubemap)
2018                                         {
2019                                                 m.texcubemap[1] = R_GetTexture(lightcubemap);
2020 #ifdef USETEXMATRIX
2021                                                 m.pointer_texcoord3f[1] = vertex3f;
2022                                                 m.texmatrix[1] = *matrix_modeltolight;
2023 #else
2024                                                 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
2025                                                 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
2026 #endif
2027                                         }
2028                                 }
2029                                 R_Mesh_State(&m);
2030                                 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
2031                                 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2032                                 VectorScale(lightcolor, colorscale, color2);
2033                                 GL_LockArrays(0, numverts);
2034                                 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2035                                 {
2036                                         GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
2037                                         R_Mesh_Draw(numverts, numtriangles, elements);
2038                                         c_rt_lightmeshes++;
2039                                         c_rt_lighttris += numtriangles;
2040                                 }
2041                                 GL_LockArrays(0, 0);
2042                         }
2043                 }
2044         }
2045         else
2046         {
2047                 if (ambientscale)
2048                 {
2049                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2050                         VectorScale(lightcolor, r_shadow_lightintensityscale.value * ambientscale, color2);
2051                         memset(&m, 0, sizeof(m));
2052                         m.pointer_vertex = vertex3f;
2053                         m.tex[0] = R_GetTexture(basetexture);
2054                         m.pointer_texcoord[0] = texcoord2f;
2055                         if (r_textureunits.integer >= 2)
2056                         {
2057                                 // voodoo2
2058                                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2059 #ifdef USETEXMATRIX
2060                                 m.pointer_texcoord3f[1] = vertex3f;
2061                                 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2062 #else
2063                                 m.pointer_texcoord[1] = varray_texcoord2f[1];
2064                                 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
2065 #endif
2066                                 if (r_textureunits.integer >= 3)
2067                                 {
2068                                         // Geforce3/Radeon class but not using dot3
2069                                         m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2070 #ifdef USETEXMATRIX
2071                                         m.pointer_texcoord3f[2] = vertex3f;
2072                                         m.texmatrix[2] = *matrix_modeltoattenuationz;
2073 #else
2074                                         m.pointer_texcoord[2] = varray_texcoord2f[2];
2075                                         R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationz);
2076 #endif
2077                                 }
2078                         }
2079                         if (r_textureunits.integer >= 3)
2080                                 m.pointer_color = NULL;
2081                         else
2082                                 m.pointer_color = varray_color4f;
2083                         R_Mesh_State(&m);
2084                         for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2085                         {
2086                                 color[0] = bound(0, color2[0], 1);
2087                                 color[1] = bound(0, color2[1], 1);
2088                                 color[2] = bound(0, color2[2], 1);
2089                                 if (r_textureunits.integer >= 3)
2090                                         GL_Color(color[0], color[1], color[2], 1);
2091                                 else if (r_textureunits.integer >= 2)
2092                                         R_Shadow_VertexNoShadingWithZAttenuation(numverts, vertex3f, color, matrix_modeltolight);
2093                                 else
2094                                         R_Shadow_VertexNoShadingWithXYZAttenuation(numverts, vertex3f, color, matrix_modeltolight);
2095                                 GL_LockArrays(0, numverts);
2096                                 R_Mesh_Draw(numverts, numtriangles, elements);
2097                                 GL_LockArrays(0, 0);
2098                                 c_rt_lightmeshes++;
2099                                 c_rt_lighttris += numtriangles;
2100                         }
2101                 }
2102                 if (diffusescale)
2103                 {
2104                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2105                         VectorScale(lightcolor, r_shadow_lightintensityscale.value * diffusescale, color2);
2106                         memset(&m, 0, sizeof(m));
2107                         m.pointer_vertex = vertex3f;
2108                         m.pointer_color = varray_color4f;
2109                         m.tex[0] = R_GetTexture(basetexture);
2110                         m.pointer_texcoord[0] = texcoord2f;
2111                         if (r_textureunits.integer >= 2)
2112                         {
2113                                 // voodoo2
2114                                 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2115 #ifdef USETEXMATRIX
2116                                 m.pointer_texcoord3f[1] = vertex3f;
2117                                 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
2118 #else
2119                                 m.pointer_texcoord[1] = varray_texcoord2f[1];
2120                                 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
2121 #endif
2122                                 if (r_textureunits.integer >= 3)
2123                                 {
2124                                         // Geforce3/Radeon class but not using dot3
2125                                         m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2126 #ifdef USETEXMATRIX
2127                                         m.pointer_texcoord3f[2] = vertex3f;
2128                                         m.texmatrix[2] = *matrix_modeltoattenuationz;
2129 #else
2130                                         m.pointer_texcoord[2] = varray_texcoord2f[2];
2131                                         R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationz);
2132 #endif
2133                                 }
2134                         }
2135                         R_Mesh_State(&m);
2136                         for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
2137                         {
2138                                 color[0] = bound(0, color2[0], 1);
2139                                 color[1] = bound(0, color2[1], 1);
2140                                 color[2] = bound(0, color2[2], 1);
2141                                 if (r_textureunits.integer >= 3)
2142                                         R_Shadow_VertexShading(numverts, vertex3f, normal3f, color, matrix_modeltolight);
2143                                 else if (r_textureunits.integer >= 2)
2144                                         R_Shadow_VertexShadingWithZAttenuation(numverts, vertex3f, normal3f, color, matrix_modeltolight);
2145                                 else
2146                                         R_Shadow_VertexShadingWithXYZAttenuation(numverts, vertex3f, normal3f, color, matrix_modeltolight);
2147                                 GL_LockArrays(0, numverts);
2148                                 R_Mesh_Draw(numverts, numtriangles, elements);
2149                                 GL_LockArrays(0, 0);
2150                                 c_rt_lightmeshes++;
2151                                 c_rt_lighttris += numtriangles;
2152                         }
2153                 }
2154         }
2155 }
2156
2157 void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
2158 {
2159         int j, k;
2160         float scale;
2161         R_RTLight_Uncompile(rtlight);
2162         memset(rtlight, 0, sizeof(*rtlight));
2163
2164         VectorCopy(light->origin, rtlight->shadoworigin);
2165         VectorCopy(light->color, rtlight->color);
2166         rtlight->radius = light->radius;
2167         //rtlight->cullradius = rtlight->radius;
2168         //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2169         rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2170         rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2171         rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2172         rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2173         rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2174         rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2175         rtlight->cubemapname[0] = 0;
2176         if (light->cubemapname[0])
2177                 strcpy(rtlight->cubemapname, light->cubemapname);
2178         else if (light->cubemapnum > 0)
2179                 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
2180         rtlight->shadow = light->shadow;
2181         rtlight->corona = light->corona;
2182         rtlight->style = light->style;
2183         rtlight->isstatic = isstatic;
2184         rtlight->coronasizescale = light->coronasizescale;
2185         rtlight->ambientscale = light->ambientscale;
2186         rtlight->diffusescale = light->diffusescale;
2187         rtlight->specularscale = light->specularscale;
2188         rtlight->flags = light->flags;
2189         Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
2190         // ConcatScale won't work here because this needs to scale rotate and
2191         // translate, not just rotate
2192         scale = 1.0f / rtlight->radius;
2193         for (k = 0;k < 3;k++)
2194                 for (j = 0;j < 4;j++)
2195                         rtlight->matrix_worldtolight.m[k][j] *= scale;
2196         Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationxyz, &matrix_attenuationxyz, &rtlight->matrix_worldtolight);
2197         Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationz, &matrix_attenuationz, &rtlight->matrix_worldtolight);
2198
2199         rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
2200         rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
2201         VectorScale(rtlight->color, rtlight->radius * (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * 0.125f, rtlight->lightmap_light);
2202         rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
2203 }
2204
2205 // compiles rtlight geometry
2206 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2207 void R_RTLight_Compile(rtlight_t *rtlight)
2208 {
2209         int shadowmeshes, shadowtris, lightmeshes, lighttris, numclusters, numsurfaces;
2210         entity_render_t *ent = &cl_entities[0].render;
2211         model_t *model = ent->model;
2212
2213         // compile the light
2214         rtlight->compiled = true;
2215         rtlight->static_numclusters = 0;
2216         rtlight->static_numclusterpvsbytes = 0;
2217         rtlight->static_clusterlist = NULL;
2218         rtlight->static_clusterpvs = NULL;
2219         rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2220         rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2221         rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2222         rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2223         rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2224         rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2225
2226         if (model && model->GetLightInfo)
2227         {
2228                 // this variable directs the DrawShadowVolume and DrawLight code to capture into the mesh chain instead of rendering
2229                 r_shadow_compilingrtlight = rtlight;
2230                 R_Shadow_EnlargeClusterBuffer(model->brush.num_pvsclusters);
2231                 R_Shadow_EnlargeSurfaceBuffer(model->nummodelsurfaces); 
2232                 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);
2233                 if (numclusters)
2234                 {
2235                         rtlight->static_numclusters = numclusters;
2236                         rtlight->static_numclusterpvsbytes = (model->brush.num_pvsclusters + 7) >> 3;
2237                         rtlight->static_clusterlist = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
2238                         rtlight->static_clusterpvs = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusterpvsbytes);
2239                         memcpy(rtlight->static_clusterlist, r_shadow_buffer_clusterlist, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
2240                         memcpy(rtlight->static_clusterpvs, r_shadow_buffer_clusterpvs, rtlight->static_numclusterpvsbytes);
2241                 }
2242                 if (model->DrawShadowVolume && rtlight->shadow)
2243                 {
2244                         rtlight->static_meshchain_shadow = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
2245                         model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2246                         rtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_shadow, false, false);
2247                 }
2248                 if (model->DrawLight)
2249                 {
2250                         rtlight->static_meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true);
2251                         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);
2252                         rtlight->static_meshchain_light = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_light, true, false);
2253                 }
2254                 // switch back to rendering when DrawShadowVolume or DrawLight is called
2255                 r_shadow_compilingrtlight = NULL;
2256         }
2257
2258
2259         // use smallest available cullradius - box radius or light radius
2260         //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2261         //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2262
2263         shadowmeshes = 0;
2264         shadowtris = 0;
2265         if (rtlight->static_meshchain_shadow)
2266         {
2267                 shadowmesh_t *mesh;
2268                 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2269                 {
2270                         shadowmeshes++;
2271                         shadowtris += mesh->numtriangles;
2272                 }
2273         }
2274
2275         lightmeshes = 0;
2276         lighttris = 0;
2277         if (rtlight->static_meshchain_light)
2278         {
2279                 shadowmesh_t *mesh;
2280                 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2281                 {
2282                         lightmeshes++;
2283                         lighttris += mesh->numtriangles;
2284                 }
2285         }
2286
2287         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);
2288 }
2289
2290 void R_RTLight_Uncompile(rtlight_t *rtlight)
2291 {
2292         if (rtlight->compiled)
2293         {
2294                 if (rtlight->static_meshchain_shadow)
2295                         Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2296                 rtlight->static_meshchain_shadow = NULL;
2297                 if (rtlight->static_meshchain_light)
2298                         Mod_ShadowMesh_Free(rtlight->static_meshchain_light);
2299                 rtlight->static_meshchain_light = NULL;
2300                 if (rtlight->static_clusterlist)
2301                         Mem_Free(rtlight->static_clusterlist);
2302                 rtlight->static_clusterlist = NULL;
2303                 if (rtlight->static_clusterpvs)
2304                         Mem_Free(rtlight->static_clusterpvs);
2305                 rtlight->static_clusterpvs = NULL;
2306                 rtlight->static_numclusters = 0;
2307                 rtlight->static_numclusterpvsbytes = 0;
2308                 rtlight->compiled = false;
2309         }
2310 }
2311
2312 void R_Shadow_UncompileWorldLights(void)
2313 {
2314         dlight_t *light;
2315         for (light = r_shadow_worldlightchain;light;light = light->next)
2316                 R_RTLight_Uncompile(&light->rtlight);
2317 }
2318
2319 void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes)
2320 {
2321         int i, shadow;
2322         entity_render_t *ent;
2323         float f;
2324         vec3_t relativelightorigin, relativeeyeorigin, lightcolor, lightcolor2;
2325         rtexture_t *cubemaptexture;
2326         matrix4x4_t matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz;
2327         int numclusters, numsurfaces;
2328         int *clusterlist, *surfacelist;
2329         qbyte *clusterpvs;
2330         vec3_t cullmins, cullmaxs;
2331         shadowmesh_t *mesh;
2332         rmeshstate_t m;
2333
2334         // loading is done before visibility checks because loading should happen
2335         // all at once at the start of a level, not when it stalls gameplay.
2336         // (especially important to benchmarks)
2337         if (rtlight->isstatic && !rtlight->compiled && r_shadow_staticworldlights.integer)
2338                 R_RTLight_Compile(rtlight);
2339         if (rtlight->cubemapname[0])
2340                 cubemaptexture = R_Shadow_Cubemap(rtlight->cubemapname);
2341         else
2342                 cubemaptexture = NULL;
2343
2344         cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2345         cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2346         cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2347         cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2348         cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2349         cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2350         if (rtlight->style >= 0 && d_lightstylevalue[rtlight->style] <= 0)
2351                 return;
2352         numclusters = 0;
2353         clusterlist = NULL;
2354         clusterpvs = NULL;
2355         numsurfaces = 0;
2356         surfacelist = NULL;
2357         if (rtlight->compiled && r_shadow_staticworldlights.integer)
2358         {
2359                 // compiled light, world available and can receive realtime lighting
2360                 // retrieve cluster information
2361                 numclusters = rtlight->static_numclusters;
2362                 clusterlist = rtlight->static_clusterlist;
2363                 clusterpvs = rtlight->static_clusterpvs;
2364                 VectorCopy(rtlight->cullmins, cullmins);
2365                 VectorCopy(rtlight->cullmaxs, cullmaxs);
2366         }
2367         else if (r_refdef.worldmodel && r_refdef.worldmodel->GetLightInfo)
2368         {
2369                 // dynamic light, world available and can receive realtime lighting
2370                 // if the light box is offscreen, skip it right away
2371                 if (R_CullBox(cullmins, cullmaxs))
2372                         return;
2373                 // calculate lit surfaces and clusters
2374                 R_Shadow_EnlargeClusterBuffer(r_refdef.worldmodel->brush.num_pvsclusters);
2375                 R_Shadow_EnlargeSurfaceBuffer(r_refdef.worldmodel->nummodelsurfaces); 
2376                 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);
2377                 clusterlist = r_shadow_buffer_clusterlist;
2378                 clusterpvs = r_shadow_buffer_clusterpvs;
2379                 surfacelist = r_shadow_buffer_surfacelist;
2380         }
2381         // if the reduced cluster bounds are offscreen, skip it
2382         if (R_CullBox(cullmins, cullmaxs))
2383                 return;
2384         // check if light is illuminating any visible clusters
2385         if (numclusters)
2386         {
2387                 for (i = 0;i < numclusters;i++)
2388                         if (CHECKPVSBIT(r_pvsbits, clusterlist[i]))
2389                                 break;
2390                 if (i == numclusters)
2391                         return;
2392         }
2393         // set up a scissor rectangle for this light
2394         if (R_Shadow_ScissorForBBox(cullmins, cullmaxs))
2395                 return;
2396
2397         f = (rtlight->style >= 0 ? d_lightstylevalue[rtlight->style] : 128) * (1.0f / 256.0f);
2398         VectorScale(rtlight->color, f, lightcolor);
2399         /*
2400         if (rtlight->selected)
2401         {
2402                 f = 2 + sin(realtime * M_PI * 4.0);
2403                 VectorScale(lightcolor, f, lightcolor);
2404         }
2405         */
2406
2407         shadow = rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows);
2408
2409         if (shadow && (gl_stencil || visiblevolumes))
2410         {
2411                 if (!visiblevolumes)
2412                         R_Shadow_Stage_ShadowVolumes();
2413                 ent = &cl_entities[0].render;
2414                 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2415                 {
2416                         memset(&m, 0, sizeof(m));
2417                         R_Mesh_Matrix(&ent->matrix);
2418                         for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2419                         {
2420                                 m.pointer_vertex = mesh->vertex3f;
2421                                 R_Mesh_State(&m);
2422                                 GL_LockArrays(0, mesh->numverts);
2423                                 if (r_shadowstage == SHADOWSTAGE_STENCIL)
2424                                 {
2425                                         // decrement stencil if frontface is behind depthbuffer
2426                                         qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2427                                         qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2428                                         R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2429                                         c_rtcached_shadowmeshes++;
2430                                         c_rtcached_shadowtris += mesh->numtriangles;
2431                                         // increment stencil if backface is behind depthbuffer
2432                                         qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2433                                         qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2434                                 }
2435                                 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2436                                 c_rtcached_shadowmeshes++;
2437                                 c_rtcached_shadowtris += mesh->numtriangles;
2438                                 GL_LockArrays(0, 0);
2439                         }
2440                 }
2441                 else if (numsurfaces)
2442                 {
2443                         Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2444                         ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, numsurfaces, surfacelist);
2445                 }
2446                 if (r_drawentities.integer)
2447                 {
2448                         for (i = 0;i < r_refdef.numentities;i++)
2449                         {
2450                                 ent = r_refdef.entities[i];
2451                                 // rough checks
2452                                 if (r_shadow_cull.integer)
2453                                 {
2454                                         if (!BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs))
2455                                                 continue;
2456                                         if (r_refdef.worldmodel != NULL && r_refdef.worldmodel->brush.BoxTouchingPVS != NULL && !r_refdef.worldmodel->brush.BoxTouchingPVS(r_refdef.worldmodel, clusterpvs, ent->mins, ent->maxs))
2457                                                 continue;
2458                                 }
2459                                 if (!(ent->flags & RENDER_SHADOW) || !ent->model || !ent->model->DrawShadowVolume)
2460                                         continue;
2461                                 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2462                                 // light emitting entities should not cast their own shadow
2463                                 if (VectorLength2(relativelightorigin) < 0.1)
2464                                         continue;
2465                                 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, ent->model->nummodelsurfaces, ent->model->surfacelist);
2466                         }
2467                 }
2468         }
2469
2470         if (!visiblevolumes)
2471         {
2472                 R_Shadow_Stage_Light(shadow && gl_stencil);
2473
2474                 ent = &cl_entities[0].render;
2475                 if (ent->model && ent->model->DrawLight && (ent->flags & RENDER_LIGHT))
2476                 {
2477                         lightcolor2[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
2478                         lightcolor2[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
2479                         lightcolor2[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
2480                         Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2481                         Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2482                         Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2483                         Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2484                         Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2485                         if (r_shadow_staticworldlights.integer && rtlight->compiled)
2486                         {
2487                                 R_Mesh_Matrix(&ent->matrix);
2488                                 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2489                                         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);
2490                         }
2491                         else
2492                                 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor2, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, rtlight->ambientscale, rtlight->diffusescale, rtlight->specularscale, numsurfaces, surfacelist);
2493                 }
2494                 if (r_drawentities.integer)
2495                 {
2496                         for (i = 0;i < r_refdef.numentities;i++)
2497                         {
2498                                 ent = r_refdef.entities[i];
2499                                 // can't draw transparent entity lighting here because
2500                                 // transparent meshes are deferred for later
2501                                 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)
2502                                 {
2503                                         lightcolor2[0] = lightcolor[0] * ent->colormod[0] * ent->alpha;
2504                                         lightcolor2[1] = lightcolor[1] * ent->colormod[1] * ent->alpha;
2505                                         lightcolor2[2] = lightcolor[2] * ent->colormod[2] * ent->alpha;
2506                                         Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2507                                         Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2508                                         Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2509                                         Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2510                                         Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2511                                         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);
2512                                 }
2513                         }
2514                 }
2515         }
2516 }
2517
2518 void R_ShadowVolumeLighting(int visiblevolumes)
2519 {
2520         int lnum, flag;
2521         dlight_t *light;
2522         rmeshstate_t m;
2523
2524         if (r_refdef.worldmodel && strncmp(r_refdef.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
2525                 R_Shadow_EditLights_Reload_f();
2526
2527         if (visiblevolumes)
2528         {
2529                 memset(&m, 0, sizeof(m));
2530                 R_Mesh_State(&m);
2531
2532                 GL_BlendFunc(GL_ONE, GL_ONE);
2533                 GL_DepthMask(false);
2534                 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
2535                 qglDisable(GL_CULL_FACE);
2536                 GL_Color(0.0, 0.0125, 0.1, 1);
2537         }
2538         else
2539                 R_Shadow_Stage_Begin();
2540         flag = r_rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2541         if (r_shadow_debuglight.integer >= 0)
2542         {
2543                 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2544                         if (lnum == r_shadow_debuglight.integer && (light->flags & flag))
2545                                 R_DrawRTLight(&light->rtlight, visiblevolumes);
2546         }
2547         else
2548                 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2549                         if (light->flags & flag)
2550                                 R_DrawRTLight(&light->rtlight, visiblevolumes);
2551         if (r_rtdlight)
2552                 for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
2553                         R_DrawRTLight(&light->rtlight, visiblevolumes);
2554
2555         if (visiblevolumes)
2556         {
2557                 qglEnable(GL_CULL_FACE);
2558                 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
2559         }
2560         else
2561                 R_Shadow_Stage_End();
2562 }
2563
2564 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2565 typedef struct suffixinfo_s
2566 {
2567         char *suffix;
2568         qboolean flipx, flipy, flipdiagonal;
2569 }
2570 suffixinfo_t;
2571 static suffixinfo_t suffix[3][6] =
2572 {
2573         {
2574                 {"px",   false, false, false},
2575                 {"nx",   false, false, false},
2576                 {"py",   false, false, false},
2577                 {"ny",   false, false, false},
2578                 {"pz",   false, false, false},
2579                 {"nz",   false, false, false}
2580         },
2581         {
2582                 {"posx", false, false, false},
2583                 {"negx", false, false, false},
2584                 {"posy", false, false, false},
2585                 {"negy", false, false, false},
2586                 {"posz", false, false, false},
2587                 {"negz", false, false, false}
2588         },
2589         {
2590                 {"rt",    true, false,  true},
2591                 {"lf",   false,  true,  true},
2592                 {"ft",    true,  true, false},
2593                 {"bk",   false, false, false},
2594                 {"up",    true, false,  true},
2595                 {"dn",    true, false,  true}
2596         }
2597 };
2598
2599 static int componentorder[4] = {0, 1, 2, 3};
2600
2601 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2602 {
2603         int i, j, cubemapsize;
2604         qbyte *cubemappixels, *image_rgba;
2605         rtexture_t *cubemaptexture;
2606         char name[256];
2607         // must start 0 so the first loadimagepixels has no requested width/height
2608         cubemapsize = 0;
2609         cubemappixels = NULL;
2610         cubemaptexture = NULL;
2611         // keep trying different suffix groups (posx, px, rt) until one loads
2612         for (j = 0;j < 3 && !cubemappixels;j++)
2613         {
2614                 // load the 6 images in the suffix group
2615                 for (i = 0;i < 6;i++)
2616                 {
2617                         // generate an image name based on the base and and suffix
2618                         snprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2619                         // load it
2620                         if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2621                         {
2622                                 // an image loaded, make sure width and height are equal
2623                                 if (image_width == image_height)
2624                                 {
2625                                         // if this is the first image to load successfully, allocate the cubemap memory
2626                                         if (!cubemappixels && image_width >= 1)
2627                                         {
2628                                                 cubemapsize = image_width;
2629                                                 // note this clears to black, so unavailable sides are black
2630                                                 cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2631                                         }
2632                                         // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2633                                         if (cubemappixels)
2634                                                 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);
2635                                 }
2636                                 else
2637                                         Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2638                                 // free the image
2639                                 Mem_Free(image_rgba);
2640                         }
2641                 }
2642         }
2643         // if a cubemap loaded, upload it
2644         if (cubemappixels)
2645         {
2646                 if (!r_shadow_filters_texturepool)
2647                         r_shadow_filters_texturepool = R_AllocTexturePool();
2648                 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
2649                 Mem_Free(cubemappixels);
2650         }
2651         else
2652         {
2653                 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
2654                 for (j = 0;j < 3;j++)
2655                         for (i = 0;i < 6;i++)
2656                                 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2657                 Con_Print(" and was unable to find any of them.\n");
2658         }
2659         return cubemaptexture;
2660 }
2661
2662 rtexture_t *R_Shadow_Cubemap(const char *basename)
2663 {
2664         int i;
2665         for (i = 0;i < numcubemaps;i++)
2666                 if (!strcasecmp(cubemaps[i].basename, basename))
2667                         return cubemaps[i].texture;
2668         if (i >= MAX_CUBEMAPS)
2669                 return NULL;
2670         numcubemaps++;
2671         strcpy(cubemaps[i].basename, basename);
2672         cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
2673         return cubemaps[i].texture;
2674 }
2675
2676 void R_Shadow_FreeCubemaps(void)
2677 {
2678         numcubemaps = 0;
2679         R_FreeTexturePool(&r_shadow_filters_texturepool);
2680 }
2681
2682 dlight_t *R_Shadow_NewWorldLight(void)
2683 {
2684         dlight_t *light;
2685         light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
2686         light->next = r_shadow_worldlightchain;
2687         r_shadow_worldlightchain = light;
2688         return light;
2689 }
2690
2691 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)
2692 {
2693         VectorCopy(origin, light->origin);
2694         light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
2695         light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
2696         light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
2697         light->color[0] = max(color[0], 0);
2698         light->color[1] = max(color[1], 0);
2699         light->color[2] = max(color[2], 0);
2700         light->radius = max(radius, 0);
2701         light->style = style;
2702         if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
2703         {
2704                 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
2705                 light->style = 0;
2706         }
2707         light->shadow = shadowenable;
2708         light->corona = corona;
2709         if (!cubemapname)
2710                 cubemapname = "";
2711         strlcpy(light->cubemapname, cubemapname, strlen(light->cubemapname));
2712         light->coronasizescale = coronasizescale;
2713         light->ambientscale = ambientscale;
2714         light->diffusescale = diffusescale;
2715         light->specularscale = specularscale;
2716         light->flags = flags;
2717         Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
2718
2719         R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
2720 }
2721
2722 void R_Shadow_FreeWorldLight(dlight_t *light)
2723 {
2724         dlight_t **lightpointer;
2725         R_RTLight_Uncompile(&light->rtlight);
2726         for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
2727         if (*lightpointer != light)
2728                 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
2729         *lightpointer = light->next;
2730         Mem_Free(light);
2731 }
2732
2733 void R_Shadow_ClearWorldLights(void)
2734 {
2735         while (r_shadow_worldlightchain)
2736                 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
2737         r_shadow_selectedlight = NULL;
2738         R_Shadow_FreeCubemaps();
2739 }
2740
2741 void R_Shadow_SelectLight(dlight_t *light)
2742 {
2743         if (r_shadow_selectedlight)
2744                 r_shadow_selectedlight->selected = false;
2745         r_shadow_selectedlight = light;
2746         if (r_shadow_selectedlight)
2747                 r_shadow_selectedlight->selected = true;
2748 }
2749
2750 void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
2751 {
2752         float scale = r_editlights_cursorgrid.value * 0.5f;
2753         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);
2754 }
2755
2756 void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
2757 {
2758         float intensity;
2759         const dlight_t *light;
2760         light = calldata1;
2761         intensity = 0.5;
2762         if (light->selected)
2763                 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
2764         if (!light->shadow)
2765                 intensity *= 0.5f;
2766         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);
2767 }
2768
2769 void R_Shadow_DrawLightSprites(void)
2770 {
2771         int i;
2772         cachepic_t *pic;
2773         dlight_t *light;
2774
2775         for (i = 0;i < 5;i++)
2776         {
2777                 lighttextures[i] = NULL;
2778                 if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1))))
2779                         lighttextures[i] = pic->tex;
2780         }
2781
2782         for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
2783                 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, i % 5);
2784         R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
2785 }
2786
2787 void R_Shadow_SelectLightInView(void)
2788 {
2789         float bestrating, rating, temp[3];
2790         dlight_t *best, *light;
2791         best = NULL;
2792         bestrating = 0;
2793         for (light = r_shadow_worldlightchain;light;light = light->next)
2794         {
2795                 VectorSubtract(light->origin, r_vieworigin, temp);
2796                 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
2797                 if (rating >= 0.95)
2798                 {
2799                         rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
2800                         if (bestrating < rating && CL_TraceLine(light->origin, r_vieworigin, NULL, NULL, true, NULL, SUPERCONTENTS_SOLID) == 1.0f)
2801                         {
2802                                 bestrating = rating;
2803                                 best = light;
2804                         }
2805                 }
2806         }
2807         R_Shadow_SelectLight(best);
2808 }
2809
2810 void R_Shadow_LoadWorldLights(void)
2811 {
2812         int n, a, style, shadow, flags;
2813         char name[MAX_QPATH], cubemapname[MAX_QPATH], *lightsstring, *s, *t;
2814         float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
2815         if (r_refdef.worldmodel == NULL)
2816         {
2817                 Con_Print("No map loaded.\n");
2818                 return;
2819         }
2820         FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
2821         strlcat (name, ".rtlights", sizeof (name));
2822         lightsstring = FS_LoadFile(name, tempmempool, false);
2823         if (lightsstring)
2824         {
2825                 s = lightsstring;
2826                 n = 0;
2827                 while (*s)
2828                 {
2829                         t = s;
2830                         /*
2831                         shadow = true;
2832                         for (;COM_Parse(t, true) && strcmp(
2833                         if (COM_Parse(t, true))
2834                         {
2835                                 if (com_token[0] == '!')
2836                                 {
2837                                         shadow = false;
2838                                         origin[0] = atof(com_token+1);
2839                                 }
2840                                 else
2841                                         origin[0] = atof(com_token);
2842                                 if (Com_Parse(t
2843                         }
2844                         */
2845                         t = s;
2846                         while (*s && *s != '\n')
2847                                 s++;
2848                         if (!*s)
2849                                 break;
2850                         *s = 0;
2851                         shadow = true;
2852                         // check for modifier flags
2853                         if (*t == '!')
2854                         {
2855                                 shadow = false;
2856                                 t++;
2857                         }
2858                         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);
2859                         if (a < 18)
2860                                 flags = LIGHTFLAG_REALTIMEMODE;
2861                         if (a < 17)
2862                                 specularscale = 1;
2863                         if (a < 16)
2864                                 diffusescale = 1;
2865                         if (a < 15)
2866                                 ambientscale = 0;
2867                         if (a < 14)
2868                                 coronasizescale = 0.25f;
2869                         if (a < 13)
2870                                 VectorClear(angles);
2871                         if (a < 10)
2872                                 corona = 0;
2873                         if (a < 9 || !strcmp(cubemapname, "\"\""))
2874                                 cubemapname[0] = 0;
2875                         *s = '\n';
2876                         if (a < 8)
2877                         {
2878                                 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);
2879                                 break;
2880                         }
2881                         VectorScale(color, r_editlights_rtlightscolorscale.value, color);
2882                         radius *= r_editlights_rtlightssizescale.value;
2883                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
2884                         s++;
2885                         n++;
2886                 }
2887                 if (*s)
2888                         Con_Printf("invalid rtlights file \"%s\"\n", name);
2889                 Mem_Free(lightsstring);
2890         }
2891 }
2892
2893 void R_Shadow_SaveWorldLights(void)
2894 {
2895         dlight_t *light;
2896         int bufchars, bufmaxchars;
2897         char *buf, *oldbuf;
2898         char name[MAX_QPATH];
2899         char line[1024];
2900         if (!r_shadow_worldlightchain)
2901                 return;
2902         if (r_refdef.worldmodel == NULL)
2903         {
2904                 Con_Print("No map loaded.\n");
2905                 return;
2906         }
2907         FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
2908         strlcat (name, ".rtlights", sizeof (name));
2909         bufchars = bufmaxchars = 0;
2910         buf = NULL;
2911         for (light = r_shadow_worldlightchain;light;light = light->next)
2912         {
2913                 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
2914                         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);
2915                 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
2916                         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]);
2917                 else
2918                         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);
2919                 if (bufchars + (int) strlen(line) > bufmaxchars)
2920                 {
2921                         bufmaxchars = bufchars + strlen(line) + 2048;
2922                         oldbuf = buf;
2923                         buf = Mem_Alloc(r_shadow_mempool, bufmaxchars);
2924                         if (oldbuf)
2925                         {
2926                                 if (bufchars)
2927                                         memcpy(buf, oldbuf, bufchars);
2928                                 Mem_Free(oldbuf);
2929                         }
2930                 }
2931                 if (strlen(line))
2932                 {
2933                         memcpy(buf + bufchars, line, strlen(line));
2934                         bufchars += strlen(line);
2935                 }
2936         }
2937         if (bufchars)
2938                 FS_WriteFile(name, buf, bufchars);
2939         if (buf)
2940                 Mem_Free(buf);
2941 }
2942
2943 void R_Shadow_LoadLightsFile(void)
2944 {
2945         int n, a, style;
2946         char name[MAX_QPATH], *lightsstring, *s, *t;
2947         float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
2948         if (r_refdef.worldmodel == NULL)
2949         {
2950                 Con_Print("No map loaded.\n");
2951                 return;
2952         }
2953         FS_StripExtension (r_refdef.worldmodel->name, name, sizeof (name));
2954         strlcat (name, ".lights", sizeof (name));
2955         lightsstring = FS_LoadFile(name, tempmempool, false);
2956         if (lightsstring)
2957         {
2958                 s = lightsstring;
2959                 n = 0;
2960                 while (*s)
2961                 {
2962                         t = s;
2963                         while (*s && *s != '\n')
2964                                 s++;
2965                         if (!*s)
2966                                 break;
2967                         *s = 0;
2968                         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);
2969                         *s = '\n';
2970                         if (a < 14)
2971                         {
2972                                 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);
2973                                 break;
2974                         }
2975                         radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
2976                         radius = bound(15, radius, 4096);
2977                         VectorScale(color, (2.0f / (8388608.0f)), color);
2978                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
2979                         s++;
2980                         n++;
2981                 }
2982                 if (*s)
2983                         Con_Printf("invalid lights file \"%s\"\n", name);
2984                 Mem_Free(lightsstring);
2985         }
2986 }
2987
2988 // tyrlite/hmap2 light types in the delay field
2989 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
2990
2991 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
2992 {
2993         int entnum, style, islight, skin, pflags, effects, type, n;
2994         char *entfiledata;
2995         const char *data;
2996         float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
2997         char key[256], value[1024];
2998
2999         if (r_refdef.worldmodel == NULL)
3000         {
3001                 Con_Print("No map loaded.\n");
3002                 return;
3003         }
3004         // try to load a .ent file first
3005         FS_StripExtension (r_refdef.worldmodel->name, key, sizeof (key));
3006         strlcat (key, ".ent", sizeof (key));
3007         data = entfiledata = FS_LoadFile(key, tempmempool, true);
3008         // and if that is not found, fall back to the bsp file entity string
3009         if (!data)
3010                 data = r_refdef.worldmodel->brush.entities;
3011         if (!data)
3012                 return;
3013         for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
3014         {
3015                 type = LIGHTTYPE_MINUSX;
3016                 origin[0] = origin[1] = origin[2] = 0;
3017                 originhack[0] = originhack[1] = originhack[2] = 0;
3018                 angles[0] = angles[1] = angles[2] = 0;
3019                 color[0] = color[1] = color[2] = 1;
3020                 light[0] = light[1] = light[2] = 1;light[3] = 300;
3021                 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
3022                 fadescale = 1;
3023                 lightscale = 1;
3024                 style = 0;
3025                 skin = 0;
3026                 pflags = 0;
3027                 effects = 0;
3028                 islight = false;
3029                 while (1)
3030                 {
3031                         if (!COM_ParseToken(&data, false))
3032                                 break; // error
3033                         if (com_token[0] == '}')
3034                                 break; // end of entity
3035                         if (com_token[0] == '_')
3036                                 strcpy(key, com_token + 1);
3037                         else
3038                                 strcpy(key, com_token);
3039                         while (key[strlen(key)-1] == ' ') // remove trailing spaces
3040                                 key[strlen(key)-1] = 0;
3041                         if (!COM_ParseToken(&data, false))
3042                                 break; // error
3043                         strcpy(value, com_token);
3044
3045                         // now that we have the key pair worked out...
3046                         if (!strcmp("light", key))
3047                         {
3048                                 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
3049                                 if (n == 1)
3050                                 {
3051                                         // quake
3052                                         light[0] = vec[0] * (1.0f / 256.0f);
3053                                         light[1] = vec[0] * (1.0f / 256.0f);
3054                                         light[2] = vec[0] * (1.0f / 256.0f);
3055                                         light[3] = vec[0];
3056                                 }
3057                                 else if (n == 4)
3058                                 {
3059                                         // halflife
3060                                         light[0] = vec[0] * (1.0f / 255.0f);
3061                                         light[1] = vec[1] * (1.0f / 255.0f);
3062                                         light[2] = vec[2] * (1.0f / 255.0f);
3063                                         light[3] = vec[3];
3064                                 }
3065                         }
3066                         else if (!strcmp("delay", key))
3067                                 type = atoi(value);
3068                         else if (!strcmp("origin", key))
3069                                 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
3070                         else if (!strcmp("angle", key))
3071                                 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
3072                         else if (!strcmp("angles", key))
3073                                 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
3074                         else if (!strcmp("color", key))
3075                                 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
3076                         else if (!strcmp("wait", key))
3077                                 fadescale = atof(value);
3078                         else if (!strcmp("classname", key))
3079                         {
3080                                 if (!strncmp(value, "light", 5))
3081                                 {
3082                                         islight = true;
3083                                         if (!strcmp(value, "light_fluoro"))
3084                                         {
3085                                                 originhack[0] = 0;
3086                                                 originhack[1] = 0;
3087                                                 originhack[2] = 0;
3088                                                 overridecolor[0] = 1;
3089                                                 overridecolor[1] = 1;
3090                                                 overridecolor[2] = 1;
3091                                         }
3092                                         if (!strcmp(value, "light_fluorospark"))
3093                                         {
3094                                                 originhack[0] = 0;
3095                                                 originhack[1] = 0;
3096                                                 originhack[2] = 0;
3097                                                 overridecolor[0] = 1;
3098                                                 overridecolor[1] = 1;
3099                                                 overridecolor[2] = 1;
3100                                         }
3101                                         if (!strcmp(value, "light_globe"))
3102                                         {
3103                                                 originhack[0] = 0;
3104                                                 originhack[1] = 0;
3105                                                 originhack[2] = 0;
3106                                                 overridecolor[0] = 1;
3107                                                 overridecolor[1] = 0.8;
3108                                                 overridecolor[2] = 0.4;
3109                                         }
3110                                         if (!strcmp(value, "light_flame_large_yellow"))
3111                                         {
3112                                                 originhack[0] = 0;
3113                                                 originhack[1] = 0;
3114                                                 originhack[2] = 48;
3115                                                 overridecolor[0] = 1;
3116                                                 overridecolor[1] = 0.5;
3117                                                 overridecolor[2] = 0.1;
3118                                         }
3119                                         if (!strcmp(value, "light_flame_small_yellow"))
3120                                         {
3121                                                 originhack[0] = 0;
3122                                                 originhack[1] = 0;
3123                                                 originhack[2] = 40;
3124                                                 overridecolor[0] = 1;
3125                                                 overridecolor[1] = 0.5;
3126                                                 overridecolor[2] = 0.1;
3127                                         }
3128                                         if (!strcmp(value, "light_torch_small_white"))
3129                                         {
3130                                                 originhack[0] = 0;
3131                                                 originhack[1] = 0;
3132                                                 originhack[2] = 40;
3133                                                 overridecolor[0] = 1;
3134                                                 overridecolor[1] = 0.5;
3135                                                 overridecolor[2] = 0.1;
3136                                         }
3137                                         if (!strcmp(value, "light_torch_small_walltorch"))
3138                                         {
3139                                                 originhack[0] = 0;
3140                                                 originhack[1] = 0;
3141                                                 originhack[2] = 40;
3142                                                 overridecolor[0] = 1;
3143                                                 overridecolor[1] = 0.5;
3144                                                 overridecolor[2] = 0.1;
3145                                         }
3146                                 }
3147                         }
3148                         else if (!strcmp("style", key))
3149                                 style = atoi(value);
3150                         else if (r_refdef.worldmodel->type == mod_brushq3)
3151                         {
3152                                 if (!strcmp("scale", key))
3153                                         lightscale = atof(value);
3154                                 if (!strcmp("fade", key))
3155                                         fadescale = atof(value);
3156                         }
3157                         else if (!strcmp("skin", key))
3158                                 skin = (int)atof(value);
3159                         else if (!strcmp("pflags", key))
3160                                 pflags = (int)atof(value);
3161                         else if (!strcmp("effects", key))
3162                                 effects = (int)atof(value);
3163                 }
3164                 if (!islight)
3165                         continue;
3166                 if (lightscale <= 0)
3167                         lightscale = 1;
3168                 if (fadescale <= 0)
3169                         fadescale = 1;
3170                 if (color[0] == color[1] && color[0] == color[2])
3171                 {
3172                         color[0] *= overridecolor[0];
3173                         color[1] *= overridecolor[1];
3174                         color[2] *= overridecolor[2];
3175                 }
3176                 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
3177                 color[0] = color[0] * light[0];
3178                 color[1] = color[1] * light[1];
3179                 color[2] = color[2] * light[2];
3180                 switch (type)
3181                 {
3182                 case LIGHTTYPE_MINUSX:
3183                         break;
3184                 case LIGHTTYPE_RECIPX:
3185                         radius *= 2;
3186                         VectorScale(color, (1.0f / 16.0f), color);
3187                         break;
3188                 case LIGHTTYPE_RECIPXX:
3189                         radius *= 2;
3190                         VectorScale(color, (1.0f / 16.0f), color);
3191                         break;
3192                 default:
3193                 case LIGHTTYPE_NONE:
3194                         break;
3195                 case LIGHTTYPE_SUN:
3196                         break;
3197                 case LIGHTTYPE_MINUSXX:
3198                         break;
3199                 }
3200                 VectorAdd(origin, originhack, origin);
3201                 if (radius >= 1)
3202                         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);
3203         }
3204         if (entfiledata)
3205                 Mem_Free(entfiledata);
3206 }
3207
3208
3209 void R_Shadow_SetCursorLocationForView(void)
3210 {
3211         vec_t dist, push, frac;
3212         vec3_t dest, endpos, normal;
3213         VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
3214         frac = CL_TraceLine(r_vieworigin, dest, endpos, normal, true, NULL, SUPERCONTENTS_SOLID);
3215         if (frac < 1)
3216         {
3217                 dist = frac * r_editlights_cursordistance.value;
3218                 push = r_editlights_cursorpushback.value;
3219                 if (push > dist)
3220                         push = dist;
3221                 push = -push;
3222                 VectorMA(endpos, push, r_viewforward, endpos);
3223                 VectorMA(endpos, r_editlights_cursorpushoff.value, normal, endpos);
3224         }
3225         r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3226         r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3227         r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
3228 }
3229
3230 void R_Shadow_UpdateWorldLightSelection(void)
3231 {
3232         if (r_editlights.integer)
3233         {
3234                 R_Shadow_SetCursorLocationForView();
3235                 R_Shadow_SelectLightInView();
3236                 R_Shadow_DrawLightSprites();
3237         }
3238         else
3239                 R_Shadow_SelectLight(NULL);
3240 }
3241
3242 void R_Shadow_EditLights_Clear_f(void)
3243 {
3244         R_Shadow_ClearWorldLights();
3245 }
3246
3247 void R_Shadow_EditLights_Reload_f(void)
3248 {
3249         if (!r_refdef.worldmodel)
3250                 return;
3251         strlcpy(r_shadow_mapname, r_refdef.worldmodel->name, sizeof(r_shadow_mapname));
3252         R_Shadow_ClearWorldLights();
3253         R_Shadow_LoadWorldLights();
3254         if (r_shadow_worldlightchain == NULL)
3255         {
3256                 R_Shadow_LoadLightsFile();
3257                 if (r_shadow_worldlightchain == NULL)
3258                         R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3259         }
3260 }
3261
3262 void R_Shadow_EditLights_Save_f(void)
3263 {
3264         if (!r_refdef.worldmodel)
3265                 return;
3266         R_Shadow_SaveWorldLights();
3267 }
3268
3269 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
3270 {
3271         R_Shadow_ClearWorldLights();
3272         R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
3273 }
3274
3275 void R_Shadow_EditLights_ImportLightsFile_f(void)
3276 {
3277         R_Shadow_ClearWorldLights();
3278         R_Shadow_LoadLightsFile();
3279 }
3280
3281 void R_Shadow_EditLights_Spawn_f(void)
3282 {
3283         vec3_t color;
3284         if (!r_editlights.integer)
3285         {
3286                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
3287                 return;
3288         }
3289         if (Cmd_Argc() != 1)
3290         {
3291                 Con_Print("r_editlights_spawn does not take parameters\n");
3292                 return;
3293         }
3294         color[0] = color[1] = color[2] = 1;
3295         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
3296 }
3297
3298 void R_Shadow_EditLights_Edit_f(void)
3299 {
3300         vec3_t origin, angles, color;
3301         vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
3302         int style, shadows, flags, normalmode, realtimemode;
3303         char cubemapname[1024];
3304         if (!r_editlights.integer)
3305         {
3306                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
3307                 return;
3308         }
3309         if (!r_shadow_selectedlight)
3310         {
3311                 Con_Print("No selected light.\n");
3312                 return;
3313         }
3314         VectorCopy(r_shadow_selectedlight->origin, origin);
3315         VectorCopy(r_shadow_selectedlight->angles, angles);
3316         VectorCopy(r_shadow_selectedlight->color, color);
3317         radius = r_shadow_selectedlight->radius;
3318         style = r_shadow_selectedlight->style;
3319         if (r_shadow_selectedlight->cubemapname)
3320                 strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
3321         else
3322                 cubemapname[0] = 0;
3323         shadows = r_shadow_selectedlight->shadow;
3324         corona = r_shadow_selectedlight->corona;
3325         coronasizescale = r_shadow_selectedlight->coronasizescale;
3326         ambientscale = r_shadow_selectedlight->ambientscale;
3327         diffusescale = r_shadow_selectedlight->diffusescale;
3328         specularscale = r_shadow_selectedlight->specularscale;
3329         flags = r_shadow_selectedlight->flags;
3330         normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
3331         realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
3332         if (!strcmp(Cmd_Argv(1), "origin"))
3333         {
3334                 if (Cmd_Argc() != 5)
3335                 {
3336                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3337                         return;
3338                 }
3339                 origin[0] = atof(Cmd_Argv(2));
3340                 origin[1] = atof(Cmd_Argv(3));
3341                 origin[2] = atof(Cmd_Argv(4));
3342         }
3343         else if (!strcmp(Cmd_Argv(1), "originx"))
3344         {
3345                 if (Cmd_Argc() != 3)
3346                 {
3347                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3348                         return;
3349                 }
3350                 origin[0] = atof(Cmd_Argv(2));
3351         }
3352         else if (!strcmp(Cmd_Argv(1), "originy"))
3353         {
3354                 if (Cmd_Argc() != 3)
3355                 {
3356                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3357                         return;
3358                 }
3359                 origin[1] = atof(Cmd_Argv(2));
3360         }
3361         else if (!strcmp(Cmd_Argv(1), "originz"))
3362         {
3363                 if (Cmd_Argc() != 3)
3364                 {
3365                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3366                         return;
3367                 }
3368                 origin[2] = atof(Cmd_Argv(2));
3369         }
3370         else if (!strcmp(Cmd_Argv(1), "move"))
3371         {
3372                 if (Cmd_Argc() != 5)
3373                 {
3374                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3375                         return;
3376                 }
3377                 origin[0] += atof(Cmd_Argv(2));
3378                 origin[1] += atof(Cmd_Argv(3));
3379                 origin[2] += atof(Cmd_Argv(4));
3380         }
3381         else if (!strcmp(Cmd_Argv(1), "movex"))
3382         {
3383                 if (Cmd_Argc() != 3)
3384                 {
3385                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3386                         return;
3387                 }
3388                 origin[0] += atof(Cmd_Argv(2));
3389         }
3390         else if (!strcmp(Cmd_Argv(1), "movey"))
3391         {
3392                 if (Cmd_Argc() != 3)
3393                 {
3394                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3395                         return;
3396                 }
3397                 origin[1] += atof(Cmd_Argv(2));
3398         }
3399         else if (!strcmp(Cmd_Argv(1), "movez"))
3400         {
3401                 if (Cmd_Argc() != 3)
3402                 {
3403                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3404                         return;
3405                 }
3406                 origin[2] += atof(Cmd_Argv(2));
3407         }
3408         else if (!strcmp(Cmd_Argv(1), "angles"))
3409         {
3410                 if (Cmd_Argc() != 5)
3411                 {
3412                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3413                         return;
3414                 }
3415                 angles[0] = atof(Cmd_Argv(2));
3416                 angles[1] = atof(Cmd_Argv(3));
3417                 angles[2] = atof(Cmd_Argv(4));
3418         }
3419         else if (!strcmp(Cmd_Argv(1), "anglesx"))
3420         {
3421                 if (Cmd_Argc() != 3)
3422                 {
3423                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3424                         return;
3425                 }
3426                 angles[0] = atof(Cmd_Argv(2));
3427         }
3428         else if (!strcmp(Cmd_Argv(1), "anglesy"))
3429         {
3430                 if (Cmd_Argc() != 3)
3431                 {
3432                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3433                         return;
3434                 }
3435                 angles[1] = atof(Cmd_Argv(2));
3436         }
3437         else if (!strcmp(Cmd_Argv(1), "anglesz"))
3438         {
3439                 if (Cmd_Argc() != 3)
3440                 {
3441                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3442                         return;
3443                 }
3444                 angles[2] = atof(Cmd_Argv(2));
3445         }
3446         else if (!strcmp(Cmd_Argv(1), "color"))
3447         {
3448                 if (Cmd_Argc() != 5)
3449                 {
3450                         Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3451                         return;
3452                 }
3453                 color[0] = atof(Cmd_Argv(2));
3454                 color[1] = atof(Cmd_Argv(3));
3455                 color[2] = atof(Cmd_Argv(4));
3456         }
3457         else if (!strcmp(Cmd_Argv(1), "radius"))
3458         {
3459                 if (Cmd_Argc() != 3)
3460                 {
3461                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3462                         return;
3463                 }
3464                 radius = atof(Cmd_Argv(2));
3465         }
3466         else if (!strcmp(Cmd_Argv(1), "style"))
3467         {
3468                 if (Cmd_Argc() != 3)
3469                 {
3470                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3471                         return;
3472                 }
3473                 style = atoi(Cmd_Argv(2));
3474         }
3475         else if (!strcmp(Cmd_Argv(1), "cubemap"))
3476         {
3477                 if (Cmd_Argc() > 3)
3478                 {
3479                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3480                         return;
3481                 }
3482                 if (Cmd_Argc() == 3)
3483                         strcpy(cubemapname, Cmd_Argv(2));
3484                 else
3485                         cubemapname[0] = 0;
3486         }
3487         else if (!strcmp(Cmd_Argv(1), "shadows"))
3488         {
3489                 if (Cmd_Argc() != 3)
3490                 {
3491                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3492                         return;
3493                 }
3494                 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3495         }
3496         else if (!strcmp(Cmd_Argv(1), "corona"))
3497         {
3498                 if (Cmd_Argc() != 3)
3499                 {
3500                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3501                         return;
3502                 }
3503                 corona = atof(Cmd_Argv(2));
3504         }
3505         else if (!strcmp(Cmd_Argv(1), "coronasize"))
3506         {
3507                 if (Cmd_Argc() != 3)
3508                 {
3509                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3510                         return;
3511                 }
3512                 coronasizescale = atof(Cmd_Argv(2));
3513         }
3514         else if (!strcmp(Cmd_Argv(1), "ambient"))
3515         {
3516                 if (Cmd_Argc() != 3)
3517                 {
3518                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3519                         return;
3520                 }
3521                 ambientscale = atof(Cmd_Argv(2));
3522         }
3523         else if (!strcmp(Cmd_Argv(1), "diffuse"))
3524         {
3525                 if (Cmd_Argc() != 3)
3526                 {
3527                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3528                         return;
3529                 }
3530                 diffusescale = atof(Cmd_Argv(2));
3531         }
3532         else if (!strcmp(Cmd_Argv(1), "specular"))
3533         {
3534                 if (Cmd_Argc() != 3)
3535                 {
3536                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3537                         return;
3538                 }
3539                 specularscale = atof(Cmd_Argv(2));
3540         }
3541         else if (!strcmp(Cmd_Argv(1), "normalmode"))
3542         {
3543                 if (Cmd_Argc() != 3)
3544                 {
3545                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3546                         return;
3547                 }
3548                 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3549         }
3550         else if (!strcmp(Cmd_Argv(1), "realtimemode"))
3551         {
3552                 if (Cmd_Argc() != 3)
3553                 {
3554                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3555                         return;
3556                 }
3557                 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3558         }
3559         else
3560         {
3561                 Con_Print("usage: r_editlights_edit [property] [value]\n");
3562                 Con_Print("Selected light's properties:\n");
3563                 Con_Printf("Origin       : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3564                 Con_Printf("Angles       : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3565                 Con_Printf("Color        : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3566                 Con_Printf("Radius       : %f\n", r_shadow_selectedlight->radius);
3567                 Con_Printf("Corona       : %f\n", r_shadow_selectedlight->corona);
3568                 Con_Printf("Style        : %i\n", r_shadow_selectedlight->style);
3569                 Con_Printf("Shadows      : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3570                 Con_Printf("Cubemap      : %s\n", r_shadow_selectedlight->cubemapname);
3571                 Con_Printf("CoronaSize   : %f\n", r_shadow_selectedlight->coronasizescale);
3572                 Con_Printf("Ambient      : %f\n", r_shadow_selectedlight->ambientscale);
3573                 Con_Printf("Diffuse      : %f\n", r_shadow_selectedlight->diffusescale);
3574                 Con_Printf("Specular     : %f\n", r_shadow_selectedlight->specularscale);
3575                 Con_Printf("NormalMode   : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
3576                 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
3577                 return;
3578         }
3579         flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
3580         R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
3581 }
3582
3583 void R_Shadow_EditLights_EditAll_f(void)
3584 {
3585         dlight_t *light;
3586
3587         if (!r_editlights.integer)
3588         {
3589                 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
3590                 return;
3591         }
3592
3593         for (light = r_shadow_worldlightchain;light;light = light->next)
3594         {
3595                 R_Shadow_SelectLight(light);
3596                 R_Shadow_EditLights_Edit_f();
3597         }
3598 }
3599
3600 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3601 {
3602         int lightnumber, lightcount;
3603         dlight_t *light;
3604         float x, y;
3605         char temp[256];
3606         if (!r_editlights.integer)
3607                 return;
3608         x = 0;
3609         y = con_vislines;
3610         lightnumber = -1;
3611         lightcount = 0;
3612         for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next)
3613                 if (light == r_shadow_selectedlight)
3614                         lightnumber = lightcount;
3615         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;
3616         if (r_shadow_selectedlight == NULL)
3617                 return;
3618         sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3619         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;
3620         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;
3621         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;
3622         sprintf(temp, "Radius       : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3623         sprintf(temp, "Corona       : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3624         sprintf(temp, "Style        : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3625         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;
3626         sprintf(temp, "Cubemap      : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3627         sprintf(temp, "CoronaSize   : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3628         sprintf(temp, "Ambient      : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3629         sprintf(temp, "Diffuse      : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3630         sprintf(temp, "Specular     : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3631         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;
3632         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;
3633 }                 
3634
3635 void R_Shadow_EditLights_ToggleShadow_f(void)
3636 {
3637         if (!r_editlights.integer)
3638         {
3639                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
3640                 return;
3641         }
3642         if (!r_shadow_selectedlight)
3643         {
3644                 Con_Print("No selected light.\n");
3645                 return;
3646         }
3647         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);
3648 }
3649
3650 void R_Shadow_EditLights_ToggleCorona_f(void)
3651 {
3652         if (!r_editlights.integer)
3653         {
3654                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
3655                 return;
3656         }
3657         if (!r_shadow_selectedlight)
3658         {
3659                 Con_Print("No selected light.\n");
3660                 return;
3661         }
3662         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);
3663 }
3664
3665 void R_Shadow_EditLights_Remove_f(void)
3666 {
3667         if (!r_editlights.integer)
3668         {
3669                 Con_Print("Cannot remove light when not in editing mode.  Set r_editlights to 1.\n");
3670                 return;
3671         }
3672         if (!r_shadow_selectedlight)
3673         {
3674                 Con_Print("No selected light.\n");
3675                 return;
3676         }
3677         R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3678         r_shadow_selectedlight = NULL;
3679 }
3680
3681 void R_Shadow_EditLights_Help_f(void)
3682 {
3683         Con_Print(
3684 "Documentation on r_editlights system:\n"
3685 "Settings:\n"
3686 "r_editlights : enable/disable editing mode\n"
3687 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
3688 "r_editlights_cursorpushback : push back cursor this far from surface\n"
3689 "r_editlights_cursorpushoff : push cursor off surface this far\n"
3690 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
3691 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
3692 "r_editlights_rtlightssizescale : imported rtlight size scaling\n"
3693 "r_editlights_rtlightscolorscale : imported rtlight color scaling\n"
3694 "Commands:\n"
3695 "r_editlights_help : this help\n"
3696 "r_editlights_clear : remove all lights\n"
3697 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
3698 "r_editlights_save : save to .rtlights file\n"
3699 "r_editlights_spawn : create a light with default settings\n"
3700 "r_editlights_edit command : edit selected light - more documentation below\n"
3701 "r_editlights_remove : remove selected light\n"
3702 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
3703 "r_editlights_importlightentitiesfrommap : reload light entities\n"
3704 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
3705 "Edit commands:\n"
3706 "origin x y z : set light location\n"
3707 "originx x: set x component of light location\n"
3708 "originy y: set y component of light location\n"
3709 "originz z: set z component of light location\n"
3710 "move x y z : adjust light location\n"
3711 "movex x: adjust x component of light location\n"
3712 "movey y: adjust y component of light location\n"
3713 "movez z: adjust z component of light location\n"
3714 "angles x y z : set light angles\n"
3715 "anglesx x: set x component of light angles\n"
3716 "anglesy y: set y component of light angles\n"
3717 "anglesz z: set z component of light angles\n"
3718 "color r g b : set color of light (can be brighter than 1 1 1)\n"
3719 "radius radius : set radius (size) of light\n"
3720 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
3721 "cubemap basename : set filter cubemap of light (not yet supported)\n"
3722 "shadows 1/0 : turn on/off shadows\n"
3723 "corona n : set corona intensity\n"
3724 "coronasize n : set corona size (0-1)\n"
3725 "ambient n : set ambient intensity (0-1)\n"
3726 "diffuse n : set diffuse intensity (0-1)\n"
3727 "specular n : set specular intensity (0-1)\n"
3728 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
3729 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
3730 "<nothing> : print light properties to console\n"
3731         );
3732 }
3733
3734 void R_Shadow_EditLights_CopyInfo_f(void)
3735 {
3736         if (!r_editlights.integer)
3737         {
3738                 Con_Print("Cannot copy light info when not in editing mode.  Set r_editlights to 1.\n");
3739                 return;
3740         }
3741         if (!r_shadow_selectedlight)
3742         {
3743                 Con_Print("No selected light.\n");
3744                 return;
3745         }
3746         VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
3747         VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
3748         r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
3749         r_shadow_bufferlight.style = r_shadow_selectedlight->style;
3750         if (r_shadow_selectedlight->cubemapname)
3751                 strcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname);
3752         else
3753                 r_shadow_bufferlight.cubemapname[0] = 0;
3754         r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
3755         r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
3756         r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
3757         r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
3758         r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
3759         r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
3760         r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
3761 }
3762
3763 void R_Shadow_EditLights_PasteInfo_f(void)
3764 {
3765         if (!r_editlights.integer)
3766         {
3767                 Con_Print("Cannot paste light info when not in editing mode.  Set r_editlights to 1.\n");
3768                 return;
3769         }
3770         if (!r_shadow_selectedlight)
3771         {
3772                 Con_Print("No selected light.\n");
3773                 return;
3774         }
3775         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);
3776 }
3777
3778 void R_Shadow_EditLights_Init(void)
3779 {
3780         Cvar_RegisterVariable(&r_editlights);
3781         Cvar_RegisterVariable(&r_editlights_cursordistance);
3782         Cvar_RegisterVariable(&r_editlights_cursorpushback);
3783         Cvar_RegisterVariable(&r_editlights_cursorpushoff);
3784         Cvar_RegisterVariable(&r_editlights_cursorgrid);
3785         Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
3786         Cvar_RegisterVariable(&r_editlights_rtlightssizescale);
3787         Cvar_RegisterVariable(&r_editlights_rtlightscolorscale);
3788         Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
3789         Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
3790         Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
3791         Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
3792         Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
3793         Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
3794         Cmd_AddCommand("r_editlights_editall", R_Shadow_EditLights_EditAll_f);
3795         Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
3796         Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
3797         Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
3798         Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
3799         Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);
3800         Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f);
3801         Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f);
3802 }
3803