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