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