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_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0"};
166 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4"};
167 cvar_t r_shadow_cull = {0, "r_shadow_cull", "1"};
168 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1"};
169 cvar_t r_shadow_gloss = {0, "r_shadow_gloss", "1"};
170 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.25"};
171 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1"};
172 cvar_t r_shadow_lightattenuationpower = {0, "r_shadow_lightattenuationpower", "0.5"};
173 cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1"};
174 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1"};
175 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0"};
176 cvar_t r_shadow_polygonoffset = {0, "r_shadow_polygonoffset", "1"};
177 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1"};
178 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000"};
179 cvar_t r_shadow_realtime_dlight = {0, "r_shadow_realtime_dlight", "1"};
180 cvar_t r_shadow_realtime_dlight_shadows = {0, "r_shadow_realtime_dlight_shadows", "0"};
181 cvar_t r_shadow_realtime_world = {0, "r_shadow_realtime_world", "0"};
182 cvar_t r_shadow_realtime_world_dlightshadows = {0, "r_shadow_realtime_world_dlightshadows", "1"};
183 cvar_t r_shadow_realtime_world_lightmaps = {0, "r_shadow_realtime_world_lightmaps", "0"};
184 cvar_t r_shadow_realtime_world_shadows = {0, "r_shadow_realtime_world_shadows", "1"};
185 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1"};
186 cvar_t r_shadow_singlepassvolumegeneration = {0, "r_shadow_singlepassvolumegeneration", "1"};
187 cvar_t r_shadow_staticworldlights = {0, "r_shadow_staticworldlights", "1"};
188 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1"};
189 cvar_t r_shadow_visiblevolumes = {0, "r_shadow_visiblevolumes", "0"};
190 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1"};
192 int c_rt_lights, c_rt_clears, c_rt_scissored;
193 int c_rt_shadowmeshes, c_rt_shadowtris, c_rt_lightmeshes, c_rt_lighttris;
194 int c_rtcached_shadowmeshes, c_rtcached_shadowtris;
196 void R_Shadow_ClearWorldLights(void);
197 void R_Shadow_SaveWorldLights(void);
198 void R_Shadow_LoadWorldLights(void);
199 void R_Shadow_LoadLightsFile(void);
200 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
202 void r_shadow_start(void)
204 // allocate vertex processing arrays
205 r_shadow_mempool = Mem_AllocPool("R_Shadow");
206 maxshadowelements = 0;
207 shadowelements = NULL;
215 shadowmarklist = NULL;
217 r_shadow_buffer_numclusterpvsbytes = 0;
218 r_shadow_buffer_clusterpvs = NULL;
219 r_shadow_buffer_clusterlist = NULL;
220 r_shadow_buffer_numsurfacepvsbytes = 0;
221 r_shadow_buffer_surfacepvs = NULL;
222 r_shadow_buffer_surfacelist = NULL;
223 r_shadow_normalcubetexture = NULL;
224 r_shadow_attenuation2dtexture = NULL;
225 r_shadow_attenuation3dtexture = NULL;
226 r_shadow_blankbumptexture = NULL;
227 r_shadow_blankglosstexture = NULL;
228 r_shadow_blankwhitetexture = NULL;
229 r_shadow_texturepool = NULL;
230 r_shadow_filters_texturepool = NULL;
231 R_Shadow_ClearWorldLights();
232 r_shadow_reloadlights = true;
235 void r_shadow_shutdown(void)
237 R_Shadow_ClearWorldLights();
238 r_shadow_reloadlights = true;
239 r_shadow_normalcubetexture = NULL;
240 r_shadow_attenuation2dtexture = NULL;
241 r_shadow_attenuation3dtexture = NULL;
242 r_shadow_blankbumptexture = NULL;
243 r_shadow_blankglosstexture = NULL;
244 r_shadow_blankwhitetexture = NULL;
245 R_FreeTexturePool(&r_shadow_texturepool);
246 R_FreeTexturePool(&r_shadow_filters_texturepool);
247 maxshadowelements = 0;
248 shadowelements = NULL;
256 shadowmarklist = NULL;
258 r_shadow_buffer_numclusterpvsbytes = 0;
259 r_shadow_buffer_clusterpvs = NULL;
260 r_shadow_buffer_clusterlist = NULL;
261 r_shadow_buffer_numsurfacepvsbytes = 0;
262 r_shadow_buffer_surfacepvs = NULL;
263 r_shadow_buffer_surfacelist = NULL;
264 Mem_FreePool(&r_shadow_mempool);
267 void r_shadow_newmap(void)
269 R_Shadow_ClearWorldLights();
270 r_shadow_reloadlights = true;
273 void R_Shadow_Help_f(void)
276 "Documentation on r_shadow system:\n"
278 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
279 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
280 "r_shadow_debuglight : render only this light number (-1 = all)\n"
281 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
282 "r_shadow_gloss2intensity : brightness of forced gloss\n"
283 "r_shadow_glossintensity : brightness of textured gloss\n"
284 "r_shadow_lightattenuationpower : used to generate attenuation texture\n"
285 "r_shadow_lightattenuationscale : used to generate attenuation texture\n"
286 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
287 "r_shadow_polygonfactor : nudge shadow volumes closer/further\n"
288 "r_shadow_polygonoffset : nudge shadow volumes closer/further\n"
289 "r_shadow_portallight : use portal visibility for static light precomputation\n"
290 "r_shadow_projectdistance : shadow volume projection distance\n"
291 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
292 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
293 "r_shadow_realtime_world : use high quality world lighting mode\n"
294 "r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n"
295 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
296 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
297 "r_shadow_scissor : use scissor optimization\n"
298 "r_shadow_singlepassvolumegeneration : selects shadow volume algorithm\n"
299 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
300 "r_shadow_visiblevolumes : useful for performance testing; bright = slow!\n"
302 "r_shadow_help : this help\n"
306 void R_Shadow_Init(void)
308 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
309 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
310 Cvar_RegisterVariable(&r_shadow_cull);
311 Cvar_RegisterVariable(&r_shadow_debuglight);
312 Cvar_RegisterVariable(&r_shadow_gloss);
313 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
314 Cvar_RegisterVariable(&r_shadow_glossintensity);
315 Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
316 Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
317 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
318 Cvar_RegisterVariable(&r_shadow_polygonfactor);
319 Cvar_RegisterVariable(&r_shadow_polygonoffset);
320 Cvar_RegisterVariable(&r_shadow_portallight);
321 Cvar_RegisterVariable(&r_shadow_projectdistance);
322 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
323 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
324 Cvar_RegisterVariable(&r_shadow_realtime_world);
325 Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows);
326 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
327 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
328 Cvar_RegisterVariable(&r_shadow_scissor);
329 Cvar_RegisterVariable(&r_shadow_singlepassvolumegeneration);
330 Cvar_RegisterVariable(&r_shadow_staticworldlights);
331 Cvar_RegisterVariable(&r_shadow_texture3d);
332 Cvar_RegisterVariable(&r_shadow_visiblevolumes);
333 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
334 if (gamemode == GAME_TENEBRAE)
336 Cvar_SetValue("r_shadow_gloss", 2);
337 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
339 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f);
340 R_Shadow_EditLights_Init();
341 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
344 matrix4x4_t matrix_attenuationxyz =
347 {0.5, 0.0, 0.0, 0.5},
348 {0.0, 0.5, 0.0, 0.5},
349 {0.0, 0.0, 0.5, 0.5},
354 matrix4x4_t matrix_attenuationz =
357 {0.0, 0.0, 0.5, 0.5},
358 {0.0, 0.0, 0.0, 0.5},
359 {0.0, 0.0, 0.0, 0.5},
364 int *R_Shadow_ResizeShadowElements(int numtris)
366 // make sure shadowelements is big enough for this volume
367 if (maxshadowelements < numtris * 24)
369 maxshadowelements = numtris * 24;
371 Mem_Free(shadowelements);
372 shadowelements = Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int));
374 return shadowelements;
377 void R_Shadow_EnlargeClusterBuffer(int numclusters)
379 int numclusterpvsbytes = (((numclusters + 7) >> 3) + 255) & ~255;
380 if (r_shadow_buffer_numclusterpvsbytes < numclusterpvsbytes)
382 if (r_shadow_buffer_clusterpvs)
383 Mem_Free(r_shadow_buffer_clusterpvs);
384 if (r_shadow_buffer_clusterlist)
385 Mem_Free(r_shadow_buffer_clusterlist);
386 r_shadow_buffer_numclusterpvsbytes = numclusterpvsbytes;
387 r_shadow_buffer_clusterpvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numclusterpvsbytes);
388 r_shadow_buffer_clusterlist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numclusterpvsbytes * 8 * sizeof(*r_shadow_buffer_clusterlist));
392 void R_Shadow_EnlargeSurfaceBuffer(int numsurfaces)
394 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
395 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
397 if (r_shadow_buffer_surfacepvs)
398 Mem_Free(r_shadow_buffer_surfacepvs);
399 if (r_shadow_buffer_surfacelist)
400 Mem_Free(r_shadow_buffer_surfacelist);
401 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
402 r_shadow_buffer_surfacepvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes);
403 r_shadow_buffer_surfacelist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
407 void R_Shadow_PrepareShadowMark(int numtris)
409 // make sure shadowmark is big enough for this volume
410 if (maxshadowmark < numtris)
412 maxshadowmark = numtris;
414 Mem_Free(shadowmark);
416 Mem_Free(shadowmarklist);
417 shadowmark = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmark));
418 shadowmarklist = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmarklist));
422 // if shadowmarkcount wrapped we clear the array and adjust accordingly
423 if (shadowmarkcount == 0)
426 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
431 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)
433 int i, j, tris = 0, vr[3], t, outvertices = 0;
437 if (maxvertexupdate < innumvertices)
439 maxvertexupdate = innumvertices;
441 Mem_Free(vertexupdate);
443 Mem_Free(vertexremap);
444 vertexupdate = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
445 vertexremap = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
449 if (vertexupdatenum == 0)
452 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
453 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
456 for (i = 0;i < numshadowmarktris;i++)
458 t = shadowmarktris[i];
459 shadowmark[t] = shadowmarkcount;
460 e = inelement3i + t * 3;
461 // make sure the vertices are created
462 for (j = 0;j < 3;j++)
464 if (vertexupdate[e[j]] != vertexupdatenum)
466 vertexupdate[e[j]] = vertexupdatenum;
467 vertexremap[e[j]] = outvertices;
468 VectorSubtract(invertex3f + e[j] * 3, projectorigin, temp);
469 f = projectdistance / VectorLength(temp);
470 VectorCopy(invertex3f + e[j] * 3, outvertex3f);
471 VectorMA(projectorigin, f, temp, (outvertex3f + 3));
476 // output the front and back triangles
477 outelement3i[0] = vertexremap[e[0]];
478 outelement3i[1] = vertexremap[e[1]];
479 outelement3i[2] = vertexremap[e[2]];
480 outelement3i[3] = vertexremap[e[2]] + 1;
481 outelement3i[4] = vertexremap[e[1]] + 1;
482 outelement3i[5] = vertexremap[e[0]] + 1;
487 for (i = 0;i < numshadowmarktris;i++)
489 t = shadowmarktris[i];
490 e = inelement3i + t * 3;
491 n = inneighbor3i + t * 3;
492 // output the sides (facing outward from this triangle)
493 if (shadowmark[n[0]] != shadowmarkcount)
495 vr[0] = vertexremap[e[0]];
496 vr[1] = vertexremap[e[1]];
497 outelement3i[0] = vr[1];
498 outelement3i[1] = vr[0];
499 outelement3i[2] = vr[0] + 1;
500 outelement3i[3] = vr[1];
501 outelement3i[4] = vr[0] + 1;
502 outelement3i[5] = vr[1] + 1;
506 if (shadowmark[n[1]] != shadowmarkcount)
508 vr[1] = vertexremap[e[1]];
509 vr[2] = vertexremap[e[2]];
510 outelement3i[0] = vr[2];
511 outelement3i[1] = vr[1];
512 outelement3i[2] = vr[1] + 1;
513 outelement3i[3] = vr[2];
514 outelement3i[4] = vr[1] + 1;
515 outelement3i[5] = vr[2] + 1;
519 if (shadowmark[n[2]] != shadowmarkcount)
521 vr[0] = vertexremap[e[0]];
522 vr[2] = vertexremap[e[2]];
523 outelement3i[0] = vr[0];
524 outelement3i[1] = vr[2];
525 outelement3i[2] = vr[2] + 1;
526 outelement3i[3] = vr[0];
527 outelement3i[4] = vr[2] + 1;
528 outelement3i[5] = vr[0] + 1;
534 *outnumvertices = outvertices;
538 float varray_vertex3f2[65536*3];
540 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)
543 if (projectdistance < 0.1)
545 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
548 if (!numverts || !nummarktris)
550 // make sure shadowelements is big enough for this volume
551 if (maxshadowelements < nummarktris * 24)
552 R_Shadow_ResizeShadowElements((nummarktris + 256) * 24);
553 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, varray_vertex3f2, projectorigin, projectdistance, nummarktris, marktris);
554 R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements);
557 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)
562 // check which triangles are facing the , and then output
563 // triangle elements and vertices... by clever use of elements we
564 // can construct the whole shadow from the unprojected vertices and
565 // the projected vertices
567 // identify lit faces within the bounding box
568 R_Shadow_PrepareShadowMark(numtris);
569 for (i = 0;i < numtris;i++)
571 v[0] = invertex3f + elements[i*3+0] * 3;
572 v[1] = invertex3f + elements[i*3+1] * 3;
573 v[2] = invertex3f + elements[i*3+2] * 3;
574 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])))
575 shadowmarklist[numshadowmark++] = i;
577 R_Shadow_VolumeFromList(numverts, numtris, invertex3f, elements, neighbors, projectorigin, projectdistance, numshadowmark, shadowmarklist);
580 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)
583 mins[0] = projectorigin[0] - radius;
584 mins[1] = projectorigin[1] - radius;
585 mins[2] = projectorigin[2] - radius;
586 maxs[0] = projectorigin[0] + radius;
587 maxs[1] = projectorigin[1] + radius;
588 maxs[2] = projectorigin[2] + radius;
589 R_Shadow_VolumeFromBox(numverts, numtris, invertex3f, elements, neighbors, projectorigin, projectdistance, mins, maxs);
592 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
595 if (r_shadow_compilingrtlight)
597 // if we're compiling an rtlight, capture the mesh
598 Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
601 memset(&m, 0, sizeof(m));
602 m.pointer_vertex = vertex3f;
604 GL_LockArrays(0, numvertices);
605 if (r_shadowstage == SHADOWSTAGE_STENCIL)
607 // increment stencil if backface is behind depthbuffer
608 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
609 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
610 R_Mesh_Draw(numvertices, numtriangles, element3i);
612 c_rt_shadowtris += numtriangles;
613 // decrement stencil if frontface is behind depthbuffer
614 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
615 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
617 R_Mesh_Draw(numvertices, numtriangles, element3i);
619 c_rt_shadowtris += numtriangles;
623 float r_shadow_attenpower, r_shadow_attenscale;
624 static void R_Shadow_MakeTextures(void)
626 int x, y, z, d, side;
627 float v[3], s, t, intensity;
629 R_FreeTexturePool(&r_shadow_texturepool);
630 r_shadow_texturepool = R_AllocTexturePool();
631 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
632 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
634 #define ATTEN2DSIZE 64
635 #define ATTEN3DSIZE 32
636 data = Mem_Alloc(tempmempool, max(6*NORMSIZE*NORMSIZE*4, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4)));
641 r_shadow_blankbumptexture = R_LoadTexture2D(r_shadow_texturepool, "blankbump", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
646 r_shadow_blankglosstexture = R_LoadTexture2D(r_shadow_texturepool, "blankgloss", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
651 r_shadow_blankwhitetexture = R_LoadTexture2D(r_shadow_texturepool, "blankwhite", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
652 if (gl_texturecubemap)
654 for (side = 0;side < 6;side++)
656 for (y = 0;y < NORMSIZE;y++)
658 for (x = 0;x < NORMSIZE;x++)
660 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
661 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
695 intensity = 127.0f / sqrt(DotProduct(v, v));
696 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+0] = 128.0f + intensity * v[0];
697 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+1] = 128.0f + intensity * v[1];
698 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+2] = 128.0f + intensity * v[2];
699 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+3] = 255;
703 r_shadow_normalcubetexture = R_LoadTextureCubeMap(r_shadow_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
706 r_shadow_normalcubetexture = NULL;
707 for (y = 0;y < ATTEN2DSIZE;y++)
709 for (x = 0;x < ATTEN2DSIZE;x++)
711 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
712 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
714 intensity = 1.0f - sqrt(DotProduct(v, v));
716 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
717 d = bound(0, intensity, 255);
718 data[(y*ATTEN2DSIZE+x)*4+0] = d;
719 data[(y*ATTEN2DSIZE+x)*4+1] = d;
720 data[(y*ATTEN2DSIZE+x)*4+2] = d;
721 data[(y*ATTEN2DSIZE+x)*4+3] = d;
724 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
725 if (r_shadow_texture3d.integer)
727 for (z = 0;z < ATTEN3DSIZE;z++)
729 for (y = 0;y < ATTEN3DSIZE;y++)
731 for (x = 0;x < ATTEN3DSIZE;x++)
733 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
734 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
735 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
736 intensity = 1.0f - sqrt(DotProduct(v, v));
738 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
739 d = bound(0, intensity, 255);
740 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
741 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
742 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
743 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
747 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
752 void R_Shadow_Stage_Begin(void)
756 if (r_shadow_texture3d.integer && !gl_texture3d)
757 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
758 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
759 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
761 if (!r_shadow_attenuation2dtexture
762 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
763 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
764 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
765 R_Shadow_MakeTextures();
767 memset(&m, 0, sizeof(m));
768 GL_BlendFunc(GL_ONE, GL_ZERO);
772 GL_Color(0, 0, 0, 1);
773 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
774 qglEnable(GL_CULL_FACE);
775 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
776 r_shadowstage = SHADOWSTAGE_NONE;
778 c_rt_lights = c_rt_clears = c_rt_scissored = 0;
779 c_rt_shadowmeshes = c_rt_shadowtris = c_rt_lightmeshes = c_rt_lighttris = 0;
780 c_rtcached_shadowmeshes = c_rtcached_shadowtris = 0;
783 void R_Shadow_LoadWorldLightsIfNeeded(void)
785 if (r_shadow_reloadlights && cl.worldmodel)
787 R_Shadow_ClearWorldLights();
788 r_shadow_reloadlights = false;
789 R_Shadow_LoadWorldLights();
790 if (r_shadow_worldlightchain == NULL)
792 R_Shadow_LoadLightsFile();
793 if (r_shadow_worldlightchain == NULL)
794 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
799 void R_Shadow_Stage_ShadowVolumes(void)
802 memset(&m, 0, sizeof(m));
804 GL_Color(1, 1, 1, 1);
805 GL_ColorMask(0, 0, 0, 0);
806 GL_BlendFunc(GL_ONE, GL_ZERO);
809 qglPolygonOffset(r_shadow_polygonfactor.value, r_shadow_polygonoffset.value);
810 //if (r_shadow_polygonoffset.value != 0)
812 // qglPolygonOffset(r_shadow_polygonfactor.value, r_shadow_polygonoffset.value);
813 // qglEnable(GL_POLYGON_OFFSET_FILL);
816 // qglDisable(GL_POLYGON_OFFSET_FILL);
817 qglDepthFunc(GL_LESS);
818 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
819 qglEnable(GL_STENCIL_TEST);
820 qglStencilFunc(GL_ALWAYS, 128, ~0);
821 if (gl_ext_stenciltwoside.integer)
823 r_shadowstage = SHADOWSTAGE_STENCILTWOSIDE;
824 qglDisable(GL_CULL_FACE);
825 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
826 qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
828 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
829 qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
831 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
835 r_shadowstage = SHADOWSTAGE_STENCIL;
836 qglEnable(GL_CULL_FACE);
838 // this is changed by every shadow render so its value here is unimportant
839 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
841 GL_Clear(GL_STENCIL_BUFFER_BIT);
843 // LordHavoc note: many shadow volumes reside entirely inside the world
844 // (that is to say they are entirely bounded by their lit surfaces),
845 // which can be optimized by handling things as an inverted light volume,
846 // with the shadow boundaries of the world being simulated by an altered
847 // (129) bias to stencil clearing on such lights
848 // FIXME: generate inverted light volumes for use as shadow volumes and
849 // optimize for them as noted above
852 void R_Shadow_Stage_LightWithoutShadows(void)
855 memset(&m, 0, sizeof(m));
857 GL_BlendFunc(GL_ONE, GL_ONE);
860 qglPolygonOffset(0, 0);
861 //qglDisable(GL_POLYGON_OFFSET_FILL);
862 GL_Color(1, 1, 1, 1);
863 GL_ColorMask(1, 1, 1, 1);
864 qglDepthFunc(GL_EQUAL);
865 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
866 qglEnable(GL_CULL_FACE);
867 qglDisable(GL_STENCIL_TEST);
868 if (gl_support_stenciltwoside)
869 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
871 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
872 qglStencilFunc(GL_EQUAL, 128, ~0);
873 r_shadowstage = SHADOWSTAGE_LIGHT;
877 void R_Shadow_Stage_LightWithShadows(void)
880 memset(&m, 0, sizeof(m));
882 GL_BlendFunc(GL_ONE, GL_ONE);
885 qglPolygonOffset(0, 0);
886 //qglDisable(GL_POLYGON_OFFSET_FILL);
887 GL_Color(1, 1, 1, 1);
888 GL_ColorMask(1, 1, 1, 1);
889 qglDepthFunc(GL_EQUAL);
890 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
891 qglEnable(GL_STENCIL_TEST);
892 if (gl_support_stenciltwoside)
893 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
895 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
896 // only draw light where this geometry was already rendered AND the
897 // stencil is 128 (values other than this mean shadow)
898 qglStencilFunc(GL_EQUAL, 128, ~0);
899 r_shadowstage = SHADOWSTAGE_LIGHT;
903 void R_Shadow_Stage_End(void)
906 memset(&m, 0, sizeof(m));
908 GL_BlendFunc(GL_ONE, GL_ZERO);
911 qglPolygonOffset(0, 0);
912 //qglDisable(GL_POLYGON_OFFSET_FILL);
913 GL_Color(1, 1, 1, 1);
914 GL_ColorMask(1, 1, 1, 1);
915 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
916 qglDepthFunc(GL_LEQUAL);
917 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
918 qglDisable(GL_STENCIL_TEST);
919 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
920 if (gl_support_stenciltwoside)
921 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
923 qglStencilFunc(GL_ALWAYS, 128, ~0);
924 r_shadowstage = SHADOWSTAGE_NONE;
927 int R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
929 int i, ix1, iy1, ix2, iy2;
930 float x1, y1, x2, y2, x, y, f;
933 if (!r_shadow_scissor.integer)
935 // if view is inside the box, just say yes it's visible
936 if (BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
938 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
941 for (i = 0;i < 3;i++)
943 if (r_viewforward[i] >= 0)
954 f = DotProduct(r_viewforward, r_vieworigin) + 1;
955 if (DotProduct(r_viewforward, v2) <= f)
957 // entirely behind nearclip plane
960 if (DotProduct(r_viewforward, v) >= f)
962 // entirely infront of nearclip plane
963 x1 = y1 = x2 = y2 = 0;
964 for (i = 0;i < 8;i++)
966 v[0] = (i & 1) ? mins[0] : maxs[0];
967 v[1] = (i & 2) ? mins[1] : maxs[1];
968 v[2] = (i & 4) ? mins[2] : maxs[2];
970 GL_TransformToScreen(v, v2);
971 //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]);
990 // clipped by nearclip plane
991 // this is nasty and crude...
992 // create viewspace bbox
993 for (i = 0;i < 8;i++)
995 v[0] = ((i & 1) ? mins[0] : maxs[0]) - r_vieworigin[0];
996 v[1] = ((i & 2) ? mins[1] : maxs[1]) - r_vieworigin[1];
997 v[2] = ((i & 4) ? mins[2] : maxs[2]) - r_vieworigin[2];
998 v2[0] = -DotProduct(v, r_viewleft);
999 v2[1] = DotProduct(v, r_viewup);
1000 v2[2] = DotProduct(v, r_viewforward);
1003 if (smins[0] > v2[0]) smins[0] = v2[0];
1004 if (smaxs[0] < v2[0]) smaxs[0] = v2[0];
1005 if (smins[1] > v2[1]) smins[1] = v2[1];
1006 if (smaxs[1] < v2[1]) smaxs[1] = v2[1];
1007 if (smins[2] > v2[2]) smins[2] = v2[2];
1008 if (smaxs[2] < v2[2]) smaxs[2] = v2[2];
1012 smins[0] = smaxs[0] = v2[0];
1013 smins[1] = smaxs[1] = v2[1];
1014 smins[2] = smaxs[2] = v2[2];
1017 // now we have a bbox in viewspace
1018 // clip it to the view plane
1021 // return true if that culled the box
1022 if (smins[2] >= smaxs[2])
1024 // ok some of it is infront of the view, transform each corner back to
1025 // worldspace and then to screenspace and make screen rect
1026 // initialize these variables just to avoid compiler warnings
1027 x1 = y1 = x2 = y2 = 0;
1028 for (i = 0;i < 8;i++)
1030 v2[0] = (i & 1) ? smins[0] : smaxs[0];
1031 v2[1] = (i & 2) ? smins[1] : smaxs[1];
1032 v2[2] = (i & 4) ? smins[2] : smaxs[2];
1033 v[0] = v2[0] * -r_viewleft[0] + v2[1] * r_viewup[0] + v2[2] * r_viewforward[0] + r_vieworigin[0];
1034 v[1] = v2[0] * -r_viewleft[1] + v2[1] * r_viewup[1] + v2[2] * r_viewforward[1] + r_vieworigin[1];
1035 v[2] = v2[0] * -r_viewleft[2] + v2[1] * r_viewup[2] + v2[2] * r_viewforward[2] + r_vieworigin[2];
1037 GL_TransformToScreen(v, v2);
1038 //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]);
1055 // this code doesn't handle boxes with any points behind view properly
1056 x1 = 1000;x2 = -1000;
1057 y1 = 1000;y2 = -1000;
1058 for (i = 0;i < 8;i++)
1060 v[0] = (i & 1) ? mins[0] : maxs[0];
1061 v[1] = (i & 2) ? mins[1] : maxs[1];
1062 v[2] = (i & 4) ? mins[2] : maxs[2];
1064 GL_TransformToScreen(v, v2);
1065 //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]);
1083 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1084 if (ix1 < r_view_x) ix1 = r_view_x;
1085 if (iy1 < r_view_y) iy1 = r_view_y;
1086 if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
1087 if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
1088 if (ix2 <= ix1 || iy2 <= iy1)
1090 // set up the scissor rectangle
1091 GL_Scissor(ix1, vid.realheight - iy2, ix2 - ix1, iy2 - iy1);
1092 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1093 //qglEnable(GL_SCISSOR_TEST);
1098 static void R_Shadow_VertexShadingWithXYZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1100 float *color4f = varray_color4f;
1101 float dist, dot, intensity, v[3], n[3];
1102 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1104 Matrix4x4_Transform(m, vertex3f, v);
1105 if ((dist = DotProduct(v, v)) < 1)
1107 Matrix4x4_Transform3x3(m, normal3f, n);
1108 if ((dot = DotProduct(n, v)) > 0)
1111 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1112 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1113 VectorScale(lightcolor, intensity, color4f);
1118 VectorClear(color4f);
1124 VectorClear(color4f);
1130 static void R_Shadow_VertexShadingWithZAttenuation(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1132 float *color4f = varray_color4f;
1133 float dist, dot, intensity, v[3], n[3];
1134 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1136 Matrix4x4_Transform(m, vertex3f, v);
1137 if ((dist = fabs(v[2])) < 1)
1139 Matrix4x4_Transform3x3(m, normal3f, n);
1140 if ((dot = DotProduct(n, v)) > 0)
1142 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1143 intensity *= pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale;
1144 VectorScale(lightcolor, intensity, color4f);
1149 VectorClear(color4f);
1155 VectorClear(color4f);
1161 static void R_Shadow_VertexShading(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1163 float *color4f = varray_color4f;
1164 float dot, intensity, v[3], n[3];
1165 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1167 Matrix4x4_Transform(m, vertex3f, v);
1168 Matrix4x4_Transform3x3(m, normal3f, n);
1169 if ((dot = DotProduct(n, v)) > 0)
1171 intensity = dot / sqrt(VectorLength2(v) * VectorLength2(n));
1172 VectorScale(lightcolor, intensity, color4f);
1177 VectorClear(color4f);
1183 #define USETEXMATRIX 1
1184 #ifndef USETEXMATRIX
1185 // FIXME: this should be done in a texture matrix or vertex program when possible
1186 // FIXME: if vertex program not available, this would really benefit from 3DNow! or SSE
1187 static void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1191 tc3f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1192 tc3f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1193 tc3f[2] = vertex3f[0] * matrix->m[2][0] + vertex3f[1] * matrix->m[2][1] + vertex3f[2] * matrix->m[2][2] + matrix->m[2][3];
1200 static void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1204 tc2f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1205 tc2f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1213 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(float *out3f, int numverts, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const vec3_t relativelightorigin)
1217 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1219 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1220 // the cubemap normalizes this for us
1221 out3f[0] = DotProduct(svector3f, lightdir);
1222 out3f[1] = DotProduct(tvector3f, lightdir);
1223 out3f[2] = DotProduct(normal3f, lightdir);
1227 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(float *out3f, int numverts, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const vec3_t relativelightorigin, const vec3_t relativeeyeorigin)
1230 float lightdir[3], eyedir[3], halfdir[3];
1231 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1233 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1234 VectorNormalizeFast(lightdir);
1235 VectorSubtract(vertex3f, relativeeyeorigin, eyedir);
1236 VectorNormalizeFast(eyedir);
1237 VectorAdd(lightdir, eyedir, halfdir);
1238 // the cubemap normalizes this for us
1239 out3f[0] = DotProduct(svector3f, halfdir);
1240 out3f[1] = DotProduct(tvector3f, halfdir);
1241 out3f[2] = DotProduct(normal3f, halfdir);
1245 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)
1248 float color[3], color2[3], colorscale;
1251 bumptexture = r_shadow_blankbumptexture;
1253 glosstexture = r_shadow_blankglosstexture;
1254 GL_DepthMask(false);
1256 if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
1258 if (lighting & LIGHTING_DIFFUSE)
1261 colorscale = r_shadow_lightintensityscale.value;
1262 // colorscale accounts for how much we multiply the brightness
1265 // mult is how many times the final pass of the lighting will be
1266 // performed to get more brightness than otherwise possible.
1268 // Limit mult to 64 for sanity sake.
1269 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1271 // 3/2 3D combine path (Geforce3, Radeon 8500)
1272 memset(&m, 0, sizeof(m));
1273 m.pointer_vertex = vertex3f;
1274 m.tex[0] = R_GetTexture(bumptexture);
1275 m.texcombinergb[0] = GL_REPLACE;
1276 m.pointer_texcoord[0] = texcoord2f;
1277 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1278 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1279 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1280 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1281 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1283 m.pointer_texcoord3f[2] = vertex3f;
1284 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
1286 m.pointer_texcoord3f[2] = varray_texcoord3f[2];
1287 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1290 GL_ColorMask(0,0,0,1);
1291 GL_BlendFunc(GL_ONE, GL_ZERO);
1292 GL_LockArrays(0, numverts);
1293 R_Mesh_Draw(numverts, numtriangles, elements);
1294 GL_LockArrays(0, 0);
1296 c_rt_lighttris += numtriangles;
1298 memset(&m, 0, sizeof(m));
1299 m.pointer_vertex = vertex3f;
1300 m.tex[0] = R_GetTexture(basetexture);
1301 m.pointer_texcoord[0] = texcoord2f;
1304 m.texcubemap[1] = R_GetTexture(lightcubemap);
1306 m.pointer_texcoord3f[1] = vertex3f;
1307 m.texmatrix[1] = *matrix_modeltolight;
1309 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1310 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1314 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap)
1316 // 1/2/2 3D combine path (original Radeon)
1317 memset(&m, 0, sizeof(m));
1318 m.pointer_vertex = vertex3f;
1319 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1321 m.pointer_texcoord3f[0] = vertex3f;
1322 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1324 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1325 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1328 GL_ColorMask(0,0,0,1);
1329 GL_BlendFunc(GL_ONE, GL_ZERO);
1330 GL_LockArrays(0, numverts);
1331 R_Mesh_Draw(numverts, numtriangles, elements);
1332 GL_LockArrays(0, 0);
1334 c_rt_lighttris += numtriangles;
1336 memset(&m, 0, sizeof(m));
1337 m.pointer_vertex = vertex3f;
1338 m.tex[0] = R_GetTexture(bumptexture);
1339 m.texcombinergb[0] = GL_REPLACE;
1340 m.pointer_texcoord[0] = texcoord2f;
1341 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1342 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1343 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1344 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1346 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1347 GL_LockArrays(0, numverts);
1348 R_Mesh_Draw(numverts, numtriangles, elements);
1349 GL_LockArrays(0, 0);
1351 c_rt_lighttris += numtriangles;
1353 memset(&m, 0, sizeof(m));
1354 m.pointer_vertex = vertex3f;
1355 m.tex[0] = R_GetTexture(basetexture);
1356 m.pointer_texcoord[0] = texcoord2f;
1359 m.texcubemap[1] = R_GetTexture(lightcubemap);
1361 m.pointer_texcoord3f[1] = vertex3f;
1362 m.texmatrix[1] = *matrix_modeltolight;
1364 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1365 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1369 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap)
1371 // 2/2 3D combine path (original Radeon)
1372 memset(&m, 0, sizeof(m));
1373 m.pointer_vertex = vertex3f;
1374 m.tex[0] = R_GetTexture(bumptexture);
1375 m.texcombinergb[0] = GL_REPLACE;
1376 m.pointer_texcoord[0] = texcoord2f;
1377 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1378 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1379 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1380 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1382 GL_ColorMask(0,0,0,1);
1383 GL_BlendFunc(GL_ONE, GL_ZERO);
1384 GL_LockArrays(0, numverts);
1385 R_Mesh_Draw(numverts, numtriangles, elements);
1386 GL_LockArrays(0, 0);
1388 c_rt_lighttris += numtriangles;
1390 memset(&m, 0, sizeof(m));
1391 m.pointer_vertex = vertex3f;
1392 m.tex[0] = R_GetTexture(basetexture);
1393 m.pointer_texcoord[0] = texcoord2f;
1394 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1396 m.pointer_texcoord3f[1] = vertex3f;
1397 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1399 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1400 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1403 else if (r_textureunits.integer >= 4)
1405 // 4/2 2D combine path (Geforce3, Radeon 8500)
1406 memset(&m, 0, sizeof(m));
1407 m.pointer_vertex = vertex3f;
1408 m.tex[0] = R_GetTexture(bumptexture);
1409 m.texcombinergb[0] = GL_REPLACE;
1410 m.pointer_texcoord[0] = texcoord2f;
1411 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1412 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1413 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1414 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1415 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1417 m.pointer_texcoord3f[2] = vertex3f;
1418 m.texmatrix[2] = *matrix_modeltoattenuationxyz;
1420 m.pointer_texcoord[2] = varray_texcoord2f[2];
1421 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1423 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1425 m.pointer_texcoord3f[3] = vertex3f;
1426 m.texmatrix[3] = *matrix_modeltoattenuationz;
1428 m.pointer_texcoord[3] = varray_texcoord2f[3];
1429 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[3], numverts, vertex3f, matrix_modeltoattenuationz);
1432 GL_ColorMask(0,0,0,1);
1433 GL_BlendFunc(GL_ONE, GL_ZERO);
1434 GL_LockArrays(0, numverts);
1435 R_Mesh_Draw(numverts, numtriangles, elements);
1436 GL_LockArrays(0, 0);
1438 c_rt_lighttris += numtriangles;
1440 memset(&m, 0, sizeof(m));
1441 m.pointer_vertex = vertex3f;
1442 m.tex[0] = R_GetTexture(basetexture);
1443 m.pointer_texcoord[0] = texcoord2f;
1446 m.texcubemap[1] = R_GetTexture(lightcubemap);
1448 m.pointer_texcoord3f[1] = vertex3f;
1449 m.texmatrix[1] = *matrix_modeltolight;
1451 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1452 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1458 // 2/2/2 2D combine path (any dot3 card)
1459 memset(&m, 0, sizeof(m));
1460 m.pointer_vertex = vertex3f;
1461 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1463 m.pointer_texcoord3f[0] = vertex3f;
1464 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1466 m.pointer_texcoord[0] = varray_texcoord2f[0];
1467 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1469 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1471 m.pointer_texcoord3f[1] = vertex3f;
1472 m.texmatrix[1] = *matrix_modeltoattenuationz;
1474 m.pointer_texcoord[1] = varray_texcoord2f[1];
1475 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1478 GL_ColorMask(0,0,0,1);
1479 GL_BlendFunc(GL_ONE, GL_ZERO);
1480 GL_LockArrays(0, numverts);
1481 R_Mesh_Draw(numverts, numtriangles, elements);
1482 GL_LockArrays(0, 0);
1484 c_rt_lighttris += numtriangles;
1486 memset(&m, 0, sizeof(m));
1487 m.pointer_vertex = vertex3f;
1488 m.tex[0] = R_GetTexture(bumptexture);
1489 m.texcombinergb[0] = GL_REPLACE;
1490 m.pointer_texcoord[0] = texcoord2f;
1491 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1492 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1493 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1494 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1496 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1497 GL_LockArrays(0, numverts);
1498 R_Mesh_Draw(numverts, numtriangles, elements);
1499 GL_LockArrays(0, 0);
1501 c_rt_lighttris += numtriangles;
1503 memset(&m, 0, sizeof(m));
1504 m.pointer_vertex = vertex3f;
1505 m.tex[0] = R_GetTexture(basetexture);
1506 m.pointer_texcoord[0] = texcoord2f;
1509 m.texcubemap[1] = R_GetTexture(lightcubemap);
1511 m.pointer_texcoord3f[1] = vertex3f;
1512 m.texmatrix[1] = *matrix_modeltolight;
1514 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1515 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1519 // this final code is shared
1521 GL_ColorMask(1,1,1,0);
1522 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1523 VectorScale(lightcolor, colorscale, color2);
1524 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1526 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1527 GL_LockArrays(0, numverts);
1528 R_Mesh_Draw(numverts, numtriangles, elements);
1529 GL_LockArrays(0, 0);
1531 c_rt_lighttris += numtriangles;
1534 if ((lighting & LIGHTING_SPECULAR) && (r_shadow_gloss.integer >= 2 || (r_shadow_gloss.integer >= 1 && glosstexture != r_shadow_blankglosstexture)))
1536 // FIXME: detect blendsquare!
1537 //if (gl_support_blendsquare)
1539 colorscale = r_shadow_lightintensityscale.value * r_shadow_glossintensity.value;
1540 if (glosstexture == r_shadow_blankglosstexture)
1541 colorscale *= r_shadow_gloss2intensity.value;
1543 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1545 // 2/0/0/1/2 3D combine blendsquare path
1546 memset(&m, 0, sizeof(m));
1547 m.pointer_vertex = vertex3f;
1548 m.tex[0] = R_GetTexture(bumptexture);
1549 m.pointer_texcoord[0] = texcoord2f;
1550 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1551 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1552 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1553 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1555 GL_ColorMask(0,0,0,1);
1556 // this squares the result
1557 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1558 GL_LockArrays(0, numverts);
1559 R_Mesh_Draw(numverts, numtriangles, elements);
1560 GL_LockArrays(0, 0);
1562 c_rt_lighttris += numtriangles;
1564 memset(&m, 0, sizeof(m));
1565 m.pointer_vertex = vertex3f;
1567 GL_LockArrays(0, numverts);
1568 // square alpha in framebuffer a few times to make it shiny
1569 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1570 // these comments are a test run through this math for intensity 0.5
1571 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1572 // 0.25 * 0.25 = 0.0625 (this is another pass)
1573 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1574 R_Mesh_Draw(numverts, numtriangles, elements);
1576 c_rt_lighttris += numtriangles;
1577 R_Mesh_Draw(numverts, numtriangles, elements);
1579 c_rt_lighttris += numtriangles;
1580 GL_LockArrays(0, 0);
1582 memset(&m, 0, sizeof(m));
1583 m.pointer_vertex = vertex3f;
1584 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1586 m.pointer_texcoord3f[0] = vertex3f;
1587 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1589 m.pointer_texcoord3f[0] = varray_texcoord3f[0];
1590 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1593 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1594 GL_LockArrays(0, numverts);
1595 R_Mesh_Draw(numverts, numtriangles, elements);
1596 GL_LockArrays(0, 0);
1598 c_rt_lighttris += numtriangles;
1600 memset(&m, 0, sizeof(m));
1601 m.pointer_vertex = vertex3f;
1602 m.tex[0] = R_GetTexture(glosstexture);
1603 m.pointer_texcoord[0] = texcoord2f;
1606 m.texcubemap[1] = R_GetTexture(lightcubemap);
1608 m.pointer_texcoord3f[1] = vertex3f;
1609 m.texmatrix[1] = *matrix_modeltolight;
1611 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1612 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1616 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1618 // 2/0/0/2 3D combine blendsquare path
1619 memset(&m, 0, sizeof(m));
1620 m.pointer_vertex = vertex3f;
1621 m.tex[0] = R_GetTexture(bumptexture);
1622 m.pointer_texcoord[0] = texcoord2f;
1623 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1624 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1625 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1626 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1628 GL_ColorMask(0,0,0,1);
1629 // this squares the result
1630 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1631 GL_LockArrays(0, numverts);
1632 R_Mesh_Draw(numverts, numtriangles, elements);
1633 GL_LockArrays(0, 0);
1635 c_rt_lighttris += numtriangles;
1637 memset(&m, 0, sizeof(m));
1638 m.pointer_vertex = vertex3f;
1640 GL_LockArrays(0, numverts);
1641 // square alpha in framebuffer a few times to make it shiny
1642 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1643 // these comments are a test run through this math for intensity 0.5
1644 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1645 // 0.25 * 0.25 = 0.0625 (this is another pass)
1646 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1647 R_Mesh_Draw(numverts, numtriangles, elements);
1649 c_rt_lighttris += numtriangles;
1650 R_Mesh_Draw(numverts, numtriangles, elements);
1652 c_rt_lighttris += numtriangles;
1653 GL_LockArrays(0, 0);
1655 memset(&m, 0, sizeof(m));
1656 m.pointer_vertex = vertex3f;
1657 m.tex[0] = R_GetTexture(glosstexture);
1658 m.pointer_texcoord[0] = texcoord2f;
1659 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1661 m.pointer_texcoord3f[1] = vertex3f;
1662 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1664 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1665 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1670 // 2/0/0/2/2 2D combine blendsquare path
1671 memset(&m, 0, sizeof(m));
1672 m.pointer_vertex = vertex3f;
1673 m.tex[0] = R_GetTexture(bumptexture);
1674 m.pointer_texcoord[0] = texcoord2f;
1675 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1676 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1677 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1678 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1680 GL_ColorMask(0,0,0,1);
1681 // this squares the result
1682 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1683 GL_LockArrays(0, numverts);
1684 R_Mesh_Draw(numverts, numtriangles, elements);
1685 GL_LockArrays(0, 0);
1687 c_rt_lighttris += numtriangles;
1689 memset(&m, 0, sizeof(m));
1690 m.pointer_vertex = vertex3f;
1692 GL_LockArrays(0, numverts);
1693 // square alpha in framebuffer a few times to make it shiny
1694 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1695 // these comments are a test run through this math for intensity 0.5
1696 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1697 // 0.25 * 0.25 = 0.0625 (this is another pass)
1698 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1699 R_Mesh_Draw(numverts, numtriangles, elements);
1701 c_rt_lighttris += numtriangles;
1702 R_Mesh_Draw(numverts, numtriangles, elements);
1704 c_rt_lighttris += numtriangles;
1705 GL_LockArrays(0, 0);
1707 memset(&m, 0, sizeof(m));
1708 m.pointer_vertex = vertex3f;
1709 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1711 m.pointer_texcoord3f[0] = vertex3f;
1712 m.texmatrix[0] = *matrix_modeltoattenuationxyz;
1714 m.pointer_texcoord[0] = varray_texcoord2f[0];
1715 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1717 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1719 m.pointer_texcoord3f[1] = vertex3f;
1720 m.texmatrix[1] = *matrix_modeltoattenuationz;
1722 m.pointer_texcoord[1] = varray_texcoord2f[1];
1723 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1726 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1727 GL_LockArrays(0, numverts);
1728 R_Mesh_Draw(numverts, numtriangles, elements);
1729 GL_LockArrays(0, 0);
1731 c_rt_lighttris += numtriangles;
1733 memset(&m, 0, sizeof(m));
1734 m.pointer_vertex = vertex3f;
1735 m.tex[0] = R_GetTexture(glosstexture);
1736 m.pointer_texcoord[0] = texcoord2f;
1739 m.texcubemap[1] = R_GetTexture(lightcubemap);
1741 m.pointer_texcoord3f[1] = vertex3f;
1742 m.texmatrix[1] = *matrix_modeltolight;
1744 m.pointer_texcoord3f[1] = varray_texcoord3f[1];
1745 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1751 GL_ColorMask(1,1,1,0);
1752 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1753 VectorScale(lightcolor, colorscale, color2);
1754 GL_LockArrays(0, numverts);
1755 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1757 GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
1758 R_Mesh_Draw(numverts, numtriangles, elements);
1760 c_rt_lighttris += numtriangles;
1762 GL_LockArrays(0, 0);
1767 if (lighting & LIGHTING_DIFFUSE)
1769 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1770 VectorScale(lightcolor, r_shadow_lightintensityscale.value, color2);
1771 memset(&m, 0, sizeof(m));
1772 m.pointer_vertex = vertex3f;
1773 m.pointer_color = varray_color4f;
1774 m.tex[0] = R_GetTexture(basetexture);
1775 m.pointer_texcoord[0] = texcoord2f;
1776 if (r_textureunits.integer >= 2)
1779 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1781 m.pointer_texcoord3f[1] = vertex3f;
1782 m.texmatrix[1] = *matrix_modeltoattenuationxyz;
1784 m.pointer_texcoord[1] = varray_texcoord2f[1];
1785 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1787 if (r_textureunits.integer >= 3)
1789 // Geforce3/Radeon class but not using dot3
1790 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1792 m.pointer_texcoord3f[2] = vertex3f;
1793 m.texmatrix[2] = *matrix_modeltoattenuationz;
1795 m.pointer_texcoord[2] = varray_texcoord2f[2];
1796 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationz);
1801 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1803 color[0] = bound(0, color2[0], 1);
1804 color[1] = bound(0, color2[1], 1);
1805 color[2] = bound(0, color2[2], 1);
1806 if (r_textureunits.integer >= 3)
1807 R_Shadow_VertexShading(numverts, vertex3f, normal3f, color, matrix_modeltolight);
1808 else if (r_textureunits.integer >= 2)
1809 R_Shadow_VertexShadingWithZAttenuation(numverts, vertex3f, normal3f, color, matrix_modeltolight);
1811 R_Shadow_VertexShadingWithXYZAttenuation(numverts, vertex3f, normal3f, color, matrix_modeltolight);
1812 GL_LockArrays(0, numverts);
1813 R_Mesh_Draw(numverts, numtriangles, elements);
1814 GL_LockArrays(0, 0);
1816 c_rt_lighttris += numtriangles;
1822 void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
1826 R_RTLight_Uncompile(rtlight);
1827 memset(rtlight, 0, sizeof(*rtlight));
1829 VectorCopy(light->origin, rtlight->shadoworigin);
1830 VectorCopy(light->color, rtlight->color);
1831 rtlight->radius = light->radius;
1832 //rtlight->cullradius = rtlight->radius;
1833 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
1834 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
1835 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
1836 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
1837 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
1838 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
1839 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
1840 rtlight->cubemapname[0] = 0;
1841 if (light->cubemapname[0])
1842 strcpy(rtlight->cubemapname, light->cubemapname);
1843 else if (light->cubemapnum > 0)
1844 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
1845 rtlight->shadow = light->shadow;
1846 rtlight->corona = light->corona;
1847 rtlight->style = light->style;
1848 rtlight->isstatic = isstatic;
1849 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
1850 // ConcatScale won't work here because this needs to scale rotate and
1851 // translate, not just rotate
1852 scale = 1.0f / rtlight->radius;
1853 for (k = 0;k < 3;k++)
1854 for (j = 0;j < 4;j++)
1855 rtlight->matrix_worldtolight.m[k][j] *= scale;
1856 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationxyz, &matrix_attenuationxyz, &rtlight->matrix_worldtolight);
1857 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationz, &matrix_attenuationz, &rtlight->matrix_worldtolight);
1859 rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
1860 rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
1861 VectorScale(rtlight->color, rtlight->radius * d_lightstylevalue[rtlight->style] * 0.125f, rtlight->lightmap_light);
1862 rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
1865 rtlight_t *r_shadow_compilingrtlight;
1867 // compiles rtlight geometry
1868 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
1869 void R_RTLight_Compile(rtlight_t *rtlight)
1871 int shadowmeshes, shadowtris, lightmeshes, lighttris, numclusters, numsurfaces;
1872 entity_render_t *ent = &cl_entities[0].render;
1873 model_t *model = ent->model;
1875 // compile the light
1876 rtlight->compiled = true;
1877 rtlight->static_numclusters = 0;
1878 rtlight->static_numclusterpvsbytes = 0;
1879 rtlight->static_clusterlist = NULL;
1880 rtlight->static_clusterpvs = NULL;
1881 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
1882 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
1883 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
1884 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
1885 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
1886 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
1888 if (model && model->GetLightInfo)
1890 // this variable directs the DrawShadowVolume and DrawLight code to capture into the mesh chain instead of rendering
1891 r_shadow_compilingrtlight = rtlight;
1892 R_Shadow_EnlargeClusterBuffer(model->brush.num_pvsclusters);
1893 R_Shadow_EnlargeSurfaceBuffer(model->nummodelsurfaces);
1894 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);
1897 rtlight->static_numclusters = numclusters;
1898 rtlight->static_numclusterpvsbytes = (model->brush.num_pvsclusters + 7) >> 3;
1899 rtlight->static_clusterlist = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
1900 rtlight->static_clusterpvs = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusterpvsbytes);
1901 memcpy(rtlight->static_clusterlist, r_shadow_buffer_clusterlist, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
1902 memcpy(rtlight->static_clusterpvs, r_shadow_buffer_clusterpvs, rtlight->static_numclusterpvsbytes);
1904 if (model->DrawShadowVolume && rtlight->shadow)
1906 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
1907 model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
1908 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_shadow, false, false);
1910 if (model->DrawLight)
1912 rtlight->static_meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true);
1913 model->DrawLight(ent, rtlight->shadoworigin, vec3_origin, rtlight->radius, vec3_origin, &r_identitymatrix, &r_identitymatrix, &r_identitymatrix, NULL, numsurfaces, r_shadow_buffer_surfacelist);
1914 rtlight->static_meshchain_light = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_light, true, false);
1916 // switch back to rendering when DrawShadowVolume or DrawLight is called
1917 r_shadow_compilingrtlight = NULL;
1921 // use smallest available cullradius - box radius or light radius
1922 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
1923 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
1927 if (rtlight->static_meshchain_shadow)
1930 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
1933 shadowtris += mesh->numtriangles;
1939 if (rtlight->static_meshchain_light)
1942 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
1945 lighttris += mesh->numtriangles;
1949 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);
1952 void R_RTLight_Uncompile(rtlight_t *rtlight)
1954 if (rtlight->compiled)
1956 if (rtlight->static_meshchain_shadow)
1957 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
1958 rtlight->static_meshchain_shadow = NULL;
1959 if (rtlight->static_meshchain_light)
1960 Mod_ShadowMesh_Free(rtlight->static_meshchain_light);
1961 rtlight->static_meshchain_light = NULL;
1962 if (rtlight->static_clusterlist)
1963 Mem_Free(rtlight->static_clusterlist);
1964 rtlight->static_clusterlist = NULL;
1965 if (rtlight->static_clusterpvs)
1966 Mem_Free(rtlight->static_clusterpvs);
1967 rtlight->static_clusterpvs = NULL;
1968 rtlight->static_numclusters = 0;
1969 rtlight->static_numclusterpvsbytes = 0;
1970 rtlight->compiled = false;
1974 int shadowframecount = 0;
1976 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light);
1978 void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes)
1981 entity_render_t *ent;
1983 vec3_t relativelightorigin, relativeeyeorigin, lightcolor;
1984 rtexture_t *cubemaptexture;
1985 matrix4x4_t matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz;
1986 int numclusters, numsurfaces;
1987 int *clusterlist, *surfacelist;
1989 vec3_t cullmins, cullmaxs;
1993 if (d_lightstylevalue[rtlight->style] <= 0)
1995 cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
1996 cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
1997 cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
1998 cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
1999 cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2000 cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2001 if (R_CullBox(cullmins, cullmaxs))
2003 if (rtlight->isstatic && !rtlight->compiled && r_shadow_staticworldlights.integer)
2004 R_RTLight_Compile(rtlight);
2010 if (rtlight->compiled && r_shadow_staticworldlights.integer)
2012 numclusters = rtlight->static_numclusters;
2013 clusterlist = rtlight->static_clusterlist;
2014 clusterpvs = rtlight->static_clusterpvs;
2015 VectorCopy(rtlight->cullmins, cullmins);
2016 VectorCopy(rtlight->cullmaxs, cullmaxs);
2018 else if (cl.worldmodel && cl.worldmodel->GetLightInfo)
2020 R_Shadow_EnlargeClusterBuffer(cl.worldmodel->brush.num_pvsclusters);
2021 R_Shadow_EnlargeSurfaceBuffer(cl.worldmodel->nummodelsurfaces);
2022 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);
2023 clusterlist = r_shadow_buffer_clusterlist;
2024 clusterpvs = r_shadow_buffer_clusterpvs;
2025 surfacelist = r_shadow_buffer_surfacelist;
2029 for (i = 0;i < numclusters;i++)
2030 if (CHECKPVSBIT(r_pvsbits, clusterlist[i]))
2032 if (i == numclusters)
2035 if (R_CullBox(cullmins, cullmaxs))
2037 if (R_Shadow_ScissorForBBox(cullmins, cullmaxs))
2040 f = d_lightstylevalue[rtlight->style] * (1.0f / 256.0f);
2041 VectorScale(rtlight->color, f, lightcolor);
2043 if (rtlight->selected)
2045 f = 2 + sin(realtime * M_PI * 4.0);
2046 VectorScale(lightcolor, f, lightcolor);
2050 if (rtlight->cubemapname[0])
2051 cubemaptexture = R_Shadow_Cubemap(rtlight->cubemapname);
2053 cubemaptexture = NULL;
2056 shadow = rtlight->shadow && (rtlight->isstatic ? r_shadow_realtime_world_shadows.integer : (r_shadow_realtime_world.integer ? r_shadow_realtime_world_dlightshadows.integer : r_shadow_realtime_dlight_shadows.integer));
2059 if (rtlight->shadow)
2061 if (rtlight->isstatic)
2062 shadow = r_shadow_realtime_world_shadows.integer;
2065 if (r_shadow_realtime_world.integer)
2066 shadow = r_shadow_realtime_world_dlightshadows.integer;
2068 shadow = r_shadow_realtime_dlight_shadows.integer;
2073 if (shadow && (gl_stencil || visiblevolumes))
2075 if (!visiblevolumes)
2076 R_Shadow_Stage_ShadowVolumes();
2077 ent = &cl_entities[0].render;
2078 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2080 memset(&m, 0, sizeof(m));
2081 R_Mesh_Matrix(&ent->matrix);
2082 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2084 m.pointer_vertex = mesh->vertex3f;
2086 GL_LockArrays(0, mesh->numverts);
2087 if (r_shadowstage == SHADOWSTAGE_STENCIL)
2089 // decrement stencil if frontface is behind depthbuffer
2090 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2091 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2092 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2093 c_rtcached_shadowmeshes++;
2094 c_rtcached_shadowtris += mesh->numtriangles;
2095 // increment stencil if backface is behind depthbuffer
2096 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2097 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2099 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2100 c_rtcached_shadowmeshes++;
2101 c_rtcached_shadowtris += mesh->numtriangles;
2102 GL_LockArrays(0, 0);
2107 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2108 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, numsurfaces, surfacelist);
2110 if (r_drawentities.integer)
2112 for (i = 0;i < r_refdef.numentities;i++)
2114 ent = r_refdef.entities[i];
2116 if (r_shadow_cull.integer)
2118 if (!BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs))
2120 if (cl.worldmodel != NULL && cl.worldmodel->brush.BoxTouchingPVS != NULL && !cl.worldmodel->brush.BoxTouchingPVS(cl.worldmodel, clusterpvs, ent->mins, ent->maxs))
2123 if (!(ent->flags & RENDER_SHADOW) || !ent->model || !ent->model->DrawShadowVolume)
2125 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2126 // light emitting entities should not cast their own shadow
2127 if (VectorLength2(relativelightorigin) < 0.1)
2129 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, ent->model->nummodelsurfaces, ent->model->surfacelist);
2134 if (!visiblevolumes)
2136 if (shadow && gl_stencil)
2137 R_Shadow_Stage_LightWithShadows();
2139 R_Shadow_Stage_LightWithoutShadows();
2141 ent = &cl_entities[0].render;
2142 if (ent->model && ent->model->DrawLight)
2144 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2145 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2146 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2147 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2148 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2149 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2151 R_Mesh_Matrix(&ent->matrix);
2152 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2153 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);
2156 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, numsurfaces, surfacelist);
2158 if (r_drawentities.integer)
2160 for (i = 0;i < r_refdef.numentities;i++)
2162 ent = r_refdef.entities[i];
2163 if (ent->visframe == r_framecount && BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs) && ent->model && ent->model->DrawLight && (ent->flags & RENDER_LIGHT))
2165 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2166 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2167 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2168 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2169 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2170 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, ent->model->nummodelsurfaces, ent->model->surfacelist);
2177 void R_ShadowVolumeLighting(int visiblevolumes)
2185 memset(&m, 0, sizeof(m));
2188 GL_BlendFunc(GL_ONE, GL_ONE);
2189 GL_DepthMask(false);
2190 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
2191 qglDisable(GL_CULL_FACE);
2192 GL_Color(0.0, 0.0125, 0.1, 1);
2195 R_Shadow_Stage_Begin();
2197 if (r_shadow_realtime_world.integer)
2199 R_Shadow_LoadWorldLightsIfNeeded();
2200 if (r_shadow_debuglight.integer >= 0)
2202 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2203 if (lnum == r_shadow_debuglight.integer)
2204 R_DrawRTLight(&light->rtlight, visiblevolumes);
2207 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2208 R_DrawRTLight(&light->rtlight, visiblevolumes);
2210 if (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer)
2211 for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
2212 R_DrawRTLight(&light->rtlight, visiblevolumes);
2216 qglEnable(GL_CULL_FACE);
2217 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
2220 R_Shadow_Stage_End();
2223 cvar_t r_editlights = {0, "r_editlights", "0"};
2224 cvar_t r_editlights_cursordistance = {0, "r_editlights_distance", "1024"};
2225 cvar_t r_editlights_cursorpushback = {0, "r_editlights_pushback", "0"};
2226 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_pushoff", "4"};
2227 cvar_t r_editlights_cursorgrid = {0, "r_editlights_grid", "4"};
2228 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "0.8"};
2229 cvar_t r_editlights_rtlightssizescale = {CVAR_SAVE, "r_editlights_rtlightssizescale", "0.7"};
2230 cvar_t r_editlights_rtlightscolorscale = {CVAR_SAVE, "r_editlights_rtlightscolorscale", "2"};
2231 dlight_t *r_shadow_worldlightchain;
2232 dlight_t *r_shadow_selectedlight;
2233 vec3_t r_editlights_cursorlocation;
2235 typedef struct cubemapinfo_s
2238 rtexture_t *texture;
2242 #define MAX_CUBEMAPS 128
2243 static int numcubemaps;
2244 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
2246 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2247 typedef struct suffixinfo_s
2250 qboolean flipx, flipy, flipdiagonal;
2253 static suffixinfo_t suffix[3][6] =
2256 {"posx", false, false, false},
2257 {"negx", false, false, false},
2258 {"posy", false, false, false},
2259 {"negy", false, false, false},
2260 {"posz", false, false, false},
2261 {"negz", false, false, false}
2264 {"px", false, false, false},
2265 {"nx", false, false, false},
2266 {"py", false, false, false},
2267 {"ny", false, false, false},
2268 {"pz", false, false, false},
2269 {"nz", false, false, false}
2272 {"rt", true, false, true},
2273 {"lf", false, true, true},
2274 {"ft", true, true, false},
2275 {"bk", false, false, false},
2276 {"up", true, false, true},
2277 {"dn", true, false, true}
2281 static int componentorder[4] = {0, 1, 2, 3};
2283 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2285 int i, j, cubemapsize;
2286 qbyte *cubemappixels, *image_rgba;
2287 rtexture_t *cubemaptexture;
2289 // must start 0 so the first loadimagepixels has no requested width/height
2291 cubemappixels = NULL;
2292 cubemaptexture = NULL;
2293 // keep trying different suffix groups (posx, px, rt) until one loads
2294 for (j = 0;j < 3 && !cubemappixels;j++)
2296 // load the 6 images in the suffix group
2297 for (i = 0;i < 6;i++)
2299 // generate an image name based on the base and and suffix
2300 snprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2302 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2304 // an image loaded, make sure width and height are equal
2305 if (image_width == image_height)
2307 // if this is the first image to load successfully, allocate the cubemap memory
2308 if (!cubemappixels && image_width >= 1)
2310 cubemapsize = image_width;
2311 // note this clears to black, so unavailable sides are black
2312 cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2314 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2316 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);
2319 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2321 Mem_Free(image_rgba);
2325 // if a cubemap loaded, upload it
2328 if (!r_shadow_filters_texturepool)
2329 r_shadow_filters_texturepool = R_AllocTexturePool();
2330 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
2331 Mem_Free(cubemappixels);
2335 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
2336 for (j = 0;j < 3;j++)
2337 for (i = 0;i < 6;i++)
2338 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2339 Con_Print(" and was unable to find any of them.\n");
2341 return cubemaptexture;
2344 rtexture_t *R_Shadow_Cubemap(const char *basename)
2347 for (i = 0;i < numcubemaps;i++)
2348 if (!strcasecmp(cubemaps[i].basename, basename))
2349 return cubemaps[i].texture;
2350 if (i >= MAX_CUBEMAPS)
2353 strcpy(cubemaps[i].basename, basename);
2354 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
2355 return cubemaps[i].texture;
2358 void R_Shadow_FreeCubemaps(void)
2361 R_FreeTexturePool(&r_shadow_filters_texturepool);
2364 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)
2368 if (radius < 15 || DotProduct(color, color) < 0.03)
2370 Con_Print("R_Shadow_NewWorldLight: refusing to create a light too small/dim\n");
2374 light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
2375 VectorCopy(origin, light->origin);
2376 VectorCopy(angles, light->angles);
2377 VectorCopy(color, light->color);
2378 light->radius = radius;
2379 light->style = style;
2380 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
2382 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
2385 light->shadow = shadowenable;
2386 light->corona = corona;
2387 if (cubemapname && cubemapname[0] && strlen(cubemapname) < sizeof(light->cubemapname))
2388 strcpy(light->cubemapname, cubemapname);
2389 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
2390 light->next = r_shadow_worldlightchain;
2391 r_shadow_worldlightchain = light;
2393 R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
2394 if (r_shadow_staticworldlights.integer)
2395 R_RTLight_Compile(&light->rtlight);
2398 void R_Shadow_FreeWorldLight(dlight_t *light)
2400 dlight_t **lightpointer;
2401 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
2402 if (*lightpointer != light)
2403 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
2404 *lightpointer = light->next;
2405 R_RTLight_Uncompile(&light->rtlight);
2409 void R_Shadow_ClearWorldLights(void)
2411 while (r_shadow_worldlightchain)
2412 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
2413 r_shadow_selectedlight = NULL;
2414 R_Shadow_FreeCubemaps();
2417 void R_Shadow_SelectLight(dlight_t *light)
2419 if (r_shadow_selectedlight)
2420 r_shadow_selectedlight->selected = false;
2421 r_shadow_selectedlight = light;
2422 if (r_shadow_selectedlight)
2423 r_shadow_selectedlight->selected = true;
2426 rtexture_t *lighttextures[5];
2428 void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
2430 float scale = r_editlights_cursorgrid.value * 0.5f;
2431 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);
2434 void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
2437 const dlight_t *light;
2440 if (light->selected)
2441 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
2444 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);
2447 void R_Shadow_DrawLightSprites(void)
2453 for (i = 0;i < 5;i++)
2455 lighttextures[i] = NULL;
2456 if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1))))
2457 lighttextures[i] = pic->tex;
2460 for (light = r_shadow_worldlightchain;light;light = light->next)
2461 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, ((int) light) % 5);
2462 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
2465 void R_Shadow_SelectLightInView(void)
2467 float bestrating, rating, temp[3];
2468 dlight_t *best, *light;
2471 for (light = r_shadow_worldlightchain;light;light = light->next)
2473 VectorSubtract(light->origin, r_vieworigin, temp);
2474 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
2477 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
2478 if (bestrating < rating && CL_TraceLine(light->origin, r_vieworigin, NULL, NULL, true, NULL, SUPERCONTENTS_SOLID) == 1.0f)
2480 bestrating = rating;
2485 R_Shadow_SelectLight(best);
2488 void R_Shadow_LoadWorldLights(void)
2490 int n, a, style, shadow;
2491 char name[MAX_QPATH], cubemapname[MAX_QPATH], *lightsstring, *s, *t;
2492 float origin[3], radius, color[3], angles[3], corona;
2493 if (cl.worldmodel == NULL)
2495 Con_Print("No map loaded.\n");
2498 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2499 strlcat (name, ".rtlights", sizeof (name));
2500 lightsstring = FS_LoadFile(name, tempmempool, false);
2510 for (;COM_Parse(t, true) && strcmp(
2511 if (COM_Parse(t, true))
2513 if (com_token[0] == '!')
2516 origin[0] = atof(com_token+1);
2519 origin[0] = atof(com_token);
2524 while (*s && *s != '\n')
2530 // check for modifier flags
2536 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]);
2538 VectorClear(angles);
2541 if (a < 9 || !strcmp(cubemapname, "\"\""))
2546 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);
2549 VectorScale(color, r_editlights_rtlightscolorscale.value, color);
2550 radius *= r_editlights_rtlightssizescale.value;
2551 R_Shadow_NewWorldLight(origin, angles, color, radius, corona, style, shadow, cubemapname);
2556 Con_Printf("invalid rtlights file \"%s\"\n", name);
2557 Mem_Free(lightsstring);
2561 void R_Shadow_SaveWorldLights(void)
2564 int bufchars, bufmaxchars;
2566 char name[MAX_QPATH];
2568 if (!r_shadow_worldlightchain)
2570 if (cl.worldmodel == NULL)
2572 Con_Print("No map loaded.\n");
2575 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2576 strlcat (name, ".rtlights", sizeof (name));
2577 bufchars = bufmaxchars = 0;
2579 for (light = r_shadow_worldlightchain;light;light = light->next)
2581 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]);
2582 if (bufchars + (int) strlen(line) > bufmaxchars)
2584 bufmaxchars = bufchars + strlen(line) + 2048;
2586 buf = Mem_Alloc(r_shadow_mempool, bufmaxchars);
2590 memcpy(buf, oldbuf, bufchars);
2596 memcpy(buf + bufchars, line, strlen(line));
2597 bufchars += strlen(line);
2601 FS_WriteFile(name, buf, bufchars);
2606 void R_Shadow_LoadLightsFile(void)
2609 char name[MAX_QPATH], *lightsstring, *s, *t;
2610 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
2611 if (cl.worldmodel == NULL)
2613 Con_Print("No map loaded.\n");
2616 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2617 strlcat (name, ".lights", sizeof (name));
2618 lightsstring = FS_LoadFile(name, tempmempool, false);
2626 while (*s && *s != '\n')
2631 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);
2635 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);
2638 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
2639 radius = bound(15, radius, 4096);
2640 VectorScale(color, (2.0f / (8388608.0f)), color);
2641 R_Shadow_NewWorldLight(origin, vec3_origin, color, radius, 0, style, true, NULL);
2646 Con_Printf("invalid lights file \"%s\"\n", name);
2647 Mem_Free(lightsstring);
2651 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
2653 int entnum, style, islight, skin, pflags, effects;
2654 char key[256], value[1024];
2655 float origin[3], angles[3], radius, color[3], light, fadescale, lightscale, originhack[3], overridecolor[3];
2658 if (cl.worldmodel == NULL)
2660 Con_Print("No map loaded.\n");
2663 data = cl.worldmodel->brush.entities;
2666 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
2669 origin[0] = origin[1] = origin[2] = 0;
2670 originhack[0] = originhack[1] = originhack[2] = 0;
2671 angles[0] = angles[1] = angles[2] = 0;
2672 color[0] = color[1] = color[2] = 1;
2673 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
2683 if (!COM_ParseToken(&data, false))
2685 if (com_token[0] == '}')
2686 break; // end of entity
2687 if (com_token[0] == '_')
2688 strcpy(key, com_token + 1);
2690 strcpy(key, com_token);
2691 while (key[strlen(key)-1] == ' ') // remove trailing spaces
2692 key[strlen(key)-1] = 0;
2693 if (!COM_ParseToken(&data, false))
2695 strcpy(value, com_token);
2697 // now that we have the key pair worked out...
2698 if (!strcmp("light", key))
2699 light = atof(value);
2700 else if (!strcmp("origin", key))
2701 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
2702 else if (!strcmp("angle", key))
2703 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
2704 else if (!strcmp("angles", key))
2705 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
2706 else if (!strcmp("color", key))
2707 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
2708 else if (!strcmp("wait", key))
2709 fadescale = atof(value);
2710 else if (!strcmp("classname", key))
2712 if (!strncmp(value, "light", 5))
2715 if (!strcmp(value, "light_fluoro"))
2720 overridecolor[0] = 1;
2721 overridecolor[1] = 1;
2722 overridecolor[2] = 1;
2724 if (!strcmp(value, "light_fluorospark"))
2729 overridecolor[0] = 1;
2730 overridecolor[1] = 1;
2731 overridecolor[2] = 1;
2733 if (!strcmp(value, "light_globe"))
2738 overridecolor[0] = 1;
2739 overridecolor[1] = 0.8;
2740 overridecolor[2] = 0.4;
2742 if (!strcmp(value, "light_flame_large_yellow"))
2747 overridecolor[0] = 1;
2748 overridecolor[1] = 0.5;
2749 overridecolor[2] = 0.1;
2751 if (!strcmp(value, "light_flame_small_yellow"))
2756 overridecolor[0] = 1;
2757 overridecolor[1] = 0.5;
2758 overridecolor[2] = 0.1;
2760 if (!strcmp(value, "light_torch_small_white"))
2765 overridecolor[0] = 1;
2766 overridecolor[1] = 0.5;
2767 overridecolor[2] = 0.1;
2769 if (!strcmp(value, "light_torch_small_walltorch"))
2774 overridecolor[0] = 1;
2775 overridecolor[1] = 0.5;
2776 overridecolor[2] = 0.1;
2780 else if (!strcmp("style", key))
2781 style = atoi(value);
2782 else if (cl.worldmodel->type == mod_brushq3)
2784 if (!strcmp("scale", key))
2785 lightscale = atof(value);
2786 if (!strcmp("fade", key))
2787 fadescale = atof(value);
2789 else if (!strcmp("skin", key))
2790 skin = (int)atof(value);
2791 else if (!strcmp("pflags", key))
2792 pflags = (int)atof(value);
2793 else if (!strcmp("effects", key))
2794 effects = (int)atof(value);
2796 if (light <= 0 && islight)
2798 if (lightscale <= 0)
2802 if (gamemode == GAME_TENEBRAE)
2804 if (effects & EF_NODRAW)
2806 pflags |= PFLAGS_FULLDYNAMIC;
2807 effects &= ~EF_NODRAW;
2810 radius = min(light * r_editlights_quakelightsizescale.value * lightscale / fadescale, 1048576);
2811 light = sqrt(bound(0, light, 1048576)) * (1.0f / 16.0f);
2812 if (color[0] == 1 && color[1] == 1 && color[2] == 1)
2813 VectorCopy(overridecolor, color);
2814 VectorScale(color, light, color);
2815 VectorAdd(origin, originhack, origin);
2816 if (radius >= 15 && !(pflags & PFLAGS_FULLDYNAMIC))
2817 R_Shadow_NewWorldLight(origin, angles, color, radius, (pflags & PFLAGS_CORONA) != 0, style, (pflags & PFLAGS_NOSHADOW) == 0, skin >= 16 ? va("cubemaps/%i", skin) : NULL);
2822 void R_Shadow_SetCursorLocationForView(void)
2824 vec_t dist, push, frac;
2825 vec3_t dest, endpos, normal;
2826 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
2827 frac = CL_TraceLine(r_vieworigin, dest, endpos, normal, true, NULL, SUPERCONTENTS_SOLID);
2830 dist = frac * r_editlights_cursordistance.value;
2831 push = r_editlights_cursorpushback.value;
2835 VectorMA(endpos, push, r_viewforward, endpos);
2836 VectorMA(endpos, r_editlights_cursorpushoff.value, normal, endpos);
2838 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2839 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2840 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2843 void R_Shadow_UpdateWorldLightSelection(void)
2845 if (r_editlights.integer)
2847 R_Shadow_SetCursorLocationForView();
2848 R_Shadow_SelectLightInView();
2849 R_Shadow_DrawLightSprites();
2852 R_Shadow_SelectLight(NULL);
2855 void R_Shadow_EditLights_Clear_f(void)
2857 R_Shadow_ClearWorldLights();
2860 void R_Shadow_EditLights_Reload_f(void)
2862 r_shadow_reloadlights = true;
2865 void R_Shadow_EditLights_Save_f(void)
2868 R_Shadow_SaveWorldLights();
2871 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
2873 R_Shadow_ClearWorldLights();
2874 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
2877 void R_Shadow_EditLights_ImportLightsFile_f(void)
2879 R_Shadow_ClearWorldLights();
2880 R_Shadow_LoadLightsFile();
2883 void R_Shadow_EditLights_Spawn_f(void)
2886 if (!r_editlights.integer)
2888 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
2891 if (Cmd_Argc() != 1)
2893 Con_Print("r_editlights_spawn does not take parameters\n");
2896 color[0] = color[1] = color[2] = 1;
2897 R_Shadow_NewWorldLight(r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL);
2900 void R_Shadow_EditLights_Edit_f(void)
2902 vec3_t origin, angles, color;
2903 vec_t radius, corona;
2905 char cubemapname[1024];
2906 if (!r_editlights.integer)
2908 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
2911 if (!r_shadow_selectedlight)
2913 Con_Print("No selected light.\n");
2916 VectorCopy(r_shadow_selectedlight->origin, origin);
2917 VectorCopy(r_shadow_selectedlight->angles, angles);
2918 VectorCopy(r_shadow_selectedlight->color, color);
2919 radius = r_shadow_selectedlight->radius;
2920 style = r_shadow_selectedlight->style;
2921 if (r_shadow_selectedlight->cubemapname)
2922 strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
2925 shadows = r_shadow_selectedlight->shadow;
2926 corona = r_shadow_selectedlight->corona;
2927 if (!strcmp(Cmd_Argv(1), "origin"))
2929 if (Cmd_Argc() != 5)
2931 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
2934 origin[0] = atof(Cmd_Argv(2));
2935 origin[1] = atof(Cmd_Argv(3));
2936 origin[2] = atof(Cmd_Argv(4));
2938 else if (!strcmp(Cmd_Argv(1), "originx"))
2940 if (Cmd_Argc() != 3)
2942 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2945 origin[0] = atof(Cmd_Argv(2));
2947 else if (!strcmp(Cmd_Argv(1), "originy"))
2949 if (Cmd_Argc() != 3)
2951 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2954 origin[1] = atof(Cmd_Argv(2));
2956 else if (!strcmp(Cmd_Argv(1), "originz"))
2958 if (Cmd_Argc() != 3)
2960 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2963 origin[2] = atof(Cmd_Argv(2));
2965 else if (!strcmp(Cmd_Argv(1), "move"))
2967 if (Cmd_Argc() != 5)
2969 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
2972 origin[0] += atof(Cmd_Argv(2));
2973 origin[1] += atof(Cmd_Argv(3));
2974 origin[2] += atof(Cmd_Argv(4));
2976 else if (!strcmp(Cmd_Argv(1), "movex"))
2978 if (Cmd_Argc() != 3)
2980 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2983 origin[0] += atof(Cmd_Argv(2));
2985 else if (!strcmp(Cmd_Argv(1), "movey"))
2987 if (Cmd_Argc() != 3)
2989 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2992 origin[1] += atof(Cmd_Argv(2));
2994 else if (!strcmp(Cmd_Argv(1), "movez"))
2996 if (Cmd_Argc() != 3)
2998 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3001 origin[2] += atof(Cmd_Argv(2));
3003 else if (!strcmp(Cmd_Argv(1), "angles"))
3005 if (Cmd_Argc() != 5)
3007 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3010 angles[0] = atof(Cmd_Argv(2));
3011 angles[1] = atof(Cmd_Argv(3));
3012 angles[2] = atof(Cmd_Argv(4));
3014 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3016 if (Cmd_Argc() != 3)
3018 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3021 angles[0] = atof(Cmd_Argv(2));
3023 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3025 if (Cmd_Argc() != 3)
3027 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3030 angles[1] = atof(Cmd_Argv(2));
3032 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3034 if (Cmd_Argc() != 3)
3036 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3039 angles[2] = atof(Cmd_Argv(2));
3041 else if (!strcmp(Cmd_Argv(1), "color"))
3043 if (Cmd_Argc() != 5)
3045 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3048 color[0] = atof(Cmd_Argv(2));
3049 color[1] = atof(Cmd_Argv(3));
3050 color[2] = atof(Cmd_Argv(4));
3052 else if (!strcmp(Cmd_Argv(1), "radius"))
3054 if (Cmd_Argc() != 3)
3056 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3059 radius = atof(Cmd_Argv(2));
3061 else if (!strcmp(Cmd_Argv(1), "style"))
3063 if (Cmd_Argc() != 3)
3065 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3068 style = atoi(Cmd_Argv(2));
3070 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3074 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3077 if (Cmd_Argc() == 3)
3078 strcpy(cubemapname, Cmd_Argv(2));
3082 else if (!strcmp(Cmd_Argv(1), "shadows"))
3084 if (Cmd_Argc() != 3)
3086 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3089 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3091 else if (!strcmp(Cmd_Argv(1), "corona"))
3093 if (Cmd_Argc() != 3)
3095 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3098 corona = atof(Cmd_Argv(2));
3102 Con_Print("usage: r_editlights_edit [property] [value]\n");
3103 Con_Print("Selected light's properties:\n");
3104 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3105 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3106 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3107 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3108 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3109 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3110 Con_Printf("Shadows: %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3111 Con_Printf("Cubemap: %s\n", r_shadow_selectedlight->cubemapname);
3114 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3115 r_shadow_selectedlight = NULL;
3116 R_Shadow_NewWorldLight(origin, angles, color, radius, corona, style, shadows, cubemapname);
3119 extern int con_vislines;
3120 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3124 if (r_shadow_selectedlight == NULL)
3128 sprintf(temp, "Light properties");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3129 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;
3130 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;
3131 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;
3132 sprintf(temp, "Radius %f", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3133 sprintf(temp, "Corona %f", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3134 sprintf(temp, "Style %i", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3135 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;
3136 sprintf(temp, "Cubemap %s", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3139 void R_Shadow_EditLights_ToggleShadow_f(void)
3141 if (!r_editlights.integer)
3143 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3146 if (!r_shadow_selectedlight)
3148 Con_Print("No selected light.\n");
3151 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);
3152 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3153 r_shadow_selectedlight = NULL;
3156 void R_Shadow_EditLights_ToggleCorona_f(void)
3158 if (!r_editlights.integer)
3160 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3163 if (!r_shadow_selectedlight)
3165 Con_Print("No selected light.\n");
3168 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);
3169 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3170 r_shadow_selectedlight = NULL;
3173 void R_Shadow_EditLights_Remove_f(void)
3175 if (!r_editlights.integer)
3177 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
3180 if (!r_shadow_selectedlight)
3182 Con_Print("No selected light.\n");
3185 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3186 r_shadow_selectedlight = NULL;
3189 void R_Shadow_EditLights_Help_f(void)
3192 "Documentation on r_editlights system:\n"
3194 "r_editlights : enable/disable editing mode\n"
3195 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
3196 "r_editlights_cursorpushback : push back cursor this far from surface\n"
3197 "r_editlights_cursorpushoff : push cursor off surface this far\n"
3198 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
3199 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
3200 "r_editlights_rtlightssizescale : imported rtlight size scaling\n"
3201 "r_editlights_rtlightscolorscale : imported rtlight color scaling\n"
3203 "r_editlights_help : this help\n"
3204 "r_editlights_clear : remove all lights\n"
3205 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
3206 "r_editlights_save : save to .rtlights file\n"
3207 "r_editlights_spawn : create a light with default settings\n"
3208 "r_editlights_edit command : edit selected light - more documentation below\n"
3209 "r_editlights_remove : remove selected light\n"
3210 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
3211 "r_editlights_importlightentitiesfrommap : reload light entities\n"
3212 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
3214 "origin x y z : set light location\n"
3215 "originx x: set x component of light location\n"
3216 "originy y: set y component of light location\n"
3217 "originz z: set z component of light location\n"
3218 "move x y z : adjust light location\n"
3219 "movex x: adjust x component of light location\n"
3220 "movey y: adjust y component of light location\n"
3221 "movez z: adjust z component of light location\n"
3222 "angles x y z : set light angles\n"
3223 "anglesx x: set x component of light angles\n"
3224 "anglesy y: set y component of light angles\n"
3225 "anglesz z: set z component of light angles\n"
3226 "color r g b : set color of light (can be brighter than 1 1 1)\n"
3227 "radius radius : set radius (size) of light\n"
3228 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
3229 "cubemap basename : set filter cubemap of light (not yet supported)\n"
3230 "shadows 1/0 : turn on/off shadows\n"
3231 "corona n : set corona intensity\n"
3232 "<nothing> : print light properties to console\n"
3236 void R_Shadow_EditLights_Init(void)
3238 Cvar_RegisterVariable(&r_editlights);
3239 Cvar_RegisterVariable(&r_editlights_cursordistance);
3240 Cvar_RegisterVariable(&r_editlights_cursorpushback);
3241 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
3242 Cvar_RegisterVariable(&r_editlights_cursorgrid);
3243 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
3244 Cvar_RegisterVariable(&r_editlights_rtlightssizescale);
3245 Cvar_RegisterVariable(&r_editlights_rtlightscolorscale);
3246 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
3247 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
3248 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
3249 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
3250 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
3251 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
3252 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
3253 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
3254 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
3255 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
3256 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);