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)
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.
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).
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
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).
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
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.
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.
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.
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).
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.
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.
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).
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.
114 #include "quakedef.h"
115 #include "r_shadow.h"
116 #include "cl_collision.h"
120 extern void R_Shadow_EditLights_Init(void);
122 #define SHADOWSTAGE_NONE 0
123 #define SHADOWSTAGE_STENCIL 1
124 #define SHADOWSTAGE_LIGHT 2
125 #define SHADOWSTAGE_STENCILTWOSIDE 3
127 int r_shadowstage = SHADOWSTAGE_NONE;
128 int r_shadow_reloadlights = false;
130 mempool_t *r_shadow_mempool;
132 int maxshadowelements;
146 int r_shadow_buffer_numclusterpvsbytes;
147 qbyte *r_shadow_buffer_clusterpvs;
148 int *r_shadow_buffer_clusterlist;
150 int r_shadow_buffer_numsurfacepvsbytes;
151 qbyte *r_shadow_buffer_surfacepvs;
152 int *r_shadow_buffer_surfacelist;
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;
162 // used only for light filters (cubemaps)
163 rtexturepool_t *r_shadow_filters_texturepool;
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"};
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;
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);
201 void r_shadow_start(void)
203 // allocate vertex processing arrays
204 r_shadow_mempool = Mem_AllocPool("R_Shadow");
205 maxshadowelements = 0;
206 shadowelements = NULL;
214 shadowmarklist = NULL;
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;
234 void r_shadow_shutdown(void)
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;
255 shadowmarklist = NULL;
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);
266 void r_shadow_newmap(void)
268 R_Shadow_ClearWorldLights();
269 r_shadow_reloadlights = true;
272 void R_Shadow_Help_f(void)
275 "Documentation on r_shadow system:\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"
300 "r_shadow_help : this help\n"
304 void R_Shadow_Init(void)
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)
333 Cvar_SetValue("r_shadow_gloss", 2);
334 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
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);
341 matrix4x4_t matrix_attenuationxyz =
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},
351 matrix4x4_t matrix_attenuationz =
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},
361 int *R_Shadow_ResizeShadowElements(int numtris)
363 // make sure shadowelements is big enough for this volume
364 if (maxshadowelements < numtris * 24)
366 maxshadowelements = numtris * 24;
368 Mem_Free(shadowelements);
369 shadowelements = Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int));
371 return shadowelements;
374 void R_Shadow_EnlargeClusterBuffer(int numclusters)
376 int numclusterpvsbytes = (((numclusters + 7) >> 3) + 255) & ~255;
377 if (r_shadow_buffer_numclusterpvsbytes < numclusterpvsbytes)
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));
389 void R_Shadow_EnlargeSurfaceBuffer(int numsurfaces)
391 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
392 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
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));
404 void R_Shadow_PrepareShadowMark(int numtris)
406 // make sure shadowmark is big enough for this volume
407 if (maxshadowmark < numtris)
409 maxshadowmark = numtris;
411 Mem_Free(shadowmark);
413 Mem_Free(shadowmarklist);
414 shadowmark = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmark));
415 shadowmarklist = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmarklist));
419 // if shadowmarkcount wrapped we clear the array and adjust accordingly
420 if (shadowmarkcount == 0)
423 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
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)
430 int i, j, tris = 0, vr[3], t, outvertices = 0;
434 if (maxvertexupdate < innumvertices)
436 maxvertexupdate = innumvertices;
438 Mem_Free(vertexupdate);
440 Mem_Free(vertexremap);
441 vertexupdate = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
442 vertexremap = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
446 if (vertexupdatenum == 0)
449 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
450 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
453 for (i = 0;i < numshadowmarktris;i++)
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++)
461 if (vertexupdate[e[j]] != vertexupdatenum)
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));
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;
484 for (i = 0;i < numshadowmarktris;i++)
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)
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;
503 if (shadowmark[n[1]] != shadowmarkcount)
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;
516 if (shadowmark[n[2]] != shadowmarkcount)
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;
531 *outnumvertices = outvertices;
535 float varray_vertex3f2[65536*3];
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)
540 if (projectdistance < 0.1)
542 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
545 if (!numverts || !nummarktris)
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);
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)
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
564 // identify lit faces within the bounding box
565 R_Shadow_PrepareShadowMark(numtris);
566 for (i = 0;i < numtris;i++)
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;
574 R_Shadow_VolumeFromList(numverts, numtris, invertex3f, elements, neighbors, projectorigin, projectdistance, numshadowmark, shadowmarklist);
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)
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);
589 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
592 if (r_shadow_compilingrtlight)
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);
598 memset(&m, 0, sizeof(m));
599 m.pointer_vertex = vertex3f;
601 GL_LockArrays(0, numvertices);
602 if (r_shadowstage == SHADOWSTAGE_STENCIL)
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);
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);
614 R_Mesh_Draw(numvertices, numtriangles, element3i);
616 c_rt_shadowtris += numtriangles;
620 float r_shadow_attenpower, r_shadow_attenscale;
621 static void R_Shadow_MakeTextures(void)
623 int x, y, z, d, side;
624 float v[3], s, t, intensity;
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;
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)));
638 r_shadow_blankbumptexture = R_LoadTexture2D(r_shadow_texturepool, "blankbump", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
643 r_shadow_blankglosstexture = R_LoadTexture2D(r_shadow_texturepool, "blankgloss", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
648 r_shadow_blankwhitetexture = R_LoadTexture2D(r_shadow_texturepool, "blankwhite", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
649 if (gl_texturecubemap)
651 for (side = 0;side < 6;side++)
653 for (y = 0;y < NORMSIZE;y++)
655 for (x = 0;x < NORMSIZE;x++)
657 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
658 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
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;
700 r_shadow_normalcubetexture = R_LoadTextureCubeMap(r_shadow_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
703 r_shadow_normalcubetexture = NULL;
704 for (y = 0;y < ATTEN2DSIZE;y++)
706 for (x = 0;x < ATTEN2DSIZE;x++)
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);
711 intensity = 1.0f - sqrt(DotProduct(v, v));
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;
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)
724 for (z = 0;z < ATTEN3DSIZE;z++)
726 for (y = 0;y < ATTEN3DSIZE;y++)
728 for (x = 0;x < ATTEN3DSIZE;x++)
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));
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;
744 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
749 void R_Shadow_Stage_Begin(void)
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);
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();
764 memset(&m, 0, sizeof(m));
765 GL_BlendFunc(GL_ONE, GL_ZERO);
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;
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;
780 void R_Shadow_LoadWorldLightsIfNeeded(void)
782 if (r_shadow_reloadlights && cl.worldmodel)
784 R_Shadow_ClearWorldLights();
785 r_shadow_reloadlights = false;
786 R_Shadow_LoadWorldLights();
787 if (r_shadow_worldlightchain == NULL)
789 R_Shadow_LoadLightsFile();
790 if (r_shadow_worldlightchain == NULL)
791 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
796 void R_Shadow_Stage_ShadowVolumes(void)
799 memset(&m, 0, sizeof(m));
801 GL_Color(1, 1, 1, 1);
802 GL_ColorMask(0, 0, 0, 0);
803 GL_BlendFunc(GL_ONE, GL_ZERO);
806 qglPolygonOffset(r_shadow_polygonfactor.value, r_shadow_polygonoffset.value);
807 //if (r_shadow_polygonoffset.value != 0)
809 // qglPolygonOffset(r_shadow_polygonfactor.value, r_shadow_polygonoffset.value);
810 // qglEnable(GL_POLYGON_OFFSET_FILL);
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)
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
825 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
826 qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
828 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
832 r_shadowstage = SHADOWSTAGE_STENCIL;
833 qglEnable(GL_CULL_FACE);
835 // this is changed by every shadow render so its value here is unimportant
836 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
838 GL_Clear(GL_STENCIL_BUFFER_BIT);
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
849 void R_Shadow_Stage_LightWithoutShadows(void)
852 memset(&m, 0, sizeof(m));
854 GL_BlendFunc(GL_ONE, GL_ONE);
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);
868 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
869 qglStencilFunc(GL_EQUAL, 128, ~0);
870 r_shadowstage = SHADOWSTAGE_LIGHT;
874 void R_Shadow_Stage_LightWithShadows(void)
877 memset(&m, 0, sizeof(m));
879 GL_BlendFunc(GL_ONE, GL_ONE);
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);
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;
900 void R_Shadow_Stage_End(void)
903 memset(&m, 0, sizeof(m));
905 GL_BlendFunc(GL_ONE, GL_ZERO);
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);
920 qglStencilFunc(GL_ALWAYS, 128, ~0);
921 r_shadowstage = SHADOWSTAGE_NONE;
924 int R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
926 int i, ix1, iy1, ix2, iy2;
927 float x1, y1, x2, y2, x, y, f;
930 if (!r_shadow_scissor.integer)
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))
937 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
940 for (i = 0;i < 3;i++)
942 if (r_viewforward[i] >= 0)
953 f = DotProduct(r_viewforward, r_vieworigin) + 1;
954 if (DotProduct(r_viewforward, v2) <= f)
956 // entirely behind nearclip plane
959 if (DotProduct(r_viewforward, v) >= f)
961 // entirely infront of nearclip plane
962 x1 = y1 = x2 = y2 = 0;
963 for (i = 0;i < 8;i++)
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];
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]);
989 // clipped by nearclip plane
990 // this is nasty and crude...
991 // create viewspace bbox
992 for (i = 0;i < 8;i++)
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);
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];
1011 smins[0] = smaxs[0] = v2[0];
1012 smins[1] = smaxs[1] = v2[1];
1013 smins[2] = smaxs[2] = v2[2];
1016 // now we have a bbox in viewspace
1017 // clip it to the view plane
1020 // return true if that culled the box
1021 if (smins[2] >= smaxs[2])
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++)
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];
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]);
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++)
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];
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]);
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)
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);
1097 void R_Shadow_VertexLighting(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
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)
1103 Matrix4x4_Transform(m, vertex3f, v);
1104 if ((dist = DotProduct(v, v)) < 1)
1106 Matrix4x4_Transform3x3(m, normal3f, n);
1107 if ((dot = DotProduct(n, v)) > 0)
1110 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale * dot / sqrt(DotProduct(n,n));
1111 VectorScale(lightcolor, intensity, color4f);
1116 VectorClear(color4f);
1122 VectorClear(color4f);
1128 void R_Shadow_VertexLightingWithXYAttenuationTexture(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
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)
1134 Matrix4x4_Transform(m, vertex3f, v);
1135 if ((dist = fabs(v[2])) < 1)
1137 Matrix4x4_Transform3x3(m, normal3f, n);
1138 if ((dot = DotProduct(n, v)) > 0)
1140 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale * dot / sqrt(DotProduct(n,n));
1141 VectorScale(lightcolor, intensity, color4f);
1146 VectorClear(color4f);
1152 VectorClear(color4f);
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)
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];
1173 void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
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];
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)
1189 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
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);
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)
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)
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);
1217 #define USETEXMATRIX 0 // broken
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)
1221 float color[3], color2[3], colorscale;
1224 bumptexture = r_shadow_blankbumptexture;
1226 glosstexture = r_shadow_blankglosstexture;
1227 GL_DepthMask(false);
1229 if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
1231 if (lighting & LIGHTING_DIFFUSE)
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)
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);
1252 m.pointer_texcoord3f[2] = vertex3f;
1253 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
1255 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1256 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
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);
1265 c_rt_lighttris += numtriangles;
1267 memset(&m, 0, sizeof(m));
1268 m.pointer_vertex = vertex3f;
1269 m.tex[0] = R_GetTexture(basetexture);
1270 m.pointer_texcoord[0] = texcoord2f;
1273 m.texcubemap[1] = R_GetTexture(lightcubemap);
1275 m.pointer_texcoord3f[1] = vertex3f;
1276 m.texmatrix[1] = *matrix_modeltolight;
1278 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1279 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
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]--)
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);
1295 c_rt_lighttris += numtriangles;
1297 GL_LockArrays(0, 0);
1299 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap)
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);
1306 m.pointer_texcoord3f[0] = vertex3f;
1307 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1309 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1310 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
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);
1319 c_rt_lighttris += numtriangles;
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);
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);
1336 c_rt_lighttris += numtriangles;
1338 memset(&m, 0, sizeof(m));
1339 m.pointer_vertex = vertex3f;
1340 m.tex[0] = R_GetTexture(basetexture);
1341 m.pointer_texcoord[0] = texcoord2f;
1344 m.texcubemap[1] = R_GetTexture(lightcubemap);
1346 m.pointer_texcoord3f[1] = vertex3f;
1347 m.texmatrix[1] = *matrix_modeltolight;
1349 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1350 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
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]--)
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);
1366 c_rt_lighttris += numtriangles;
1368 GL_LockArrays(0, 0);
1370 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap)
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);
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);
1389 c_rt_lighttris += numtriangles;
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);
1397 m.pointer_texcoord3f[1] = vertex3f;
1398 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1400 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1401 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
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]--)
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);
1416 c_rt_lighttris += numtriangles;
1418 GL_LockArrays(0, 0);
1420 else if (r_textureunits.integer >= 4)
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);
1434 m.pointer_texcoord3f[2] = vertex3f;
1435 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
1437 m.pointer_texcoord[2] = varray_texcoord2f[2];
1438 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1440 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1442 m.pointer_texcoord3f[3] = vertex3f;
1443 m.texmatrix[3] = *matrix_modeltoattenuationz;
1445 m.pointer_texcoord[3] = varray_texcoord2f[3];
1446 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[3], numverts, vertex3f, matrix_modeltoattenuationz);
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);
1455 c_rt_lighttris += numtriangles;
1457 memset(&m, 0, sizeof(m));
1458 m.pointer_vertex = vertex3f;
1459 m.tex[0] = R_GetTexture(basetexture);
1460 m.pointer_texcoord[0] = texcoord2f;
1463 m.texcubemap[1] = R_GetTexture(lightcubemap);
1465 m.pointer_texcoord3f[1] = vertex3f;
1466 m.texmatrix[1] = *matrix_modeltolight;
1468 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1469 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
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]--)
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);
1485 c_rt_lighttris += numtriangles;
1487 GL_LockArrays(0, 0);
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);
1496 m.pointer_texcoord3f[0] = vertex3f;
1497 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1499 m.pointer_texcoord[0] = varray_texcoord2f[0];
1500 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1502 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1504 m.pointer_texcoord3f[1] = vertex3f;
1505 m.texmatrix[1] = *matrix_modeltoattenuationz;
1507 m.pointer_texcoord[1] = varray_texcoord2f[1];
1508 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
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);
1517 c_rt_lighttris += numtriangles;
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);
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);
1534 c_rt_lighttris += numtriangles;
1536 memset(&m, 0, sizeof(m));
1537 m.pointer_vertex = vertex3f;
1538 m.tex[0] = R_GetTexture(basetexture);
1539 m.pointer_texcoord[0] = texcoord2f;
1542 m.texcubemap[1] = R_GetTexture(lightcubemap);
1544 m.pointer_texcoord3f[1] = vertex3f;
1545 m.texmatrix[1] = *matrix_modeltolight;
1547 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1548 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
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]--)
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);
1564 c_rt_lighttris += numtriangles;
1566 GL_LockArrays(0, 0);
1569 if ((lighting & LIGHTING_SPECULAR) && (r_shadow_gloss.integer >= 2 || (r_shadow_gloss.integer >= 1 && glosstexture != r_shadow_blankglosstexture)))
1571 colorscale = r_shadow_glossintensity.value;
1572 if (glosstexture == r_shadow_blankglosstexture)
1573 colorscale *= r_shadow_gloss2intensity.value;
1575 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
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);
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);
1594 c_rt_lighttris += numtriangles;
1596 memset(&m, 0, sizeof(m));
1597 m.pointer_vertex = vertex3f;
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);
1608 c_rt_lighttris += numtriangles;
1609 R_Mesh_Draw(numverts, numtriangles, elements);
1611 c_rt_lighttris += numtriangles;
1612 GL_LockArrays(0, 0);
1614 memset(&m, 0, sizeof(m));
1615 m.pointer_vertex = vertex3f;
1616 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1618 m.pointer_texcoord3f[0] = vertex3f;
1619 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1621 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1622 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
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);
1630 c_rt_lighttris += numtriangles;
1632 memset(&m, 0, sizeof(m));
1633 m.pointer_vertex = vertex3f;
1634 m.tex[0] = R_GetTexture(glosstexture);
1635 m.pointer_texcoord[0] = texcoord2f;
1638 m.texcubemap[1] = R_GetTexture(lightcubemap);
1640 m.pointer_texcoord3f[1] = vertex3f;
1641 m.texmatrix[1] = *matrix_modeltolight;
1643 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1644 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
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]--)
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);
1660 c_rt_lighttris += numtriangles;
1662 GL_LockArrays(0, 0);
1664 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
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);
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);
1683 c_rt_lighttris += numtriangles;
1685 memset(&m, 0, sizeof(m));
1686 m.pointer_vertex = vertex3f;
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);
1697 c_rt_lighttris += numtriangles;
1698 R_Mesh_Draw(numverts, numtriangles, elements);
1700 c_rt_lighttris += numtriangles;
1701 GL_LockArrays(0, 0);
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);
1709 m.pointer_texcoord3f[1] = vertex3f;
1710 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1712 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1713 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
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]--)
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);
1728 c_rt_lighttris += numtriangles;
1730 GL_LockArrays(0, 0);
1732 else if (r_textureunits.integer >= 2 /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
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);
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);
1751 c_rt_lighttris += numtriangles;
1753 memset(&m, 0, sizeof(m));
1754 m.pointer_vertex = vertex3f;
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);
1765 c_rt_lighttris += numtriangles;
1766 R_Mesh_Draw(numverts, numtriangles, elements);
1768 c_rt_lighttris += numtriangles;
1769 GL_LockArrays(0, 0);
1771 memset(&m, 0, sizeof(m));
1772 m.pointer_vertex = vertex3f;
1773 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1775 m.pointer_texcoord3f[0] = vertex3f;
1776 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1778 m.pointer_texcoord[0] = varray_texcoord2f[0];
1779 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1781 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1783 m.pointer_texcoord3f[1] = vertex3f;
1784 m.texmatrix[1] = *matrix_modeltoattenuationz;
1786 m.pointer_texcoord[1] = varray_texcoord2f[1];
1787 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
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);
1795 c_rt_lighttris += numtriangles;
1797 memset(&m, 0, sizeof(m));
1798 m.pointer_vertex = vertex3f;
1799 m.tex[0] = R_GetTexture(glosstexture);
1800 m.pointer_texcoord[0] = texcoord2f;
1803 m.texcubemap[1] = R_GetTexture(lightcubemap);
1805 m.pointer_texcoord3f[1] = vertex3f;
1806 m.texmatrix[1] = *matrix_modeltolight;
1808 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1809 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
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]--)
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);
1825 c_rt_lighttris += numtriangles;
1827 GL_LockArrays(0, 0);
1833 if (lighting & LIGHTING_DIFFUSE)
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)
1845 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1847 m.pointer_texcoord3f[1] = vertex3f;
1848 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1850 m.pointer_texcoord[1] = varray_texcoord2f[1];
1851 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1855 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
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);
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);
1868 c_rt_lighttris += numtriangles;
1874 void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
1878 R_RTLight_Uncompile(rtlight);
1879 memset(rtlight, 0, sizeof(*rtlight));
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);
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;
1917 rtlight_t *r_shadow_compilingrtlight;
1919 // compiles rtlight geometry
1920 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
1921 void R_RTLight_Compile(rtlight_t *rtlight)
1923 int shadowmeshes, shadowtris, lightmeshes, lighttris, numclusters, numsurfaces;
1924 entity_render_t *ent = &cl_entities[0].render;
1925 model_t *model = ent->model;
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;
1940 if (model && model->GetLightInfo)
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);
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);
1956 if (model->DrawShadowVolume && rtlight->shadow)
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);
1962 if (model->DrawLight)
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);
1968 // switch back to rendering when DrawShadowVolume or DrawLight is called
1969 r_shadow_compilingrtlight = NULL;
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);
1979 if (rtlight->static_meshchain_shadow)
1982 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
1985 shadowtris += mesh->numtriangles;
1991 if (rtlight->static_meshchain_light)
1994 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
1997 lighttris += mesh->numtriangles;
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);
2004 void R_RTLight_Uncompile(rtlight_t *rtlight)
2006 if (rtlight->compiled)
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;
2026 int shadowframecount = 0;
2028 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light);
2030 void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes)
2033 entity_render_t *ent;
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;
2041 vec3_t cullmins, cullmaxs;
2045 if (d_lightstylevalue[rtlight->style] <= 0)
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))
2055 if (rtlight->isstatic && !rtlight->compiled && r_shadow_staticworldlights.integer)
2056 R_RTLight_Compile(rtlight);
2062 if (rtlight->compiled && r_shadow_staticworldlights.integer)
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);
2070 else if (cl.worldmodel && cl.worldmodel->GetLightInfo)
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;
2081 for (i = 0;i < numclusters;i++)
2082 if (CHECKPVSBIT(r_pvsbits, clusterlist[i]))
2084 if (i == numclusters)
2087 if (R_CullBox(cullmins, cullmaxs))
2089 if (R_Shadow_ScissorForBBox(cullmins, cullmaxs))
2092 f = d_lightstylevalue[rtlight->style] * (1.0f / 256.0f);
2093 VectorScale(rtlight->color, f, lightcolor);
2095 if (rtlight->selected)
2097 f = 2 + sin(realtime * M_PI * 4.0);
2098 VectorScale(lightcolor, f, lightcolor);
2102 if (rtlight->cubemapname[0])
2103 cubemaptexture = R_Shadow_Cubemap(rtlight->cubemapname);
2105 cubemaptexture = NULL;
2107 shadow = rtlight->shadow && (rtlight->isstatic ? r_shadow_worldshadows.integer : r_shadow_dlightshadows.integer);
2108 if (shadow && (gl_stencil || visiblevolumes))
2110 if (!visiblevolumes)
2111 R_Shadow_Stage_ShadowVolumes();
2112 ent = &cl_entities[0].render;
2113 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2115 memset(&m, 0, sizeof(m));
2116 R_Mesh_Matrix(&ent->matrix);
2117 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2119 m.pointer_vertex = mesh->vertex3f;
2121 GL_LockArrays(0, mesh->numverts);
2122 if (r_shadowstage == SHADOWSTAGE_STENCIL)
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);
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);
2142 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2143 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, numsurfaces, surfacelist);
2145 if (r_drawentities.integer)
2147 for (i = 0;i < r_refdef.numentities;i++)
2149 ent = r_refdef.entities[i];
2151 if (r_shadow_cull.integer)
2153 if (!BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs))
2155 if (cl.worldmodel != NULL && cl.worldmodel->brush.BoxTouchingPVS != NULL && !cl.worldmodel->brush.BoxTouchingPVS(cl.worldmodel, clusterpvs, ent->mins, ent->maxs))
2158 if (!(ent->flags & RENDER_SHADOW) || !ent->model || !ent->model->DrawShadowVolume)
2160 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2161 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, ent->model->numsurfaces, ent->model->surfacelist);
2166 if (!visiblevolumes)
2168 if (shadow && gl_stencil)
2169 R_Shadow_Stage_LightWithShadows();
2171 R_Shadow_Stage_LightWithoutShadows();
2173 ent = &cl_entities[0].render;
2174 if (ent->model && ent->model->DrawLight)
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)
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);
2188 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, numsurfaces, surfacelist);
2190 if (r_drawentities.integer)
2192 for (i = 0;i < r_refdef.numentities;i++)
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))
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);
2209 void R_ShadowVolumeLighting(int visiblevolumes)
2217 memset(&m, 0, sizeof(m));
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);
2227 R_Shadow_Stage_Begin();
2229 if (r_shadow_realtime_world.integer)
2231 R_Shadow_LoadWorldLightsIfNeeded();
2232 if (r_shadow_debuglight.integer >= 0)
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);
2239 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2240 R_DrawRTLight(&light->rtlight, visiblevolumes);
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);
2248 qglEnable(GL_CULL_FACE);
2249 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
2252 R_Shadow_Stage_End();
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;
2267 typedef struct cubemapinfo_s
2270 rtexture_t *texture;
2274 #define MAX_CUBEMAPS 128
2275 static int numcubemaps;
2276 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
2278 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2279 typedef struct suffixinfo_s
2282 int flipx, flipy, flipdiagonal;
2285 static suffixinfo_t suffix[3][6] =
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}
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}
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}
2313 static int componentorder[4] = {0, 1, 2, 3};
2315 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2317 int i, j, cubemapsize;
2318 qbyte *cubemappixels, *image_rgba;
2319 rtexture_t *cubemaptexture;
2321 // must start 0 so the first loadimagepixels has no requested width/height
2323 cubemappixels = NULL;
2324 cubemaptexture = NULL;
2325 for (j = 0;j < 3 && !cubemappixels;j++)
2327 for (i = 0;i < 6;i++)
2329 snprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2330 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2332 if (image_width == image_height)
2334 if (!cubemappixels && image_width >= 1)
2336 cubemapsize = image_width;
2337 // note this clears to black, so unavailable sizes are black
2338 cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
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);
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);
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);
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");
2364 return cubemaptexture;
2367 rtexture_t *R_Shadow_Cubemap(const char *basename)
2370 for (i = 0;i < numcubemaps;i++)
2371 if (!strcasecmp(cubemaps[i].basename, basename))
2372 return cubemaps[i].texture;
2373 if (i >= MAX_CUBEMAPS)
2376 strcpy(cubemaps[i].basename, basename);
2377 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
2378 return cubemaps[i].texture;
2381 void R_Shadow_FreeCubemaps(void)
2384 R_FreeTexturePool(&r_shadow_filters_texturepool);
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)
2391 if (radius < 15 || DotProduct(color, color) < 0.03)
2393 Con_Print("R_Shadow_NewWorldLight: refusing to create a light too small/dim\n");
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)
2405 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
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;
2416 R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
2417 if (r_shadow_staticworldlights.integer)
2418 R_RTLight_Compile(&light->rtlight);
2421 void R_Shadow_FreeWorldLight(dlight_t *light)
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);
2432 void R_Shadow_ClearWorldLights(void)
2434 while (r_shadow_worldlightchain)
2435 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
2436 r_shadow_selectedlight = NULL;
2437 R_Shadow_FreeCubemaps();
2440 void R_Shadow_SelectLight(dlight_t *light)
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;
2449 rtexture_t *lighttextures[5];
2451 void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
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);
2457 void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
2460 const dlight_t *light;
2463 if (light->selected)
2464 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
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);
2470 void R_Shadow_DrawLightSprites(void)
2476 for (i = 0;i < 5;i++)
2478 lighttextures[i] = NULL;
2479 if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1))))
2480 lighttextures[i] = pic->tex;
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);
2488 void R_Shadow_SelectLightInView(void)
2490 float bestrating, rating, temp[3];
2491 dlight_t *best, *light;
2494 for (light = r_shadow_worldlightchain;light;light = light->next)
2496 VectorSubtract(light->origin, r_vieworigin, temp);
2497 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
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)
2503 bestrating = rating;
2508 R_Shadow_SelectLight(best);
2511 void R_Shadow_LoadWorldLights(void)
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)
2518 Con_Print("No map loaded.\n");
2521 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2522 strlcat (name, ".rtlights", sizeof (name));
2523 lightsstring = FS_LoadFile(name, false);
2533 for (;COM_Parse(t, true) && strcmp(
2534 if (COM_Parse(t, true))
2536 if (com_token[0] == '!')
2539 origin[0] = atof(com_token+1);
2542 origin[0] = atof(com_token);
2547 while (*s && *s != '\n')
2553 // check for modifier flags
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]);
2561 VectorClear(angles);
2564 if (a < 9 || !strcmp(cubemapname, "\"\""))
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);
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);
2579 Con_Printf("invalid rtlights file \"%s\"\n", name);
2580 Mem_Free(lightsstring);
2584 void R_Shadow_SaveWorldLights(void)
2587 int bufchars, bufmaxchars;
2589 char name[MAX_QPATH];
2591 if (!r_shadow_worldlightchain)
2593 if (cl.worldmodel == NULL)
2595 Con_Print("No map loaded.\n");
2598 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2599 strlcat (name, ".rtlights", sizeof (name));
2600 bufchars = bufmaxchars = 0;
2602 for (light = r_shadow_worldlightchain;light;light = light->next)
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)
2607 bufmaxchars = bufchars + strlen(line) + 2048;
2609 buf = Mem_Alloc(r_shadow_mempool, bufmaxchars);
2613 memcpy(buf, oldbuf, bufchars);
2619 memcpy(buf + bufchars, line, strlen(line));
2620 bufchars += strlen(line);
2624 FS_WriteFile(name, buf, bufchars);
2629 void R_Shadow_LoadLightsFile(void)
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)
2636 Con_Print("No map loaded.\n");
2639 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2640 strlcat (name, ".lights", sizeof (name));
2641 lightsstring = FS_LoadFile(name, false);
2649 while (*s && *s != '\n')
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);
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);
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);
2669 Con_Printf("invalid lights file \"%s\"\n", name);
2670 Mem_Free(lightsstring);
2674 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
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];
2681 if (cl.worldmodel == NULL)
2683 Con_Print("No map loaded.\n");
2686 data = cl.worldmodel->brush.entities;
2689 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
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;
2706 if (!COM_ParseToken(&data, false))
2708 if (com_token[0] == '}')
2709 break; // end of entity
2710 if (com_token[0] == '_')
2711 strcpy(key, com_token + 1);
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))
2718 strcpy(value, com_token);
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))
2735 if (!strncmp(value, "light", 5))
2738 if (!strcmp(value, "light_fluoro"))
2743 overridecolor[0] = 1;
2744 overridecolor[1] = 1;
2745 overridecolor[2] = 1;
2747 if (!strcmp(value, "light_fluorospark"))
2752 overridecolor[0] = 1;
2753 overridecolor[1] = 1;
2754 overridecolor[2] = 1;
2756 if (!strcmp(value, "light_globe"))
2761 overridecolor[0] = 1;
2762 overridecolor[1] = 0.8;
2763 overridecolor[2] = 0.4;
2765 if (!strcmp(value, "light_flame_large_yellow"))
2770 overridecolor[0] = 1;
2771 overridecolor[1] = 0.5;
2772 overridecolor[2] = 0.1;
2774 if (!strcmp(value, "light_flame_small_yellow"))
2779 overridecolor[0] = 1;
2780 overridecolor[1] = 0.5;
2781 overridecolor[2] = 0.1;
2783 if (!strcmp(value, "light_torch_small_white"))
2788 overridecolor[0] = 1;
2789 overridecolor[1] = 0.5;
2790 overridecolor[2] = 0.1;
2792 if (!strcmp(value, "light_torch_small_walltorch"))
2797 overridecolor[0] = 1;
2798 overridecolor[1] = 0.5;
2799 overridecolor[2] = 0.1;
2803 else if (!strcmp("style", key))
2804 style = atoi(value);
2805 else if (cl.worldmodel->type == mod_brushq3)
2807 if (!strcmp("scale", key))
2808 lightscale = atof(value);
2809 if (!strcmp("fade", key))
2810 fadescale = atof(value);
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);
2819 if (light <= 0 && islight)
2821 if (lightscale <= 0)
2825 if (gamemode == GAME_TENEBRAE)
2827 if (effects & EF_NODRAW)
2829 pflags |= PFLAGS_FULLDYNAMIC;
2830 effects &= ~EF_NODRAW;
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);
2845 void R_Shadow_SetCursorLocationForView(void)
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);
2853 dist = frac * r_editlights_cursordistance.value;
2854 push = r_editlights_cursorpushback.value;
2858 VectorMA(endpos, push, r_viewforward, endpos);
2859 VectorMA(endpos, r_editlights_cursorpushoff.value, normal, endpos);
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;
2866 void R_Shadow_UpdateWorldLightSelection(void)
2868 if (r_editlights.integer)
2870 R_Shadow_SetCursorLocationForView();
2871 R_Shadow_SelectLightInView();
2872 R_Shadow_DrawLightSprites();
2875 R_Shadow_SelectLight(NULL);
2878 void R_Shadow_EditLights_Clear_f(void)
2880 R_Shadow_ClearWorldLights();
2883 void R_Shadow_EditLights_Reload_f(void)
2885 r_shadow_reloadlights = true;
2888 void R_Shadow_EditLights_Save_f(void)
2891 R_Shadow_SaveWorldLights();
2894 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
2896 R_Shadow_ClearWorldLights();
2897 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
2900 void R_Shadow_EditLights_ImportLightsFile_f(void)
2902 R_Shadow_ClearWorldLights();
2903 R_Shadow_LoadLightsFile();
2906 void R_Shadow_EditLights_Spawn_f(void)
2909 if (!r_editlights.integer)
2911 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
2914 if (Cmd_Argc() != 1)
2916 Con_Print("r_editlights_spawn does not take parameters\n");
2919 color[0] = color[1] = color[2] = 1;
2920 R_Shadow_NewWorldLight(r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL);
2923 void R_Shadow_EditLights_Edit_f(void)
2925 vec3_t origin, angles, color;
2926 vec_t radius, corona;
2928 char cubemapname[1024];
2929 if (!r_editlights.integer)
2931 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
2934 if (!r_shadow_selectedlight)
2936 Con_Print("No selected light.\n");
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);
2948 shadows = r_shadow_selectedlight->shadow;
2949 corona = r_shadow_selectedlight->corona;
2950 if (!strcmp(Cmd_Argv(1), "origin"))
2952 if (Cmd_Argc() != 5)
2954 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
2957 origin[0] = atof(Cmd_Argv(2));
2958 origin[1] = atof(Cmd_Argv(3));
2959 origin[2] = atof(Cmd_Argv(4));
2961 else if (!strcmp(Cmd_Argv(1), "originx"))
2963 if (Cmd_Argc() != 3)
2965 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2968 origin[0] = atof(Cmd_Argv(2));
2970 else if (!strcmp(Cmd_Argv(1), "originy"))
2972 if (Cmd_Argc() != 3)
2974 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2977 origin[1] = atof(Cmd_Argv(2));
2979 else if (!strcmp(Cmd_Argv(1), "originz"))
2981 if (Cmd_Argc() != 3)
2983 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2986 origin[2] = atof(Cmd_Argv(2));
2988 else if (!strcmp(Cmd_Argv(1), "move"))
2990 if (Cmd_Argc() != 5)
2992 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
2995 origin[0] += atof(Cmd_Argv(2));
2996 origin[1] += atof(Cmd_Argv(3));
2997 origin[2] += atof(Cmd_Argv(4));
2999 else if (!strcmp(Cmd_Argv(1), "movex"))
3001 if (Cmd_Argc() != 3)
3003 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3006 origin[0] += atof(Cmd_Argv(2));
3008 else if (!strcmp(Cmd_Argv(1), "movey"))
3010 if (Cmd_Argc() != 3)
3012 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3015 origin[1] += atof(Cmd_Argv(2));
3017 else if (!strcmp(Cmd_Argv(1), "movez"))
3019 if (Cmd_Argc() != 3)
3021 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3024 origin[2] += atof(Cmd_Argv(2));
3026 else if (!strcmp(Cmd_Argv(1), "angles"))
3028 if (Cmd_Argc() != 5)
3030 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3033 angles[0] = atof(Cmd_Argv(2));
3034 angles[1] = atof(Cmd_Argv(3));
3035 angles[2] = atof(Cmd_Argv(4));
3037 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3039 if (Cmd_Argc() != 3)
3041 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3044 angles[0] = atof(Cmd_Argv(2));
3046 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3048 if (Cmd_Argc() != 3)
3050 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3053 angles[1] = atof(Cmd_Argv(2));
3055 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3057 if (Cmd_Argc() != 3)
3059 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3062 angles[2] = atof(Cmd_Argv(2));
3064 else if (!strcmp(Cmd_Argv(1), "color"))
3066 if (Cmd_Argc() != 5)
3068 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3071 color[0] = atof(Cmd_Argv(2));
3072 color[1] = atof(Cmd_Argv(3));
3073 color[2] = atof(Cmd_Argv(4));
3075 else if (!strcmp(Cmd_Argv(1), "radius"))
3077 if (Cmd_Argc() != 3)
3079 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3082 radius = atof(Cmd_Argv(2));
3084 else if (!strcmp(Cmd_Argv(1), "style"))
3086 if (Cmd_Argc() != 3)
3088 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3091 style = atoi(Cmd_Argv(2));
3093 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3097 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3100 if (Cmd_Argc() == 3)
3101 strcpy(cubemapname, Cmd_Argv(2));
3105 else if (!strcmp(Cmd_Argv(1), "shadows"))
3107 if (Cmd_Argc() != 3)
3109 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3112 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3114 else if (!strcmp(Cmd_Argv(1), "corona"))
3116 if (Cmd_Argc() != 3)
3118 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3121 corona = atof(Cmd_Argv(2));
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);
3137 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3138 r_shadow_selectedlight = NULL;
3139 R_Shadow_NewWorldLight(origin, angles, color, radius, corona, style, shadows, cubemapname);
3142 extern int con_vislines;
3143 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3147 if (r_shadow_selectedlight == NULL)
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;
3162 void R_Shadow_EditLights_ToggleShadow_f(void)
3164 if (!r_editlights.integer)
3166 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3169 if (!r_shadow_selectedlight)
3171 Con_Print("No selected light.\n");
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;
3179 void R_Shadow_EditLights_ToggleCorona_f(void)
3181 if (!r_editlights.integer)
3183 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3186 if (!r_shadow_selectedlight)
3188 Con_Print("No selected light.\n");
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;
3196 void R_Shadow_EditLights_Remove_f(void)
3198 if (!r_editlights.integer)
3200 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
3203 if (!r_shadow_selectedlight)
3205 Con_Print("No selected light.\n");
3208 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3209 r_shadow_selectedlight = NULL;
3212 void R_Shadow_EditLights_Help_f(void)
3215 "Documentation on r_editlights system:\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"
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"
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"
3259 void R_Shadow_EditLights_Init(void)
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);