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