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 rtexturepool_t *r_shadow_texturepool;
147 rtexture_t *r_shadow_normalcubetexture;
148 rtexture_t *r_shadow_attenuation2dtexture;
149 rtexture_t *r_shadow_attenuation3dtexture;
150 rtexture_t *r_shadow_blankbumptexture;
151 rtexture_t *r_shadow_blankglosstexture;
152 rtexture_t *r_shadow_blankwhitetexture;
154 // used only for light filters (cubemaps)
155 rtexturepool_t *r_shadow_filters_texturepool;
157 cvar_t r_shadow_realtime_world_lightmaps = {0, "r_shadow_realtime_world_lightmaps", "0"};
158 cvar_t r_shadow_lightattenuationpower = {0, "r_shadow_lightattenuationpower", "0.5"};
159 cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1"};
160 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1"};
161 cvar_t r_shadow_realtime_world = {0, "r_shadow_realtime_world", "0"};
162 cvar_t r_shadow_realtime_dlight = {0, "r_shadow_realtime_dlight", "0"};
163 cvar_t r_shadow_visiblevolumes = {0, "r_shadow_visiblevolumes", "0"};
164 cvar_t r_shadow_gloss = {0, "r_shadow_gloss", "1"};
165 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1"};
166 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.25"};
167 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1"};
168 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1"};
169 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4"};
170 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0"};
171 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0"};
172 cvar_t r_shadow_polygonoffset = {0, "r_shadow_polygonoffset", "1"};
173 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1"};
174 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "10000"};
175 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1"};
176 cvar_t r_shadow_singlepassvolumegeneration = {0, "r_shadow_singlepassvolumegeneration", "1"};
177 cvar_t r_shadow_worldshadows = {0, "r_shadow_worldshadows", "1"};
178 cvar_t r_shadow_dlightshadows = {CVAR_SAVE, "r_shadow_dlightshadows", "1"};
179 cvar_t r_shadow_staticworldlights = {0, "r_shadow_staticworldlights", "1"};
180 cvar_t r_shadow_cull = {0, "r_shadow_cull", "1"};
181 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1"};
183 int c_rt_lights, c_rt_clears, c_rt_scissored;
184 int c_rt_shadowmeshes, c_rt_shadowtris, c_rt_lightmeshes, c_rt_lighttris;
185 int c_rtcached_shadowmeshes, c_rtcached_shadowtris;
187 void R_Shadow_ClearWorldLights(void);
188 void R_Shadow_SaveWorldLights(void);
189 void R_Shadow_LoadWorldLights(void);
190 void R_Shadow_LoadLightsFile(void);
191 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
193 void r_shadow_start(void)
195 // allocate vertex processing arrays
196 r_shadow_mempool = Mem_AllocPool("R_Shadow");
197 maxshadowelements = 0;
198 shadowelements = NULL;
206 shadowmarklist = NULL;
208 r_shadow_normalcubetexture = NULL;
209 r_shadow_attenuation2dtexture = NULL;
210 r_shadow_attenuation3dtexture = NULL;
211 r_shadow_blankbumptexture = NULL;
212 r_shadow_blankglosstexture = NULL;
213 r_shadow_blankwhitetexture = NULL;
214 r_shadow_texturepool = NULL;
215 r_shadow_filters_texturepool = NULL;
216 R_Shadow_ClearWorldLights();
217 r_shadow_reloadlights = true;
220 void r_shadow_shutdown(void)
222 R_Shadow_ClearWorldLights();
223 r_shadow_reloadlights = true;
224 r_shadow_normalcubetexture = NULL;
225 r_shadow_attenuation2dtexture = NULL;
226 r_shadow_attenuation3dtexture = NULL;
227 r_shadow_blankbumptexture = NULL;
228 r_shadow_blankglosstexture = NULL;
229 r_shadow_blankwhitetexture = NULL;
230 R_FreeTexturePool(&r_shadow_texturepool);
231 R_FreeTexturePool(&r_shadow_filters_texturepool);
232 maxshadowelements = 0;
233 shadowelements = NULL;
241 shadowmarklist = NULL;
243 Mem_FreePool(&r_shadow_mempool);
246 void r_shadow_newmap(void)
248 R_Shadow_ClearWorldLights();
249 r_shadow_reloadlights = true;
252 void R_Shadow_Help_f(void)
255 "Documentation on r_shadow system:\n"
257 "r_shadow_lightattenuationpower : used to generate attenuation texture\n"
258 "r_shadow_lightattenuationscale : used to generate attenuation texture\n"
259 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
260 "r_shadow_realtime_world : use realtime world light rendering\n"
261 "r_shadow_realtime_dlight : use high quality dlight rendering\n"
262 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to rtlights\n"
263 "r_shadow_visiblevolumes : useful for performance testing; bright = slow!\n"
264 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
265 "r_shadow_glossintensity : brightness of textured gloss\n"
266 "r_shadow_gloss2intensity : brightness of forced gloss\n"
267 "r_shadow_debuglight : render only this light number (-1 = all)\n"
268 "r_shadow_scissor : use scissor optimization\n"
269 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
270 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
271 "r_shadow_polygonfactor : nudge shadow volumes closer/further\n"
272 "r_shadow_polygonoffset : nudge shadow volumes closer/further\n"
273 "r_shadow_portallight : use portal visibility for static light precomputation\n"
274 "r_shadow_projectdistance : shadow volume projection distance\n"
275 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
276 "r_shadow_singlepassvolumegeneration : selects shadow volume algorithm\n"
277 "r_shadow_worldshadows : enable world shadows\n"
278 "r_shadow_dlightshadows : enable dlight shadows\n"
280 "r_shadow_help : this help\n"
284 void R_Shadow_Init(void)
286 Cvar_RegisterVariable(&r_shadow_lightattenuationpower);
287 Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
288 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
289 Cvar_RegisterVariable(&r_shadow_realtime_world);
290 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
291 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
292 Cvar_RegisterVariable(&r_shadow_visiblevolumes);
293 Cvar_RegisterVariable(&r_shadow_gloss);
294 Cvar_RegisterVariable(&r_shadow_glossintensity);
295 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
296 Cvar_RegisterVariable(&r_shadow_debuglight);
297 Cvar_RegisterVariable(&r_shadow_scissor);
298 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
299 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
300 Cvar_RegisterVariable(&r_shadow_polygonfactor);
301 Cvar_RegisterVariable(&r_shadow_polygonoffset);
302 Cvar_RegisterVariable(&r_shadow_portallight);
303 Cvar_RegisterVariable(&r_shadow_projectdistance);
304 Cvar_RegisterVariable(&r_shadow_texture3d);
305 Cvar_RegisterVariable(&r_shadow_singlepassvolumegeneration);
306 Cvar_RegisterVariable(&r_shadow_worldshadows);
307 Cvar_RegisterVariable(&r_shadow_dlightshadows);
308 Cvar_RegisterVariable(&r_shadow_staticworldlights);
309 Cvar_RegisterVariable(&r_shadow_cull);
310 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
311 if (gamemode == GAME_TENEBRAE)
313 Cvar_SetValue("r_shadow_gloss", 2);
314 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
316 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f);
317 R_Shadow_EditLights_Init();
318 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
321 matrix4x4_t matrix_attenuationxyz =
324 {0.5, 0.0, 0.0, 0.5},
325 {0.0, 0.5, 0.0, 0.5},
326 {0.0, 0.0, 0.5, 0.5},
331 matrix4x4_t matrix_attenuationz =
334 {0.0, 0.0, 0.5, 0.5},
335 {0.0, 0.0, 0.0, 0.0},
336 {0.0, 0.0, 0.0, 0.0},
341 int *R_Shadow_ResizeShadowElements(int numtris)
343 // make sure shadowelements is big enough for this volume
344 if (maxshadowelements < numtris * 24)
346 maxshadowelements = numtris * 24;
348 Mem_Free(shadowelements);
349 shadowelements = Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int));
351 return shadowelements;
354 void R_Shadow_PrepareShadowMark(int numtris)
356 // make sure shadowmark is big enough for this volume
357 if (maxshadowmark < numtris)
359 maxshadowmark = numtris;
361 Mem_Free(shadowmark);
363 Mem_Free(shadowmarklist);
364 shadowmark = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmark));
365 shadowmarklist = Mem_Alloc(r_shadow_mempool, maxshadowmark * sizeof(*shadowmarklist));
369 // if shadowmarkcount wrapped we clear the array and adjust accordingly
370 if (shadowmarkcount == 0)
373 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
378 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)
380 int i, j, tris = 0, vr[3], t, outvertices = 0;
384 if (maxvertexupdate < innumvertices)
386 maxvertexupdate = innumvertices;
388 Mem_Free(vertexupdate);
390 Mem_Free(vertexremap);
391 vertexupdate = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
392 vertexremap = Mem_Alloc(r_shadow_mempool, maxvertexupdate * sizeof(int));
396 if (vertexupdatenum == 0)
399 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
400 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
403 for (i = 0;i < numshadowmarktris;i++)
405 t = shadowmarktris[i];
406 shadowmark[t] = shadowmarkcount;
407 e = inelement3i + t * 3;
408 // make sure the vertices are created
409 for (j = 0;j < 3;j++)
411 if (vertexupdate[e[j]] != vertexupdatenum)
413 vertexupdate[e[j]] = vertexupdatenum;
414 vertexremap[e[j]] = outvertices;
415 VectorSubtract(invertex3f + e[j] * 3, projectorigin, temp);
416 f = projectdistance / VectorLength(temp);
417 VectorCopy(invertex3f + e[j] * 3, outvertex3f);
418 VectorMA(projectorigin, f, temp, (outvertex3f + 3));
423 // output the front and back triangles
424 outelement3i[0] = vertexremap[e[0]];
425 outelement3i[1] = vertexremap[e[1]];
426 outelement3i[2] = vertexremap[e[2]];
427 outelement3i[3] = vertexremap[e[2]] + 1;
428 outelement3i[4] = vertexremap[e[1]] + 1;
429 outelement3i[5] = vertexremap[e[0]] + 1;
434 for (i = 0;i < numshadowmarktris;i++)
436 t = shadowmarktris[i];
437 e = inelement3i + t * 3;
438 n = inneighbor3i + t * 3;
439 // output the sides (facing outward from this triangle)
440 if (shadowmark[n[0]] != shadowmarkcount)
442 vr[0] = vertexremap[e[0]];
443 vr[1] = vertexremap[e[1]];
444 outelement3i[0] = vr[1];
445 outelement3i[1] = vr[0];
446 outelement3i[2] = vr[0] + 1;
447 outelement3i[3] = vr[1];
448 outelement3i[4] = vr[0] + 1;
449 outelement3i[5] = vr[1] + 1;
453 if (shadowmark[n[1]] != shadowmarkcount)
455 vr[1] = vertexremap[e[1]];
456 vr[2] = vertexremap[e[2]];
457 outelement3i[0] = vr[2];
458 outelement3i[1] = vr[1];
459 outelement3i[2] = vr[1] + 1;
460 outelement3i[3] = vr[2];
461 outelement3i[4] = vr[1] + 1;
462 outelement3i[5] = vr[2] + 1;
466 if (shadowmark[n[2]] != shadowmarkcount)
468 vr[0] = vertexremap[e[0]];
469 vr[2] = vertexremap[e[2]];
470 outelement3i[0] = vr[0];
471 outelement3i[1] = vr[2];
472 outelement3i[2] = vr[2] + 1;
473 outelement3i[3] = vr[0];
474 outelement3i[4] = vr[2] + 1;
475 outelement3i[5] = vr[0] + 1;
481 *outnumvertices = outvertices;
485 float varray_vertex3f2[65536*3];
487 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)
490 if (projectdistance < 0.1)
492 Con_Printf("R_Shadow_Volume: projectdistance %f\n");
495 if (!numverts || !nummarktris)
497 // make sure shadowelements is big enough for this volume
498 if (maxshadowelements < nummarktris * 24)
499 R_Shadow_ResizeShadowElements((nummarktris + 256) * 24);
500 tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, varray_vertex3f2, projectorigin, projectdistance, nummarktris, marktris);
501 R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements);
504 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)
509 // check which triangles are facing the , and then output
510 // triangle elements and vertices... by clever use of elements we
511 // can construct the whole shadow from the unprojected vertices and
512 // the projected vertices
514 // identify lit faces within the bounding box
515 R_Shadow_PrepareShadowMark(numtris);
516 for (i = 0;i < numtris;i++)
518 v[0] = invertex3f + elements[i*3+0] * 3;
519 v[1] = invertex3f + elements[i*3+1] * 3;
520 v[2] = invertex3f + elements[i*3+2] * 3;
521 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])))
522 shadowmarklist[numshadowmark++] = i;
524 R_Shadow_VolumeFromList(numverts, numtris, invertex3f, elements, neighbors, projectorigin, projectdistance, numshadowmark, shadowmarklist);
527 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)
530 mins[0] = projectorigin[0] - radius;
531 mins[1] = projectorigin[1] - radius;
532 mins[2] = projectorigin[2] - radius;
533 maxs[0] = projectorigin[0] + radius;
534 maxs[1] = projectorigin[1] + radius;
535 maxs[2] = projectorigin[2] + radius;
536 R_Shadow_VolumeFromBox(numverts, numtris, invertex3f, elements, neighbors, projectorigin, projectdistance, mins, maxs);
539 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
542 memset(&m, 0, sizeof(m));
543 m.pointer_vertex = vertex3f;
545 if (r_shadowstage == SHADOWSTAGE_STENCIL)
547 // decrement stencil if frontface is behind depthbuffer
548 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
549 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
550 R_Mesh_Draw(numvertices, numtriangles, element3i);
552 c_rt_shadowtris += numtriangles;
553 // increment stencil if backface is behind depthbuffer
554 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
555 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
557 R_Mesh_Draw(numvertices, numtriangles, element3i);
559 c_rt_shadowtris += numtriangles;
562 void R_Shadow_RenderShadowMeshVolume(shadowmesh_t *firstmesh)
566 memset(&m, 0, sizeof(m));
567 for (mesh = firstmesh;mesh;mesh = mesh->next)
569 m.pointer_vertex = mesh->vertex3f;
571 if (r_shadowstage == SHADOWSTAGE_STENCIL)
573 // decrement stencil if frontface is behind depthbuffer
574 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
575 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
576 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
577 c_rtcached_shadowmeshes++;
578 c_rtcached_shadowtris += mesh->numtriangles;
579 // increment stencil if backface is behind depthbuffer
580 qglCullFace(GL_BACK); // quake is backwards, this culls front faces
581 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
583 R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->element3i);
584 c_rtcached_shadowmeshes++;
585 c_rtcached_shadowtris += mesh->numtriangles;
589 float r_shadow_attenpower, r_shadow_attenscale;
590 static void R_Shadow_MakeTextures(void)
592 int x, y, z, d, side;
593 float v[3], s, t, intensity;
595 R_FreeTexturePool(&r_shadow_texturepool);
596 r_shadow_texturepool = R_AllocTexturePool();
597 r_shadow_attenpower = r_shadow_lightattenuationpower.value;
598 r_shadow_attenscale = r_shadow_lightattenuationscale.value;
600 #define ATTEN2DSIZE 64
601 #define ATTEN3DSIZE 32
602 data = Mem_Alloc(tempmempool, max(6*NORMSIZE*NORMSIZE*4, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4)));
607 r_shadow_blankbumptexture = R_LoadTexture2D(r_shadow_texturepool, "blankbump", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
612 r_shadow_blankglosstexture = R_LoadTexture2D(r_shadow_texturepool, "blankgloss", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
617 r_shadow_blankwhitetexture = R_LoadTexture2D(r_shadow_texturepool, "blankwhite", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
618 if (gl_texturecubemap)
620 for (side = 0;side < 6;side++)
622 for (y = 0;y < NORMSIZE;y++)
624 for (x = 0;x < NORMSIZE;x++)
626 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
627 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
661 intensity = 127.0f / sqrt(DotProduct(v, v));
662 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+0] = 128.0f + intensity * v[0];
663 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+1] = 128.0f + intensity * v[1];
664 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+2] = 128.0f + intensity * v[2];
665 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+3] = 255;
669 r_shadow_normalcubetexture = R_LoadTextureCubeMap(r_shadow_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
672 r_shadow_normalcubetexture = NULL;
673 for (y = 0;y < ATTEN2DSIZE;y++)
675 for (x = 0;x < ATTEN2DSIZE;x++)
677 v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
678 v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375);
680 intensity = 1.0f - sqrt(DotProduct(v, v));
682 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
683 d = bound(0, intensity, 255);
684 data[(y*ATTEN2DSIZE+x)*4+0] = d;
685 data[(y*ATTEN2DSIZE+x)*4+1] = d;
686 data[(y*ATTEN2DSIZE+x)*4+2] = d;
687 data[(y*ATTEN2DSIZE+x)*4+3] = d;
690 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
691 if (r_shadow_texture3d.integer)
693 for (z = 0;z < ATTEN3DSIZE;z++)
695 for (y = 0;y < ATTEN3DSIZE;y++)
697 for (x = 0;x < ATTEN3DSIZE;x++)
699 v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
700 v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
701 v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375);
702 intensity = 1.0f - sqrt(DotProduct(v, v));
704 intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f;
705 d = bound(0, intensity, 255);
706 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d;
707 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d;
708 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d;
709 data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d;
713 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL);
718 void R_Shadow_Stage_Begin(void)
722 if (r_shadow_texture3d.integer && !gl_texture3d)
723 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
724 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
725 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
727 if (!r_shadow_attenuation2dtexture
728 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
729 || r_shadow_lightattenuationpower.value != r_shadow_attenpower
730 || r_shadow_lightattenuationscale.value != r_shadow_attenscale)
731 R_Shadow_MakeTextures();
733 memset(&m, 0, sizeof(m));
734 GL_BlendFunc(GL_ONE, GL_ZERO);
738 GL_Color(0, 0, 0, 1);
739 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
740 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
741 r_shadowstage = SHADOWSTAGE_NONE;
743 c_rt_lights = c_rt_clears = c_rt_scissored = 0;
744 c_rt_shadowmeshes = c_rt_shadowtris = c_rt_lightmeshes = c_rt_lighttris = 0;
745 c_rtcached_shadowmeshes = c_rtcached_shadowtris = 0;
748 void R_Shadow_LoadWorldLightsIfNeeded(void)
750 if (r_shadow_reloadlights && cl.worldmodel)
752 R_Shadow_ClearWorldLights();
753 r_shadow_reloadlights = false;
754 R_Shadow_LoadWorldLights();
755 if (r_shadow_worldlightchain == NULL)
757 R_Shadow_LoadLightsFile();
758 if (r_shadow_worldlightchain == NULL)
759 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
764 void R_Shadow_Stage_ShadowVolumes(void)
767 memset(&m, 0, sizeof(m));
769 GL_Color(1, 1, 1, 1);
770 GL_ColorMask(0, 0, 0, 0);
771 GL_BlendFunc(GL_ONE, GL_ZERO);
774 qglPolygonOffset(r_shadow_polygonfactor.value, r_shadow_polygonoffset.value);
775 //if (r_shadow_polygonoffset.value != 0)
777 // qglPolygonOffset(r_shadow_polygonfactor.value, r_shadow_polygonoffset.value);
778 // qglEnable(GL_POLYGON_OFFSET_FILL);
781 // qglDisable(GL_POLYGON_OFFSET_FILL);
782 qglDepthFunc(GL_LESS);
783 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
784 qglEnable(GL_STENCIL_TEST);
785 qglStencilFunc(GL_ALWAYS, 128, ~0);
786 if (gl_ext_stenciltwoside.integer)
788 r_shadowstage = SHADOWSTAGE_STENCILTWOSIDE;
789 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
790 qglActiveStencilFaceEXT(GL_FRONT); // quake is backwards, this is back faces
792 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
793 qglActiveStencilFaceEXT(GL_BACK); // quake is backwards, this is front faces
795 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
799 r_shadowstage = SHADOWSTAGE_STENCIL;
801 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
803 GL_Clear(GL_STENCIL_BUFFER_BIT);
805 // LordHavoc note: many shadow volumes reside entirely inside the world
806 // (that is to say they are entirely bounded by their lit surfaces),
807 // which can be optimized by handling things as an inverted light volume,
808 // with the shadow boundaries of the world being simulated by an altered
809 // (129) bias to stencil clearing on such lights
810 // FIXME: generate inverted light volumes for use as shadow volumes and
811 // optimize for them as noted above
814 void R_Shadow_Stage_LightWithoutShadows(void)
817 memset(&m, 0, sizeof(m));
819 GL_BlendFunc(GL_ONE, GL_ONE);
822 qglPolygonOffset(0, 0);
823 //qglDisable(GL_POLYGON_OFFSET_FILL);
824 GL_Color(1, 1, 1, 1);
825 GL_ColorMask(1, 1, 1, 1);
826 qglDepthFunc(GL_EQUAL);
827 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
828 qglDisable(GL_STENCIL_TEST);
829 if (gl_support_stenciltwoside)
830 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
832 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
833 qglStencilFunc(GL_EQUAL, 128, 0xFF);
834 r_shadowstage = SHADOWSTAGE_LIGHT;
838 void R_Shadow_Stage_LightWithShadows(void)
841 memset(&m, 0, sizeof(m));
843 GL_BlendFunc(GL_ONE, GL_ONE);
846 qglPolygonOffset(0, 0);
847 //qglDisable(GL_POLYGON_OFFSET_FILL);
848 GL_Color(1, 1, 1, 1);
849 GL_ColorMask(1, 1, 1, 1);
850 qglDepthFunc(GL_EQUAL);
851 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
852 qglEnable(GL_STENCIL_TEST);
853 if (gl_support_stenciltwoside)
854 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
856 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
857 // only draw light where this geometry was already rendered AND the
858 // stencil is 128 (values other than this mean shadow)
859 qglStencilFunc(GL_EQUAL, 128, 0xFF);
860 r_shadowstage = SHADOWSTAGE_LIGHT;
864 void R_Shadow_Stage_End(void)
867 memset(&m, 0, sizeof(m));
869 GL_BlendFunc(GL_ONE, GL_ZERO);
872 qglPolygonOffset(0, 0);
873 //qglDisable(GL_POLYGON_OFFSET_FILL);
874 GL_Color(1, 1, 1, 1);
875 GL_ColorMask(1, 1, 1, 1);
876 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
877 qglDepthFunc(GL_LEQUAL);
878 qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
879 qglDisable(GL_STENCIL_TEST);
880 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
881 if (gl_support_stenciltwoside)
882 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
884 qglStencilFunc(GL_ALWAYS, 128, 0xFF);
885 r_shadowstage = SHADOWSTAGE_NONE;
888 int R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
890 int i, ix1, iy1, ix2, iy2;
891 float x1, y1, x2, y2, x, y, f;
894 if (!r_shadow_scissor.integer)
896 // if view is inside the box, just say yes it's visible
897 // LordHavoc: for some odd reason scissor seems broken without stencil
898 // (?!? seems like a driver bug) so abort if gl_stencil is false
899 if (!gl_stencil || BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
901 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
904 for (i = 0;i < 3;i++)
906 if (r_viewforward[i] >= 0)
917 f = DotProduct(r_viewforward, r_vieworigin) + 1;
918 if (DotProduct(r_viewforward, v2) <= f)
920 // entirely behind nearclip plane
923 if (DotProduct(r_viewforward, v) >= f)
925 // entirely infront of nearclip plane
926 x1 = y1 = x2 = y2 = 0;
927 for (i = 0;i < 8;i++)
929 v[0] = (i & 1) ? mins[0] : maxs[0];
930 v[1] = (i & 2) ? mins[1] : maxs[1];
931 v[2] = (i & 4) ? mins[2] : maxs[2];
933 GL_TransformToScreen(v, v2);
934 //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]);
953 // clipped by nearclip plane
954 // this is nasty and crude...
955 // create viewspace bbox
956 for (i = 0;i < 8;i++)
958 v[0] = ((i & 1) ? mins[0] : maxs[0]) - r_vieworigin[0];
959 v[1] = ((i & 2) ? mins[1] : maxs[1]) - r_vieworigin[1];
960 v[2] = ((i & 4) ? mins[2] : maxs[2]) - r_vieworigin[2];
961 v2[0] = -DotProduct(v, r_viewleft);
962 v2[1] = DotProduct(v, r_viewup);
963 v2[2] = DotProduct(v, r_viewforward);
966 if (smins[0] > v2[0]) smins[0] = v2[0];
967 if (smaxs[0] < v2[0]) smaxs[0] = v2[0];
968 if (smins[1] > v2[1]) smins[1] = v2[1];
969 if (smaxs[1] < v2[1]) smaxs[1] = v2[1];
970 if (smins[2] > v2[2]) smins[2] = v2[2];
971 if (smaxs[2] < v2[2]) smaxs[2] = v2[2];
975 smins[0] = smaxs[0] = v2[0];
976 smins[1] = smaxs[1] = v2[1];
977 smins[2] = smaxs[2] = v2[2];
980 // now we have a bbox in viewspace
981 // clip it to the view plane
984 // return true if that culled the box
985 if (smins[2] >= smaxs[2])
987 // ok some of it is infront of the view, transform each corner back to
988 // worldspace and then to screenspace and make screen rect
989 // initialize these variables just to avoid compiler warnings
990 x1 = y1 = x2 = y2 = 0;
991 for (i = 0;i < 8;i++)
993 v2[0] = (i & 1) ? smins[0] : smaxs[0];
994 v2[1] = (i & 2) ? smins[1] : smaxs[1];
995 v2[2] = (i & 4) ? smins[2] : smaxs[2];
996 v[0] = v2[0] * -r_viewleft[0] + v2[1] * r_viewup[0] + v2[2] * r_viewforward[0] + r_vieworigin[0];
997 v[1] = v2[0] * -r_viewleft[1] + v2[1] * r_viewup[1] + v2[2] * r_viewforward[1] + r_vieworigin[1];
998 v[2] = v2[0] * -r_viewleft[2] + v2[1] * r_viewup[2] + v2[2] * r_viewforward[2] + r_vieworigin[2];
1000 GL_TransformToScreen(v, v2);
1001 //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]);
1018 // this code doesn't handle boxes with any points behind view properly
1019 x1 = 1000;x2 = -1000;
1020 y1 = 1000;y2 = -1000;
1021 for (i = 0;i < 8;i++)
1023 v[0] = (i & 1) ? mins[0] : maxs[0];
1024 v[1] = (i & 2) ? mins[1] : maxs[1];
1025 v[2] = (i & 4) ? mins[2] : maxs[2];
1027 GL_TransformToScreen(v, v2);
1028 //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]);
1046 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1047 if (ix1 < r_view_x) ix1 = r_view_x;
1048 if (iy1 < r_view_y) iy1 = r_view_y;
1049 if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
1050 if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
1051 if (ix2 <= ix1 || iy2 <= iy1)
1053 // set up the scissor rectangle
1054 GL_Scissor(ix1, vid.realheight - iy2, ix2 - ix1, iy2 - iy1);
1055 //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
1056 //qglEnable(GL_SCISSOR_TEST);
1061 void R_Shadow_VertexLighting(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1063 float *color4f = varray_color4f;
1064 float dist, dot, intensity, v[3], n[3];
1065 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1067 Matrix4x4_Transform(m, vertex3f, v);
1068 if ((dist = DotProduct(v, v)) < 1)
1070 Matrix4x4_Transform3x3(m, normal3f, n);
1071 if ((dot = DotProduct(n, v)) > 0)
1074 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale * dot / sqrt(DotProduct(n,n));
1075 VectorScale(lightcolor, intensity, color4f);
1080 VectorClear(color4f);
1086 VectorClear(color4f);
1092 void R_Shadow_VertexLightingWithXYAttenuationTexture(int numverts, const float *vertex3f, const float *normal3f, const float *lightcolor, const matrix4x4_t *m)
1094 float *color4f = varray_color4f;
1095 float dist, dot, intensity, v[3], n[3];
1096 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1098 Matrix4x4_Transform(m, vertex3f, v);
1099 if ((dist = fabs(v[2])) < 1)
1101 Matrix4x4_Transform3x3(m, normal3f, n);
1102 if ((dot = DotProduct(n, v)) > 0)
1104 intensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale * dot / sqrt(DotProduct(n,n));
1105 VectorScale(lightcolor, intensity, color4f);
1110 VectorClear(color4f);
1116 VectorClear(color4f);
1122 // FIXME: this should be done in a vertex program when possible
1123 // FIXME: if vertex program not available, this would really benefit from 3DNow! or SSE
1124 void R_Shadow_Transform_Vertex3f_TexCoord3f(float *tc3f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1128 tc3f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1129 tc3f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1130 tc3f[2] = vertex3f[0] * matrix->m[2][0] + vertex3f[1] * matrix->m[2][1] + vertex3f[2] * matrix->m[2][2] + matrix->m[2][3];
1137 void R_Shadow_Transform_Vertex3f_TexCoord2f(float *tc2f, int numverts, const float *vertex3f, const matrix4x4_t *matrix)
1141 tc2f[0] = vertex3f[0] * matrix->m[0][0] + vertex3f[1] * matrix->m[0][1] + vertex3f[2] * matrix->m[0][2] + matrix->m[0][3];
1142 tc2f[1] = vertex3f[0] * matrix->m[1][0] + vertex3f[1] * matrix->m[1][1] + vertex3f[2] * matrix->m[1][2] + matrix->m[1][3];
1149 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)
1153 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1155 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1156 // the cubemap normalizes this for us
1157 out3f[0] = DotProduct(svector3f, lightdir);
1158 out3f[1] = DotProduct(tvector3f, lightdir);
1159 out3f[2] = DotProduct(normal3f, lightdir);
1163 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)
1166 float lightdir[3], eyedir[3], halfdir[3];
1167 for (i = 0;i < numverts;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1169 VectorSubtract(vertex3f, relativelightorigin, lightdir);
1170 VectorNormalizeFast(lightdir);
1171 VectorSubtract(vertex3f, relativeeyeorigin, eyedir);
1172 VectorNormalizeFast(eyedir);
1173 VectorAdd(lightdir, eyedir, halfdir);
1174 // the cubemap normalizes this for us
1175 out3f[0] = DotProduct(svector3f, halfdir);
1176 out3f[1] = DotProduct(tvector3f, halfdir);
1177 out3f[2] = DotProduct(normal3f, halfdir);
1181 void R_Shadow_DiffuseLighting(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 *lightcolor, const matrix4x4_t *matrix_modeltolight, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz, rtexture_t *basetexture, rtexture_t *bumptexture, rtexture_t *lightcubemap)
1184 float color[3], color2[3];
1186 if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
1189 bumptexture = r_shadow_blankbumptexture;
1191 // colorscale accounts for how much we multiply the brightness during combine
1192 // mult is how many times the final pass of the lighting will be
1193 // performed to get more brightness than otherwise possible
1194 // limit mult to 64 for sanity sake
1195 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
1197 // 3/2 3D combine path (Geforce3, Radeon 8500)
1198 memset(&m, 0, sizeof(m));
1199 m.pointer_vertex = vertex3f;
1200 m.tex[0] = R_GetTexture(bumptexture);
1201 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1202 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
1203 m.texcombinergb[0] = GL_REPLACE;
1204 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1205 m.pointer_texcoord[0] = texcoord2f;
1206 m.pointer_texcoord[1] = varray_texcoord3f[1];
1207 m.pointer_texcoord[2] = varray_texcoord3f[2];
1209 GL_ColorMask(0,0,0,1);
1210 GL_BlendFunc(GL_ONE, GL_ZERO);
1211 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1212 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1213 R_Mesh_Draw(numverts, numtriangles, elements);
1215 c_rt_lighttris += numtriangles;
1217 memset(&m, 0, sizeof(m));
1218 m.pointer_vertex = vertex3f;
1219 m.tex[0] = R_GetTexture(basetexture);
1220 m.pointer_texcoord[0] = texcoord2f;
1223 m.texcubemap[1] = R_GetTexture(lightcubemap);
1224 m.pointer_texcoord[1] = varray_texcoord3f[1];
1225 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1228 GL_ColorMask(1,1,1,0);
1229 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1230 VectorScale(lightcolor, r_shadow_lightintensityscale.value, color2);
1231 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1233 color[0] = bound(0, color2[0], 1);
1234 color[1] = bound(0, color2[1], 1);
1235 color[2] = bound(0, color2[2], 1);
1236 GL_Color(color[0], color[1], color[2], 1);
1237 R_Mesh_Draw(numverts, numtriangles, elements);
1239 c_rt_lighttris += numtriangles;
1242 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap)
1244 // 1/2/2 3D combine path (original Radeon)
1245 memset(&m, 0, sizeof(m));
1246 m.pointer_vertex = vertex3f;
1247 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1248 m.pointer_texcoord[0] = varray_texcoord3f[0];
1250 GL_ColorMask(0,0,0,1);
1251 GL_BlendFunc(GL_ONE, GL_ZERO);
1252 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1253 R_Mesh_Draw(numverts, numtriangles, elements);
1255 c_rt_lighttris += numtriangles;
1257 memset(&m, 0, sizeof(m));
1258 m.pointer_vertex = vertex3f;
1259 m.tex[0] = R_GetTexture(bumptexture);
1260 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1261 m.texcombinergb[0] = GL_REPLACE;
1262 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1263 m.pointer_texcoord[0] = texcoord2f;
1264 m.pointer_texcoord[1] = varray_texcoord3f[1];
1266 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1267 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1268 R_Mesh_Draw(numverts, numtriangles, elements);
1270 c_rt_lighttris += numtriangles;
1272 memset(&m, 0, sizeof(m));
1273 m.pointer_vertex = vertex3f;
1274 m.tex[0] = R_GetTexture(basetexture);
1275 m.pointer_texcoord[0] = texcoord2f;
1278 m.texcubemap[1] = R_GetTexture(lightcubemap);
1279 m.pointer_texcoord[1] = varray_texcoord3f[1];
1280 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1283 GL_ColorMask(1,1,1,0);
1284 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1285 VectorScale(lightcolor, r_shadow_lightintensityscale.value, color2);
1286 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1288 color[0] = bound(0, color2[0], 1);
1289 color[1] = bound(0, color2[1], 1);
1290 color[2] = bound(0, color2[2], 1);
1291 GL_Color(color[0], color[1], color[2], 1);
1292 R_Mesh_Draw(numverts, numtriangles, elements);
1294 c_rt_lighttris += numtriangles;
1297 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap)
1299 // 2/2 3D combine path (original Radeon)
1300 memset(&m, 0, sizeof(m));
1301 m.pointer_vertex = vertex3f;
1302 m.tex[0] = R_GetTexture(bumptexture);
1303 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1304 m.texcombinergb[0] = GL_REPLACE;
1305 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1306 m.pointer_texcoord[0] = texcoord2f;
1307 m.pointer_texcoord[1] = varray_texcoord3f[1];
1309 GL_ColorMask(0,0,0,1);
1310 GL_BlendFunc(GL_ONE, GL_ZERO);
1311 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1312 R_Mesh_Draw(numverts, numtriangles, elements);
1314 c_rt_lighttris += numtriangles;
1316 memset(&m, 0, sizeof(m));
1317 m.pointer_vertex = vertex3f;
1318 m.tex[0] = R_GetTexture(basetexture);
1319 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1320 m.pointer_texcoord[0] = texcoord2f;
1321 m.pointer_texcoord[1] = varray_texcoord3f[1];
1323 GL_ColorMask(1,1,1,0);
1324 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1325 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1326 VectorScale(lightcolor, r_shadow_lightintensityscale.value, color2);
1327 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1329 color[0] = bound(0, color2[0], 1);
1330 color[1] = bound(0, color2[1], 1);
1331 color[2] = bound(0, color2[2], 1);
1332 GL_Color(color[0], color[1], color[2], 1);
1333 R_Mesh_Draw(numverts, numtriangles, elements);
1335 c_rt_lighttris += numtriangles;
1338 else if (r_textureunits.integer >= 4)
1340 // 4/2 2D combine path (Geforce3, Radeon 8500)
1341 memset(&m, 0, sizeof(m));
1342 m.pointer_vertex = vertex3f;
1343 m.tex[0] = R_GetTexture(bumptexture);
1344 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1345 m.texcombinergb[0] = GL_REPLACE;
1346 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1347 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
1348 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
1349 m.pointer_texcoord[0] = texcoord2f;
1350 m.pointer_texcoord[1] = varray_texcoord3f[1];
1351 m.pointer_texcoord[2] = varray_texcoord2f[2];
1352 m.pointer_texcoord[3] = varray_texcoord2f[3];
1354 GL_ColorMask(0,0,0,1);
1355 GL_BlendFunc(GL_ONE, GL_ZERO);
1356 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1357 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[2], numverts, vertex3f, matrix_modeltoattenuationxyz);
1358 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[3], numverts, vertex3f, matrix_modeltoattenuationz);
1359 R_Mesh_Draw(numverts, numtriangles, elements);
1361 c_rt_lighttris += numtriangles;
1363 memset(&m, 0, sizeof(m));
1364 m.pointer_vertex = vertex3f;
1365 m.tex[0] = R_GetTexture(basetexture);
1366 m.pointer_texcoord[0] = texcoord2f;
1369 m.texcubemap[1] = R_GetTexture(lightcubemap);
1370 m.pointer_texcoord[1] = varray_texcoord3f[1];
1371 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1374 GL_ColorMask(1,1,1,0);
1375 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1376 VectorScale(lightcolor, r_shadow_lightintensityscale.value, color2);
1377 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1379 color[0] = bound(0, color2[0], 1);
1380 color[1] = bound(0, color2[1], 1);
1381 color[2] = bound(0, color2[2], 1);
1382 GL_Color(color[0], color[1], color[2], 1);
1383 R_Mesh_Draw(numverts, numtriangles, elements);
1385 c_rt_lighttris += numtriangles;
1390 // 2/2/2 2D combine path (any dot3 card)
1391 memset(&m, 0, sizeof(m));
1392 m.pointer_vertex = vertex3f;
1393 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1394 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1395 m.pointer_texcoord[0] = varray_texcoord2f[0];
1396 m.pointer_texcoord[1] = varray_texcoord2f[1];
1398 GL_ColorMask(0,0,0,1);
1399 GL_BlendFunc(GL_ONE, GL_ZERO);
1400 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1401 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1402 R_Mesh_Draw(numverts, numtriangles, elements);
1404 c_rt_lighttris += numtriangles;
1406 memset(&m, 0, sizeof(m));
1407 m.pointer_vertex = vertex3f;
1408 m.tex[0] = R_GetTexture(bumptexture);
1409 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1410 m.texcombinergb[0] = GL_REPLACE;
1411 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1412 m.pointer_texcoord[0] = texcoord2f;
1413 m.pointer_texcoord[1] = varray_texcoord3f[1];
1415 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1416 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin);
1417 R_Mesh_Draw(numverts, numtriangles, elements);
1419 c_rt_lighttris += numtriangles;
1421 memset(&m, 0, sizeof(m));
1422 m.pointer_vertex = vertex3f;
1423 m.tex[0] = R_GetTexture(basetexture);
1424 m.pointer_texcoord[0] = texcoord2f;
1427 m.texcubemap[1] = R_GetTexture(lightcubemap);
1428 m.pointer_texcoord[1] = varray_texcoord3f[1];
1429 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1432 GL_ColorMask(1,1,1,0);
1433 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1434 VectorScale(lightcolor, r_shadow_lightintensityscale.value, color2);
1435 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1437 color[0] = bound(0, color2[0], 1);
1438 color[1] = bound(0, color2[1], 1);
1439 color[2] = bound(0, color2[2], 1);
1440 GL_Color(color[0], color[1], color[2], 1);
1441 R_Mesh_Draw(numverts, numtriangles, elements);
1443 c_rt_lighttris += numtriangles;
1449 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1450 GL_DepthMask(false);
1452 VectorScale(lightcolor, r_shadow_lightintensityscale.value, color2);
1453 memset(&m, 0, sizeof(m));
1454 m.pointer_vertex = vertex3f;
1455 m.pointer_color = varray_color4f;
1456 m.tex[0] = R_GetTexture(basetexture);
1457 m.pointer_texcoord[0] = texcoord2f;
1458 if (r_textureunits.integer >= 2)
1461 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1462 m.pointer_texcoord[1] = varray_texcoord2f[1];
1463 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1466 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1468 color[0] = bound(0, color2[0], 1);
1469 color[1] = bound(0, color2[1], 1);
1470 color[2] = bound(0, color2[2], 1);
1471 if (r_textureunits.integer >= 2)
1472 R_Shadow_VertexLightingWithXYAttenuationTexture(numverts, vertex3f, normal3f, color, matrix_modeltolight);
1474 R_Shadow_VertexLighting(numverts, vertex3f, normal3f, color, matrix_modeltolight);
1475 R_Mesh_Draw(numverts, numtriangles, elements);
1477 c_rt_lighttris += numtriangles;
1482 void R_Shadow_SpecularLighting(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 *glosstexture, rtexture_t *bumptexture, rtexture_t *lightcubemap)
1485 float color[3], color2[3], colorscale;
1487 if (!gl_dot3arb || !gl_texturecubemap || !gl_combine.integer || !gl_stencil)
1490 glosstexture = r_shadow_blankglosstexture;
1491 if (r_shadow_gloss.integer >= 2 || (r_shadow_gloss.integer >= 1 && glosstexture != r_shadow_blankglosstexture))
1493 colorscale = r_shadow_glossintensity.value;
1495 bumptexture = r_shadow_blankbumptexture;
1496 if (glosstexture == r_shadow_blankglosstexture)
1497 colorscale *= r_shadow_gloss2intensity.value;
1499 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1501 // 2/0/0/1/2 3D combine blendsquare path
1502 memset(&m, 0, sizeof(m));
1503 m.pointer_vertex = vertex3f;
1504 m.tex[0] = R_GetTexture(bumptexture);
1505 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1506 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1507 m.pointer_texcoord[0] = texcoord2f;
1508 m.pointer_texcoord[1] = varray_texcoord3f[1];
1510 GL_ColorMask(0,0,0,1);
1511 // this squares the result
1512 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1513 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1514 R_Mesh_Draw(numverts, numtriangles, elements);
1516 c_rt_lighttris += numtriangles;
1518 memset(&m, 0, sizeof(m));
1519 m.pointer_vertex = vertex3f;
1521 // square alpha in framebuffer a few times to make it shiny
1522 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1523 // these comments are a test run through this math for intensity 0.5
1524 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1525 // 0.25 * 0.25 = 0.0625 (this is another pass)
1526 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1527 R_Mesh_Draw(numverts, numtriangles, elements);
1529 c_rt_lighttris += numtriangles;
1530 R_Mesh_Draw(numverts, numtriangles, elements);
1532 c_rt_lighttris += numtriangles;
1534 memset(&m, 0, sizeof(m));
1535 m.pointer_vertex = vertex3f;
1536 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
1537 m.pointer_texcoord[0] = varray_texcoord3f[0];
1539 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1540 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1541 R_Mesh_Draw(numverts, numtriangles, elements);
1543 c_rt_lighttris += numtriangles;
1545 memset(&m, 0, sizeof(m));
1546 m.pointer_vertex = vertex3f;
1547 m.tex[0] = R_GetTexture(glosstexture);
1550 m.texcubemap[1] = R_GetTexture(lightcubemap);
1551 m.pointer_texcoord[1] = varray_texcoord3f[1];
1552 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1554 m.pointer_texcoord[0] = texcoord2f;
1556 GL_ColorMask(1,1,1,0);
1557 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1558 VectorScale(lightcolor, colorscale, color2);
1559 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1561 color[0] = bound(0, color2[0], 1);
1562 color[1] = bound(0, color2[1], 1);
1563 color[2] = bound(0, color2[2], 1);
1564 GL_Color(color[0], color[1], color[2], 1);
1565 R_Mesh_Draw(numverts, numtriangles, elements);
1567 c_rt_lighttris += numtriangles;
1570 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && !lightcubemap /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1572 // 2/0/0/2 3D combine blendsquare path
1573 memset(&m, 0, sizeof(m));
1574 m.pointer_vertex = vertex3f;
1575 m.tex[0] = R_GetTexture(bumptexture);
1576 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1577 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1578 m.pointer_texcoord[0] = texcoord2f;
1579 m.pointer_texcoord[1] = varray_texcoord3f[1];
1581 GL_ColorMask(0,0,0,1);
1582 // this squares the result
1583 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1584 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1585 R_Mesh_Draw(numverts, numtriangles, elements);
1587 c_rt_lighttris += numtriangles;
1589 memset(&m, 0, sizeof(m));
1590 m.pointer_vertex = vertex3f;
1592 // square alpha in framebuffer a few times to make it shiny
1593 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1594 // these comments are a test run through this math for intensity 0.5
1595 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1596 // 0.25 * 0.25 = 0.0625 (this is another pass)
1597 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1598 R_Mesh_Draw(numverts, numtriangles, elements);
1600 c_rt_lighttris += numtriangles;
1601 R_Mesh_Draw(numverts, numtriangles, elements);
1603 c_rt_lighttris += numtriangles;
1605 memset(&m, 0, sizeof(m));
1606 m.pointer_vertex = vertex3f;
1607 m.tex[0] = R_GetTexture(glosstexture);
1608 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
1609 m.pointer_texcoord[0] = texcoord2f;
1610 m.pointer_texcoord[1] = varray_texcoord3f[1];
1612 GL_ColorMask(1,1,1,0);
1613 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1614 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltoattenuationxyz);
1615 VectorScale(lightcolor, colorscale, color2);
1616 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1618 color[0] = bound(0, color2[0], 1);
1619 color[1] = bound(0, color2[1], 1);
1620 color[2] = bound(0, color2[2], 1);
1621 GL_Color(color[0], color[1], color[2], 1);
1622 R_Mesh_Draw(numverts, numtriangles, elements);
1624 c_rt_lighttris += numtriangles;
1627 else if (r_textureunits.integer >= 2 /*&& gl_support_blendsquare*/) // FIXME: detect blendsquare!
1629 // 2/0/0/2/2 2D combine blendsquare path
1630 memset(&m, 0, sizeof(m));
1631 m.pointer_vertex = vertex3f;
1632 m.tex[0] = R_GetTexture(bumptexture);
1633 m.texcubemap[1] = R_GetTexture(r_shadow_normalcubetexture);
1634 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
1635 m.pointer_texcoord[0] = texcoord2f;
1636 m.pointer_texcoord[1] = varray_texcoord3f[1];
1638 GL_ColorMask(0,0,0,1);
1639 // this squares the result
1640 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
1641 R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord3f[1], numverts, vertex3f, svector3f, tvector3f, normal3f, relativelightorigin, relativeeyeorigin);
1642 R_Mesh_Draw(numverts, numtriangles, elements);
1644 c_rt_lighttris += numtriangles;
1646 memset(&m, 0, sizeof(m));
1647 m.pointer_vertex = vertex3f;
1649 // square alpha in framebuffer a few times to make it shiny
1650 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
1651 // these comments are a test run through this math for intensity 0.5
1652 // 0.5 * 0.5 = 0.25 (done by the BlendFunc earlier)
1653 // 0.25 * 0.25 = 0.0625 (this is another pass)
1654 // 0.0625 * 0.0625 = 0.00390625 (this is another pass)
1655 R_Mesh_Draw(numverts, numtriangles, elements);
1657 c_rt_lighttris += numtriangles;
1658 R_Mesh_Draw(numverts, numtriangles, elements);
1660 c_rt_lighttris += numtriangles;
1662 memset(&m, 0, sizeof(m));
1663 m.pointer_vertex = vertex3f;
1664 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
1665 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
1666 m.pointer_texcoord[0] = varray_texcoord2f[0];
1667 m.pointer_texcoord[1] = varray_texcoord2f[1];
1669 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
1670 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0], numverts, vertex3f, matrix_modeltoattenuationxyz);
1671 R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1], numverts, vertex3f, matrix_modeltoattenuationz);
1672 R_Mesh_Draw(numverts, numtriangles, elements);
1674 c_rt_lighttris += numtriangles;
1676 memset(&m, 0, sizeof(m));
1677 m.pointer_vertex = vertex3f;
1678 m.tex[0] = R_GetTexture(glosstexture);
1681 m.texcubemap[1] = R_GetTexture(lightcubemap);
1682 m.pointer_texcoord[1] = varray_texcoord3f[1];
1683 R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1], numverts, vertex3f, matrix_modeltolight);
1685 m.pointer_texcoord[0] = texcoord2f;
1687 GL_ColorMask(1,1,1,0);
1688 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
1689 VectorScale(lightcolor, colorscale, color2);
1690 for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
1692 color[0] = bound(0, color2[0], 1);
1693 color[1] = bound(0, color2[1], 1);
1694 color[2] = bound(0, color2[2], 1);
1695 GL_Color(color[0], color[1], color[2], 1);
1696 R_Mesh_Draw(numverts, numtriangles, elements);
1698 c_rt_lighttris += numtriangles;
1704 void R_RTLight_UpdateFromDLight(rtlight_t *rtlight, const dlight_t *light, int isstatic)
1708 R_RTLight_Uncompile(rtlight);
1709 memset(rtlight, 0, sizeof(*rtlight));
1711 VectorCopy(light->origin, rtlight->shadoworigin);
1712 VectorCopy(light->color, rtlight->color);
1713 rtlight->radius = light->radius;
1714 rtlight->cullradius = rtlight->radius;
1715 rtlight->cullradius2 = rtlight->cullradius * rtlight->cullradius;
1716 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->cullradius;
1717 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->cullradius;
1718 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->cullradius;
1719 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->cullradius;
1720 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->cullradius;
1721 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->cullradius;
1722 rtlight->cubemapname[0] = 0;
1723 if (light->cubemapname[0])
1724 strcpy(rtlight->cubemapname, light->cubemapname);
1725 else if (light->cubemapnum > 0)
1726 sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
1727 rtlight->shadow = light->shadow;
1728 rtlight->corona = light->corona;
1729 rtlight->style = light->style;
1730 rtlight->isstatic = isstatic;
1731 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
1732 // ConcatScale won't work here because this needs to scale rotate and
1733 // translate, not just rotate
1734 scale = 1.0f / rtlight->radius;
1735 for (k = 0;k < 3;k++)
1736 for (j = 0;j < 4;j++)
1737 rtlight->matrix_worldtolight.m[k][j] *= scale;
1738 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationxyz, &matrix_attenuationxyz, &rtlight->matrix_worldtolight);
1739 Matrix4x4_Concat(&rtlight->matrix_worldtoattenuationz, &matrix_attenuationz, &rtlight->matrix_worldtolight);
1741 rtlight->lightmap_cullradius = bound(0, rtlight->radius, 2048.0f);
1742 rtlight->lightmap_cullradius2 = rtlight->lightmap_cullradius * rtlight->lightmap_cullradius;
1743 VectorScale(rtlight->color, rtlight->radius * d_lightstylevalue[rtlight->style] * 0.25f, rtlight->lightmap_light);
1744 rtlight->lightmap_subtract = 1.0f / rtlight->lightmap_cullradius2;
1747 // compiles rtlight geometry
1748 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
1749 void R_RTLight_Compile(rtlight_t *rtlight)
1751 int i, j, k, l, maxverts = 256, tris;
1752 float *vertex3f = NULL, mins[3], maxs[3];
1753 shadowmesh_t *mesh, *castmesh = NULL;
1755 qbyte lightpvs[(MAX_MAP_LEAFS + 7)/ 8];
1756 qbyte lightfullpvs[(MAX_MAP_LEAFS + 7)/ 8];
1758 // compile the light
1759 rtlight->compiled = true;
1760 VectorCopy(rtlight->cullmins, mins);
1761 VectorCopy(rtlight->cullmaxs, maxs);
1762 if (rtlight->shadow)
1763 castmesh = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
1764 rtlight->static_meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true);
1767 lightpvsbytes = cl.worldmodel->brush.FatPVS(cl.worldmodel, rtlight->shadoworigin, 0, lightfullpvs, sizeof(lightfullpvs));
1768 memset(lightpvs, 0, lightpvsbytes);
1769 if (cl.worldmodel->brushq3.num_leafs)
1774 // make a pvs that only includes things within the box
1775 for (i = 0, leaf = cl.worldmodel->brushq3.data_leafs;i < cl.worldmodel->brushq3.num_leafs;i++, leaf++)
1776 if (CHECKPVSBIT(lightfullpvs, leaf->clusterindex) && BoxesOverlap(leaf->mins, leaf->maxs, mins, maxs))
1777 SETPVSBIT(lightpvs, leaf->clusterindex);
1779 // make a cluster list for fast visibility checking during rendering
1780 for (i = 0, rtlight->static_numclusters = 0;i < cl.worldmodel->brush.num_pvsclusters;i++)
1781 if (CHECKPVSBIT(lightpvs, i))
1782 rtlight->static_numclusters++;
1783 rtlight->static_clusterindices = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusters * sizeof(int));
1784 for (i = 0, rtlight->static_numclusters = 0;i < cl.worldmodel->brush.num_pvsclusters;i++)
1785 if (CHECKPVSBIT(lightpvs, i))
1786 rtlight->static_clusterindices[rtlight->static_numclusters++] = i;
1788 VectorCopy(rtlight->shadoworigin, rtlight->cullmins);
1789 VectorCopy(rtlight->shadoworigin, rtlight->cullmaxs);
1790 for (i = 0, face = cl.worldmodel->brushq3.data_thismodel->firstface;i < cl.worldmodel->brushq3.data_thismodel->numfaces;i++, face++)
1791 face->lighttemp_castshadow = false;
1792 for (i = 0, leaf = cl.worldmodel->brushq3.data_leafs;i < cl.worldmodel->brushq3.num_leafs;i++, leaf++)
1794 if (CHECKPVSBIT(lightpvs, leaf->clusterindex) && BoxesOverlap(leaf->mins, leaf->maxs, mins, maxs))
1796 for (k = 0;k < 3;k++)
1798 if (rtlight->cullmins[k] > leaf->mins[k]) rtlight->cullmins[k] = leaf->mins[k];
1799 if (rtlight->cullmaxs[k] < leaf->maxs[k]) rtlight->cullmaxs[k] = leaf->maxs[k];
1801 for (j = 0;j < leaf->numleaffaces;j++)
1803 face = leaf->firstleafface[j];
1804 if (BoxesOverlap(face->mins, face->maxs, mins, maxs))
1805 face->lighttemp_castshadow = true;
1810 // add surfaces to shadow casting mesh and light mesh
1811 for (i = 0, face = cl.worldmodel->brushq3.data_thismodel->firstface;i < cl.worldmodel->brushq3.data_thismodel->numfaces;i++, face++)
1813 if (face->lighttemp_castshadow)
1815 face->lighttemp_castshadow = false;
1816 if (!(face->texture->surfaceflags & (Q3SURFACEFLAG_NODRAW | Q3SURFACEFLAG_SKY)))
1818 if (rtlight->shadow)
1819 if (!(face->texture->nativecontents & CONTENTSQ3_TRANSLUCENT))
1820 Mod_ShadowMesh_AddMesh(r_shadow_mempool, castmesh, NULL, NULL, NULL, face->data_vertex3f, NULL, NULL, NULL, NULL, face->num_triangles, face->data_element3i);
1821 if (!(face->texture->surfaceflags & Q3SURFACEFLAG_SKY))
1822 Mod_ShadowMesh_AddMesh(r_shadow_mempool, rtlight->static_meshchain_light, face->texture->skin.base, face->texture->skin.gloss, face->texture->skin.nmap, face->data_vertex3f, face->data_svector3f, face->data_tvector3f, face->data_normal3f, face->data_texcoordtexture2f, face->num_triangles, face->data_element3i);
1827 else if (cl.worldmodel->brushq1.num_leafs)
1831 VectorCopy(rtlight->shadoworigin, rtlight->cullmins);
1832 VectorCopy(rtlight->shadoworigin, rtlight->cullmaxs);
1833 i = CL_PointQ1Contents(rtlight->shadoworigin);
1835 for (i = 0, surf = cl.worldmodel->brushq1.surfaces + cl.worldmodel->brushq1.firstmodelsurface;i < cl.worldmodel->brushq1.nummodelsurfaces;i++, surf++)
1836 surf->lighttemp_castshadow = false;
1838 if (r_shadow_portallight.integer && i != CONTENTS_SOLID && i != CONTENTS_SKY)
1841 qbyte *bytesurfacepvs;
1843 byteleafpvs = Mem_Alloc(tempmempool, cl.worldmodel->brushq1.num_leafs);
1844 bytesurfacepvs = Mem_Alloc(tempmempool, cl.worldmodel->brushq1.numsurfaces);
1846 Portal_Visibility(cl.worldmodel, rtlight->shadoworigin, byteleafpvs, bytesurfacepvs, NULL, 0, true, mins, maxs, rtlight->cullmins, rtlight->cullmaxs);
1848 // make a pvs that only includes things within the box
1849 for (i = 0, leaf = cl.worldmodel->brushq1.data_leafs;i < cl.worldmodel->brushq1.num_leafs;i++, leaf++)
1851 if (byteleafpvs[i] && BoxesOverlap(leaf->mins, leaf->maxs, mins, maxs))
1853 SETPVSBIT(lightpvs, leaf->clusterindex);
1854 for (k = 0;k < 3;k++)
1856 if (rtlight->cullmins[k] > leaf->mins[k]) rtlight->cullmins[k] = leaf->mins[k];
1857 if (rtlight->cullmaxs[k] < leaf->maxs[k]) rtlight->cullmaxs[k] = leaf->maxs[k];
1862 for (i = 0, surf = cl.worldmodel->brushq1.surfaces;i < cl.worldmodel->brushq1.numsurfaces;i++, surf++)
1863 if (bytesurfacepvs[i] && BoxesOverlap(surf->poly_mins, surf->poly_maxs, mins, maxs))
1864 surf->lighttemp_castshadow = true;
1866 Mem_Free(byteleafpvs);
1867 Mem_Free(bytesurfacepvs);
1869 // make a cluster list for fast visibility checking during rendering
1870 for (i = 0, rtlight->static_numclusters = 0;i < cl.worldmodel->brush.num_pvsclusters;i++)
1871 if (CHECKPVSBIT(lightpvs, i))
1872 rtlight->static_numclusters++;
1873 rtlight->static_clusterindices = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusters * sizeof(int));
1874 for (i = 0, rtlight->static_numclusters = 0;i < cl.worldmodel->brush.num_pvsclusters;i++)
1875 if (CHECKPVSBIT(lightpvs, i))
1876 rtlight->static_clusterindices[rtlight->static_numclusters++] = i;
1880 for (i = 0, leaf = cl.worldmodel->brushq1.data_leafs;i < cl.worldmodel->brushq1.num_leafs;i++, leaf++)
1882 if (CHECKPVSBIT(lightfullpvs, leaf->clusterindex) && BoxesOverlap(leaf->mins, leaf->maxs, mins, maxs))
1884 // make a pvs that only includes things within the box
1885 SETPVSBIT(lightpvs, leaf->clusterindex);
1886 for (k = 0;k < 3;k++)
1888 if (rtlight->cullmins[k] > leaf->mins[k]) rtlight->cullmins[k] = leaf->mins[k];
1889 if (rtlight->cullmaxs[k] < leaf->maxs[k]) rtlight->cullmaxs[k] = leaf->maxs[k];
1891 for (j = 0;j < leaf->nummarksurfaces;j++)
1893 surf = cl.worldmodel->brushq1.surfaces + leaf->firstmarksurface[j];
1894 if (!surf->lighttemp_castshadow && BoxesOverlap(surf->poly_mins, surf->poly_maxs, mins, maxs))
1895 surf->lighttemp_castshadow = true;
1900 // make a pvs that only includes things within the box
1901 for (i = 0, leaf = cl.worldmodel->brushq1.data_leafs;i < cl.worldmodel->brushq1.num_leafs;i++, leaf++)
1902 if (CHECKPVSBIT(lightfullpvs, leaf->clusterindex) && BoxesOverlap(leaf->mins, leaf->maxs, mins, maxs))
1903 SETPVSBIT(lightpvs, leaf->clusterindex);
1905 // make a cluster list for fast visibility checking during rendering
1906 for (i = 0, rtlight->static_numclusters = 0;i < cl.worldmodel->brush.num_pvsclusters;i++)
1907 if (CHECKPVSBIT(lightpvs, i))
1908 rtlight->static_numclusters++;
1909 rtlight->static_clusterindices = Mem_Alloc(r_shadow_mempool, rtlight->static_numclusters * sizeof(int));
1910 for (i = 0, rtlight->static_numclusters = 0;i < cl.worldmodel->brush.num_pvsclusters;i++)
1911 if (CHECKPVSBIT(lightpvs, i))
1912 rtlight->static_clusterindices[rtlight->static_numclusters++] = i;
1915 // add surfaces to shadow casting mesh and light mesh
1916 for (i = 0, surf = cl.worldmodel->brushq1.surfaces + cl.worldmodel->brushq1.firstmodelsurface;i < cl.worldmodel->brushq1.nummodelsurfaces;i++, surf++)
1918 if (surf->lighttemp_castshadow)
1920 surf->lighttemp_castshadow = false;
1921 if (rtlight->shadow && (surf->flags & SURF_SHADOWCAST))
1922 Mod_ShadowMesh_AddMesh(r_shadow_mempool, castmesh, NULL, NULL, NULL, surf->mesh.data_vertex3f, NULL, NULL, NULL, NULL, surf->mesh.num_triangles, surf->mesh.data_element3i);
1923 if (!(surf->flags & SURF_DRAWSKY))
1924 Mod_ShadowMesh_AddMesh(r_shadow_mempool, rtlight->static_meshchain_light, surf->texinfo->texture->skin.base, surf->texinfo->texture->skin.gloss, surf->texinfo->texture->skin.nmap, surf->mesh.data_vertex3f, surf->mesh.data_svector3f, surf->mesh.data_tvector3f, surf->mesh.data_normal3f, surf->mesh.data_texcoordtexture2f, surf->mesh.num_triangles, surf->mesh.data_element3i);
1930 // limit box to light bounds (in case it grew larger)
1931 for (k = 0;k < 3;k++)
1933 if (rtlight->cullmins[k] < rtlight->shadoworigin[k] - rtlight->radius) rtlight->cullmins[k] = rtlight->shadoworigin[k] - rtlight->radius;
1934 if (rtlight->cullmaxs[k] > rtlight->shadoworigin[k] + rtlight->radius) rtlight->cullmaxs[k] = rtlight->shadoworigin[k] + rtlight->radius;
1936 rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
1937 rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
1939 // cast shadow volume from castmesh
1940 castmesh = Mod_ShadowMesh_Finish(r_shadow_mempool, castmesh, false, true);
1944 for (mesh = castmesh;mesh;mesh = mesh->next)
1946 R_Shadow_ResizeShadowElements(mesh->numtriangles);
1947 maxverts = max(maxverts, mesh->numverts * 2);
1952 vertex3f = Mem_Alloc(r_shadow_mempool, maxverts * sizeof(float[3]));
1953 // now that we have the buffers big enough, construct and add
1954 // the shadow volume mesh
1955 if (rtlight->shadow)
1956 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
1957 for (mesh = castmesh;mesh;mesh = mesh->next)
1959 Mod_BuildTriangleNeighbors(mesh->neighbor3i, mesh->element3i, mesh->numtriangles);
1960 R_Shadow_PrepareShadowMark(mesh->numtriangles);
1961 for (i = 0;i < mesh->numtriangles;i++)
1964 v[0] = mesh->vertex3f + mesh->element3i[i*3+0] * 3;
1965 v[1] = mesh->vertex3f + mesh->element3i[i*3+1] * 3;
1966 v[2] = mesh->vertex3f + mesh->element3i[i*3+2] * 3;
1967 if (PointInfrontOfTriangle(rtlight->shadoworigin, v[0], v[1], v[2]) && rtlight->cullmaxs[0] > min(v[0][0], min(v[1][0], v[2][0])) && rtlight->cullmins[0] < max(v[0][0], max(v[1][0], v[2][0])) && rtlight->cullmaxs[1] > min(v[0][1], min(v[1][1], v[2][1])) && rtlight->cullmins[1] < max(v[0][1], max(v[1][1], v[2][1])) && rtlight->cullmaxs[2] > min(v[0][2], min(v[1][2], v[2][2])) && rtlight->cullmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
1968 shadowmarklist[numshadowmark++] = i;
1970 if (maxshadowelements < numshadowmark * 24)
1971 R_Shadow_ResizeShadowElements((numshadowmark + 256) * 24);
1972 if ((tris = R_Shadow_ConstructShadowVolume(mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->neighbor3i, mesh->vertex3f, NULL, shadowelements, vertex3f, rtlight->shadoworigin, r_shadow_projectdistance.value, numshadowmark, shadowmarklist)))
1973 Mod_ShadowMesh_AddMesh(r_shadow_mempool, rtlight->static_meshchain_shadow, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1978 // we're done with castmesh now
1979 Mod_ShadowMesh_Free(castmesh);
1982 rtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_shadow, false, false);
1983 rtlight->static_meshchain_light = Mod_ShadowMesh_Finish(r_shadow_mempool, rtlight->static_meshchain_light, true, false);
1986 if (rtlight->static_meshchain_shadow)
1987 for (mesh = rtlight->static_meshchain_shadow;mesh;mesh = mesh->next)
1988 k += mesh->numtriangles;
1990 if (rtlight->static_meshchain_light)
1991 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
1992 l += mesh->numtriangles;
1993 Con_DPrintf("static light built: %f %f %f : %f %f %f box, %i shadow volume triangles, %i light triangles\n", rtlight->cullmins[0], rtlight->cullmins[1], rtlight->cullmins[2], rtlight->cullmaxs[0], rtlight->cullmaxs[1], rtlight->cullmaxs[2], k, l);
1996 void R_RTLight_Uncompile(rtlight_t *rtlight)
1998 if (rtlight->compiled)
2000 if (rtlight->static_meshchain_shadow)
2001 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow);
2002 rtlight->static_meshchain_shadow = NULL;
2003 if (rtlight->static_meshchain_light)
2004 Mod_ShadowMesh_Free(rtlight->static_meshchain_light);
2005 rtlight->static_meshchain_light = NULL;
2006 if (rtlight->static_clusterindices)
2007 Mem_Free(rtlight->static_clusterindices);
2008 rtlight->static_clusterindices = NULL;
2009 rtlight->static_numclusters = 0;
2010 rtlight->compiled = false;
2014 int shadowframecount = 0;
2016 void R_TestAndDrawShadowVolume(entity_render_t *ent, vec3_t shadoworigin, vec_t shadowradius, vec3_t cullmins, vec3_t cullmaxs)
2019 if ((BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs) || !r_shadow_cull.integer) && (ent->flags & RENDER_SHADOW) && ent->model && ent->model->DrawShadowVolume)
2021 vec3_t relativeshadoworigin;
2022 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativeshadoworigin);
2023 ent->model->DrawShadowVolume (ent, relativeshadoworigin, shadowradius);
2027 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, dlight_t *light);
2029 void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes)
2032 entity_render_t *ent;
2034 vec3_t relativelightorigin, relativeeyeorigin, lightcolor;
2035 rtexture_t *cubemaptexture;
2036 matrix4x4_t matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz;
2038 if (d_lightstylevalue[rtlight->style] <= 0)
2040 if (rtlight->compiled)
2042 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2044 for (i = 0;i < rtlight->static_numclusters;i++)
2045 if (CHECKPVSBIT(r_pvsbits, rtlight->static_clusterindices[i]))
2047 if (i == rtlight->static_numclusters)
2050 else if (VIS_CullBox(rtlight->cullmins, rtlight->cullmaxs))
2052 if (R_Shadow_ScissorForBBox(rtlight->cullmins, rtlight->cullmaxs))
2055 if (rtlight->isstatic && !rtlight->compiled && r_shadow_staticworldlights.integer)
2056 R_RTLight_Compile(rtlight);
2058 f = d_lightstylevalue[rtlight->style] * (1.0f / 256.0f);
2059 VectorScale(rtlight->color, f, lightcolor);
2061 if (rtlight->selected)
2063 f = 2 + sin(realtime * M_PI * 4.0);
2064 VectorScale(lightcolor, f, lightcolor);
2068 if (rtlight->cubemapname[0])
2069 cubemaptexture = R_Shadow_Cubemap(rtlight->cubemapname);
2071 cubemaptexture = NULL;
2073 shadow = rtlight->shadow && (rtlight->isstatic ? r_shadow_worldshadows.integer : r_shadow_dlightshadows.integer);
2074 if (shadow && (gl_stencil || visiblevolumes))
2076 if (!visiblevolumes)
2077 R_Shadow_Stage_ShadowVolumes();
2078 ent = &cl_entities[0].render;
2079 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2081 R_Mesh_Matrix(&ent->matrix);
2082 R_Shadow_RenderShadowMeshVolume(rtlight->static_meshchain_shadow);
2085 R_TestAndDrawShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, rtlight->cullmins, rtlight->cullmaxs);
2086 if (r_drawentities.integer)
2087 for (i = 0;i < r_refdef.numentities;i++)
2088 if (r_refdef.entities[i]->flags & RENDER_SHADOW)
2089 R_TestAndDrawShadowVolume(r_refdef.entities[i], rtlight->shadoworigin, rtlight->radius, rtlight->cullmins, rtlight->cullmaxs);
2092 if (!visiblevolumes)
2094 if (shadow && gl_stencil)
2095 R_Shadow_Stage_LightWithShadows();
2097 R_Shadow_Stage_LightWithoutShadows();
2099 ent = &cl_entities[0].render;
2100 if (ent->model && ent->model->DrawLight)
2102 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2103 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2104 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2105 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2106 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2107 if (r_shadow_staticworldlights.integer && rtlight->compiled)
2109 //R_Shadow_DrawStaticWorldLight_Light(rtlight, &ent->matrix, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture);
2111 R_Mesh_Matrix(&ent->matrix);
2112 for (mesh = rtlight->static_meshchain_light;mesh;mesh = mesh->next)
2114 R_Shadow_DiffuseLighting(mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->vertex3f, mesh->svector3f, mesh->tvector3f, mesh->normal3f, mesh->texcoord2f, relativelightorigin, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, mesh->map_diffuse, mesh->map_normal, cubemaptexture);
2115 R_Shadow_SpecularLighting(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_specular, mesh->map_normal, cubemaptexture);
2119 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture);
2121 if (r_drawentities.integer)
2123 for (i = 0;i < r_refdef.numentities;i++)
2125 ent = r_refdef.entities[i];
2126 if (ent->visframe == r_framecount && ent->model && ent->model->DrawLight
2127 && BoxesOverlap(ent->mins, ent->maxs, rtlight->cullmins, rtlight->cullmaxs)
2128 && (ent->flags & RENDER_LIGHT))
2130 Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
2131 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
2132 Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
2133 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
2134 Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
2135 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture);
2142 void R_ShadowVolumeLighting(int visiblevolumes)
2150 memset(&m, 0, sizeof(m));
2153 GL_BlendFunc(GL_ONE, GL_ONE);
2154 GL_DepthMask(false);
2155 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
2156 qglDisable(GL_CULL_FACE);
2157 GL_Color(0.0, 0.0125, 0.1, 1);
2160 R_Shadow_Stage_Begin();
2162 if (r_shadow_realtime_world.integer)
2164 R_Shadow_LoadWorldLightsIfNeeded();
2165 if (r_shadow_debuglight.integer >= 0)
2167 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2168 if (lnum == r_shadow_debuglight.integer)
2169 R_DrawRTLight(&light->rtlight, visiblevolumes);
2172 for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
2173 R_DrawRTLight(&light->rtlight, visiblevolumes);
2175 if (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer)
2176 for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
2177 R_DrawRTLight(&light->rtlight, visiblevolumes);
2181 qglEnable(GL_CULL_FACE);
2182 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
2185 R_Shadow_Stage_End();
2188 cvar_t r_editlights = {0, "r_editlights", "0"};
2189 cvar_t r_editlights_cursordistance = {0, "r_editlights_distance", "1024"};
2190 cvar_t r_editlights_cursorpushback = {0, "r_editlights_pushback", "0"};
2191 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_pushoff", "4"};
2192 cvar_t r_editlights_cursorgrid = {0, "r_editlights_grid", "4"};
2193 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "0.8"};
2194 cvar_t r_editlights_rtlightssizescale = {CVAR_SAVE, "r_editlights_rtlightssizescale", "0.7"};
2195 cvar_t r_editlights_rtlightscolorscale = {CVAR_SAVE, "r_editlights_rtlightscolorscale", "2"};
2196 dlight_t *r_shadow_worldlightchain;
2197 dlight_t *r_shadow_selectedlight;
2198 vec3_t r_editlights_cursorlocation;
2200 typedef struct cubemapinfo_s
2203 rtexture_t *texture;
2207 #define MAX_CUBEMAPS 128
2208 static int numcubemaps;
2209 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
2211 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2212 typedef struct suffixinfo_s
2215 int flipx, flipy, flipdiagonal;
2218 static suffixinfo_t suffix[3][6] =
2221 {"posx", false, false, false},
2222 {"negx", false, false, false},
2223 {"posy", false, false, false},
2224 {"negy", false, false, false},
2225 {"posz", false, false, false},
2226 {"negz", false, false, false}
2229 {"px", false, false, false},
2230 {"nx", false, false, false},
2231 {"py", false, false, false},
2232 {"ny", false, false, false},
2233 {"pz", false, false, false},
2234 {"nz", false, false, false}
2237 {"ft", true, false, true},
2238 {"bk", false, true, true},
2239 {"lf", true, true, false},
2240 {"rt", false, false, false},
2241 {"up", false, false, false},
2242 {"dn", false, false, false}
2246 static int componentorder[4] = {0, 1, 2, 3};
2248 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
2250 int i, j, cubemapsize;
2251 qbyte *cubemappixels, *image_rgba;
2252 rtexture_t *cubemaptexture;
2254 // must start 0 so the first loadimagepixels has no requested width/height
2256 cubemappixels = NULL;
2257 cubemaptexture = NULL;
2258 for (j = 0;j < 3 && !cubemappixels;j++)
2260 for (i = 0;i < 6;i++)
2262 snprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2263 if ((image_rgba = loadimagepixels(name, false, cubemapsize, cubemapsize)))
2265 if (image_width == image_height)
2267 if (!cubemappixels && image_width >= 1)
2269 cubemapsize = image_width;
2270 // note this clears to black, so unavailable sizes are black
2271 cubemappixels = Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2274 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);
2277 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2278 Mem_Free(image_rgba);
2284 if (!r_shadow_filters_texturepool)
2285 r_shadow_filters_texturepool = R_AllocTexturePool();
2286 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
2287 Mem_Free(cubemappixels);
2291 Con_Printf("Failed to load Cubemap \"%s\", tried ", basename);
2292 for (j = 0;j < 3;j++)
2293 for (i = 0;i < 6;i++)
2294 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2295 Con_Print(" and was unable to find any of them.\n");
2297 return cubemaptexture;
2300 rtexture_t *R_Shadow_Cubemap(const char *basename)
2303 for (i = 0;i < numcubemaps;i++)
2304 if (!strcasecmp(cubemaps[i].basename, basename))
2305 return cubemaps[i].texture;
2306 if (i >= MAX_CUBEMAPS)
2309 strcpy(cubemaps[i].basename, basename);
2310 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
2311 return cubemaps[i].texture;
2314 void R_Shadow_FreeCubemaps(void)
2317 R_FreeTexturePool(&r_shadow_filters_texturepool);
2320 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)
2324 if (radius < 15 || DotProduct(color, color) < 0.03)
2326 Con_Print("R_Shadow_NewWorldLight: refusing to create a light too small/dim\n");
2330 light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
2331 VectorCopy(origin, light->origin);
2332 VectorCopy(angles, light->angles);
2333 VectorCopy(color, light->color);
2334 light->radius = radius;
2335 light->style = style;
2336 if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
2338 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
2341 light->shadow = shadowenable;
2342 light->corona = corona;
2343 if (cubemapname && cubemapname[0] && strlen(cubemapname) < sizeof(light->cubemapname))
2344 strcpy(light->cubemapname, cubemapname);
2345 Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
2346 light->next = r_shadow_worldlightchain;
2347 r_shadow_worldlightchain = light;
2349 R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
2350 if (r_shadow_staticworldlights.integer)
2351 R_RTLight_Compile(&light->rtlight);
2354 void R_Shadow_FreeWorldLight(dlight_t *light)
2356 dlight_t **lightpointer;
2357 for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
2358 if (*lightpointer != light)
2359 Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
2360 *lightpointer = light->next;
2361 R_RTLight_Uncompile(&light->rtlight);
2365 void R_Shadow_ClearWorldLights(void)
2367 while (r_shadow_worldlightchain)
2368 R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
2369 r_shadow_selectedlight = NULL;
2370 R_Shadow_FreeCubemaps();
2373 void R_Shadow_SelectLight(dlight_t *light)
2375 if (r_shadow_selectedlight)
2376 r_shadow_selectedlight->selected = false;
2377 r_shadow_selectedlight = light;
2378 if (r_shadow_selectedlight)
2379 r_shadow_selectedlight->selected = true;
2382 rtexture_t *lighttextures[5];
2384 void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
2386 float scale = r_editlights_cursorgrid.value * 0.5f;
2387 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);
2390 void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
2393 const dlight_t *light;
2396 if (light->selected)
2397 intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
2400 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);
2403 void R_Shadow_DrawLightSprites(void)
2409 for (i = 0;i < 5;i++)
2411 lighttextures[i] = NULL;
2412 if ((pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1))))
2413 lighttextures[i] = pic->tex;
2416 for (light = r_shadow_worldlightchain;light;light = light->next)
2417 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, ((int) light) % 5);
2418 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
2421 void R_Shadow_SelectLightInView(void)
2423 float bestrating, rating, temp[3];
2424 dlight_t *best, *light;
2427 for (light = r_shadow_worldlightchain;light;light = light->next)
2429 VectorSubtract(light->origin, r_vieworigin, temp);
2430 rating = (DotProduct(temp, r_viewforward) / sqrt(DotProduct(temp, temp)));
2433 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
2434 if (bestrating < rating && CL_TraceLine(light->origin, r_vieworigin, NULL, NULL, true, NULL, SUPERCONTENTS_SOLID) == 1.0f)
2436 bestrating = rating;
2441 R_Shadow_SelectLight(best);
2444 void R_Shadow_LoadWorldLights(void)
2446 int n, a, style, shadow;
2447 char name[MAX_QPATH], cubemapname[MAX_QPATH], *lightsstring, *s, *t;
2448 float origin[3], radius, color[3], angles[3], corona;
2449 if (cl.worldmodel == NULL)
2451 Con_Print("No map loaded.\n");
2454 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2455 strlcat (name, ".rtlights", sizeof (name));
2456 lightsstring = FS_LoadFile(name, false);
2466 for (;COM_Parse(t, true) && strcmp(
2467 if (COM_Parse(t, true))
2469 if (com_token[0] == '!')
2472 origin[0] = atof(com_token+1);
2475 origin[0] = atof(com_token);
2480 while (*s && *s != '\n')
2486 // check for modifier flags
2492 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]);
2494 VectorClear(angles);
2497 if (a < 9 || !strcmp(cubemapname, "\"\""))
2502 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);
2505 VectorScale(color, r_editlights_rtlightscolorscale.value, color);
2506 radius *= r_editlights_rtlightssizescale.value;
2507 R_Shadow_NewWorldLight(origin, angles, color, radius, corona, style, shadow, cubemapname);
2512 Con_Printf("invalid rtlights file \"%s\"\n", name);
2513 Mem_Free(lightsstring);
2517 void R_Shadow_SaveWorldLights(void)
2520 int bufchars, bufmaxchars;
2522 char name[MAX_QPATH];
2524 if (!r_shadow_worldlightchain)
2526 if (cl.worldmodel == NULL)
2528 Con_Print("No map loaded.\n");
2531 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2532 strlcat (name, ".rtlights", sizeof (name));
2533 bufchars = bufmaxchars = 0;
2535 for (light = r_shadow_worldlightchain;light;light = light->next)
2537 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]);
2538 if (bufchars + (int) strlen(line) > bufmaxchars)
2540 bufmaxchars = bufchars + strlen(line) + 2048;
2542 buf = Mem_Alloc(r_shadow_mempool, bufmaxchars);
2546 memcpy(buf, oldbuf, bufchars);
2552 memcpy(buf + bufchars, line, strlen(line));
2553 bufchars += strlen(line);
2557 FS_WriteFile(name, buf, bufchars);
2562 void R_Shadow_LoadLightsFile(void)
2565 char name[MAX_QPATH], *lightsstring, *s, *t;
2566 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
2567 if (cl.worldmodel == NULL)
2569 Con_Print("No map loaded.\n");
2572 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
2573 strlcat (name, ".lights", sizeof (name));
2574 lightsstring = FS_LoadFile(name, false);
2582 while (*s && *s != '\n')
2587 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);
2591 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);
2594 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
2595 radius = bound(15, radius, 4096);
2596 VectorScale(color, (2.0f / (8388608.0f)), color);
2597 R_Shadow_NewWorldLight(origin, vec3_origin, color, radius, 0, style, true, NULL);
2602 Con_Printf("invalid lights file \"%s\"\n", name);
2603 Mem_Free(lightsstring);
2607 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
2609 int entnum, style, islight, skin, pflags, effects;
2610 char key[256], value[1024];
2611 float origin[3], angles[3], radius, color[3], light, fadescale, lightscale, originhack[3], overridecolor[3];
2614 if (cl.worldmodel == NULL)
2616 Con_Print("No map loaded.\n");
2619 data = cl.worldmodel->brush.entities;
2622 for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++)
2625 origin[0] = origin[1] = origin[2] = 0;
2626 originhack[0] = originhack[1] = originhack[2] = 0;
2627 angles[0] = angles[1] = angles[2] = 0;
2628 color[0] = color[1] = color[2] = 1;
2629 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
2639 if (!COM_ParseToken(&data, false))
2641 if (com_token[0] == '}')
2642 break; // end of entity
2643 if (com_token[0] == '_')
2644 strcpy(key, com_token + 1);
2646 strcpy(key, com_token);
2647 while (key[strlen(key)-1] == ' ') // remove trailing spaces
2648 key[strlen(key)-1] = 0;
2649 if (!COM_ParseToken(&data, false))
2651 strcpy(value, com_token);
2653 // now that we have the key pair worked out...
2654 if (!strcmp("light", key))
2655 light = atof(value);
2656 else if (!strcmp("origin", key))
2657 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
2658 else if (!strcmp("angle", key))
2659 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
2660 else if (!strcmp("angles", key))
2661 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
2662 else if (!strcmp("color", key))
2663 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
2664 else if (!strcmp("wait", key))
2665 fadescale = atof(value);
2666 else if (!strcmp("classname", key))
2668 if (!strncmp(value, "light", 5))
2671 if (!strcmp(value, "light_fluoro"))
2676 overridecolor[0] = 1;
2677 overridecolor[1] = 1;
2678 overridecolor[2] = 1;
2680 if (!strcmp(value, "light_fluorospark"))
2685 overridecolor[0] = 1;
2686 overridecolor[1] = 1;
2687 overridecolor[2] = 1;
2689 if (!strcmp(value, "light_globe"))
2694 overridecolor[0] = 1;
2695 overridecolor[1] = 0.8;
2696 overridecolor[2] = 0.4;
2698 if (!strcmp(value, "light_flame_large_yellow"))
2703 overridecolor[0] = 1;
2704 overridecolor[1] = 0.5;
2705 overridecolor[2] = 0.1;
2707 if (!strcmp(value, "light_flame_small_yellow"))
2712 overridecolor[0] = 1;
2713 overridecolor[1] = 0.5;
2714 overridecolor[2] = 0.1;
2716 if (!strcmp(value, "light_torch_small_white"))
2721 overridecolor[0] = 1;
2722 overridecolor[1] = 0.5;
2723 overridecolor[2] = 0.1;
2725 if (!strcmp(value, "light_torch_small_walltorch"))
2730 overridecolor[0] = 1;
2731 overridecolor[1] = 0.5;
2732 overridecolor[2] = 0.1;
2736 else if (!strcmp("style", key))
2737 style = atoi(value);
2738 else if (cl.worldmodel->type == mod_brushq3)
2740 if (!strcmp("scale", key))
2741 lightscale = atof(value);
2742 if (!strcmp("fade", key))
2743 fadescale = atof(value);
2745 else if (!strcmp("skin", key))
2746 skin = (int)atof(value);
2747 else if (!strcmp("pflags", key))
2748 pflags = (int)atof(value);
2749 else if (!strcmp("effects", key))
2750 effects = (int)atof(value);
2752 if (light <= 0 && islight)
2754 if (lightscale <= 0)
2758 if (gamemode == GAME_TENEBRAE)
2760 if (effects & EF_NODRAW)
2762 pflags |= PFLAGS_FULLDYNAMIC;
2763 effects &= ~EF_NODRAW;
2766 radius = min(light * r_editlights_quakelightsizescale.value * lightscale / fadescale, 1048576);
2767 light = sqrt(bound(0, light, 1048576)) * (1.0f / 16.0f);
2768 if (color[0] == 1 && color[1] == 1 && color[2] == 1)
2769 VectorCopy(overridecolor, color);
2770 VectorScale(color, light, color);
2771 VectorAdd(origin, originhack, origin);
2772 if (radius >= 15 && !(pflags & PFLAGS_FULLDYNAMIC))
2773 R_Shadow_NewWorldLight(origin, angles, color, radius, (pflags & PFLAGS_CORONA) != 0, style, (pflags & PFLAGS_NOSHADOW) == 0, skin >= 16 ? va("cubemaps/%i", skin) : NULL);
2778 void R_Shadow_SetCursorLocationForView(void)
2780 vec_t dist, push, frac;
2781 vec3_t dest, endpos, normal;
2782 VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
2783 frac = CL_TraceLine(r_vieworigin, dest, endpos, normal, true, NULL, SUPERCONTENTS_SOLID);
2786 dist = frac * r_editlights_cursordistance.value;
2787 push = r_editlights_cursorpushback.value;
2791 VectorMA(endpos, push, r_viewforward, endpos);
2792 VectorMA(endpos, r_editlights_cursorpushoff.value, normal, endpos);
2794 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2795 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2796 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
2799 void R_Shadow_UpdateWorldLightSelection(void)
2801 if (r_editlights.integer)
2803 R_Shadow_SetCursorLocationForView();
2804 R_Shadow_SelectLightInView();
2805 R_Shadow_DrawLightSprites();
2808 R_Shadow_SelectLight(NULL);
2811 void R_Shadow_EditLights_Clear_f(void)
2813 R_Shadow_ClearWorldLights();
2816 void R_Shadow_EditLights_Reload_f(void)
2818 r_shadow_reloadlights = true;
2821 void R_Shadow_EditLights_Save_f(void)
2824 R_Shadow_SaveWorldLights();
2827 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
2829 R_Shadow_ClearWorldLights();
2830 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
2833 void R_Shadow_EditLights_ImportLightsFile_f(void)
2835 R_Shadow_ClearWorldLights();
2836 R_Shadow_LoadLightsFile();
2839 void R_Shadow_EditLights_Spawn_f(void)
2842 if (!r_editlights.integer)
2844 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
2847 if (Cmd_Argc() != 1)
2849 Con_Print("r_editlights_spawn does not take parameters\n");
2852 color[0] = color[1] = color[2] = 1;
2853 R_Shadow_NewWorldLight(r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL);
2856 void R_Shadow_EditLights_Edit_f(void)
2858 vec3_t origin, angles, color;
2859 vec_t radius, corona;
2861 char cubemapname[1024];
2862 if (!r_editlights.integer)
2864 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
2867 if (!r_shadow_selectedlight)
2869 Con_Print("No selected light.\n");
2872 VectorCopy(r_shadow_selectedlight->origin, origin);
2873 VectorCopy(r_shadow_selectedlight->angles, angles);
2874 VectorCopy(r_shadow_selectedlight->color, color);
2875 radius = r_shadow_selectedlight->radius;
2876 style = r_shadow_selectedlight->style;
2877 if (r_shadow_selectedlight->cubemapname)
2878 strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
2881 shadows = r_shadow_selectedlight->shadow;
2882 corona = r_shadow_selectedlight->corona;
2883 if (!strcmp(Cmd_Argv(1), "origin"))
2885 if (Cmd_Argc() != 5)
2887 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
2890 origin[0] = atof(Cmd_Argv(2));
2891 origin[1] = atof(Cmd_Argv(3));
2892 origin[2] = atof(Cmd_Argv(4));
2894 else if (!strcmp(Cmd_Argv(1), "originx"))
2896 if (Cmd_Argc() != 3)
2898 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2901 origin[0] = atof(Cmd_Argv(2));
2903 else if (!strcmp(Cmd_Argv(1), "originy"))
2905 if (Cmd_Argc() != 3)
2907 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2910 origin[1] = atof(Cmd_Argv(2));
2912 else if (!strcmp(Cmd_Argv(1), "originz"))
2914 if (Cmd_Argc() != 3)
2916 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2919 origin[2] = atof(Cmd_Argv(2));
2921 else if (!strcmp(Cmd_Argv(1), "move"))
2923 if (Cmd_Argc() != 5)
2925 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
2928 origin[0] += atof(Cmd_Argv(2));
2929 origin[1] += atof(Cmd_Argv(3));
2930 origin[2] += atof(Cmd_Argv(4));
2932 else if (!strcmp(Cmd_Argv(1), "movex"))
2934 if (Cmd_Argc() != 3)
2936 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2939 origin[0] += atof(Cmd_Argv(2));
2941 else if (!strcmp(Cmd_Argv(1), "movey"))
2943 if (Cmd_Argc() != 3)
2945 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2948 origin[1] += atof(Cmd_Argv(2));
2950 else if (!strcmp(Cmd_Argv(1), "movez"))
2952 if (Cmd_Argc() != 3)
2954 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2957 origin[2] += atof(Cmd_Argv(2));
2959 else if (!strcmp(Cmd_Argv(1), "angles"))
2961 if (Cmd_Argc() != 5)
2963 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
2966 angles[0] = atof(Cmd_Argv(2));
2967 angles[1] = atof(Cmd_Argv(3));
2968 angles[2] = atof(Cmd_Argv(4));
2970 else if (!strcmp(Cmd_Argv(1), "anglesx"))
2972 if (Cmd_Argc() != 3)
2974 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2977 angles[0] = atof(Cmd_Argv(2));
2979 else if (!strcmp(Cmd_Argv(1), "anglesy"))
2981 if (Cmd_Argc() != 3)
2983 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2986 angles[1] = atof(Cmd_Argv(2));
2988 else if (!strcmp(Cmd_Argv(1), "anglesz"))
2990 if (Cmd_Argc() != 3)
2992 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
2995 angles[2] = atof(Cmd_Argv(2));
2997 else if (!strcmp(Cmd_Argv(1), "color"))
2999 if (Cmd_Argc() != 5)
3001 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
3004 color[0] = atof(Cmd_Argv(2));
3005 color[1] = atof(Cmd_Argv(3));
3006 color[2] = atof(Cmd_Argv(4));
3008 else if (!strcmp(Cmd_Argv(1), "radius"))
3010 if (Cmd_Argc() != 3)
3012 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3015 radius = atof(Cmd_Argv(2));
3017 else if (!strcmp(Cmd_Argv(1), "style"))
3019 if (Cmd_Argc() != 3)
3021 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3024 style = atoi(Cmd_Argv(2));
3026 else if (!strcmp(Cmd_Argv(1), "cubemap"))
3030 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3033 if (Cmd_Argc() == 3)
3034 strcpy(cubemapname, Cmd_Argv(2));
3038 else if (!strcmp(Cmd_Argv(1), "shadows"))
3040 if (Cmd_Argc() != 3)
3042 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3045 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
3047 else if (!strcmp(Cmd_Argv(1), "corona"))
3049 if (Cmd_Argc() != 3)
3051 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
3054 corona = atof(Cmd_Argv(2));
3058 Con_Print("usage: r_editlights_edit [property] [value]\n");
3059 Con_Print("Selected light's properties:\n");
3060 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
3061 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
3062 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
3063 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
3064 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
3065 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
3066 Con_Printf("Shadows: %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
3067 Con_Printf("Cubemap: %s\n", r_shadow_selectedlight->cubemapname);
3070 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3071 r_shadow_selectedlight = NULL;
3072 R_Shadow_NewWorldLight(origin, angles, color, radius, corona, style, shadows, cubemapname);
3075 extern int con_vislines;
3076 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
3080 if (r_shadow_selectedlight == NULL)
3084 sprintf(temp, "Light properties");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3085 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;
3086 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;
3087 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;
3088 sprintf(temp, "Radius %f", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3089 sprintf(temp, "Corona %f", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3090 sprintf(temp, "Style %i", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3091 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;
3092 sprintf(temp, "Cubemap %s", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
3095 void R_Shadow_EditLights_ToggleShadow_f(void)
3097 if (!r_editlights.integer)
3099 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3102 if (!r_shadow_selectedlight)
3104 Con_Print("No selected light.\n");
3107 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);
3108 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3109 r_shadow_selectedlight = NULL;
3112 void R_Shadow_EditLights_ToggleCorona_f(void)
3114 if (!r_editlights.integer)
3116 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
3119 if (!r_shadow_selectedlight)
3121 Con_Print("No selected light.\n");
3124 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);
3125 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3126 r_shadow_selectedlight = NULL;
3129 void R_Shadow_EditLights_Remove_f(void)
3131 if (!r_editlights.integer)
3133 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
3136 if (!r_shadow_selectedlight)
3138 Con_Print("No selected light.\n");
3141 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
3142 r_shadow_selectedlight = NULL;
3145 void R_Shadow_EditLights_Help_f(void)
3148 "Documentation on r_editlights system:\n"
3150 "r_editlights : enable/disable editing mode\n"
3151 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
3152 "r_editlights_cursorpushback : push back cursor this far from surface\n"
3153 "r_editlights_cursorpushoff : push cursor off surface this far\n"
3154 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
3155 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
3156 "r_editlights_rtlightssizescale : imported rtlight size scaling\n"
3157 "r_editlights_rtlightscolorscale : imported rtlight color scaling\n"
3159 "r_editlights_help : this help\n"
3160 "r_editlights_clear : remove all lights\n"
3161 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
3162 "r_editlights_save : save to .rtlights file\n"
3163 "r_editlights_spawn : create a light with default settings\n"
3164 "r_editlights_edit command : edit selected light - more documentation below\n"
3165 "r_editlights_remove : remove selected light\n"
3166 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
3167 "r_editlights_importlightentitiesfrommap : reload light entities\n"
3168 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
3170 "origin x y z : set light location\n"
3171 "originx x: set x component of light location\n"
3172 "originy y: set y component of light location\n"
3173 "originz z: set z component of light location\n"
3174 "move x y z : adjust light location\n"
3175 "movex x: adjust x component of light location\n"
3176 "movey y: adjust y component of light location\n"
3177 "movez z: adjust z component of light location\n"
3178 "angles x y z : set light angles\n"
3179 "anglesx x: set x component of light angles\n"
3180 "anglesy y: set y component of light angles\n"
3181 "anglesz z: set z component of light angles\n"
3182 "color r g b : set color of light (can be brighter than 1 1 1)\n"
3183 "radius radius : set radius (size) of light\n"
3184 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
3185 "cubemap basename : set filter cubemap of light (not yet supported)\n"
3186 "shadows 1/0 : turn on/off shadows\n"
3187 "corona n : set corona intensity\n"
3188 "<nothing> : print light properties to console\n"
3192 void R_Shadow_EditLights_Init(void)
3194 Cvar_RegisterVariable(&r_editlights);
3195 Cvar_RegisterVariable(&r_editlights_cursordistance);
3196 Cvar_RegisterVariable(&r_editlights_cursorpushback);
3197 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
3198 Cvar_RegisterVariable(&r_editlights_cursorgrid);
3199 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
3200 Cvar_RegisterVariable(&r_editlights_rtlightssizescale);
3201 Cvar_RegisterVariable(&r_editlights_rtlightscolorscale);
3202 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f);
3203 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
3204 Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
3205 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
3206 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
3207 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
3208 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
3209 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
3210 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f);
3211 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
3212 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);