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