3 Terminology: Stencil Shadow Volume (sometimes called Stencil Shadows)
4 An extrusion of the lit faces, beginning at the original geometry and ending
5 further from the light source than the original geometry (presumably at least
6 as far as the light's radius, if the light has a radius at all), capped at
7 both front and back to avoid any problems (extrusion from dark faces also
8 works but has a different set of problems)
10 This is rendered using Carmack's Reverse technique, in which backfaces behind
11 zbuffer (zfail) increment the stencil, and frontfaces behind zbuffer (zfail)
12 decrement the stencil, the result is a stencil value of zero where shadows
13 did not intersect the visible geometry, suitable as a stencil mask for
14 rendering lighting everywhere but shadow.
16 In our case we use a biased stencil clear of 128 to avoid requiring the
17 stencil wrap extension (but probably should support it), and to address
18 Creative's patent on this sort of technology we also draw the frontfaces
19 first, and backfaces second (decrement, increment).
22 This algorithm may be covered by Creative's patent (US Patent #6384822)
23 on Carmack's Reverse paper (which I have not read), however that patent
24 seems to be about drawing a stencil shadow from a model in an otherwise
25 unshadowed scene, where as realtime lighting technology draws light where
30 Terminology: Stencil Light Volume (sometimes called Light Volumes)
31 Similar to a Stencil Shadow Volume, but inverted; rather than containing the
32 areas in shadow it contanis the areas in light, this can only be built
33 quickly for certain limited cases (such as portal visibility from a point),
34 but is quite useful for some effects (sunlight coming from sky polygons is
35 one possible example, translucent occluders is another example).
39 Terminology: Optimized Stencil Shadow Volume
40 A Stencil Shadow Volume that has been processed sufficiently to ensure it has
41 no duplicate coverage of areas (no need to shadow an area twice), often this
42 greatly improves performance but is an operation too costly to use on moving
43 lights (however completely optimal Stencil Light Volumes can be constructed
48 Terminology: Per Pixel Lighting (sometimes abbreviated PPL)
49 Per pixel evaluation of lighting equations, at a bare minimum this involves
50 DOT3 shading of diffuse lighting (per pixel dotproduct of negated incidence
51 vector and surface normal, using a texture of the surface bumps, called a
52 NormalMap) if supported by hardware; in our case there is support for cards
53 which are incapable of DOT3, the quality is quite poor however. Additionally
54 it is desirable to have specular evaluation per pixel, per vertex
55 normalization of specular halfangle vectors causes noticable distortion but
56 is unavoidable on hardware without GL_ARB_fragment_program.
60 Terminology: Normalization CubeMap
61 A cubemap containing normalized dot3-encoded (vectors of length 1 or less
62 encoded as RGB colors) for any possible direction, this technique allows per
63 pixel calculation of incidence vector for per pixel lighting purposes, which
64 would not otherwise be possible per pixel without GL_ARB_fragment_program.
68 Terminology: 2D Attenuation Texturing
69 A very crude approximation of light attenuation with distance which results
70 in cylindrical light shapes which fade vertically as a streak (some games
71 such as Doom3 allow this to be rotated to be less noticable in specific
72 cases), the technique is simply modulating lighting by two 2D textures (which
73 can be the same) on different axes of projection (XY and Z, typically), this
74 is the best technique available without 3D Attenuation Texturing or
75 GL_ARB_fragment_program technology.
79 Terminology: 3D Attenuation Texturing
80 A slightly crude approximation of light attenuation with distance, its flaws
81 are limited radius and resolution (performance tradeoffs).
85 Terminology: 3D Attenuation-Normalization Texturing
86 A 3D Attenuation Texture merged with a Normalization CubeMap, by making the
87 vectors shorter the lighting becomes darker, a very effective optimization of
88 diffuse lighting if 3D Attenuation Textures are already used.
92 Terminology: Light Cubemap Filtering
93 A technique for modeling non-uniform light distribution according to
94 direction, for example projecting a stained glass window image onto a wall,
95 this is done by texturing the lighting with a cubemap.
99 Terminology: Light Projection Filtering
100 A technique for modeling shadowing of light passing through translucent
101 surfaces, allowing stained glass windows and other effects to be done more
102 elegantly than possible with Light Cubemap Filtering by applying an occluder
103 texture to the lighting combined with a stencil light volume to limit the lit
104 area (this allows evaluating multiple translucent occluders in a scene).
108 Terminology: Doom3 Lighting
109 A combination of Stencil Shadow Volume, Per Pixel Lighting, Normalization
110 CubeMap, 2D Attenuation Texturing, and Light Filtering, as demonstrated by
111 the (currently upcoming) game Doom3.
114 #include "quakedef.h"
115 #include "r_shadow.h"
116 #include "cl_collision.h"
120 extern void R_Shadow_EditLights_Init(void);
122 #define SHADOWSTAGE_NONE 0
123 #define SHADOWSTAGE_STENCIL 1
124 #define SHADOWSTAGE_LIGHT 2
125 #define SHADOWSTAGE_STENCILTWOSIDE 3
127 int r_shadowstage = SHADOWSTAGE_NONE;
128 int r_shadow_reloadlights = false;
130 mempool_t *r_shadow_mempool;
132 int maxshadowelements;
146 int r_shadow_buffer_numclusterpvsbytes;
147 qbyte *r_shadow_buffer_clusterpvs;
148 int *r_shadow_buffer_clusterlist;
150 int r_shadow_buffer_numsurfacepvsbytes;
151 qbyte *r_shadow_buffer_surfacepvs;
152 int *r_shadow_buffer_surfacelist;
154 rtexturepool_t *r_shadow_texturepool;
155 rtexture_t *r_shadow_normalcubetexture;
156 rtexture_t *r_shadow_attenuation2dtexture;
157 rtexture_t *r_shadow_attenuation3dtexture;
158 rtexture_t *r_shadow_blankbumptexture;
159 rtexture_t *r_shadow_blankglosstexture;
160 rtexture_t *r_shadow_blankwhitetexture;
162 // used only for light filters (cubemaps)
163 rtexturepool_t *r_shadow_filters_texturepool;
165 cvar_t r_shadow_realtime_world_lightmaps = {0, "r_shadow_realtime_world_lightmaps", "0"};
166 cvar_t r_shadow_lightattenuationpower = {0, "r_shadow_lightattenuationpower", "0.5"};
167 cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1"};
168 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1"};
169 cvar_t r_shadow_realtime_world = {0, "r_shadow_realtime_world", "0"};
170 cvar_t r_shadow_realtime_dlight = {0, "r_shadow_realtime_dlight", "0"};
171 cvar_t r_shadow_visiblevolumes = {0, "r_shadow_visiblevolumes", "0"};
172 cvar_t r_shadow_gloss = {0, "r_shadow_gloss", "1"};
173 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1"};
174 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.25"};
175 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1"};
176 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1"};
177 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4"};
178 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0"};
179 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0"};
180 cvar_t r_shadow_polygonoffset = {0, "r_shadow_polygonoffset", "1"};
181 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1"};
182 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "10000"};
183 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1"};
184 cvar_t r_shadow_singlepassvolumegeneration = {0, "r_shadow_singlepassvolumegeneration", "1"};
185 cvar_t r_shadow_worldshadows = {0, "r_shadow_worldshadows", "1"};
186 cvar_t r_shadow_dlightshadows = {CVAR_SAVE, "r_shadow_dlightshadows", "1"};
187 cvar_t r_shadow_staticworldlights = {0, "r_shadow_staticworldlights", "1"};
188 cvar_t r_shadow_cull = {0, "r_shadow_cull", "1"};
189 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1"};
191 int c_rt_lights, c_rt_clears, c_rt_scissored;
192 int c_rt_shadowmeshes, c_rt_shadowtris, c_rt_lightmeshes, c_rt_lighttris;
193 int c_rtcached_shadowmeshes, c_rtcached_shadowtris;
195 void R_Shadow_ClearWorldLights(void);
196 void R_Shadow_SaveWorldLights(void);
197 void R_Shadow_LoadWorldLights(void);
198 void R_Shadow_LoadLightsFile(void);
199 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
201 void r_shadow_start(void)
203 // allocate vertex processing arrays
204 r_shadow_mempool = Mem_AllocPool("R_Shadow");
205 maxshadowelements = 0;
206 shadowelements = NULL;
214 shadowmarklist = NULL;
216 r_shadow_buffer_numclusterpvsbytes = 0;
217 r_shadow_buffer_clusterpvs = NULL;
218 r_shadow_buffer_clusterlist = NULL;
219 r_shadow_buffer_numsurfacepvsbytes = 0;
220 r_shadow_buffer_surfacepvs = NULL;
221 r_shadow_buffer_surfacelist = NULL;
222 r_shadow_normalcubetexture = NULL;
223 r_shadow_attenuation2dtexture = NULL;
224 r_shadow_attenuation3dtexture = NULL;
225 r_shadow_blankbumptexture = NULL;
226 r_shadow_blankglosstexture = NULL;
227 r_shadow_blankwhitetexture = NULL;
228 r_shadow_texturepool = NULL;
229 r_shadow_filters_texturepool = NULL;
230 R_Shadow_ClearWorldLights();
231 r_shadow_reloadlights = true;
234 void r_shadow_shutdown(void)
236 R_Shadow_ClearWorldLights();
237 r_shadow_reloadlights = true;
238 r_shadow_normalcubetexture = NULL;
239 r_shadow_attenuation2dtexture = NULL;
240 r_shadow_attenuation3dtexture = NULL;
241 r_shadow_blankbumptexture = NULL;
242 r_shadow_blankglosstexture = NULL;
243 r_shadow_blankwhitetexture = NULL;
244 R_FreeTexturePool(&r_shadow_texturepool);
245 R_FreeTexturePool(&r_shadow_filters_texturepool);
246 maxshadowelements = 0;
247 shadowelements = NULL;
255 shadowmarklist = NULL;
257 r_shadow_buffer_numclusterpvsbytes = 0;
258 r_shadow_buffer_clusterpvs = NULL;
259 r_shadow_buffer_clusterlist = NULL;
260 r_shadow_buffer_numsurfacepvsbytes = 0;
261 r_shadow_buffer_surfacepvs = NULL;
262 r_shadow_buffer_surfacelist = NULL;
263 Mem_FreePool(&r_shadow_mempool);
266 void r_shadow_newmap(void)
268 R_Shadow_ClearWorldLights();
269 r_shadow_reloadlights = true;
272 void R_Shadow_Help_f(void)
275 "Documentation on r_shadow system:\n"
277 "r_shadow_lightattenuationpower : used to generate attenuation texture\n"
278 "r_shadow_lightattenuationscale : used to generate attenuation texture\n"
279 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
280 "r_shadow_realtime_world : use realtime world light rendering\n"
281 "r_shadow_realtime_dlight : use high quality dlight rendering\n"
282 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to rtlights\n"
283 "r_shadow_visiblevolumes : useful for performance testing; bright = slow!\n"
284 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
285 "r_shadow_glossintensity : brightness of textured gloss\n"
286 "r_shadow_gloss2intensity : brightness of forced gloss\n"
287 "r_shadow_debuglight : render only this light number (-1 = all)\n"
288 "r_shadow_scissor : use scissor optimization\n"
289 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
290 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
291 "r_shadow_polygonfactor : nudge shadow volumes closer/further\n"
292 "r_shadow_polygonoffset : nudge shadow volumes closer/further\n"
293 "r_shadow_portallight : use portal visibility for static light precomputation\n"
294 "r_shadow_projectdistance : shadow volume projection distance\n"
295 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
296 "r_shadow_singlepassvolumegeneration : selects shadow volume algorithm\n"
297 "r_shadow_worldshadows : enable world shadows\n"
298 "r_shadow_dlightshadows : enable dlight shadows\n"
300 "r_shadow_help : this help\n"
304 void R_Shadow_Init(void)
306 Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
307 Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
308 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
309 Cvar_RegisterVariable(&r_shadow_realtime_world);
310 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
311 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
312 Cvar_RegisterVariable(&r_shadow_visiblevolumes);
313 Cvar_RegisterVariable(&r_shadow_gloss);
314 Cvar_RegisterVariable(&r_shadow_glossintensity);
315 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
316 Cvar_RegisterVariable(&r_shadow_debuglight);
317 Cvar_RegisterVariable(&r_shadow_scissor);
318 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
319 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
320 Cvar_RegisterVariable(&r_shadow_polygonfactor);
321 Cvar_RegisterVariable(&r_shadow_polygonoffset);
322 Cvar_RegisterVariable(&r_shadow_portallight);
323 Cvar_RegisterVariable(&r_shadow_projectdistance);
324 Cvar_RegisterVariable(&r_shadow_texture3d);
325 Cvar_RegisterVariable(&r_shadow_singlepassvolumegeneration);
326 Cvar_RegisterVariable(&r_shadow_worldshadows);
327 Cvar_RegisterVariable(&r_shadow_dlightshadows);
328 Cvar_RegisterVariable(&r_shadow_staticworldlights);
329 Cvar_RegisterVariable(&r_shadow_cull);
330 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
331 if (gamemode == GAME_TENEBRAE)
333 Cvar_SetValue("r_shadow_gloss", 2);
334 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
336 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f);
337 R_Shadow_EditLights_Init();
338 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
341 matrix4x4_t matrix_attenuationxyz =
344 {0.5, 0.0, 0.0, 0.5},
345 {0.0, 0.5, 0.0, 0.5},
346 {0.0, 0.0, 0.5, 0.5},
351 matrix4x4_t matrix_attenuationz =
354 {0.0, 0.0, 0.5, 0.5},
355 {0.0, 0.0, 0.0, 0.0},
356 {0.0, 0.0, 0.0, 0.0},
361 int *R_Shadow_ResizeShadowElements(int numtris)
363 // make sure shadowelements is big enough for this volume
364 if (maxshadowelements < numtris * 24)
366 maxshadowelements = numtris * 24;
368 Mem_Free(shadowelements);
369 shadowelements = Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int));
371 return shadowelements;
374 void R_Shadow_EnlargeClusterBuffer(int numclusters)
376 int numclusterpvsbytes = (((numclusters + 7) >> 3) + 255) & ~255;
377 if (r_shadow_buffer_numclusterpvsbytes < numclusterpvsbytes)
379 if (r_shadow_buffer_clusterpvs)
380 Mem_Free(r_shadow_buffer_clusterpvs);
381 if (r_shadow_buffer_clusterlist)
382 Mem_Free(r_shadow_buffer_clusterlist);
383 r_shadow_buffer_numclusterpvsbytes = numclusterpvsbytes;
384 r_shadow_buffer_clusterpvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numclusterpvsbytes);
385 r_shadow_buffer_clusterlist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numclusterpvsbytes * 8 * sizeof(*r_shadow_buffer_clusterlist));
389 void R_Shadow_EnlargeSurfaceBuffer(int numsurfaces)
391 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
392 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
394 if (r_shadow_buffer_surfacepvs)
395 Mem_Free(r_shadow_buffer_surfacepvs);
396 if (r_shadow_buffer_surfacelist)
397 Mem_Free(r_shadow_buffer_surfacelist);
398 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
399 r_shadow_buffer_surfacepvs = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes);
400 r_shadow_buffer_surfacelist = Mem_Alloc(r_shadow_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
404 void R_Shadow_PrepareShadowMark(int numtris)
406 // make sure shadowmark is big enough for this volume
407 if (maxshadowmark < numtris)
409 maxshadowmark = numtris;
411 Mem_Free(shadowmark);
413 Mem_Free(shadowmarklist);
414 shadowmark = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmark));
415 shadowmarklist = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmarklist));
419 // if shadowmarkcount wrapped we clear the array and adjust accordingly
420 if (shadowmarkcount == 0)
423 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
428 int R_Shadow_ConstructShadowVolume(int innumvertices, int innumtris, const int *inelement3i, const int *inneighbor3i, const float *invertex3f, int *outnumvertices, int *outelement3i, float *outvertex3f, const float *projectorigin, float projectdistance, int numshadowmarktris, const int *shadowmarktris)
430 int i, j, tris = 0, vr[3], t, outvertices = 0;
434 if (maxvertexupdate < innumvertices)
436 maxvertexupdate = innumvertices;
438 Mem_Free(vertexupdate);
440 Mem_Free(vertexremap);
441 vertexupdate = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
442 vertexremap = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
446 if (vertexupdatenum == 0)
449 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
450 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
453 for (i = 0;i < numshadowmarktris;i++)
455 t = shadowmarktris[i];
456 shadowmark[t] = shadowmarkcount;
457 e = inelement3i + t * 3;
458 // make sure the vertices are created
459 for (j = 0;j < 3;j++)
461 if (vertexupdate[e[j]] != vertexupdatenum)
463 vertexupdate[e[j]] = vertexupdatenum;
464 vertexremap[e[j]] = outvertices;
465 VectorSubtract(invertex3f + e[j] * 3, projectorigin, temp);
466 f = projectdistance / VectorLength(temp);
467 VectorCopy(invertex3f + e[j] * 3, outvertex3f);
468 VectorMA(projectorigin, f, temp, (outvertex3f + 3));
473 // output the front and back triangles
474 outelement3i[0] = vertexremap[e[0]];
475 outelement3i[1] = vertexremap[e[1]];
476 outelement3i[2] = vertexremap[e[2]];
477 outelement3i[3] = vertexremap[e[2]] + 1;
478 outelement3i[4] = vertexremap[e[1]] + 1;
479 outelement3i[5] = vertexremap[e[0]] + 1;
484 for (i = 0;i < numshadowmarktris;i++)
486 t = shadowmarktris[i];
487 e = inelement3i + t * 3;
488 n = inneighbor3i + t * 3;
489 // output the sides (facing outward from this triangle)
490 if (shadowmark[n[0]] != shadowmarkcount)
492 vr[0] = vertexremap[e[0]];
493 vr[1] = vertexremap[e[1]];
494 outelement3i[0] = vr[1];
495 outelement3i[1] = vr[0];
496 outelement3i[2] = vr[0] + 1;
497 outelement3i[3] = vr[1];
498 outelement3i[4] = vr[0] + 1;
499 outelement3i[5] = vr[1] + 1;
503 if (shadowmark[n[1]] != shadowmarkcount)
505 vr[1] = vertexremap[e[1]];
506 vr[2] = vertexremap[e[2]];
507 outelement3i[0] = vr[2];
508 outelement3i[1] = vr[1];
509 outelement3i[2] = vr[1] + 1;
510 outelement3i[3] = vr[2];
511 outelement3i[4] = vr[1] + 1;
512 outelement3i[5] = vr[2] + 1;
516 if (shadowmark[n[2]] != shadowmarkcount)
518 vr[0] = vertexremap[e[0]];
519 vr[2] = vertexremap[e[2]];
520 outelement3i[0] = vr[0];
521 outelement3i[1] = vr[2];
522 outelement3i[2] = vr[2] + 1;
523 outelement3i[3] = vr[0];
524 outelement3i[4] = vr[2] + 1;
525 outelement3i[5] = vr[0] + 1;
531 *outnumvertices = outvertices;
535 float varray_vertex3f2[65536*3];
537 void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, float projectdistance, int nummarktris, const int *marktris)
540 if (projectdistance < 0.1)
542 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
545 if (!numverts || !nummarktris)
547 // make sure shadowelements is big enough for this volume
548 if (maxshadowelements < nummarktris * 24)
549 R_Shadow_ResizeShadowElements((nummarktris + 256) * 24);
550 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, varray_vertex3f2, projectorigin, projectdistance, nummarktris, marktris);
551 R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements);
554 void R_Shadow_VolumeFromBox(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, float projectdistance, const vec3_t mins, const vec3_t maxs)
559 // check which triangles are facing the , and then output
560 // triangle elements and vertices... by clever use of elements we
561 // can construct the whole shadow from the unprojected vertices and
562 // the projected vertices
564 // identify lit faces within the bounding box
565 R_Shadow_PrepareShadowMark(numtris);
566 for (i = 0;i < numtris;i++)
568 v[0] = invertex3f + elements[i*3+0] * 3;
569 v[1] = invertex3f + elements[i*3+1] * 3;
570 v[2] = invertex3f + elements[i*3+2] * 3;
571 if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]) && maxs[0] > min(v[0][0], min(v[1][0], v[2][0])) && mins[0] < max(v[0][0], max(v[1][0], v[2][0])) && maxs[1] > min(v[0][1], min(v[1][1], v[2][1])) && mins[1] < max(v[0][1], max(v[1][1], v[2][1])) && maxs[2] > min(v[0][2], min(v[1][2], v[2][2])) && mins[2] < max(v[0][2], max(v[1][2], v[2][2])))
572 shadowmarklist[numshadowmark++] = i;
574 R_Shadow_VolumeFromList(numverts, numtris, invertex3f, elements, neighbors, projectorigin, projectdistance, numshadowmark, shadowmarklist);
577 void R_Shadow_VolumeFromSphere(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, float projectdistance, float radius)
580 mins[0] = projectorigin[0] - radius;
581 mins[1] = projectorigin[1] - radius;
582 mins[2] = projectorigin[2] - radius;
583 maxs[0] = projectorigin[0] + radius;
584 maxs[1] = projectorigin[1] + radius;
585 maxs[2] = projectorigin[2] + radius;
586 R_Shadow_VolumeFromBox(numverts, numtris, invertex3f, elements, neighbors, projectorigin, projectdistance, mins, maxs);
589 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
592 if (r_shadow_compilingrtlight)
594 // if we're compiling an rtlight, capture the mesh
595 Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, numtriangles, element3i);
598 memset(&m, 0, sizeof(m));
599 m.pointer_vertex = vertex3f;
601 GL_LockArrays(0, numvertices);
602 if (r_shadowstage == SHADOWSTAGE_STENCIL)
604 // increment stencil if backface is behind depthbuffer
605 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
606 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
607 R_Mesh_Draw(numvertices, numtriangles, element3i);
609 c_rt_shadowtris += numtriangles;
610 // decrement stencil if frontface is behind depthbuffer
611 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
612 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
614 R_Mesh_Draw(numvertices, numtriangles, element3i);
616 c_rt_shadowtris += numtriangles;
620 float r_shadow_attenpower, r_shadow_attenscale;
621 static void R_Shadow_MakeTextures(void)
623 int x, y, z, d, side;
624 float v[3], s, t, intensity;
626 R_FreeTexturePool(&r_shadow_texturepool);
627 r_shadow_texturepool = R_AllocTexturePool();
628 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
629 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
631 #define ATTEN2DSIZE 64
632 #define ATTEN3DSIZE 32
633 data = Mem_Alloc(tempmempool, max(6*NORMSIZE*NORMSIZE*4, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4)));
638 r_shadow_blankbumptexture = R_LoadTexture2D(r_shadow_texturepool, "blankbump", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
643 r_shadow_blankglosstexture = R_LoadTexture2D(r_shadow_texturepool, "blankgloss", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
648 r_shadow_blankwhitetexture = R_LoadTexture2D(r_shadow_texturepool, "blankwhite", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
649 if (gl_texturecubemap)
651 for (side = 0;side < 6;side++)
653 for (y = 0;y < NORMSIZE;y++)
655 for (x = 0;x < NORMSIZE;x++)
657 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
658 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
692 intensity = 127.0f / sqrt(DotProduct(v, v));
693 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+0] = 128.0f + intensity * v[0];
694 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+1] = 128.0f + intensity * v[1];
695 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+2] = 128.0f + intensity * v[2];
696 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+3] = 255;
700 r_shadow_normalcubetexture = R_LoadTextureCubeMap(r_shadow_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
703 r_shadow_normalcubetexture = NULL;
704 for (y = 0;y < ATTEN2DSIZE;y++)
706 for (x = 0;x < ATTEN2DSIZE;x++)
708 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
709 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
711 intensity = 1.0f - sqrt(DotProduct(v, v));
713 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
714 d = bound(0, intensity, 255);
715 data[(y*ATTEN2DSIZE+x)*4+0] = d;
716 data[(y*ATTEN2DSIZE+x)*4+1] = d;
717 data[(y*ATTEN2DSIZE+x)*4+2] = d;
718 data[(y*ATTEN2DSIZE+x)*4+3] = d;
721 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
722 if (r_shadow_texture3d.integer)
724 for (z = 0;z < ATTEN3DSIZE;z++)
726 for (y = 0;y < ATTEN3DSIZE;y++)
728 for (x = 0;x < ATTEN3DSIZE;x++)
730 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
731 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
732 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
733 intensity = 1.0f - sqrt(DotProduct(v, v));
735 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
736 d = bound(0, intensity, 255);
737 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
738 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
739 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
740 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
744 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
749 void R_Shadow_Stage_Begin(void)
753 if (r_shadow_texture3d.integer && !gl_texture3d)
754 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
755 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
756 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
758 if (!r_shadow_attenuation2dtexture
759 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
760 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
761 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
762 R_Shadow_MakeTextures();
764 memset(&m, 0, sizeof(m));
765 GL_BlendFunc(GL_ONE, GL_ZERO);
769 GL_Color(0, 0, 0, 1);
770 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
771 qglEnable(GL_CULL_FACE);
772 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
773 r_shadowstage = SHADOWSTAGE_NONE;
775 c_rt_lights = c_rt_clears = c_rt_scissored = 0;
776 c_rt_shadowmeshes = c_rt_shadowtris = c_rt_lightmeshes = c_rt_lighttris = 0;
777 c_rtcached_shadowmeshes = c_rtcached_shadowtris = 0;
780 void R_Shadow_LoadWorldLightsIfNeeded(void)
782 if (r_shadow_reloadlights && cl.worldmodel)
784 R_Shadow_ClearWorldLights();
785 r_shadow_reloadlights = false;
786 R_Shadow_LoadWorldLights();
787 if (r_shadow_worldlightchain == NULL)
789 R_Shadow_LoadLightsFile();
790 if (r_shadow_worldlightchain == NULL)
791 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
796 void R_Shadow_Stage_ShadowVolumes(void)
799 memset(&m, 0, sizeof(m));
801 GL_Color(1, 1, 1, 1);
802 GL_ColorMask(0, 0, 0, 0);
803 GL_BlendFunc(GL_ONE, GL_ZERO);
806 qglPolygonOffset(r_shadow_polygonfactor.value, r_shadow_polygonoffset.value);
807 //if (r_shadow_polygonoffset.value != 0)
809 // qglPolygonOffset(r_shadow_polygonfactor.value, r_shadow_polygonoffset.value);
810 // qglEnable(GL_POLYGON_OFFSET_FILL);
813 // qglDisable(GL_POLYGON_OFFSET_FILL);
814 qglDepthFunc(GL_LESS);
815 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
816 qglEnable(GL_STENCIL_TEST);
817 qglStencilFunc(GL_ALWAYS, 128, ~0);
818 if (gl_ext_stenciltwoside.integer)
820 r_shadowstage = SHADOWSTAGE_STENCILTWOSIDE;
821 qglDisable(GL_CULL_FACE);
822 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
823 qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
825 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
826 qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
828 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
832 r_shadowstage = SHADOWSTAGE_STENCIL;
833 qglEnable(GL_CULL_FACE);
835 // this is changed by every shadow render so its value here is unimportant
836 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
838 GL_Clear(GL_STENCIL_BUFFER_BIT);
840 // LordHavoc note: many shadow volumes reside entirely inside the world
841 // (that is to say they are entirely bounded by their lit surfaces),
842 // which can be optimized by handling things as an inverted light volume,
843 // with the shadow boundaries of the world being simulated by an altered
844 // (129) bias to stencil clearing on such lights
845 // FIXME: generate inverted light volumes for use as shadow volumes and
846 // optimize for them as noted above
849 void R_Shadow_Stage_LightWithoutShadows(void)
852 memset(&m, 0, sizeof(m));
854 GL_BlendFunc(GL_ONE, GL_ONE);
857 qglPolygonOffset(0, 0);
858 //qglDisable(GL_POLYGON_OFFSET_FILL);
859 GL_Color(1, 1, 1, 1);
860 GL_ColorMask(1, 1, 1, 1);
861 qglDepthFunc(GL_EQUAL);
862 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
863 qglEnable(GL_CULL_FACE);
864 qglDisable(GL_STENCIL_TEST);
865 if (gl_support_stenciltwoside)
866 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
868 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
869 qglStencilFunc(GL_EQUAL, 128, ~0);
870 r_shadowstage = SHADOWSTAGE_LIGHT;
874 void R_Shadow_Stage_LightWithShadows(void)
877 memset(&m, 0, sizeof(m));
879 GL_BlendFunc(GL_ONE, GL_ONE);
882 qglPolygonOffset(0, 0);
883 //qglDisable(GL_POLYGON_OFFSET_FILL);
884 GL_Color(1, 1, 1, 1);
885 GL_ColorMask(1, 1, 1, 1);
886 qglDepthFunc(GL_EQUAL);
887 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
888 qglEnable(GL_STENCIL_TEST);
889 if (gl_support_stenciltwoside)
890 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
892 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
893 // only draw light where this geometry was already rendered AND the
894 // stencil is 128 (values other than this mean shadow)
895 qglStencilFunc(GL_EQUAL, 128, ~0);
896 r_shadowstage = SHADOWSTAGE_LIGHT;
900 void R_Shadow_Stage_End(void)
903 memset(&m, 0, sizeof(m));
905 GL_BlendFunc(GL_ONE, GL_ZERO);
908 qglPolygonOffset(0, 0);
909 //qglDisable(GL_POLYGON_OFFSET_FILL);
910 GL_Color(1, 1, 1, 1);
911 GL_ColorMask(1, 1, 1, 1);
912 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
913 qglDepthFunc(GL_LEQUAL);
914 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
915 qglDisable(GL_STENCIL_TEST);
916 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
917 if (gl_support_stenciltwoside)
918 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
920 qglStencilFunc(GL_ALWAYS, 128, ~0);
921 r_shadowstage = SHADOWSTAGE_NONE;
924 int R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
926 int i, ix1, iy1, ix2, iy2;
927 float x1, y1, x2, y2, x, y, f;
930 if (!r_shadow_scissor.integer)
932 // if view is inside the box, just say yes it's visible
933 // LordHavoc: for some odd reason scissor seems broken without stencil
934 // (?!? seems like a driver bug) so abort if gl_stencil is false
935 if (!gl_stencil || BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
937 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
940 for (i = 0;i < 3;i++)
942 if (r_viewforward[i] >= 0)
953 f = DotProduct(r_viewforward, r_vieworigin) + 1;
954 if (DotProduct(r_viewforward, v2) <= f)
956 // entirely behind nearclip plane
959 if (DotProduct(r_viewforward, v) >= f)
961 // entirely infront of nearclip plane
962 x1 = y1 = x2 = y2 = 0;
963 for (i = 0;i < 8;i++)
965 v[0] = (i & 1) ? mins[0] : maxs[0];
966 v[1] = (i & 2) ? mins[1] : maxs[1];
967 v[2] = (i & 4) ? mins[2] : maxs[2];
969 GL_TransformToScreen(v, v2);
970 //Con_Printf("%.3f %.3f %.3f %.3f transformed to %.3f %.3f %.3f %.3f\n", v[0], v[1], v[2], v[3], v2[0], v2[1], v2[2], v2[3]);
989 // clipped by nearclip plane
990 // this is nasty and crude...
991 // create viewspace bbox
992 for (i = 0;i < 8;i++)
994 v[0] = ((i & 1) ? mins[0] : maxs[0]) - r_vieworigin[0];
995 v[1] = ((i & 2) ? mins[1] : maxs[1]) - r_vieworigin[1];
996 v[2] = ((i & 4) ? mins[2] : maxs[2]) - r_vieworigin[2];
997 v2[0] = -DotProduct(v, r_viewleft);
998 v2[1] = DotProduct(v, r_viewup);
999 v2[2] = DotProduct(v, r_viewforward);
1002 if (smins[0] > v2[0]) smins[0] = v2[0];
1003 if (smaxs[0] < v2[0]) smaxs[0] = v2[0];
1004 if (smins[1] > v2[1]) smins[1] = v2[1];
1005 if (smaxs[1] < v2[1]) smaxs[1] = v2[1];
1006 if (smins[2] > v2[2]) smins[2] = v2[2];
1007 if (smaxs[2] < v2[2]) smaxs[2] = v2[2];
1011 smins[0] = smaxs[0] = v2[0];
1012 smins[1] = smaxs[1] = v2[1];
1013 smins[2] = smaxs[2] = v2[2];
1016 // now we have a bbox in viewspace
1017 // clip it to the view plane
1020 // return true if that culled the box
1021 if (smins[2] >= smaxs[2])
1023 // ok some of it is infront of the view, transform each corner back to
1024 // worldspace and then to screenspace and make screen rect
1025 // initialize these variables just to avoid compiler warnings
1026 x1 = y1 = x2 = y2 = 0;
1027 for (i = 0;i < 8;i++)
1029 v2[0] = (i & 1) ? smins[0] : smaxs[0];
1030 v2[1] = (i & 2) ? smins[1] : smaxs[1];
1031 v2[2] = (i & 4) ? smins[2] : smaxs[2];
1032 v[0] = v2[0] * -r_viewleft[0] + v2[1] * r_viewup[0] + v2[2] * r_viewforward[0] + r_vieworigin[0];
1033 v[1] = v2[0] * -r_viewleft[1] + v2[1] * r_viewup[1] + v2[2] * r_viewforward[1] + r_vieworigin[1];
1034 v[2] = v2[0] * -r_viewleft[2] + v2[1] * r_viewup[2] + v2[2] * r_viewforward[2] + r_vieworigin[2];
1036 GL_TransformToScreen(v, v2);
1037 //Con_Printf("%.3f %.3f %.3f %.3f transformed to %.3f %.3f %.3f %.3f\n", v[0], v[1], v[2], v[3], v2[0], v2[1], v2[2], v2[3]);
1054 // this code doesn't handle boxes with any points behind view properly
1055 x1 = 1000;x2 = -1000;
1056 y1 = 1000;y2 = -1000;
1057 for (i = 0;i < 8;i++)
1059 v[0] = (i & 1) ? mins[0] : maxs[0];
1060 v[1] = (i & 2) ? mins[1] : maxs[1];
1061 v[2] = (i & 4) ? mins[2] : maxs[2];
1063 GL_TransformToScreen(v, v2);
1064 //Con_Printf("%.3f %.3f %.3f %.3f transformed to %.3f %.3f %.3f %.3f\n", v[0], v[1], v[2], v[3], v2[0], v2[1], v2[2], v2[3]);
1082 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1083 if (ix1 < r_view_x) ix1 = r_view_x;
1084 if (iy1 < r_view_y) iy1 = r_view_y;
1085 if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
1086 if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
1087 if (ix2 <= ix1 || iy2 <= iy1)
1089 // set up the scissor rectangle
1090 GL_Scissor(ix1, vid.realheight - iy2, ix2 - ix1, iy2 - iy1);
1091 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1092 //qglEnable(GL_SCISSOR_TEST);
1097 void R_Shadow_VertexLighting(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1099 float *color4f = varray_color4f;
1100 float dist, dot, intensity, v[3], n[3];
1101 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1103 Matrix4x4_Transform(m, vertex3f, v);
1104 if ((dist = DotProduct(v, v)) < 1)
1106 Matrix4x4_Transform3x3(m, normal3f, n);
1107 if ((dot = DotProduct(n, v)) > 0)
1110 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale * dot / sqrt(DotProduct(n,n));
1111 VectorScale(lightcolor, intensity, color4f);
1116 VectorClear(color4f);
1122 VectorClear(color4f);
1128 void R_Shadow_VertexLightingWithXYAttenuationTexture(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1130 float *color4f = varray_color4f;
1131 float dist, dot, intensity, v[3], n[3];
1132 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1134 Matrix4x4_Transform(m, vertex3f, v);
1135 if ((dist = fabs(v[2])) < 1)
1137 Matrix4x4_Transform3x3(m, normal3f, n);
1138 if ((dot = DotProduct(n, v)) > 0)
1140 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale * dot / sqrt(DotProduct(n,n));
1141 VectorScale(lightcolor, intensity, color4f);
1146 VectorClear(color4f);
1152 VectorClear(color4f);
1158 // FIXME: this should be done in a vertex program when possible
1159 // FIXME: if vertex program not available, this would really benefit from 3DNow! or SSE
1160 void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1164 tc3f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1165 tc3f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1166 tc3f[2] = vertex3f[0] * matrix->m[2][0] + vertex3f[1] * matrix->m[2][1] + vertex3f[2] * matrix->m[2][2] + matrix->m[2][3];
1173 void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1177 tc2f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1178 tc2f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1185 void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(float *out3f, int numverts, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const vec3_t relativelightorigin)
1189 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1191 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1192 // the cubemap normalizes this for us
1193 out3f[0] = DotProduct(svector3f, lightdir);
1194 out3f[1] = DotProduct(tvector3f, lightdir);
1195 out3f[2] = DotProduct(normal3f, lightdir);
1199 void R_Shadow_GenTexCoords_Specular_NormalCubeMap(float *out3f, int numverts, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const vec3_t relativelightorigin, const vec3_t relativeeyeorigin)
1202 float lightdir[3], eyedir[3], halfdir[3];
1203 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1205 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1206 VectorNormalizeFast(lightdir);
1207 VectorSubtract(vertex3f, relativeeyeorigin, eyedir);
1208 VectorNormalizeFast(eyedir);
1209 VectorAdd(lightdir, eyedir, halfdir);
1210 // the cubemap normalizes this for us
1211 out3f[0] = DotProduct(svector3f, halfdir);
1212 out3f[1] = DotProduct(tvector3f, halfdir);
1213 out3f[2] = DotProduct(normal3f, halfdir);
1217 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)
1220 float color[3], color2[3], colorscale;
1223 bumptexture = r_shadow_blankbumptexture;
1225 glosstexture = r_shadow_blankglosstexture;
1226 if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
1228 if (lighting & LIGHTING_DIFFUSE)
1231 // colorscale accounts for how much we multiply the brightness during combine
1232 // mult is how many times the final pass of the lighting will be
1233 // performed to get more brightness than otherwise possible
1234 // limit mult to 64 for sanity sake
1235 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1237 // 3/2 3D combine path (Geforce3, Radeon 8500)
1238 memset(&m, 0, sizeof(m));
1239 m.pointer_vertex = vertex3f;
1240 m.tex[0] = R_GetTexture(bumptexture);
1241 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1242 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1243 m.texcombinergb[0] = GL_REPLACE;
1244 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1245 m.pointer_texcoord[0] = texcoord2f;
1246 m.pointer_texcoord[1] = varray_texcoord3f[1];
1247 m.pointer_texcoord[2] = varray_texcoord3f[2];
1249 GL_ColorMask(0,0,0,1);
1250 GL_BlendFunc(GL_ONE, GL_ZERO);
1251 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1252 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1253 GL_LockArrays(0, numverts);
1254 R_Mesh_Draw(numverts, numtriangles, elements);
1255 GL_LockArrays(0, 0);
1257 c_rt_lighttris += numtriangles;
1259 memset(&m, 0, sizeof(m));
1260 m.pointer_vertex = vertex3f;
1261 m.tex[0] = R_GetTexture(basetexture);
1262 m.pointer_texcoord[0] = texcoord2f;
1265 m.texcubemap[1] = R_GetTexture(lightcubemap);
1266 m.pointer_texcoord[1] = varray_texcoord3f[1];
1267 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1270 GL_LockArrays(0, numverts);
1271 GL_ColorMask(1,1,1,0);
1272 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1273 VectorScale(lightcolor, r_shadow_lightintensityscale.value, color2);
1274 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1276 color[0] = bound(0, color2[0], 1);
1277 color[1] = bound(0, color2[1], 1);
1278 color[2] = bound(0, color2[2], 1);
1279 GL_Color(color[0], color[1], color[2], 1);
1280 R_Mesh_Draw(numverts, numtriangles, elements);
1282 c_rt_lighttris += numtriangles;
1284 GL_LockArrays(0, 0);
1286 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap)
1288 // 1/2/2 3D combine path (original Radeon)
1289 memset(&m, 0, sizeof(m));
1290 m.pointer_vertex = vertex3f;
1291 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1292 m.pointer_texcoord[0] = varray_texcoord3f[0];
1294 GL_ColorMask(0,0,0,1);
1295 GL_BlendFunc(GL_ONE, GL_ZERO);
1296 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1297 GL_LockArrays(0, numverts);
1298 R_Mesh_Draw(numverts, numtriangles, elements);
1299 GL_LockArrays(0, 0);
1301 c_rt_lighttris += numtriangles;
1303 memset(&m, 0, sizeof(m));
1304 m.pointer_vertex = vertex3f;
1305 m.tex[0] = R_GetTexture(bumptexture);
1306 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1307 m.texcombinergb[0] = GL_REPLACE;
1308 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1309 m.pointer_texcoord[0] = texcoord2f;
1310 m.pointer_texcoord[1] = varray_texcoord3f[1];
1312 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1313 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1314 GL_LockArrays(0, numverts);
1315 R_Mesh_Draw(numverts, numtriangles, elements);
1316 GL_LockArrays(0, 0);
1318 c_rt_lighttris += numtriangles;
1320 memset(&m, 0, sizeof(m));
1321 m.pointer_vertex = vertex3f;
1322 m.tex[0] = R_GetTexture(basetexture);
1323 m.pointer_texcoord[0] = texcoord2f;
1326 m.texcubemap[1] = R_GetTexture(lightcubemap);
1327 m.pointer_texcoord[1] = varray_texcoord3f[1];
1328 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1331 GL_LockArrays(0, numverts);
1332 GL_ColorMask(1,1,1,0);
1333 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1334 VectorScale(lightcolor, r_shadow_lightintensityscale.value, color2);
1335 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1337 color[0] = bound(0, color2[0], 1);
1338 color[1] = bound(0, color2[1], 1);
1339 color[2] = bound(0, color2[2], 1);
1340 GL_Color(color[0], color[1], color[2], 1);
1341 R_Mesh_Draw(numverts, numtriangles, elements);
1343 c_rt_lighttris += numtriangles;
1345 GL_LockArrays(0, 0);
1347 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap)
1349 // 2/2 3D combine path (original Radeon)
1350 memset(&m, 0, sizeof(m));
1351 m.pointer_vertex = vertex3f;
1352 m.tex[0] = R_GetTexture(bumptexture);
1353 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1354 m.texcombinergb[0] = GL_REPLACE;
1355 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1356 m.pointer_texcoord[0] = texcoord2f;
1357 m.pointer_texcoord[1] = varray_texcoord3f[1];
1359 GL_ColorMask(0,0,0,1);
1360 GL_BlendFunc(GL_ONE, GL_ZERO);
1361 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1362 GL_LockArrays(0, numverts);
1363 R_Mesh_Draw(numverts, numtriangles, elements);
1364 GL_LockArrays(0, 0);
1366 c_rt_lighttris += numtriangles;
1368 memset(&m, 0, sizeof(m));
1369 m.pointer_vertex = vertex3f;
1370 m.tex[0] = R_GetTexture(basetexture);
1371 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1372 m.pointer_texcoord[0] = texcoord2f;
1373 m.pointer_texcoord[1] = varray_texcoord3f[1];
1375 GL_LockArrays(0, numverts);
1376 GL_ColorMask(1,1,1,0);
1377 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1378 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1379 VectorScale(lightcolor, r_shadow_lightintensityscale.value, color2);
1380 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1382 color[0] = bound(0, color2[0], 1);
1383 color[1] = bound(0, color2[1], 1);
1384 color[2] = bound(0, color2[2], 1);
1385 GL_Color(color[0], color[1], color[2], 1);
1386 R_Mesh_Draw(numverts, numtriangles, elements);
1388 c_rt_lighttris += numtriangles;
1390 GL_LockArrays(0, 0);
1392 else if (r_textureunits.integer >= 4)
1394 // 4/2 2D combine path (Geforce3, Radeon 8500)
1395 memset(&m, 0, sizeof(m));
1396 m.pointer_vertex = vertex3f;
1397 m.tex[0] = R_GetTexture(bumptexture);
1398 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1399 m.texcombinergb[0] = GL_REPLACE;
1400 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1401 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1402 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1403 m.pointer_texcoord[0] = texcoord2f;
1404 m.pointer_texcoord[1] = varray_texcoord3f[1];
1405 m.pointer_texcoord[2] = varray_texcoord2f[2];
1406 m.pointer_texcoord[3] = varray_texcoord2f[3];
1408 GL_ColorMask(0,0,0,1);
1409 GL_BlendFunc(GL_ONE, GL_ZERO);
1410 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1411 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1412 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[3], numverts, vertex3f, matrix_modeltoattenuationz);
1413 GL_LockArrays(0, numverts);
1414 R_Mesh_Draw(numverts, numtriangles, elements);
1415 GL_LockArrays(0, 0);
1417 c_rt_lighttris += numtriangles;
1419 memset(&m, 0, sizeof(m));
1420 m.pointer_vertex = vertex3f;
1421 m.tex[0] = R_GetTexture(basetexture);
1422 m.pointer_texcoord[0] = texcoord2f;
1425 m.texcubemap[1] = R_GetTexture(lightcubemap);
1426 m.pointer_texcoord[1] = varray_texcoord3f[1];
1427 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1430 GL_LockArrays(0, numverts);
1431 GL_ColorMask(1,1,1,0);
1432 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1433 VectorScale(lightcolor, r_shadow_lightintensityscale.value, color2);
1434 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1436 color[0] = bound(0, color2[0], 1);
1437 color[1] = bound(0, color2[1], 1);
1438 color[2] = bound(0, color2[2], 1);
1439 GL_Color(color[0], color[1], color[2], 1);
1440 R_Mesh_Draw(numverts, numtriangles, elements);
1442 c_rt_lighttris += numtriangles;
1444 GL_LockArrays(0, 0);
1448 // 2/2/2 2D combine path (any dot3 card)
1449 memset(&m, 0, sizeof(m));
1450 m.pointer_vertex = vertex3f;
1451 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1452 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1453 m.pointer_texcoord[0] = varray_texcoord2f[0];
1454 m.pointer_texcoord[1] = varray_texcoord2f[1];
1456 GL_ColorMask(0,0,0,1);
1457 GL_BlendFunc(GL_ONE, GL_ZERO);
1458 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1459 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1460 GL_LockArrays(0, numverts);
1461 R_Mesh_Draw(numverts, numtriangles, elements);
1462 GL_LockArrays(0, 0);
1464 c_rt_lighttris += numtriangles;
1466 memset(&m, 0, sizeof(m));
1467 m.pointer_vertex = vertex3f;
1468 m.tex[0] = R_GetTexture(bumptexture);
1469 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1470 m.texcombinergb[0] = GL_REPLACE;
1471 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1472 m.pointer_texcoord[0] = texcoord2f;
1473 m.pointer_texcoord[1] = varray_texcoord3f[1];
1475 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1476 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1477 GL_LockArrays(0, numverts);
1478 R_Mesh_Draw(numverts, numtriangles, elements);
1479 GL_LockArrays(0, 0);
1481 c_rt_lighttris += numtriangles;
1483 memset(&m, 0, sizeof(m));
1484 m.pointer_vertex = vertex3f;
1485 m.tex[0] = R_GetTexture(basetexture);
1486 m.pointer_texcoord[0] = texcoord2f;
1489 m.texcubemap[1] = R_GetTexture(lightcubemap);
1490 m.pointer_texcoord[1] = varray_texcoord3f[1];
1491 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1494 GL_LockArrays(0, numverts);
1495 GL_ColorMask(1,1,1,0);
1496 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1497 VectorScale(lightcolor, r_shadow_lightintensityscale.value, color2);
1498 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1500 color[0] = bound(0, color2[0], 1);
1501 color[1] = bound(0, color2[1], 1);
1502 color[2] = bound(0, color2[2], 1);
1503 GL_Color(color[0], color[1], color[2], 1);
1504 R_Mesh_Draw(numverts, numtriangles, elements);
1506 c_rt_lighttris += numtriangles;
1508 GL_LockArrays(0, 0);
1511 if ((lighting & LIGHTING_SPECULAR) && (r_shadow_gloss.integer >= 2 || (r_shadow_gloss.integer >= 1 && glosstexture != r_shadow_blankglosstexture)))
1513 colorscale = r_shadow_glossintensity.value;
1514 if (glosstexture == r_shadow_blankglosstexture)
1515 colorscale *= r_shadow_gloss2intensity.value;
1517 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1519 // 2/0/0/1/2 3D combine blendsquare path
1520 memset(&m, 0, sizeof(m));
1521 m.pointer_vertex = vertex3f;
1522 m.tex[0] = R_GetTexture(bumptexture);
1523 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1524 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1525 m.pointer_texcoord[0] = texcoord2f;
1526 m.pointer_texcoord[1] = varray_texcoord3f[1];
1528 GL_ColorMask(0,0,0,1);
1529 // this squares the result
1530 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1531 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1532 GL_LockArrays(0, numverts);
1533 R_Mesh_Draw(numverts, numtriangles, elements);
1534 GL_LockArrays(0, 0);
1536 c_rt_lighttris += numtriangles;
1538 memset(&m, 0, sizeof(m));
1539 m.pointer_vertex = vertex3f;
1541 GL_LockArrays(0, numverts);
1542 // square alpha in framebuffer a few times to make it shiny
1543 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1544 // these comments are a test run through this math for intensity 0.5
1545 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1546 // 0.25 * 0.25 = 0.0625 (this is another pass)
1547 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1548 R_Mesh_Draw(numverts, numtriangles, elements);
1550 c_rt_lighttris += numtriangles;
1551 R_Mesh_Draw(numverts, numtriangles, elements);
1553 c_rt_lighttris += numtriangles;
1554 GL_LockArrays(0, 0);
1556 memset(&m, 0, sizeof(m));
1557 m.pointer_vertex = vertex3f;
1558 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1559 m.pointer_texcoord[0] = varray_texcoord3f[0];
1561 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1562 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1563 GL_LockArrays(0, numverts);
1564 R_Mesh_Draw(numverts, numtriangles, elements);
1565 GL_LockArrays(0, 0);
1567 c_rt_lighttris += numtriangles;
1569 memset(&m, 0, sizeof(m));
1570 m.pointer_vertex = vertex3f;
1571 m.tex[0] = R_GetTexture(glosstexture);
1574 m.texcubemap[1] = R_GetTexture(lightcubemap);
1575 m.pointer_texcoord[1] = varray_texcoord3f[1];
1576 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1578 m.pointer_texcoord[0] = texcoord2f;
1580 GL_LockArrays(0, numverts);
1581 GL_ColorMask(1,1,1,0);
1582 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1583 VectorScale(lightcolor, colorscale, color2);
1584 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1586 color[0] = bound(0, color2[0], 1);
1587 color[1] = bound(0, color2[1], 1);
1588 color[2] = bound(0, color2[2], 1);
1589 GL_Color(color[0], color[1], color[2], 1);
1590 R_Mesh_Draw(numverts, numtriangles, elements);
1592 c_rt_lighttris += numtriangles;
1594 GL_LockArrays(0, 0);
1596 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1598 // 2/0/0/2 3D combine blendsquare path
1599 memset(&m, 0, sizeof(m));
1600 m.pointer_vertex = vertex3f;
1601 m.tex[0] = R_GetTexture(bumptexture);
1602 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1603 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1604 m.pointer_texcoord[0] = texcoord2f;
1605 m.pointer_texcoord[1] = varray_texcoord3f[1];
1607 GL_ColorMask(0,0,0,1);
1608 // this squares the result
1609 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1610 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1611 GL_LockArrays(0, numverts);
1612 R_Mesh_Draw(numverts, numtriangles, elements);
1613 GL_LockArrays(0, 0);
1615 c_rt_lighttris += numtriangles;
1617 memset(&m, 0, sizeof(m));
1618 m.pointer_vertex = vertex3f;
1620 GL_LockArrays(0, numverts);
1621 // square alpha in framebuffer a few times to make it shiny
1622 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1623 // these comments are a test run through this math for intensity 0.5
1624 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1625 // 0.25 * 0.25 = 0.0625 (this is another pass)
1626 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1627 R_Mesh_Draw(numverts, numtriangles, elements);
1629 c_rt_lighttris += numtriangles;
1630 R_Mesh_Draw(numverts, numtriangles, elements);
1632 c_rt_lighttris += numtriangles;
1633 GL_LockArrays(0, 0);
1635 memset(&m, 0, sizeof(m));
1636 m.pointer_vertex = vertex3f;
1637 m.tex[0] = R_GetTexture(glosstexture);
1638 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1639 m.pointer_texcoord[0] = texcoord2f;
1640 m.pointer_texcoord[1] = varray_texcoord3f[1];
1642 GL_LockArrays(0, numverts);
1643 GL_ColorMask(1,1,1,0);
1644 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1645 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1646 VectorScale(lightcolor, colorscale, color2);
1647 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1649 color[0] = bound(0, color2[0], 1);
1650 color[1] = bound(0, color2[1], 1);
1651 color[2] = bound(0, color2[2], 1);
1652 GL_Color(color[0], color[1], color[2], 1);
1653 R_Mesh_Draw(numverts, numtriangles, elements);
1655 c_rt_lighttris += numtriangles;
1657 GL_LockArrays(0, 0);
1659 else if (r_textureunits.integer >= 2 /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1661 // 2/0/0/2/2 2D combine blendsquare path
1662 memset(&m, 0, sizeof(m));
1663 m.pointer_vertex = vertex3f;
1664 m.tex[0] = R_GetTexture(bumptexture);
1665 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1666 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1667 m.pointer_texcoord[0] = texcoord2f;
1668 m.pointer_texcoord[1] = varray_texcoord3f[1];
1670 GL_ColorMask(0,0,0,1);
1671 // this squares the result
1672 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1673 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1674 GL_LockArrays(0, numverts);
1675 R_Mesh_Draw(numverts, numtriangles, elements);
1676 GL_LockArrays(0, 0);
1678 c_rt_lighttris += numtriangles;
1680 memset(&m, 0, sizeof(m));
1681 m.pointer_vertex = vertex3f;
1683 GL_LockArrays(0, numverts);
1684 // square alpha in framebuffer a few times to make it shiny
1685 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1686 // these comments are a test run through this math for intensity 0.5
1687 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1688 // 0.25 * 0.25 = 0.0625 (this is another pass)
1689 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1690 R_Mesh_Draw(numverts, numtriangles, elements);
1692 c_rt_lighttris += numtriangles;
1693 R_Mesh_Draw(numverts, numtriangles, elements);
1695 c_rt_lighttris += numtriangles;
1696 GL_LockArrays(0, 0);
1698 memset(&m, 0, sizeof(m));
1699 m.pointer_vertex = vertex3f;
1700 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1701 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1702 m.pointer_texcoord[0] = varray_texcoord2f[0];
1703 m.pointer_texcoord[1] = varray_texcoord2f[1];
1705 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1706 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1707 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1708 GL_LockArrays(0, numverts);
1709 R_Mesh_Draw(numverts, numtriangles, elements);
1710 GL_LockArrays(0, 0);
1712 c_rt_lighttris += numtriangles;
1714 memset(&m, 0, sizeof(m));
1715 m.pointer_vertex = vertex3f;
1716 m.tex[0] = R_GetTexture(glosstexture);
1719 m.texcubemap[1] = R_GetTexture(lightcubemap);
1720 m.pointer_texcoord[1] = varray_texcoord3f[1];
1721 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1723 m.pointer_texcoord[0] = texcoord2f;
1725 GL_LockArrays(0, numverts);
1726 GL_ColorMask(1,1,1,0);
1727 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1728 VectorScale(lightcolor, colorscale, color2);
1729 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1731 color[0] = bound(0, color2[0], 1);
1732 color[1] = bound(0, color2[1], 1);
1733 color[2] = bound(0, color2[2], 1);
1734 GL_Color(color[0], color[1], color[2], 1);
1735 R_Mesh_Draw(numverts, numtriangles, elements);
1737 c_rt_lighttris += numtriangles;
1739 GL_LockArrays(0, 0);
1745 if (lighting & LIGHTING_DIFFUSE)
1747 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1748 GL_DepthMask(false);
1750 VectorScale(lightcolor, r_shadow_lightintensityscale.value, color2);
1751 memset(&m, 0, sizeof(m));
1752 m.pointer_vertex = vertex3f;
1753 m.pointer_color = varray_color4f;
1754 m.tex[0] = R_GetTexture(basetexture);
1755 m.pointer_texcoord[0] = texcoord2f;
1756 if (r_textureunits.integer >= 2)
1759 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1760 m.pointer_texcoord[1] = varray_texcoord2f[1];
1761 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1764 GL_LockArrays(0, numverts);
1765 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1767 color[0] = bound(0, color2[0], 1);
1768 color[1] = bound(0, color2[1], 1);
1769 color[2] = bound(0, color2[2], 1);
1770 if (r_textureunits.integer >= 2)
1771 R_Shadow_VertexLightingWithXYAttenuationTexture(numverts, vertex3f, normal3f, color, matrix_modeltolight);
1773 R_Shadow_VertexLighting(numverts, vertex3f, normal3f, color, matrix_modeltolight);
1774 R_Mesh_Draw(numverts, numtriangles, elements);
1776 c_rt_lighttris += numtriangles;
1778 GL_LockArrays(0, 0);
1783 void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
1787 R_RTLight_Uncompile(rtlight);
1788 memset(rtlight, 0, sizeof(*rtlight));
1790 VectorCopy(light->origin, rtlight->shadoworigin);
1791 VectorCopy(light->color, rtlight->color);
1792 rtlight->radius = light->radius;
1793 //rtlight->cullradius = rtlight->radius;
1794 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
1795 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
1796 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
1797 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
1798 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
1799 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
1800 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
1801 rtlight->cubemapname[0] = 0;
1802 if (light->cubemapname[0])
1803 strcpy(rtlight->cubemapname, light->cubemapname);
1804 else if (light->cubemapnum > 0)
1805 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
1806 rtlight->shadow = light->shadow;
1807 rtlight->corona = light->corona;
1808 rtlight->style = light->style;
1809 rtlight->isstatic = isstatic;
1810 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
1811 // ConcatScale won't work here because this needs to scale rotate and
1812 // translate, not just rotate
1813 scale = 1.0f / rtlight->radius;
1814 for (k = 0;k < 3;k++)
1815 for (j = 0;j < 4;j++)
1816 rtlight->matrix_worldtolight.m[k][j] *= scale;
1817 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationxyz, &matrix_attenuationxyz, &rtlight->matrix_worldtolight);
1818 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationz, &matrix_attenuationz, &rtlight->matrix_worldtolight);
1820 rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
1821 rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
1822 VectorScale(rtlight->color, rtlight->radius * d_lightstylevalue[rtlight->style] * 0.25f, rtlight->lightmap_light);
1823 rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
1826 rtlight_t *r_shadow_compilingrtlight;
1828 // compiles rtlight geometry
1829 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
1830 void R_RTLight_Compile(rtlight_t *rtlight)
1832 int shadowmeshes, shadowtris, lightmeshes, lighttris, numclusters, numsurfaces;
1833 entity_render_t *ent = &cl_entities[0].render;
1834 model_t *model = ent->model;
1836 // compile the light
1837 rtlight->compiled = true;
1838 rtlight->static_numclusters = 0;
1839 rtlight->static_numclusterpvsbytes = 0;
1840 rtlight->static_clusterlist = NULL;
1841 rtlight->static_clusterpvs = NULL;
1842 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
1843 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
1844 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
1845 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
1846 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
1847 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
1849 if (model && model->GetLightInfo)
1851 // this variable directs the DrawShadowVolume and DrawLight code to capture into the mesh chain instead of rendering
1852 r_shadow_compilingrtlight = rtlight;
1853 R_Shadow_EnlargeClusterBuffer(model->brush.num_pvsclusters);
1854 R_Shadow_EnlargeSurfaceBuffer(model->numsurfaces);
1855 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);
1858 rtlight->static_numclusters = numclusters;
1859 rtlight->static_numclusterpvsbytes = (model->brush.num_pvsclusters + 7) >> 3;
1860 rtlight->static_clusterlist = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
1861 rtlight->static_clusterpvs = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusterpvsbytes);
1862 memcpy(rtlight->static_clusterlist, r_shadow_buffer_clusterlist, rtlight->static_numclusters * sizeof(*rtlight->static_clusterlist));
1863 memcpy(rtlight->static_clusterpvs, r_shadow_buffer_clusterpvs, rtlight->static_numclusterpvsbytes);
1865 if (model->DrawShadowVolume && rtlight->shadow)
1867 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
1868 model->DrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
1869 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_shadow, false, false);
1871 if (model->DrawLight)
1873 rtlight->static_meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true);
1874 model->DrawLight(ent, rtlight->shadoworigin, vec3_origin, rtlight->radius, vec3_origin, &r_identitymatrix, &r_identitymatrix, &r_identitymatrix, NULL, numsurfaces, r_shadow_buffer_surfacelist);
1875 rtlight->static_meshchain_light = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_light, true, false);
1877 // switch back to rendering when DrawShadowVolume or DrawLight is called
1878 r_shadow_compilingrtlight = NULL;
1882 // use smallest available cullradius - box radius or light radius
1883 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
1884 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
1888 if (rtlight->static_meshchain_shadow)
1891 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
1894 shadowtris += mesh->numtriangles;
1900 if (rtlight->static_meshchain_light)
1903 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
1906 lighttris += mesh->numtriangles;
1910 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);
1913 void R_RTLight_Uncompile(rtlight_t *rtlight)
1915 if (rtlight->compiled)
1917 if (rtlight->static_meshchain_shadow)
1918 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
1919 rtlight->static_meshchain_shadow = NULL;
1920 if (rtlight->static_meshchain_light)
1921 Mod_ShadowMesh_Free(rtlight->static_meshchain_light);
1922 rtlight->static_meshchain_light = NULL;
1923 if (rtlight->static_clusterlist)
1924 Mem_Free(rtlight->static_clusterlist);
1925 rtlight->static_clusterlist = NULL;
1926 if (rtlight->static_clusterpvs)
1927 Mem_Free(rtlight->static_clusterpvs);
1928 rtlight->static_clusterpvs = NULL;
1929 rtlight->static_numclusters = 0;
1930 rtlight->static_numclusterpvsbytes = 0;
1931 rtlight->compiled = false;
1935 int shadowframecount = 0;
1937 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light);
1939 void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes)
1942 entity_render_t *ent;
1944 vec3_t relativelightorigin, relativeeyeorigin, lightcolor;
1945 rtexture_t *cubemaptexture;
1946 matrix4x4_t matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz;
1947 int numclusters, numsurfaces;
1948 int *clusterlist, *surfacelist;
1950 vec3_t cullmins, cullmaxs;
1954 if (d_lightstylevalue[rtlight->style] <= 0)
1956 cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
1957 cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
1958 cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
1959 cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
1960 cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
1961 cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
1962 if (R_CullBox(cullmins, cullmaxs))
1964 if (rtlight->isstatic && !rtlight->compiled && r_shadow_staticworldlights.integer)
1965 R_RTLight_Compile(rtlight);
1971 if (rtlight->compiled && r_shadow_staticworldlights.integer)
1973 numclusters = rtlight->static_numclusters;
1974 clusterlist = rtlight->static_clusterlist;
1975 clusterpvs = rtlight->static_clusterpvs;
1976 VectorCopy(rtlight->cullmins, cullmins);
1977 VectorCopy(rtlight->cullmaxs, cullmaxs);
1979 else if (cl.worldmodel && cl.worldmodel->GetLightInfo)
1981 R_Shadow_EnlargeClusterBuffer(cl.worldmodel->brush.num_pvsclusters);
1982 R_Shadow_EnlargeSurfaceBuffer(cl.worldmodel->numsurfaces);
1983 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);
1984 clusterlist = r_shadow_buffer_clusterlist;
1985 clusterpvs = r_shadow_buffer_clusterpvs;
1986 surfacelist = r_shadow_buffer_surfacelist;
1990 for (i = 0;i < numclusters;i++)
1991 if (CHECKPVSBIT(r_pvsbits, clusterlist[i]))
1993 if (i == numclusters)
1996 if (R_CullBox(cullmins, cullmaxs))
1998 if (R_Shadow_ScissorForBBox(cullmins, cullmaxs))
2001 f = d_lightstylevalue[rtlight->style] * (1.0f / 256.0f);
2002 VectorScale(rtlight->color, f, lightcolor);
2004 if (rtlight->selected)
2006 f = 2 + sin(realtime * M_PI * 4.0);
2007 VectorScale(lightcolor, f, lightcolor);
2011 if (rtlight->cubemapname[0])
2012 cubemaptexture = R_Shadow_Cubemap(rtlight->cubemapname);
2014 cubemaptexture = NULL;
2016 shadow = rtlight->shadow && (rtlight->isstatic ? r_shadow_worldshadows.integer : r_shadow_dlightshadows.integer);
2017 if (shadow && (gl_stencil || visiblevolumes))
2019 if (!visiblevolumes)
2020 R_Shadow_Stage_ShadowVolumes();
2021 ent = &cl_entities[0].render;
2022 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2024 memset(&m, 0, sizeof(m));
2025 R_Mesh_Matrix(&ent->matrix);
2026 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
2028 m.pointer_vertex = mesh->vertex3f;
2030 GL_LockArrays(0, mesh->numverts);
2031 if (r_shadowstage == SHADOWSTAGE_STENCIL)
2033 // decrement stencil if frontface is behind depthbuffer
2034 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
2035 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
2036 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2037 c_rtcached_shadowmeshes++;
2038 c_rtcached_shadowtris += mesh->numtriangles;
2039 // increment stencil if backface is behind depthbuffer
2040 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
2041 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
2043 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
2044 c_rtcached_shadowmeshes++;
2045 c_rtcached_shadowtris += mesh->numtriangles;
2046 GL_LockArrays(0, 0);
2051 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2052 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, numsurfaces, surfacelist);
2054 if (r_drawentities.integer)
2056 for (i = 0;i < r_refdef.numentities;i++)
2058 ent = r_refdef.entities[i];
2060 if (r_shadow_cull.integer)
2062 if (!BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs))
2064 if (cl.worldmodel != NULL && cl.worldmodel->brush.BoxTouchingPVS != NULL && !cl.worldmodel->brush.BoxTouchingPVS(cl.worldmodel, clusterpvs, ent->mins, ent->maxs))
2067 if (!(ent->flags & RENDER_SHADOW) || !ent->model || !ent->model->DrawShadowVolume)
2069 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2070 ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, ent->model->numsurfaces, ent->model->surfacelist);
2075 if (!visiblevolumes)
2077 if (shadow && gl_stencil)
2078 R_Shadow_Stage_LightWithShadows();
2080 R_Shadow_Stage_LightWithoutShadows();
2082 ent = &cl_entities[0].render;
2083 if (ent->model && ent->model->DrawLight)
2085 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2086 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2087 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2088 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2089 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2090 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2092 R_Mesh_Matrix(&ent->matrix);
2093 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2094 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);
2097 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, numsurfaces, surfacelist);
2099 if (r_drawentities.integer)
2101 for (i = 0;i < r_refdef.numentities;i++)
2103 ent = r_refdef.entities[i];
2104 if (ent->visframe == r_framecount && BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs) && ent->model && ent->model->DrawLight && (ent->flags & RENDER_LIGHT))
2106 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2107 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2108 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2109 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2110 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2111 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, ent->model->numsurfaces, ent->model->surfacelist);
2118 void R_ShadowVolumeLighting(int visiblevolumes)
2126 memset(&m, 0, sizeof(m));
2129 GL_BlendFunc(GL_ONE, GL_ONE);
2130 GL_DepthMask(false);
2131 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
2132 qglDisable(GL_CULL_FACE);
2133 GL_Color(0.0, 0.0125, 0.1, 1);
2136 R_Shadow_Stage_Begin();
2138 if (r_shadow_realtime_world.integer)
2140 R_Shadow_LoadWorldLightsIfNeeded();
2141 if (r_shadow_debuglight.integer >= 0)
2143 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2144 if (lnum == r_shadow_debuglight.integer)
2145 R_DrawRTLight(&light->rtlight, visiblevolumes);
2148 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2149 R_DrawRTLight(&light->rtlight, visiblevolumes);
2151 if (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer)
2152 for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
2153 R_DrawRTLight(&light->rtlight, visiblevolumes);
2157 qglEnable(GL_CULL_FACE);
2158 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
2161 R_Shadow_Stage_End();
2164 cvar_t r_editlights = {0, "r_editlights", "0"};
2165 cvar_t r_editlights_cursordistance = {0, "r_editlights_distance", "1024"};
2166 cvar_t r_editlights_cursorpushback = {0, "r_editlights_pushback", "0"};
2167 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_pushoff", "4"};
2168 cvar_t r_editlights_cursorgrid = {0, "r_editlights_grid", "4"};
2169 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "0.8"};
2170 cvar_t r_editlights_rtlightssizescale = {CVAR_SAVE, "r_editlights_rtlightssizescale", "0.7"};
2171 cvar_t r_editlights_rtlightscolorscale = {CVAR_SAVE, "r_editlights_rtlightscolorscale", "2"};
2172 dlight_t *r_shadow_worldlightchain;
2173 dlight_t *r_shadow_selectedlight;
2174 vec3_t r_editlights_cursorlocation;
2176 typedef struct cubemapinfo_s
2179 rtexture_t *texture;
2183 #define MAX_CUBEMAPS 128
2184 static int numcubemaps;
2185 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
2187 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2188 typedef struct suffixinfo_s
2191 int flipx, flipy, flipdiagonal;
2194 static suffixinfo_t suffix[3][6] =
2197 {"posx", false, false, false},
2198 {"negx", false, false, false},
2199 {"posy", false, false, false},
2200 {"negy", false, false, false},
2201 {"posz", false, false, false},
2202 {"negz", false, false, false}
2205 {"px", false, false, false},
2206 {"nx", false, false, false},
2207 {"py", false, false, false},
2208 {"ny", false, false, false},
2209 {"pz", false, false, false},
2210 {"nz", false, false, false}
2213 {"ft", true, false, true},
2214 {"bk", false, true, true},
2215 {"lf", true, true, false},
2216 {"rt", false, false, false},
2217 {"up", false, false, false},
2218 {"dn", false, false, false}
2222 static int componentorder[4] = {0, 1, 2, 3};
2224 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2226 int i, j, cubemapsize;
2227 qbyte *cubemappixels, *image_rgba;
2228 rtexture_t *cubemaptexture;
2230 // must start 0 so the first loadimagepixels has no requested width/height
2232 cubemappixels = NULL;
2233 cubemaptexture = NULL;
2234 for (j = 0;j < 3 && !cubemappixels;j++)
2236 for (i = 0;i < 6;i++)
2238 snprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2239 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2241 if (image_width == image_height)
2243 if (!cubemappixels && image_width >= 1)
2245 cubemapsize = image_width;
2246 // note this clears to black, so unavailable sizes are black
2247 cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2250 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);
2253 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2254 Mem_Free(image_rgba);
2260 if (!r_shadow_filters_texturepool)
2261 r_shadow_filters_texturepool = R_AllocTexturePool();
2262 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
2263 Mem_Free(cubemappixels);
2267 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
2268 for (j = 0;j < 3;j++)
2269 for (i = 0;i < 6;i++)
2270 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2271 Con_Print(" and was unable to find any of them.\n");
2273 return cubemaptexture;
2276 rtexture_t *R_Shadow_Cubemap(const char *basename)
2279 for (i = 0;i < numcubemaps;i++)
2280 if (!strcasecmp(cubemaps[i].basename, basename))
2281 return cubemaps[i].texture;
2282 if (i >= MAX_CUBEMAPS)
2285 strcpy(cubemaps[i].basename, basename);
2286 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
2287 return cubemaps[i].texture;
2290 void R_Shadow_FreeCubemaps(void)
2293 R_FreeTexturePool(&r_shadow_filters_texturepool);
2296 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)
2300 if (radius < 15 || DotProduct(color, color) < 0.03)
2302 Con_Print("R_Shadow_NewWorldLight: refusing to create a light too small/dim\n");
2306 light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
2307 VectorCopy(origin, light->origin);
2308 VectorCopy(angles, light->angles);
2309 VectorCopy(color, light->color);
2310 light->radius = radius;
2311 light->style = style;
2312 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
2314 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
2317 light->shadow = shadowenable;
2318 light->corona = corona;
2319 if (cubemapname && cubemapname[0] && strlen(cubemapname) < sizeof(light->cubemapname))
2320 strcpy(light->cubemapname, cubemapname);
2321 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
2322 light->next = r_shadow_worldlightchain;
2323 r_shadow_worldlightchain = light;
2325 R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
2326 if (r_shadow_staticworldlights.integer)
2327 R_RTLight_Compile(&light->rtlight);
2330 void R_Shadow_FreeWorldLight(dlight_t *light)
2332 dlight_t **lightpointer;
2333 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
2334 if (*lightpointer != light)
2335 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
2336 *lightpointer = light->next;
2337 R_RTLight_Uncompile(&light->rtlight);
2341 void R_Shadow_ClearWorldLights(void)
2343 while (r_shadow_worldlightchain)
2344 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
2345 r_shadow_selectedlight = NULL;
2346 R_Shadow_FreeCubemaps();
2349 void R_Shadow_SelectLight(dlight_t *light)
2351 if (r_shadow_selectedlight)
2352 r_shadow_selectedlight->selected = false;
2353 r_shadow_selectedlight = light;
2354 if (r_shadow_selectedlight)
2355 r_shadow_selectedlight->selected = true;
2358 rtexture_t *lighttextures[5];
2360 void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
2362 float scale = r_editlights_cursorgrid.value * 0.5f;
2363 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);
2366 void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
2369 const dlight_t *light;
2372 if (light->selected)
2373 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
2376 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);
2379 void R_Shadow_DrawLightSprites(void)
2385 for (i = 0;i < 5;i++)
2387 lighttextures[i] = NULL;
2388 if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1))))
2389 lighttextures[i] = pic->tex;
2392 for (light = r_shadow_worldlightchain;light;light = light->next)
2393 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, ((int) light) % 5);
2394 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
2397 void R_Shadow_SelectLightInView(void)
2399 float bestrating, rating, temp[3];
2400 dlight_t *best, *light;
2403 for (light = r_shadow_worldlightchain;light;light = light->next)
2405 VectorSubtract(light->origin, r_vieworigin, temp);
2406 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
2409 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
2410 if (bestrating < rating && CL_TraceLine(light->origin, r_vieworigin, NULL, NULL, true, NULL, SUPERCONTENTS_SOLID) == 1.0f)
2412 bestrating = rating;
2417 R_Shadow_SelectLight(best);
2420 void R_Shadow_LoadWorldLights(void)
2422 int n, a, style, shadow;
2423 char name[MAX_QPATH], cubemapname[MAX_QPATH], *lightsstring, *s, *t;
2424 float origin[3], radius, color[3], angles[3], corona;
2425 if (cl.worldmodel == NULL)
2427 Con_Print("No map loaded.\n");
2430 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2431 strlcat (name, ".rtlights", sizeof (name));
2432 lightsstring = FS_LoadFile(name, false);
2442 for (;COM_Parse(t, true) && strcmp(
2443 if (COM_Parse(t, true))
2445 if (com_token[0] == '!')
2448 origin[0] = atof(com_token+1);
2451 origin[0] = atof(com_token);
2456 while (*s && *s != '\n')
2462 // check for modifier flags
2468 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]);
2470 VectorClear(angles);
2473 if (a < 9 || !strcmp(cubemapname, "\"\""))
2478 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);
2481 VectorScale(color, r_editlights_rtlightscolorscale.value, color);
2482 radius *= r_editlights_rtlightssizescale.value;
2483 R_Shadow_NewWorldLight(origin, angles, color, radius, corona, style, shadow, cubemapname);
2488 Con_Printf("invalid rtlights file \"%s\"\n", name);
2489 Mem_Free(lightsstring);
2493 void R_Shadow_SaveWorldLights(void)
2496 int bufchars, bufmaxchars;
2498 char name[MAX_QPATH];
2500 if (!r_shadow_worldlightchain)
2502 if (cl.worldmodel == NULL)
2504 Con_Print("No map loaded.\n");
2507 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2508 strlcat (name, ".rtlights", sizeof (name));
2509 bufchars = bufmaxchars = 0;
2511 for (light = r_shadow_worldlightchain;light;light = light->next)
2513 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]);
2514 if (bufchars + (int) strlen(line) > bufmaxchars)
2516 bufmaxchars = bufchars + strlen(line) + 2048;
2518 buf = Mem_Alloc(r_shadow_mempool, bufmaxchars);
2522 memcpy(buf, oldbuf, bufchars);
2528 memcpy(buf + bufchars, line, strlen(line));
2529 bufchars += strlen(line);
2533 FS_WriteFile(name, buf, bufchars);
2538 void R_Shadow_LoadLightsFile(void)
2541 char name[MAX_QPATH], *lightsstring, *s, *t;
2542 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
2543 if (cl.worldmodel == NULL)
2545 Con_Print("No map loaded.\n");
2548 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2549 strlcat (name, ".lights", sizeof (name));
2550 lightsstring = FS_LoadFile(name, false);
2558 while (*s && *s != '\n')
2563 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);
2567 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);
2570 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
2571 radius = bound(15, radius, 4096);
2572 VectorScale(color, (2.0f / (8388608.0f)), color);
2573 R_Shadow_NewWorldLight(origin, vec3_origin, color, radius, 0, style, true, NULL);
2578 Con_Printf("invalid lights file \"%s\"\n", name);
2579 Mem_Free(lightsstring);
2583 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
2585 int entnum, style, islight, skin, pflags, effects;
2586 char key[256], value[1024];
2587 float origin[3], angles[3], radius, color[3], light, fadescale, lightscale, originhack[3], overridecolor[3];
2590 if (cl.worldmodel == NULL)
2592 Con_Print("No map loaded.\n");
2595 data = cl.worldmodel->brush.entities;
2598 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
2601 origin[0] = origin[1] = origin[2] = 0;
2602 originhack[0] = originhack[1] = originhack[2] = 0;
2603 angles[0] = angles[1] = angles[2] = 0;
2604 color[0] = color[1] = color[2] = 1;
2605 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
2615 if (!COM_ParseToken(&data, false))
2617 if (com_token[0] == '}')
2618 break; // end of entity
2619 if (com_token[0] == '_')
2620 strcpy(key, com_token + 1);
2622 strcpy(key, com_token);
2623 while (key[strlen(key)-1] == ' ') // remove trailing spaces
2624 key[strlen(key)-1] = 0;
2625 if (!COM_ParseToken(&data, false))
2627 strcpy(value, com_token);
2629 // now that we have the key pair worked out...
2630 if (!strcmp("light", key))
2631 light = atof(value);
2632 else if (!strcmp("origin", key))
2633 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
2634 else if (!strcmp("angle", key))
2635 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
2636 else if (!strcmp("angles", key))
2637 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
2638 else if (!strcmp("color", key))
2639 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
2640 else if (!strcmp("wait", key))
2641 fadescale = atof(value);
2642 else if (!strcmp("classname", key))
2644 if (!strncmp(value, "light", 5))
2647 if (!strcmp(value, "light_fluoro"))
2652 overridecolor[0] = 1;
2653 overridecolor[1] = 1;
2654 overridecolor[2] = 1;
2656 if (!strcmp(value, "light_fluorospark"))
2661 overridecolor[0] = 1;
2662 overridecolor[1] = 1;
2663 overridecolor[2] = 1;
2665 if (!strcmp(value, "light_globe"))
2670 overridecolor[0] = 1;
2671 overridecolor[1] = 0.8;
2672 overridecolor[2] = 0.4;
2674 if (!strcmp(value, "light_flame_large_yellow"))
2679 overridecolor[0] = 1;
2680 overridecolor[1] = 0.5;
2681 overridecolor[2] = 0.1;
2683 if (!strcmp(value, "light_flame_small_yellow"))
2688 overridecolor[0] = 1;
2689 overridecolor[1] = 0.5;
2690 overridecolor[2] = 0.1;
2692 if (!strcmp(value, "light_torch_small_white"))
2697 overridecolor[0] = 1;
2698 overridecolor[1] = 0.5;
2699 overridecolor[2] = 0.1;
2701 if (!strcmp(value, "light_torch_small_walltorch"))
2706 overridecolor[0] = 1;
2707 overridecolor[1] = 0.5;
2708 overridecolor[2] = 0.1;
2712 else if (!strcmp("style", key))
2713 style = atoi(value);
2714 else if (cl.worldmodel->type == mod_brushq3)
2716 if (!strcmp("scale", key))
2717 lightscale = atof(value);
2718 if (!strcmp("fade", key))
2719 fadescale = atof(value);
2721 else if (!strcmp("skin", key))
2722 skin = (int)atof(value);
2723 else if (!strcmp("pflags", key))
2724 pflags = (int)atof(value);
2725 else if (!strcmp("effects", key))
2726 effects = (int)atof(value);
2728 if (light <= 0 && islight)
2730 if (lightscale <= 0)
2734 if (gamemode == GAME_TENEBRAE)
2736 if (effects & EF_NODRAW)
2738 pflags |= PFLAGS_FULLDYNAMIC;
2739 effects &= ~EF_NODRAW;
2742 radius = min(light * r_editlights_quakelightsizescale.value * lightscale / fadescale, 1048576);
2743 light = sqrt(bound(0, light, 1048576)) * (1.0f / 16.0f);
2744 if (color[0] == 1 && color[1] == 1 && color[2] == 1)
2745 VectorCopy(overridecolor, color);
2746 VectorScale(color, light, color);
2747 VectorAdd(origin, originhack, origin);
2748 if (radius >= 15 && !(pflags & PFLAGS_FULLDYNAMIC))
2749 R_Shadow_NewWorldLight(origin, angles, color, radius, (pflags & PFLAGS_CORONA) != 0, style, (pflags & PFLAGS_NOSHADOW) == 0, skin >= 16 ? va("cubemaps/%i", skin) : NULL);
2754 void R_Shadow_SetCursorLocationForView(void)
2756 vec_t dist, push, frac;
2757 vec3_t dest, endpos, normal;
2758 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
2759 frac = CL_TraceLine(r_vieworigin, dest, endpos, normal, true, NULL, SUPERCONTENTS_SOLID);
2762 dist = frac * r_editlights_cursordistance.value;
2763 push = r_editlights_cursorpushback.value;
2767 VectorMA(endpos, push, r_viewforward, endpos);
2768 VectorMA(endpos, r_editlights_cursorpushoff.value, normal, endpos);
2770 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2771 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2772 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2775 void R_Shadow_UpdateWorldLightSelection(void)
2777 if (r_editlights.integer)
2779 R_Shadow_SetCursorLocationForView();
2780 R_Shadow_SelectLightInView();
2781 R_Shadow_DrawLightSprites();
2784 R_Shadow_SelectLight(NULL);
2787 void R_Shadow_EditLights_Clear_f(void)
2789 R_Shadow_ClearWorldLights();
2792 void R_Shadow_EditLights_Reload_f(void)
2794 r_shadow_reloadlights = true;
2797 void R_Shadow_EditLights_Save_f(void)
2800 R_Shadow_SaveWorldLights();
2803 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
2805 R_Shadow_ClearWorldLights();
2806 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
2809 void R_Shadow_EditLights_ImportLightsFile_f(void)
2811 R_Shadow_ClearWorldLights();
2812 R_Shadow_LoadLightsFile();
2815 void R_Shadow_EditLights_Spawn_f(void)
2818 if (!r_editlights.integer)
2820 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
2823 if (Cmd_Argc() != 1)
2825 Con_Print("r_editlights_spawn does not take parameters\n");
2828 color[0] = color[1] = color[2] = 1;
2829 R_Shadow_NewWorldLight(r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL);
2832 void R_Shadow_EditLights_Edit_f(void)
2834 vec3_t origin, angles, color;
2835 vec_t radius, corona;
2837 char cubemapname[1024];
2838 if (!r_editlights.integer)
2840 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
2843 if (!r_shadow_selectedlight)
2845 Con_Print("No selected light.\n");
2848 VectorCopy(r_shadow_selectedlight->origin, origin);
2849 VectorCopy(r_shadow_selectedlight->angles, angles);
2850 VectorCopy(r_shadow_selectedlight->color, color);
2851 radius = r_shadow_selectedlight->radius;
2852 style = r_shadow_selectedlight->style;
2853 if (r_shadow_selectedlight->cubemapname)
2854 strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
2857 shadows = r_shadow_selectedlight->shadow;
2858 corona = r_shadow_selectedlight->corona;
2859 if (!strcmp(Cmd_Argv(1), "origin"))
2861 if (Cmd_Argc() != 5)
2863 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
2866 origin[0] = atof(Cmd_Argv(2));
2867 origin[1] = atof(Cmd_Argv(3));
2868 origin[2] = atof(Cmd_Argv(4));
2870 else if (!strcmp(Cmd_Argv(1), "originx"))
2872 if (Cmd_Argc() != 3)
2874 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2877 origin[0] = atof(Cmd_Argv(2));
2879 else if (!strcmp(Cmd_Argv(1), "originy"))
2881 if (Cmd_Argc() != 3)
2883 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2886 origin[1] = atof(Cmd_Argv(2));
2888 else if (!strcmp(Cmd_Argv(1), "originz"))
2890 if (Cmd_Argc() != 3)
2892 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2895 origin[2] = atof(Cmd_Argv(2));
2897 else if (!strcmp(Cmd_Argv(1), "move"))
2899 if (Cmd_Argc() != 5)
2901 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
2904 origin[0] += atof(Cmd_Argv(2));
2905 origin[1] += atof(Cmd_Argv(3));
2906 origin[2] += atof(Cmd_Argv(4));
2908 else if (!strcmp(Cmd_Argv(1), "movex"))
2910 if (Cmd_Argc() != 3)
2912 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2915 origin[0] += atof(Cmd_Argv(2));
2917 else if (!strcmp(Cmd_Argv(1), "movey"))
2919 if (Cmd_Argc() != 3)
2921 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2924 origin[1] += atof(Cmd_Argv(2));
2926 else if (!strcmp(Cmd_Argv(1), "movez"))
2928 if (Cmd_Argc() != 3)
2930 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2933 origin[2] += atof(Cmd_Argv(2));
2935 else if (!strcmp(Cmd_Argv(1), "angles"))
2937 if (Cmd_Argc() != 5)
2939 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
2942 angles[0] = atof(Cmd_Argv(2));
2943 angles[1] = atof(Cmd_Argv(3));
2944 angles[2] = atof(Cmd_Argv(4));
2946 else if (!strcmp(Cmd_Argv(1), "anglesx"))
2948 if (Cmd_Argc() != 3)
2950 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2953 angles[0] = atof(Cmd_Argv(2));
2955 else if (!strcmp(Cmd_Argv(1), "anglesy"))
2957 if (Cmd_Argc() != 3)
2959 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2962 angles[1] = atof(Cmd_Argv(2));
2964 else if (!strcmp(Cmd_Argv(1), "anglesz"))
2966 if (Cmd_Argc() != 3)
2968 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2971 angles[2] = atof(Cmd_Argv(2));
2973 else if (!strcmp(Cmd_Argv(1), "color"))
2975 if (Cmd_Argc() != 5)
2977 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
2980 color[0] = atof(Cmd_Argv(2));
2981 color[1] = atof(Cmd_Argv(3));
2982 color[2] = atof(Cmd_Argv(4));
2984 else if (!strcmp(Cmd_Argv(1), "radius"))
2986 if (Cmd_Argc() != 3)
2988 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2991 radius = atof(Cmd_Argv(2));
2993 else if (!strcmp(Cmd_Argv(1), "style"))
2995 if (Cmd_Argc() != 3)
2997 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3000 style = atoi(Cmd_Argv(2));
3002 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3006 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3009 if (Cmd_Argc() == 3)
3010 strcpy(cubemapname, Cmd_Argv(2));
3014 else if (!strcmp(Cmd_Argv(1), "shadows"))
3016 if (Cmd_Argc() != 3)
3018 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3021 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3023 else if (!strcmp(Cmd_Argv(1), "corona"))
3025 if (Cmd_Argc() != 3)
3027 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3030 corona = atof(Cmd_Argv(2));
3034 Con_Print("usage: r_editlights_edit [property] [value]\n");
3035 Con_Print("Selected light's properties:\n");
3036 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3037 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3038 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3039 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3040 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3041 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3042 Con_Printf("Shadows: %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3043 Con_Printf("Cubemap: %s\n", r_shadow_selectedlight->cubemapname);
3046 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3047 r_shadow_selectedlight = NULL;
3048 R_Shadow_NewWorldLight(origin, angles, color, radius, corona, style, shadows, cubemapname);
3051 extern int con_vislines;
3052 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3056 if (r_shadow_selectedlight == NULL)
3060 sprintf(temp, "Light properties");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3061 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;
3062 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;
3063 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;
3064 sprintf(temp, "Radius %f", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3065 sprintf(temp, "Corona %f", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3066 sprintf(temp, "Style %i", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3067 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;
3068 sprintf(temp, "Cubemap %s", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3071 void R_Shadow_EditLights_ToggleShadow_f(void)
3073 if (!r_editlights.integer)
3075 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3078 if (!r_shadow_selectedlight)
3080 Con_Print("No selected light.\n");
3083 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);
3084 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3085 r_shadow_selectedlight = NULL;
3088 void R_Shadow_EditLights_ToggleCorona_f(void)
3090 if (!r_editlights.integer)
3092 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3095 if (!r_shadow_selectedlight)
3097 Con_Print("No selected light.\n");
3100 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);
3101 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3102 r_shadow_selectedlight = NULL;
3105 void R_Shadow_EditLights_Remove_f(void)
3107 if (!r_editlights.integer)
3109 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
3112 if (!r_shadow_selectedlight)
3114 Con_Print("No selected light.\n");
3117 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3118 r_shadow_selectedlight = NULL;
3121 void R_Shadow_EditLights_Help_f(void)
3124 "Documentation on r_editlights system:\n"
3126 "r_editlights : enable/disable editing mode\n"
3127 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
3128 "r_editlights_cursorpushback : push back cursor this far from surface\n"
3129 "r_editlights_cursorpushoff : push cursor off surface this far\n"
3130 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
3131 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
3132 "r_editlights_rtlightssizescale : imported rtlight size scaling\n"
3133 "r_editlights_rtlightscolorscale : imported rtlight color scaling\n"
3135 "r_editlights_help : this help\n"
3136 "r_editlights_clear : remove all lights\n"
3137 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
3138 "r_editlights_save : save to .rtlights file\n"
3139 "r_editlights_spawn : create a light with default settings\n"
3140 "r_editlights_edit command : edit selected light - more documentation below\n"
3141 "r_editlights_remove : remove selected light\n"
3142 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
3143 "r_editlights_importlightentitiesfrommap : reload light entities\n"
3144 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
3146 "origin x y z : set light location\n"
3147 "originx x: set x component of light location\n"
3148 "originy y: set y component of light location\n"
3149 "originz z: set z component of light location\n"
3150 "move x y z : adjust light location\n"
3151 "movex x: adjust x component of light location\n"
3152 "movey y: adjust y component of light location\n"
3153 "movez z: adjust z component of light location\n"
3154 "angles x y z : set light angles\n"
3155 "anglesx x: set x component of light angles\n"
3156 "anglesy y: set y component of light angles\n"
3157 "anglesz z: set z component of light angles\n"
3158 "color r g b : set color of light (can be brighter than 1 1 1)\n"
3159 "radius radius : set radius (size) of light\n"
3160 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
3161 "cubemap basename : set filter cubemap of light (not yet supported)\n"
3162 "shadows 1/0 : turn on/off shadows\n"
3163 "corona n : set corona intensity\n"
3164 "<nothing> : print light properties to console\n"
3168 void R_Shadow_EditLights_Init(void)
3170 Cvar_RegisterVariable(&r_editlights);
3171 Cvar_RegisterVariable(&r_editlights_cursordistance);
3172 Cvar_RegisterVariable(&r_editlights_cursorpushback);
3173 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
3174 Cvar_RegisterVariable(&r_editlights_cursorgrid);
3175 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
3176 Cvar_RegisterVariable(&r_editlights_rtlightssizescale);
3177 Cvar_RegisterVariable(&r_editlights_rtlightscolorscale);
3178 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
3179 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
3180 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
3181 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
3182 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
3183 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
3184 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
3185 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
3186 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
3187 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
3188 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);