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 / (VectorLength(v) * VectorLength(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 / (VectorLength(v) * VectorLength(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 / (VectorLength(v) * VectorLength(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 int 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 {"ft", true, false, true},
2273 {"bk", false, true, true},
2274 {"lf", true, true, false},
2275 {"rt", false, false, false},
2276 {"up", false, false, false},
2277 {"dn", false, false, false}
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 for (j = 0;j < 3 && !cubemappixels;j++)
2295 for (i = 0;i < 6;i++)
2297 snprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2298 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2300 if (image_width == image_height)
2302 if (!cubemappixels && image_width >= 1)
2304 cubemapsize = image_width;
2305 // note this clears to black, so unavailable sizes are black
2306 cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2309 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);
2312 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2313 Mem_Free(image_rgba);
2319 if (!r_shadow_filters_texturepool)
2320 r_shadow_filters_texturepool = R_AllocTexturePool();
2321 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
2322 Mem_Free(cubemappixels);
2326 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
2327 for (j = 0;j < 3;j++)
2328 for (i = 0;i < 6;i++)
2329 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2330 Con_Print(" and was unable to find any of them.\n");
2332 return cubemaptexture;
2335 rtexture_t *R_Shadow_Cubemap(const char *basename)
2338 for (i = 0;i < numcubemaps;i++)
2339 if (!strcasecmp(cubemaps[i].basename, basename))
2340 return cubemaps[i].texture;
2341 if (i >= MAX_CUBEMAPS)
2344 strcpy(cubemaps[i].basename, basename);
2345 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
2346 return cubemaps[i].texture;
2349 void R_Shadow_FreeCubemaps(void)
2352 R_FreeTexturePool(&r_shadow_filters_texturepool);
2355 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)
2359 if (radius < 15 || DotProduct(color, color) < 0.03)
2361 Con_Print("R_Shadow_NewWorldLight: refusing to create a light too small/dim\n");
2365 light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
2366 VectorCopy(origin, light->origin);
2367 VectorCopy(angles, light->angles);
2368 VectorCopy(color, light->color);
2369 light->radius = radius;
2370 light->style = style;
2371 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
2373 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
2376 light->shadow = shadowenable;
2377 light->corona = corona;
2378 if (cubemapname && cubemapname[0] && strlen(cubemapname) < sizeof(light->cubemapname))
2379 strcpy(light->cubemapname, cubemapname);
2380 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
2381 light->next = r_shadow_worldlightchain;
2382 r_shadow_worldlightchain = light;
2384 R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
2385 if (r_shadow_staticworldlights.integer)
2386 R_RTLight_Compile(&light->rtlight);
2389 void R_Shadow_FreeWorldLight(dlight_t *light)
2391 dlight_t **lightpointer;
2392 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
2393 if (*lightpointer != light)
2394 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
2395 *lightpointer = light->next;
2396 R_RTLight_Uncompile(&light->rtlight);
2400 void R_Shadow_ClearWorldLights(void)
2402 while (r_shadow_worldlightchain)
2403 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
2404 r_shadow_selectedlight = NULL;
2405 R_Shadow_FreeCubemaps();
2408 void R_Shadow_SelectLight(dlight_t *light)
2410 if (r_shadow_selectedlight)
2411 r_shadow_selectedlight->selected = false;
2412 r_shadow_selectedlight = light;
2413 if (r_shadow_selectedlight)
2414 r_shadow_selectedlight->selected = true;
2417 rtexture_t *lighttextures[5];
2419 void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
2421 float scale = r_editlights_cursorgrid.value * 0.5f;
2422 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);
2425 void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
2428 const dlight_t *light;
2431 if (light->selected)
2432 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
2435 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);
2438 void R_Shadow_DrawLightSprites(void)
2444 for (i = 0;i < 5;i++)
2446 lighttextures[i] = NULL;
2447 if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1))))
2448 lighttextures[i] = pic->tex;
2451 for (light = r_shadow_worldlightchain;light;light = light->next)
2452 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, ((int) light) % 5);
2453 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
2456 void R_Shadow_SelectLightInView(void)
2458 float bestrating, rating, temp[3];
2459 dlight_t *best, *light;
2462 for (light = r_shadow_worldlightchain;light;light = light->next)
2464 VectorSubtract(light->origin, r_vieworigin, temp);
2465 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
2468 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
2469 if (bestrating < rating && CL_TraceLine(light->origin, r_vieworigin, NULL, NULL, true, NULL, SUPERCONTENTS_SOLID) == 1.0f)
2471 bestrating = rating;
2476 R_Shadow_SelectLight(best);
2479 void R_Shadow_LoadWorldLights(void)
2481 int n, a, style, shadow;
2482 char name[MAX_QPATH], cubemapname[MAX_QPATH], *lightsstring, *s, *t;
2483 float origin[3], radius, color[3], angles[3], corona;
2484 if (cl.worldmodel == NULL)
2486 Con_Print("No map loaded.\n");
2489 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2490 strlcat (name, ".rtlights", sizeof (name));
2491 lightsstring = FS_LoadFile(name, tempmempool, false);
2501 for (;COM_Parse(t, true) && strcmp(
2502 if (COM_Parse(t, true))
2504 if (com_token[0] == '!')
2507 origin[0] = atof(com_token+1);
2510 origin[0] = atof(com_token);
2515 while (*s && *s != '\n')
2521 // check for modifier flags
2527 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]);
2529 VectorClear(angles);
2532 if (a < 9 || !strcmp(cubemapname, "\"\""))
2537 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);
2540 VectorScale(color, r_editlights_rtlightscolorscale.value, color);
2541 radius *= r_editlights_rtlightssizescale.value;
2542 R_Shadow_NewWorldLight(origin, angles, color, radius, corona, style, shadow, cubemapname);
2547 Con_Printf("invalid rtlights file \"%s\"\n", name);
2548 Mem_Free(lightsstring);
2552 void R_Shadow_SaveWorldLights(void)
2555 int bufchars, bufmaxchars;
2557 char name[MAX_QPATH];
2559 if (!r_shadow_worldlightchain)
2561 if (cl.worldmodel == NULL)
2563 Con_Print("No map loaded.\n");
2566 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2567 strlcat (name, ".rtlights", sizeof (name));
2568 bufchars = bufmaxchars = 0;
2570 for (light = r_shadow_worldlightchain;light;light = light->next)
2572 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]);
2573 if (bufchars + (int) strlen(line) > bufmaxchars)
2575 bufmaxchars = bufchars + strlen(line) + 2048;
2577 buf = Mem_Alloc(r_shadow_mempool, bufmaxchars);
2581 memcpy(buf, oldbuf, bufchars);
2587 memcpy(buf + bufchars, line, strlen(line));
2588 bufchars += strlen(line);
2592 FS_WriteFile(name, buf, bufchars);
2597 void R_Shadow_LoadLightsFile(void)
2600 char name[MAX_QPATH], *lightsstring, *s, *t;
2601 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
2602 if (cl.worldmodel == NULL)
2604 Con_Print("No map loaded.\n");
2607 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2608 strlcat (name, ".lights", sizeof (name));
2609 lightsstring = FS_LoadFile(name, tempmempool, false);
2617 while (*s && *s != '\n')
2622 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);
2626 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);
2629 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
2630 radius = bound(15, radius, 4096);
2631 VectorScale(color, (2.0f / (8388608.0f)), color);
2632 R_Shadow_NewWorldLight(origin, vec3_origin, color, radius, 0, style, true, NULL);
2637 Con_Printf("invalid lights file \"%s\"\n", name);
2638 Mem_Free(lightsstring);
2642 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
2644 int entnum, style, islight, skin, pflags, effects;
2645 char key[256], value[1024];
2646 float origin[3], angles[3], radius, color[3], light, fadescale, lightscale, originhack[3], overridecolor[3];
2649 if (cl.worldmodel == NULL)
2651 Con_Print("No map loaded.\n");
2654 data = cl.worldmodel->brush.entities;
2657 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
2660 origin[0] = origin[1] = origin[2] = 0;
2661 originhack[0] = originhack[1] = originhack[2] = 0;
2662 angles[0] = angles[1] = angles[2] = 0;
2663 color[0] = color[1] = color[2] = 1;
2664 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
2674 if (!COM_ParseToken(&data, false))
2676 if (com_token[0] == '}')
2677 break; // end of entity
2678 if (com_token[0] == '_')
2679 strcpy(key, com_token + 1);
2681 strcpy(key, com_token);
2682 while (key[strlen(key)-1] == ' ') // remove trailing spaces
2683 key[strlen(key)-1] = 0;
2684 if (!COM_ParseToken(&data, false))
2686 strcpy(value, com_token);
2688 // now that we have the key pair worked out...
2689 if (!strcmp("light", key))
2690 light = atof(value);
2691 else if (!strcmp("origin", key))
2692 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
2693 else if (!strcmp("angle", key))
2694 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
2695 else if (!strcmp("angles", key))
2696 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
2697 else if (!strcmp("color", key))
2698 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
2699 else if (!strcmp("wait", key))
2700 fadescale = atof(value);
2701 else if (!strcmp("classname", key))
2703 if (!strncmp(value, "light", 5))
2706 if (!strcmp(value, "light_fluoro"))
2711 overridecolor[0] = 1;
2712 overridecolor[1] = 1;
2713 overridecolor[2] = 1;
2715 if (!strcmp(value, "light_fluorospark"))
2720 overridecolor[0] = 1;
2721 overridecolor[1] = 1;
2722 overridecolor[2] = 1;
2724 if (!strcmp(value, "light_globe"))
2729 overridecolor[0] = 1;
2730 overridecolor[1] = 0.8;
2731 overridecolor[2] = 0.4;
2733 if (!strcmp(value, "light_flame_large_yellow"))
2738 overridecolor[0] = 1;
2739 overridecolor[1] = 0.5;
2740 overridecolor[2] = 0.1;
2742 if (!strcmp(value, "light_flame_small_yellow"))
2747 overridecolor[0] = 1;
2748 overridecolor[1] = 0.5;
2749 overridecolor[2] = 0.1;
2751 if (!strcmp(value, "light_torch_small_white"))
2756 overridecolor[0] = 1;
2757 overridecolor[1] = 0.5;
2758 overridecolor[2] = 0.1;
2760 if (!strcmp(value, "light_torch_small_walltorch"))
2765 overridecolor[0] = 1;
2766 overridecolor[1] = 0.5;
2767 overridecolor[2] = 0.1;
2771 else if (!strcmp("style", key))
2772 style = atoi(value);
2773 else if (cl.worldmodel->type == mod_brushq3)
2775 if (!strcmp("scale", key))
2776 lightscale = atof(value);
2777 if (!strcmp("fade", key))
2778 fadescale = atof(value);
2780 else if (!strcmp("skin", key))
2781 skin = (int)atof(value);
2782 else if (!strcmp("pflags", key))
2783 pflags = (int)atof(value);
2784 else if (!strcmp("effects", key))
2785 effects = (int)atof(value);
2787 if (light <= 0 && islight)
2789 if (lightscale <= 0)
2793 if (gamemode == GAME_TENEBRAE)
2795 if (effects & EF_NODRAW)
2797 pflags |= PFLAGS_FULLDYNAMIC;
2798 effects &= ~EF_NODRAW;
2801 radius = min(light * r_editlights_quakelightsizescale.value * lightscale / fadescale, 1048576);
2802 light = sqrt(bound(0, light, 1048576)) * (1.0f / 16.0f);
2803 if (color[0] == 1 && color[1] == 1 && color[2] == 1)
2804 VectorCopy(overridecolor, color);
2805 VectorScale(color, light, color);
2806 VectorAdd(origin, originhack, origin);
2807 if (radius >= 15 && !(pflags & PFLAGS_FULLDYNAMIC))
2808 R_Shadow_NewWorldLight(origin, angles, color, radius, (pflags & PFLAGS_CORONA) != 0, style, (pflags & PFLAGS_NOSHADOW) == 0, skin >= 16 ? va("cubemaps/%i", skin) : NULL);
2813 void R_Shadow_SetCursorLocationForView(void)
2815 vec_t dist, push, frac;
2816 vec3_t dest, endpos, normal;
2817 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
2818 frac = CL_TraceLine(r_vieworigin, dest, endpos, normal, true, NULL, SUPERCONTENTS_SOLID);
2821 dist = frac * r_editlights_cursordistance.value;
2822 push = r_editlights_cursorpushback.value;
2826 VectorMA(endpos, push, r_viewforward, endpos);
2827 VectorMA(endpos, r_editlights_cursorpushoff.value, normal, endpos);
2829 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2830 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2831 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2834 void R_Shadow_UpdateWorldLightSelection(void)
2836 if (r_editlights.integer)
2838 R_Shadow_SetCursorLocationForView();
2839 R_Shadow_SelectLightInView();
2840 R_Shadow_DrawLightSprites();
2843 R_Shadow_SelectLight(NULL);
2846 void R_Shadow_EditLights_Clear_f(void)
2848 R_Shadow_ClearWorldLights();
2851 void R_Shadow_EditLights_Reload_f(void)
2853 r_shadow_reloadlights = true;
2856 void R_Shadow_EditLights_Save_f(void)
2859 R_Shadow_SaveWorldLights();
2862 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
2864 R_Shadow_ClearWorldLights();
2865 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
2868 void R_Shadow_EditLights_ImportLightsFile_f(void)
2870 R_Shadow_ClearWorldLights();
2871 R_Shadow_LoadLightsFile();
2874 void R_Shadow_EditLights_Spawn_f(void)
2877 if (!r_editlights.integer)
2879 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
2882 if (Cmd_Argc() != 1)
2884 Con_Print("r_editlights_spawn does not take parameters\n");
2887 color[0] = color[1] = color[2] = 1;
2888 R_Shadow_NewWorldLight(r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL);
2891 void R_Shadow_EditLights_Edit_f(void)
2893 vec3_t origin, angles, color;
2894 vec_t radius, corona;
2896 char cubemapname[1024];
2897 if (!r_editlights.integer)
2899 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
2902 if (!r_shadow_selectedlight)
2904 Con_Print("No selected light.\n");
2907 VectorCopy(r_shadow_selectedlight->origin, origin);
2908 VectorCopy(r_shadow_selectedlight->angles, angles);
2909 VectorCopy(r_shadow_selectedlight->color, color);
2910 radius = r_shadow_selectedlight->radius;
2911 style = r_shadow_selectedlight->style;
2912 if (r_shadow_selectedlight->cubemapname)
2913 strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
2916 shadows = r_shadow_selectedlight->shadow;
2917 corona = r_shadow_selectedlight->corona;
2918 if (!strcmp(Cmd_Argv(1), "origin"))
2920 if (Cmd_Argc() != 5)
2922 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
2925 origin[0] = atof(Cmd_Argv(2));
2926 origin[1] = atof(Cmd_Argv(3));
2927 origin[2] = atof(Cmd_Argv(4));
2929 else if (!strcmp(Cmd_Argv(1), "originx"))
2931 if (Cmd_Argc() != 3)
2933 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2936 origin[0] = atof(Cmd_Argv(2));
2938 else if (!strcmp(Cmd_Argv(1), "originy"))
2940 if (Cmd_Argc() != 3)
2942 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2945 origin[1] = atof(Cmd_Argv(2));
2947 else if (!strcmp(Cmd_Argv(1), "originz"))
2949 if (Cmd_Argc() != 3)
2951 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2954 origin[2] = atof(Cmd_Argv(2));
2956 else if (!strcmp(Cmd_Argv(1), "move"))
2958 if (Cmd_Argc() != 5)
2960 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
2963 origin[0] += atof(Cmd_Argv(2));
2964 origin[1] += atof(Cmd_Argv(3));
2965 origin[2] += atof(Cmd_Argv(4));
2967 else if (!strcmp(Cmd_Argv(1), "movex"))
2969 if (Cmd_Argc() != 3)
2971 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2974 origin[0] += atof(Cmd_Argv(2));
2976 else if (!strcmp(Cmd_Argv(1), "movey"))
2978 if (Cmd_Argc() != 3)
2980 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2983 origin[1] += atof(Cmd_Argv(2));
2985 else if (!strcmp(Cmd_Argv(1), "movez"))
2987 if (Cmd_Argc() != 3)
2989 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2992 origin[2] += atof(Cmd_Argv(2));
2994 else if (!strcmp(Cmd_Argv(1), "angles"))
2996 if (Cmd_Argc() != 5)
2998 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
3001 angles[0] = atof(Cmd_Argv(2));
3002 angles[1] = atof(Cmd_Argv(3));
3003 angles[2] = atof(Cmd_Argv(4));
3005 else if (!strcmp(Cmd_Argv(1), "anglesx"))
3007 if (Cmd_Argc() != 3)
3009 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3012 angles[0] = atof(Cmd_Argv(2));
3014 else if (!strcmp(Cmd_Argv(1), "anglesy"))
3016 if (Cmd_Argc() != 3)
3018 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3021 angles[1] = atof(Cmd_Argv(2));
3023 else if (!strcmp(Cmd_Argv(1), "anglesz"))
3025 if (Cmd_Argc() != 3)
3027 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3030 angles[2] = atof(Cmd_Argv(2));
3032 else if (!strcmp(Cmd_Argv(1), "color"))
3034 if (Cmd_Argc() != 5)
3036 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3039 color[0] = atof(Cmd_Argv(2));
3040 color[1] = atof(Cmd_Argv(3));
3041 color[2] = atof(Cmd_Argv(4));
3043 else if (!strcmp(Cmd_Argv(1), "radius"))
3045 if (Cmd_Argc() != 3)
3047 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3050 radius = atof(Cmd_Argv(2));
3052 else if (!strcmp(Cmd_Argv(1), "style"))
3054 if (Cmd_Argc() != 3)
3056 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3059 style = atoi(Cmd_Argv(2));
3061 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3065 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3068 if (Cmd_Argc() == 3)
3069 strcpy(cubemapname, Cmd_Argv(2));
3073 else if (!strcmp(Cmd_Argv(1), "shadows"))
3075 if (Cmd_Argc() != 3)
3077 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3080 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3082 else if (!strcmp(Cmd_Argv(1), "corona"))
3084 if (Cmd_Argc() != 3)
3086 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3089 corona = atof(Cmd_Argv(2));
3093 Con_Print("usage: r_editlights_edit [property] [value]\n");
3094 Con_Print("Selected light's properties:\n");
3095 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3096 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3097 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3098 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3099 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3100 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3101 Con_Printf("Shadows: %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3102 Con_Printf("Cubemap: %s\n", r_shadow_selectedlight->cubemapname);
3105 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3106 r_shadow_selectedlight = NULL;
3107 R_Shadow_NewWorldLight(origin, angles, color, radius, corona, style, shadows, cubemapname);
3110 extern int con_vislines;
3111 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3115 if (r_shadow_selectedlight == NULL)
3119 sprintf(temp, "Light properties");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3120 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;
3121 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;
3122 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;
3123 sprintf(temp, "Radius %f", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3124 sprintf(temp, "Corona %f", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3125 sprintf(temp, "Style %i", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3126 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;
3127 sprintf(temp, "Cubemap %s", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3130 void R_Shadow_EditLights_ToggleShadow_f(void)
3132 if (!r_editlights.integer)
3134 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3137 if (!r_shadow_selectedlight)
3139 Con_Print("No selected light.\n");
3142 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);
3143 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3144 r_shadow_selectedlight = NULL;
3147 void R_Shadow_EditLights_ToggleCorona_f(void)
3149 if (!r_editlights.integer)
3151 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3154 if (!r_shadow_selectedlight)
3156 Con_Print("No selected light.\n");
3159 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);
3160 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3161 r_shadow_selectedlight = NULL;
3164 void R_Shadow_EditLights_Remove_f(void)
3166 if (!r_editlights.integer)
3168 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
3171 if (!r_shadow_selectedlight)
3173 Con_Print("No selected light.\n");
3176 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3177 r_shadow_selectedlight = NULL;
3180 void R_Shadow_EditLights_Help_f(void)
3183 "Documentation on r_editlights system:\n"
3185 "r_editlights : enable/disable editing mode\n"
3186 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
3187 "r_editlights_cursorpushback : push back cursor this far from surface\n"
3188 "r_editlights_cursorpushoff : push cursor off surface this far\n"
3189 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
3190 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
3191 "r_editlights_rtlightssizescale : imported rtlight size scaling\n"
3192 "r_editlights_rtlightscolorscale : imported rtlight color scaling\n"
3194 "r_editlights_help : this help\n"
3195 "r_editlights_clear : remove all lights\n"
3196 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
3197 "r_editlights_save : save to .rtlights file\n"
3198 "r_editlights_spawn : create a light with default settings\n"
3199 "r_editlights_edit command : edit selected light - more documentation below\n"
3200 "r_editlights_remove : remove selected light\n"
3201 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
3202 "r_editlights_importlightentitiesfrommap : reload light entities\n"
3203 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
3205 "origin x y z : set light location\n"
3206 "originx x: set x component of light location\n"
3207 "originy y: set y component of light location\n"
3208 "originz z: set z component of light location\n"
3209 "move x y z : adjust light location\n"
3210 "movex x: adjust x component of light location\n"
3211 "movey y: adjust y component of light location\n"
3212 "movez z: adjust z component of light location\n"
3213 "angles x y z : set light angles\n"
3214 "anglesx x: set x component of light angles\n"
3215 "anglesy y: set y component of light angles\n"
3216 "anglesz z: set z component of light angles\n"
3217 "color r g b : set color of light (can be brighter than 1 1 1)\n"
3218 "radius radius : set radius (size) of light\n"
3219 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
3220 "cubemap basename : set filter cubemap of light (not yet supported)\n"
3221 "shadows 1/0 : turn on/off shadows\n"
3222 "corona n : set corona intensity\n"
3223 "<nothing> : print light properties to console\n"
3227 void R_Shadow_EditLights_Init(void)
3229 Cvar_RegisterVariable(&r_editlights);
3230 Cvar_RegisterVariable(&r_editlights_cursordistance);
3231 Cvar_RegisterVariable(&r_editlights_cursorpushback);
3232 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
3233 Cvar_RegisterVariable(&r_editlights_cursorgrid);
3234 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
3235 Cvar_RegisterVariable(&r_editlights_rtlightssizescale);
3236 Cvar_RegisterVariable(&r_editlights_rtlightscolorscale);
3237 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
3238 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
3239 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
3240 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
3241 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
3242 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
3243 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
3244 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
3245 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
3246 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
3247 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);