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