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