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