tr_stencilshadow.cpp 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396
  1. /*
  2. ===========================================================================
  3. Doom 3 GPL Source Code
  4. Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
  6. Doom 3 Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. #include "../idlib/precompiled.h"
  21. #pragma hdrstop
  22. #include "tr_local.h"
  23. // tr_stencilShadow.c -- creaton of stencil shadow volumes
  24. /*
  25. Should we split shadow volume surfaces when they exceed max verts
  26. or max indexes?
  27. a problem is that the number of vertexes needed for the
  28. shadow volume will be twice the number in the original,
  29. and possibly up to 8/3 when near plane clipped.
  30. The maximum index count is 7x when not clipped and all
  31. triangles are completely discrete. Near plane clipping
  32. can increase this to 10x.
  33. The maximum expansions are always with discrete triangles.
  34. Meshes of triangles will result in less index expansion because
  35. there will be less silhouette edges, although it will always be
  36. greater than the source if a cap is present.
  37. can't just project onto a plane if some surface points are
  38. behind the light.
  39. The cases when a face is edge on to a light is robustly handled
  40. with closed volumes, because only a single one of it's neighbors
  41. will pass the edge test. It may be an issue with non-closed models.
  42. It is crucial that the shadow volumes be completely enclosed.
  43. The triangles identified as shadow sources will be projected
  44. directly onto the light far plane.
  45. The sil edges must be handled carefully.
  46. A partially clipped explicit sil edge will still generate a sil
  47. edge.
  48. EVERY new edge generated by clipping the triangles to the view
  49. will generate a sil edge.
  50. If a triangle has no points inside the frustum, it is completely
  51. culled away. If a sil edge is either in or on the frustum, it is
  52. added.
  53. If a triangle has no points outside the frustum, it does not
  54. need to be clipped.
  55. USING THE STENCIL BUFFER FOR SHADOWING
  56. basic triangle property
  57. view plane inside shadow volume problem
  58. quad triangulation issue
  59. issues with silhouette optimizations
  60. the shapes of shadow projections are poor for sphere or box culling
  61. the gouraud shading problem
  62. // epsilon culling rules:
  63. // the positive side of the frustum is inside
  64. d = tri->verts[i].xyz * frustum[j].Normal() + frustum[j][3];
  65. if ( d < LIGHT_CLIP_EPSILON ) {
  66. pointCull[i] |= ( 1 << j );
  67. }
  68. if ( d > -LIGHT_CLIP_EPSILON ) {
  69. pointCull[i] |= ( 1 << (6+j) );
  70. }
  71. If a low order bit is set, the point is on or outside the plane
  72. If a high order bit is set, the point is on or inside the plane
  73. If a low order bit is clear, the point is inside the plane (definately positive)
  74. If a high order bit is clear, the point is outside the plane (definately negative)
  75. */
  76. #define TRIANGLE_CULLED(p1,p2,p3) ( pointCull[p1] & pointCull[p2] & pointCull[p3] & 0x3f )
  77. //#define TRIANGLE_CLIPPED(p1,p2,p3) ( ( pointCull[p1] | pointCull[p2] | pointCull[p3] ) & 0xfc0 )
  78. #define TRIANGLE_CLIPPED(p1,p2,p3) ( ( ( pointCull[p1] & pointCull[p2] & pointCull[p3] ) & 0xfc0 ) != 0xfc0 )
  79. // an edge that is on the plane is NOT culled
  80. #define EDGE_CULLED(p1,p2) ( ( pointCull[p1] ^ 0xfc0 ) & ( pointCull[p2] ^ 0xfc0 ) & 0xfc0 )
  81. #define EDGE_CLIPPED(p1,p2) ( ( pointCull[p1] & pointCull[p2] & 0xfc0 ) != 0xfc0 )
  82. // a point that is on the plane is NOT culled
  83. //#define POINT_CULLED(p1) ( ( pointCull[p1] ^ 0xfc0 ) & 0xfc0 )
  84. #define POINT_CULLED(p1) ( ( pointCull[p1] & 0xfc0 ) != 0xfc0 )
  85. //#define LIGHT_CLIP_EPSILON 0.001f
  86. #define LIGHT_CLIP_EPSILON 0.1f
  87. #define MAX_CLIP_SIL_EDGES 2048
  88. static int numClipSilEdges;
  89. static int clipSilEdges[MAX_CLIP_SIL_EDGES][2];
  90. // facing will be 0 if forward facing, 1 if backwards facing
  91. // grabbed with alloca
  92. static byte *globalFacing;
  93. // faceCastsShadow will be 1 if the face is in the projection
  94. // and facing the apropriate direction
  95. static byte *faceCastsShadow;
  96. static int *remap;
  97. #define MAX_SHADOW_INDEXES 0x18000
  98. #define MAX_SHADOW_VERTS 0x18000
  99. static int numShadowIndexes;
  100. static glIndex_t shadowIndexes[MAX_SHADOW_INDEXES];
  101. static int numShadowVerts;
  102. static idVec4 shadowVerts[MAX_SHADOW_VERTS];
  103. static bool overflowed;
  104. idPlane pointLightFrustums[6][6] = {
  105. {
  106. idPlane( 1,0,0,0 ),
  107. idPlane( 1,1,0,0 ),
  108. idPlane( 1,-1,0,0 ),
  109. idPlane( 1,0,1,0 ),
  110. idPlane( 1,0,-1,0 ),
  111. idPlane( -1,0,0,0 ),
  112. },
  113. {
  114. idPlane( -1,0,0,0 ),
  115. idPlane( -1,1,0,0 ),
  116. idPlane( -1,-1,0,0 ),
  117. idPlane( -1,0,1,0 ),
  118. idPlane( -1,0,-1,0 ),
  119. idPlane( 1,0,0,0 ),
  120. },
  121. {
  122. idPlane( 0,1,0,0 ),
  123. idPlane( 0,1,1,0 ),
  124. idPlane( 0,1,-1,0 ),
  125. idPlane( 1,1,0,0 ),
  126. idPlane( -1,1,0,0 ),
  127. idPlane( 0,-1,0,0 ),
  128. },
  129. {
  130. idPlane( 0,-1,0,0 ),
  131. idPlane( 0,-1,1,0 ),
  132. idPlane( 0,-1,-1,0 ),
  133. idPlane( 1,-1,0,0 ),
  134. idPlane( -1,-1,0,0 ),
  135. idPlane( 0,1,0,0 ),
  136. },
  137. {
  138. idPlane( 0,0,1,0 ),
  139. idPlane( 1,0,1,0 ),
  140. idPlane( -1,0,1,0 ),
  141. idPlane( 0,1,1,0 ),
  142. idPlane( 0,-1,1,0 ),
  143. idPlane( 0,0,-1,0 ),
  144. },
  145. {
  146. idPlane( 0,0,-1,0 ),
  147. idPlane( 1,0,-1,0 ),
  148. idPlane( -1,0,-1,0 ),
  149. idPlane( 0,1,-1,0 ),
  150. idPlane( 0,-1,-1,0 ),
  151. idPlane( 0,0,1,0 ),
  152. },
  153. };
  154. int c_caps, c_sils;
  155. static bool callOptimizer; // call the preprocessor optimizer after clipping occluders
  156. typedef struct {
  157. int frontCapStart;
  158. int rearCapStart;
  159. int silStart;
  160. int end;
  161. } indexRef_t;
  162. static indexRef_t indexRef[6];
  163. static int indexFrustumNumber; // which shadow generating side of a light the indexRef is for
  164. /*
  165. ===============
  166. PointsOrdered
  167. To make sure the triangulations of the sil edges is consistant,
  168. we need to be able to order two points. We don't care about how
  169. they compare with any other points, just that when the same two
  170. points are passed in (in either order), they will always specify
  171. the same one as leading.
  172. Currently we need to have separate faces in different surfaces
  173. order the same way, so we must look at the actual coordinates.
  174. If surfaces are ever guaranteed to not have to edge match with
  175. other surfaces, we could just compare indexes.
  176. ===============
  177. */
  178. static bool PointsOrdered( const idVec3 &a, const idVec3 &b ) {
  179. float i, j;
  180. // vectors that wind up getting an equal hash value will
  181. // potentially cause a misorder, which can show as a couple
  182. // crack pixels in a shadow
  183. // scale by some odd numbers so -8, 8, 8 will not be equal
  184. // to 8, -8, 8
  185. // in the very rare case that these might be equal, all that would
  186. // happen is an oportunity for a tiny rasterization shadow crack
  187. i = a[0] + a[1]*127 + a[2]*1023;
  188. j = b[0] + b[1]*127 + b[2]*1023;
  189. return (bool)(i < j);
  190. }
  191. /*
  192. ====================
  193. R_LightProjectionMatrix
  194. ====================
  195. */
  196. void R_LightProjectionMatrix( const idVec3 &origin, const idPlane &rearPlane, idVec4 mat[4] ) {
  197. idVec4 lv;
  198. float lg;
  199. // calculate the homogenious light vector
  200. lv.x = origin.x;
  201. lv.y = origin.y;
  202. lv.z = origin.z;
  203. lv.w = 1;
  204. lg = rearPlane.ToVec4() * lv;
  205. // outer product
  206. mat[0][0] = lg -rearPlane[0] * lv[0];
  207. mat[0][1] = -rearPlane[1] * lv[0];
  208. mat[0][2] = -rearPlane[2] * lv[0];
  209. mat[0][3] = -rearPlane[3] * lv[0];
  210. mat[1][0] = -rearPlane[0] * lv[1];
  211. mat[1][1] = lg -rearPlane[1] * lv[1];
  212. mat[1][2] = -rearPlane[2] * lv[1];
  213. mat[1][3] = -rearPlane[3] * lv[1];
  214. mat[2][0] = -rearPlane[0] * lv[2];
  215. mat[2][1] = -rearPlane[1] * lv[2];
  216. mat[2][2] = lg -rearPlane[2] * lv[2];
  217. mat[2][3] = -rearPlane[3] * lv[2];
  218. mat[3][0] = -rearPlane[0] * lv[3];
  219. mat[3][1] = -rearPlane[1] * lv[3];
  220. mat[3][2] = -rearPlane[2] * lv[3];
  221. mat[3][3] = lg -rearPlane[3] * lv[3];
  222. }
  223. /*
  224. ===================
  225. R_ProjectPointsToFarPlane
  226. make a projected copy of the even verts into the odd spots
  227. that is on the far light clip plane
  228. ===================
  229. */
  230. static void R_ProjectPointsToFarPlane( const idRenderEntityLocal *ent, const idRenderLightLocal *light,
  231. const idPlane &lightPlaneLocal,
  232. int firstShadowVert, int numShadowVerts ) {
  233. idVec3 lv;
  234. idVec4 mat[4];
  235. int i;
  236. idVec4 *in;
  237. R_GlobalPointToLocal( ent->modelMatrix, light->globalLightOrigin, lv );
  238. R_LightProjectionMatrix( lv, lightPlaneLocal, mat );
  239. #if 1
  240. // make a projected copy of the even verts into the odd spots
  241. in = &shadowVerts[firstShadowVert];
  242. for ( i = firstShadowVert ; i < numShadowVerts ; i+= 2, in += 2 ) {
  243. float w, oow;
  244. in[0].w = 1;
  245. w = in->ToVec3() * mat[3].ToVec3() + mat[3][3];
  246. if ( w == 0 ) {
  247. in[1] = in[0];
  248. continue;
  249. }
  250. oow = 1.0 / w;
  251. in[1].x = ( in->ToVec3() * mat[0].ToVec3() + mat[0][3] ) * oow;
  252. in[1].y = ( in->ToVec3() * mat[1].ToVec3() + mat[1][3] ) * oow;
  253. in[1].z = ( in->ToVec3() * mat[2].ToVec3() + mat[2][3] ) * oow;
  254. in[1].w = 1;
  255. }
  256. #else
  257. // messing with W seems to cause some depth precision problems
  258. // make a projected copy of the even verts into the odd spots
  259. in = &shadowVerts[firstShadowVert];
  260. for ( i = firstShadowVert ; i < numShadowVerts ; i+= 2, in += 2 ) {
  261. in[0].w = 1;
  262. in[1].x = *in * mat[0].ToVec3() + mat[0][3];
  263. in[1].y = *in * mat[1].ToVec3() + mat[1][3];
  264. in[1].z = *in * mat[2].ToVec3() + mat[2][3];
  265. in[1].w = *in * mat[3].ToVec3() + mat[3][3];
  266. }
  267. #endif
  268. }
  269. #define MAX_CLIPPED_POINTS 20
  270. typedef struct {
  271. int numVerts;
  272. idVec3 verts[MAX_CLIPPED_POINTS];
  273. int edgeFlags[MAX_CLIPPED_POINTS];
  274. } clipTri_t;
  275. /*
  276. =============
  277. R_ChopWinding
  278. Clips a triangle from one buffer to another, setting edge flags
  279. The returned buffer may be the same as inNum if no clipping is done
  280. If entirely clipped away, clipTris[returned].numVerts == 0
  281. I have some worries about edge flag cases when polygons are clipped
  282. multiple times near the epsilon.
  283. =============
  284. */
  285. static int R_ChopWinding( clipTri_t clipTris[2], int inNum, const idPlane &plane ) {
  286. clipTri_t *in, *out;
  287. float dists[MAX_CLIPPED_POINTS];
  288. int sides[MAX_CLIPPED_POINTS];
  289. int counts[3];
  290. float dot;
  291. int i, j;
  292. idVec3 *p1, *p2;
  293. idVec3 mid;
  294. in = &clipTris[inNum];
  295. out = &clipTris[inNum^1];
  296. counts[0] = counts[1] = counts[2] = 0;
  297. // determine sides for each point
  298. for ( i = 0 ; i < in->numVerts ; i++ ) {
  299. dot = plane.Distance( in->verts[i] );
  300. dists[i] = dot;
  301. if ( dot < -LIGHT_CLIP_EPSILON ) {
  302. sides[i] = SIDE_BACK;
  303. } else if ( dot > LIGHT_CLIP_EPSILON ) {
  304. sides[i] = SIDE_FRONT;
  305. } else {
  306. sides[i] = SIDE_ON;
  307. }
  308. counts[sides[i]]++;
  309. }
  310. // if none in front, it is completely clipped away
  311. if ( !counts[SIDE_FRONT] ) {
  312. in->numVerts = 0;
  313. return inNum;
  314. }
  315. if ( !counts[SIDE_BACK] ) {
  316. return inNum; // inout stays the same
  317. }
  318. // avoid wrapping checks by duplicating first value to end
  319. sides[i] = sides[0];
  320. dists[i] = dists[0];
  321. in->verts[in->numVerts] = in->verts[0];
  322. in->edgeFlags[in->numVerts] = in->edgeFlags[0];
  323. out->numVerts = 0;
  324. for ( i = 0 ; i < in->numVerts ; i++ ) {
  325. p1 = &in->verts[i];
  326. if ( sides[i] != SIDE_BACK ) {
  327. out->verts[out->numVerts] = *p1;
  328. if ( sides[i] == SIDE_ON && sides[i+1] == SIDE_BACK ) {
  329. out->edgeFlags[out->numVerts] = 1;
  330. } else {
  331. out->edgeFlags[out->numVerts] = in->edgeFlags[i];
  332. }
  333. out->numVerts++;
  334. }
  335. if ( (sides[i] == SIDE_FRONT && sides[i+1] == SIDE_BACK)
  336. || (sides[i] == SIDE_BACK && sides[i+1] == SIDE_FRONT) ) {
  337. // generate a split point
  338. p2 = &in->verts[i+1];
  339. dot = dists[i] / (dists[i]-dists[i+1]);
  340. for ( j=0 ; j<3 ; j++ ) {
  341. mid[j] = (*p1)[j] + dot*((*p2)[j]-(*p1)[j]);
  342. }
  343. out->verts[out->numVerts] = mid;
  344. // set the edge flag
  345. if ( sides[i+1] != SIDE_FRONT ) {
  346. out->edgeFlags[out->numVerts] = 1;
  347. } else {
  348. out->edgeFlags[out->numVerts] = in->edgeFlags[i];
  349. }
  350. out->numVerts++;
  351. }
  352. }
  353. return inNum ^ 1;
  354. }
  355. /*
  356. ===================
  357. R_ClipTriangleToLight
  358. Returns false if nothing is left after clipping
  359. ===================
  360. */
  361. static bool R_ClipTriangleToLight( const idVec3 &a, const idVec3 &b, const idVec3 &c, int planeBits,
  362. const idPlane frustum[6] ) {
  363. int i;
  364. int base;
  365. clipTri_t pingPong[2], *ct;
  366. int p;
  367. pingPong[0].numVerts = 3;
  368. pingPong[0].edgeFlags[0] = 0;
  369. pingPong[0].edgeFlags[1] = 0;
  370. pingPong[0].edgeFlags[2] = 0;
  371. pingPong[0].verts[0] = a;
  372. pingPong[0].verts[1] = b;
  373. pingPong[0].verts[2] = c;
  374. p = 0;
  375. for ( i = 0 ; i < 6 ; i++ ) {
  376. if ( planeBits & ( 1 << i ) ) {
  377. p = R_ChopWinding( pingPong, p, frustum[i] );
  378. if ( pingPong[p].numVerts < 1 ) {
  379. return false;
  380. }
  381. }
  382. }
  383. ct = &pingPong[p];
  384. // copy the clipped points out to shadowVerts
  385. if ( numShadowVerts + ct->numVerts * 2 > MAX_SHADOW_VERTS ) {
  386. overflowed = true;
  387. return false;
  388. }
  389. base = numShadowVerts;
  390. for ( i = 0 ; i < ct->numVerts ; i++ ) {
  391. shadowVerts[ base + i*2 ].ToVec3() = ct->verts[i];
  392. }
  393. numShadowVerts += ct->numVerts * 2;
  394. if ( numShadowIndexes + 3 * ( ct->numVerts - 2 ) > MAX_SHADOW_INDEXES ) {
  395. overflowed = true;
  396. return false;
  397. }
  398. for ( i = 2 ; i < ct->numVerts ; i++ ) {
  399. shadowIndexes[numShadowIndexes++] = base + i * 2;
  400. shadowIndexes[numShadowIndexes++] = base + ( i - 1 ) * 2;
  401. shadowIndexes[numShadowIndexes++] = base;
  402. }
  403. // any edges that were created by the clipping process will
  404. // have a silhouette quad created for it, because it is one
  405. // of the exterior bounds of the shadow volume
  406. for ( i = 0 ; i < ct->numVerts ; i++ ) {
  407. if ( ct->edgeFlags[i] ) {
  408. if ( numClipSilEdges == MAX_CLIP_SIL_EDGES ) {
  409. break;
  410. }
  411. clipSilEdges[ numClipSilEdges ][0] = base + i * 2;
  412. if ( i == ct->numVerts - 1 ) {
  413. clipSilEdges[ numClipSilEdges ][1] = base;
  414. } else {
  415. clipSilEdges[ numClipSilEdges ][1] = base + ( i + 1 ) * 2;
  416. }
  417. numClipSilEdges++;
  418. }
  419. }
  420. return true;
  421. }
  422. /*
  423. ===================
  424. R_ClipLineToLight
  425. If neither point is clearly behind the clipping
  426. plane, the edge will be passed unmodified. A sil edge that
  427. is on a border plane must be drawn.
  428. If one point is clearly clipped by the plane and the
  429. other point is on the plane, it will be completely removed.
  430. ===================
  431. */
  432. static bool R_ClipLineToLight( const idVec3 &a, const idVec3 &b, const idPlane frustum[4],
  433. idVec3 &p1, idVec3 &p2 ) {
  434. float *clip;
  435. int j;
  436. float d1, d2;
  437. float f;
  438. p1 = a;
  439. p2 = b;
  440. // clip it
  441. for ( j = 0 ; j < 6 ; j++ ) {
  442. d1 = frustum[j].Distance( p1 );
  443. d2 = frustum[j].Distance( p2 );
  444. // if both on or in front, not clipped to this plane
  445. if ( d1 > -LIGHT_CLIP_EPSILON && d2 > -LIGHT_CLIP_EPSILON ) {
  446. continue;
  447. }
  448. // if one is behind and the other isn't clearly in front, the edge is clipped off
  449. if ( d1 <= -LIGHT_CLIP_EPSILON && d2 < LIGHT_CLIP_EPSILON ) {
  450. return false;
  451. }
  452. if ( d2 <= -LIGHT_CLIP_EPSILON && d1 < LIGHT_CLIP_EPSILON ) {
  453. return false;
  454. }
  455. // clip it, keeping the negative side
  456. if ( d1 < 0 ) {
  457. clip = p1.ToFloatPtr();
  458. } else {
  459. clip = p2.ToFloatPtr();
  460. }
  461. #if 0
  462. if ( idMath::Fabs(d1 - d2) < 0.001 ) {
  463. d2 = d1 - 0.1;
  464. }
  465. #endif
  466. f = d1 / ( d1 - d2 );
  467. clip[0] = p1[0] + f * ( p2[0] - p1[0] );
  468. clip[1] = p1[1] + f * ( p2[1] - p1[1] );
  469. clip[2] = p1[2] + f * ( p2[2] - p1[2] );
  470. }
  471. return true; // retain a fragment
  472. }
  473. /*
  474. ==================
  475. R_AddClipSilEdges
  476. Add sil edges for each triangle clipped to the side of
  477. the frustum.
  478. Only done for simple projected lights, not point lights.
  479. ==================
  480. */
  481. static void R_AddClipSilEdges( void ) {
  482. int v1, v2;
  483. int v1_back, v2_back;
  484. int i;
  485. // don't allow it to overflow
  486. if ( numShadowIndexes + numClipSilEdges * 6 > MAX_SHADOW_INDEXES ) {
  487. overflowed = true;
  488. return;
  489. }
  490. for ( i = 0 ; i < numClipSilEdges ; i++ ) {
  491. v1 = clipSilEdges[i][0];
  492. v2 = clipSilEdges[i][1];
  493. v1_back = v1 + 1;
  494. v2_back = v2 + 1;
  495. if ( PointsOrdered( shadowVerts[ v1 ].ToVec3(), shadowVerts[ v2 ].ToVec3() ) ) {
  496. shadowIndexes[numShadowIndexes++] = v1;
  497. shadowIndexes[numShadowIndexes++] = v2;
  498. shadowIndexes[numShadowIndexes++] = v1_back;
  499. shadowIndexes[numShadowIndexes++] = v2;
  500. shadowIndexes[numShadowIndexes++] = v2_back;
  501. shadowIndexes[numShadowIndexes++] = v1_back;
  502. } else {
  503. shadowIndexes[numShadowIndexes++] = v1;
  504. shadowIndexes[numShadowIndexes++] = v2;
  505. shadowIndexes[numShadowIndexes++] = v2_back;
  506. shadowIndexes[numShadowIndexes++] = v1;
  507. shadowIndexes[numShadowIndexes++] = v2_back;
  508. shadowIndexes[numShadowIndexes++] = v1_back;
  509. }
  510. }
  511. }
  512. /*
  513. =================
  514. R_AddSilEdges
  515. Add quads from the front points to the projected points
  516. for each silhouette edge in the light
  517. =================
  518. */
  519. static void R_AddSilEdges( const srfTriangles_t *tri, unsigned short *pointCull, const idPlane frustum[6] ) {
  520. int v1, v2;
  521. int i;
  522. silEdge_t *sil;
  523. int numPlanes;
  524. numPlanes = tri->numIndexes / 3;
  525. // add sil edges for any true silhouette boundaries on the surface
  526. for ( i = 0 ; i < tri->numSilEdges ; i++ ) {
  527. sil = tri->silEdges + i;
  528. if ( sil->p1 < 0 || sil->p1 > numPlanes || sil->p2 < 0 || sil->p2 > numPlanes ) {
  529. common->Error( "Bad sil planes" );
  530. }
  531. // an edge will be a silhouette edge if the face on one side
  532. // casts a shadow, but the face on the other side doesn't.
  533. // "casts a shadow" means that it has some surface in the projection,
  534. // not just that it has the correct facing direction
  535. // This will cause edges that are exactly on the frustum plane
  536. // to be considered sil edges if the face inside casts a shadow.
  537. if ( !( faceCastsShadow[ sil->p1 ] ^ faceCastsShadow[ sil->p2 ] ) ) {
  538. continue;
  539. }
  540. // if the edge is completely off the negative side of
  541. // a frustum plane, don't add it at all. This can still
  542. // happen even if the face is visible and casting a shadow
  543. // if it is partially clipped
  544. if ( EDGE_CULLED( sil->v1, sil->v2 ) ) {
  545. continue;
  546. }
  547. // see if the edge needs to be clipped
  548. if ( EDGE_CLIPPED( sil->v1, sil->v2 ) ) {
  549. if ( numShadowVerts + 4 > MAX_SHADOW_VERTS ) {
  550. overflowed = true;
  551. return;
  552. }
  553. v1 = numShadowVerts;
  554. v2 = v1 + 2;
  555. if ( !R_ClipLineToLight( tri->verts[ sil->v1 ].xyz, tri->verts[ sil->v2 ].xyz,
  556. frustum, shadowVerts[v1].ToVec3(), shadowVerts[v2].ToVec3() ) ) {
  557. continue; // clipped away
  558. }
  559. numShadowVerts += 4;
  560. } else {
  561. // use the entire edge
  562. v1 = remap[ sil->v1 ];
  563. v2 = remap[ sil->v2 ];
  564. if ( v1 < 0 || v2 < 0 ) {
  565. common->Error( "R_AddSilEdges: bad remap[]" );
  566. }
  567. }
  568. // don't overflow
  569. if ( numShadowIndexes + 6 > MAX_SHADOW_INDEXES ) {
  570. overflowed = true;
  571. return;
  572. }
  573. // we need to choose the correct way of triangulating the silhouette quad
  574. // consistantly between any two points, no matter which order they are specified.
  575. // If this wasn't done, slight rasterization cracks would show in the shadow
  576. // volume when two sil edges were exactly coincident
  577. if ( faceCastsShadow[ sil->p2 ] ) {
  578. if ( PointsOrdered( shadowVerts[ v1 ].ToVec3(), shadowVerts[ v2 ].ToVec3() ) ) {
  579. shadowIndexes[numShadowIndexes++] = v1;
  580. shadowIndexes[numShadowIndexes++] = v1+1;
  581. shadowIndexes[numShadowIndexes++] = v2;
  582. shadowIndexes[numShadowIndexes++] = v2;
  583. shadowIndexes[numShadowIndexes++] = v1+1;
  584. shadowIndexes[numShadowIndexes++] = v2+1;
  585. } else {
  586. shadowIndexes[numShadowIndexes++] = v1;
  587. shadowIndexes[numShadowIndexes++] = v2+1;
  588. shadowIndexes[numShadowIndexes++] = v2;
  589. shadowIndexes[numShadowIndexes++] = v1;
  590. shadowIndexes[numShadowIndexes++] = v1+1;
  591. shadowIndexes[numShadowIndexes++] = v2+1;
  592. }
  593. } else {
  594. if ( PointsOrdered( shadowVerts[ v1 ].ToVec3(), shadowVerts[ v2 ].ToVec3() ) ) {
  595. shadowIndexes[numShadowIndexes++] = v1;
  596. shadowIndexes[numShadowIndexes++] = v2;
  597. shadowIndexes[numShadowIndexes++] = v1+1;
  598. shadowIndexes[numShadowIndexes++] = v2;
  599. shadowIndexes[numShadowIndexes++] = v2+1;
  600. shadowIndexes[numShadowIndexes++] = v1+1;
  601. } else {
  602. shadowIndexes[numShadowIndexes++] = v1;
  603. shadowIndexes[numShadowIndexes++] = v2;
  604. shadowIndexes[numShadowIndexes++] = v2+1;
  605. shadowIndexes[numShadowIndexes++] = v1;
  606. shadowIndexes[numShadowIndexes++] = v2+1;
  607. shadowIndexes[numShadowIndexes++] = v1+1;
  608. }
  609. }
  610. }
  611. }
  612. /*
  613. ================
  614. R_CalcPointCull
  615. Also inits the remap[] array to all -1
  616. ================
  617. */
  618. static void R_CalcPointCull( const srfTriangles_t *tri, const idPlane frustum[6], unsigned short *pointCull ) {
  619. int i;
  620. int frontBits;
  621. float *planeSide;
  622. byte *side1, *side2;
  623. SIMDProcessor->Memset( remap, -1, tri->numVerts * sizeof( remap[0] ) );
  624. for ( frontBits = 0, i = 0; i < 6; i++ ) {
  625. // get front bits for the whole surface
  626. if ( tri->bounds.PlaneDistance( frustum[i] ) >= LIGHT_CLIP_EPSILON ) {
  627. frontBits |= 1<<(i+6);
  628. }
  629. }
  630. // initialize point cull
  631. for ( i = 0; i < tri->numVerts; i++ ) {
  632. pointCull[i] = frontBits;
  633. }
  634. // if the surface is not completely inside the light frustum
  635. if ( frontBits == ( ( ( 1 << 6 ) - 1 ) ) << 6 ) {
  636. return;
  637. }
  638. planeSide = (float *) _alloca16( tri->numVerts * sizeof( float ) );
  639. side1 = (byte *) _alloca16( tri->numVerts * sizeof( byte ) );
  640. side2 = (byte *) _alloca16( tri->numVerts * sizeof( byte ) );
  641. SIMDProcessor->Memset( side1, 0, tri->numVerts * sizeof( byte ) );
  642. SIMDProcessor->Memset( side2, 0, tri->numVerts * sizeof( byte ) );
  643. for ( i = 0; i < 6; i++ ) {
  644. if ( frontBits & (1<<(i+6)) ) {
  645. continue;
  646. }
  647. SIMDProcessor->Dot( planeSide, frustum[i], tri->verts, tri->numVerts );
  648. SIMDProcessor->CmpLT( side1, i, planeSide, LIGHT_CLIP_EPSILON, tri->numVerts );
  649. SIMDProcessor->CmpGT( side2, i, planeSide, -LIGHT_CLIP_EPSILON, tri->numVerts );
  650. }
  651. for ( i = 0; i < tri->numVerts; i++ ) {
  652. pointCull[i] |= side1[i] | (side2[i] << 6);
  653. }
  654. }
  655. /*
  656. =================
  657. R_CreateShadowVolumeInFrustum
  658. Adds new verts and indexes to the shadow volume.
  659. If the frustum completely defines the projected light,
  660. makeClippedPlanes should be true, which will cause sil quads to
  661. be added along all clipped edges.
  662. If the frustum is just part of a point light, clipped planes don't
  663. need to be added.
  664. =================
  665. */
  666. static void R_CreateShadowVolumeInFrustum( const idRenderEntityLocal *ent,
  667. const srfTriangles_t *tri,
  668. const idRenderLightLocal *light,
  669. const idVec3 lightOrigin,
  670. const idPlane frustum[6],
  671. const idPlane &farPlane,
  672. bool makeClippedPlanes ) {
  673. int i;
  674. int numTris;
  675. unsigned short *pointCull;
  676. int numCapIndexes;
  677. int firstShadowIndex;
  678. int firstShadowVert;
  679. int cullBits;
  680. pointCull = (unsigned short *)_alloca16( tri->numVerts * sizeof( pointCull[0] ) );
  681. // test the vertexes for inside the light frustum, which will allow
  682. // us to completely cull away some triangles from consideration.
  683. R_CalcPointCull( tri, frustum, pointCull );
  684. // this may not be the first frustum added to the volume
  685. firstShadowIndex = numShadowIndexes;
  686. firstShadowVert = numShadowVerts;
  687. // decide which triangles front shadow volumes, clipping as needed
  688. numClipSilEdges = 0;
  689. numTris = tri->numIndexes / 3;
  690. for ( i = 0 ; i < numTris ; i++ ) {
  691. int i1, i2, i3;
  692. faceCastsShadow[i] = 0; // until shown otherwise
  693. // if it isn't facing the right way, don't add it
  694. // to the shadow volume
  695. if ( globalFacing[i] ) {
  696. continue;
  697. }
  698. i1 = tri->silIndexes[ i*3 + 0 ];
  699. i2 = tri->silIndexes[ i*3 + 1 ];
  700. i3 = tri->silIndexes[ i*3 + 2 ];
  701. // if all the verts are off one side of the frustum,
  702. // don't add any of them
  703. if ( TRIANGLE_CULLED( i1, i2, i3 ) ) {
  704. continue;
  705. }
  706. // make sure the verts that are not on the negative sides
  707. // of the frustum are copied over.
  708. // we need to get the original verts even from clipped triangles
  709. // so the edges reference correctly, because an edge may be unclipped
  710. // even when a triangle is clipped.
  711. if ( numShadowVerts + 6 > MAX_SHADOW_VERTS ) {
  712. overflowed = true;
  713. return;
  714. }
  715. if ( !POINT_CULLED(i1) && remap[i1] == -1 ) {
  716. remap[i1] = numShadowVerts;
  717. shadowVerts[ numShadowVerts ].ToVec3() = tri->verts[i1].xyz;
  718. numShadowVerts+=2;
  719. }
  720. if ( !POINT_CULLED(i2) && remap[i2] == -1 ) {
  721. remap[i2] = numShadowVerts;
  722. shadowVerts[ numShadowVerts ].ToVec3() = tri->verts[i2].xyz;
  723. numShadowVerts+=2;
  724. }
  725. if ( !POINT_CULLED(i3) && remap[i3] == -1 ) {
  726. remap[i3] = numShadowVerts;
  727. shadowVerts[ numShadowVerts ].ToVec3() = tri->verts[i3].xyz;
  728. numShadowVerts+=2;
  729. }
  730. // clip the triangle if any points are on the negative sides
  731. if ( TRIANGLE_CLIPPED( i1, i2, i3 ) ) {
  732. cullBits = ( ( pointCull[ i1 ] ^ 0xfc0 ) | ( pointCull[ i2 ] ^ 0xfc0 ) | ( pointCull[ i3 ] ^ 0xfc0 ) ) >> 6;
  733. // this will also define clip edges that will become
  734. // silhouette planes
  735. if ( R_ClipTriangleToLight( tri->verts[i1].xyz, tri->verts[i2].xyz,
  736. tri->verts[i3].xyz, cullBits, frustum ) ) {
  737. faceCastsShadow[i] = 1;
  738. }
  739. } else {
  740. // instead of overflowing or drawing a streamer shadow, don't draw a shadow at all
  741. if ( numShadowIndexes + 3 > MAX_SHADOW_INDEXES ) {
  742. overflowed = true;
  743. return;
  744. }
  745. if ( remap[i1] == -1 || remap[i2] == -1 || remap[i3] == -1 ) {
  746. common->Error( "R_CreateShadowVolumeInFrustum: bad remap[]" );
  747. }
  748. shadowIndexes[numShadowIndexes++] = remap[i3];
  749. shadowIndexes[numShadowIndexes++] = remap[i2];
  750. shadowIndexes[numShadowIndexes++] = remap[i1];
  751. faceCastsShadow[i] = 1;
  752. }
  753. }
  754. // add indexes for the back caps, which will just be reversals of the
  755. // front caps using the back vertexes
  756. numCapIndexes = numShadowIndexes - firstShadowIndex;
  757. // if no faces have been defined for the shadow volume,
  758. // there won't be anything at all
  759. if ( numCapIndexes == 0 ) {
  760. return;
  761. }
  762. //--------------- off-line processing ------------------
  763. // if we are running from dmap, perform the (very) expensive shadow optimizations
  764. // to remove internal sil edges and optimize the caps
  765. if ( callOptimizer ) {
  766. optimizedShadow_t opt;
  767. // project all of the vertexes to the shadow plane, generating
  768. // an equal number of back vertexes
  769. // R_ProjectPointsToFarPlane( ent, light, farPlane, firstShadowVert, numShadowVerts );
  770. opt = SuperOptimizeOccluders( shadowVerts, shadowIndexes + firstShadowIndex, numCapIndexes, farPlane, lightOrigin );
  771. // pull off the non-optimized data
  772. numShadowIndexes = firstShadowIndex;
  773. numShadowVerts = firstShadowVert;
  774. // add the optimized data
  775. if ( numShadowIndexes + opt.totalIndexes > MAX_SHADOW_INDEXES
  776. || numShadowVerts + opt.numVerts > MAX_SHADOW_VERTS ) {
  777. overflowed = true;
  778. common->Printf( "WARNING: overflowed MAX_SHADOW tables, shadow discarded\n" );
  779. Mem_Free( opt.verts );
  780. Mem_Free( opt.indexes );
  781. return;
  782. }
  783. for ( i = 0 ; i < opt.numVerts ; i++ ) {
  784. shadowVerts[numShadowVerts+i][0] = opt.verts[i][0];
  785. shadowVerts[numShadowVerts+i][1] = opt.verts[i][1];
  786. shadowVerts[numShadowVerts+i][2] = opt.verts[i][2];
  787. shadowVerts[numShadowVerts+i][3] = 1;
  788. }
  789. for ( i = 0 ; i < opt.totalIndexes ; i++ ) {
  790. int index = opt.indexes[i];
  791. if ( index < 0 || index > opt.numVerts ) {
  792. common->Error( "optimized shadow index out of range" );
  793. }
  794. shadowIndexes[numShadowIndexes+i] = index + numShadowVerts;
  795. }
  796. numShadowVerts += opt.numVerts;
  797. numShadowIndexes += opt.totalIndexes;
  798. // note the index distribution so we can sort all the caps after all the sils
  799. indexRef[indexFrustumNumber].frontCapStart = firstShadowIndex;
  800. indexRef[indexFrustumNumber].rearCapStart = firstShadowIndex+opt.numFrontCapIndexes;
  801. indexRef[indexFrustumNumber].silStart = firstShadowIndex+opt.numFrontCapIndexes+opt.numRearCapIndexes;
  802. indexRef[indexFrustumNumber].end = numShadowIndexes;
  803. indexFrustumNumber++;
  804. Mem_Free( opt.verts );
  805. Mem_Free( opt.indexes );
  806. return;
  807. }
  808. //--------------- real-time processing ------------------
  809. // the dangling edge "face" is never considered to cast a shadow,
  810. // so any face with dangling edges that casts a shadow will have
  811. // it's dangling sil edge trigger a sil plane
  812. faceCastsShadow[numTris] = 0;
  813. // instead of overflowing or drawing a streamer shadow, don't draw a shadow at all
  814. // if we ran out of space
  815. if ( numShadowIndexes + numCapIndexes > MAX_SHADOW_INDEXES ) {
  816. overflowed = true;
  817. return;
  818. }
  819. for ( i = 0 ; i < numCapIndexes ; i += 3 ) {
  820. shadowIndexes[ numShadowIndexes + i + 0 ] = shadowIndexes[ firstShadowIndex + i + 2 ] + 1;
  821. shadowIndexes[ numShadowIndexes + i + 1 ] = shadowIndexes[ firstShadowIndex + i + 1 ] + 1;
  822. shadowIndexes[ numShadowIndexes + i + 2 ] = shadowIndexes[ firstShadowIndex + i + 0 ] + 1;
  823. }
  824. numShadowIndexes += numCapIndexes;
  825. c_caps += numCapIndexes * 2;
  826. int preSilIndexes = numShadowIndexes;
  827. // if any triangles were clipped, we will have a list of edges
  828. // on the frustum which must now become sil edges
  829. if ( makeClippedPlanes ) {
  830. R_AddClipSilEdges();
  831. }
  832. // any edges that are a transition between a shadowing and
  833. // non-shadowing triangle will cast a silhouette edge
  834. R_AddSilEdges( tri, pointCull, frustum );
  835. c_sils += numShadowIndexes - preSilIndexes;
  836. // project all of the vertexes to the shadow plane, generating
  837. // an equal number of back vertexes
  838. R_ProjectPointsToFarPlane( ent, light, farPlane, firstShadowVert, numShadowVerts );
  839. // note the index distribution so we can sort all the caps after all the sils
  840. indexRef[indexFrustumNumber].frontCapStart = firstShadowIndex;
  841. indexRef[indexFrustumNumber].rearCapStart = firstShadowIndex+numCapIndexes;
  842. indexRef[indexFrustumNumber].silStart = preSilIndexes;
  843. indexRef[indexFrustumNumber].end = numShadowIndexes;
  844. indexFrustumNumber++;
  845. }
  846. /*
  847. ===================
  848. R_MakeShadowFrustums
  849. Called at definition derivation time
  850. ===================
  851. */
  852. void R_MakeShadowFrustums( idRenderLightLocal *light ) {
  853. int i, j;
  854. if ( light->parms.pointLight ) {
  855. #if 0
  856. idVec3 adjustedRadius;
  857. // increase the light radius to cover any origin offsets.
  858. // this will cause some shadows to extend out of the exact light
  859. // volume, but is simpler than adjusting all the frustums
  860. adjustedRadius[0] = light->parms.lightRadius[0] + idMath::Fabs( light->parms.lightCenter[0] );
  861. adjustedRadius[1] = light->parms.lightRadius[1] + idMath::Fabs( light->parms.lightCenter[1] );
  862. adjustedRadius[2] = light->parms.lightRadius[2] + idMath::Fabs( light->parms.lightCenter[2] );
  863. light->numShadowFrustums = 0;
  864. // a point light has to project against six planes
  865. for ( i = 0 ; i < 6 ; i++ ) {
  866. shadowFrustum_t *frust = &light->shadowFrustums[ light->numShadowFrustums ];
  867. frust->numPlanes = 6;
  868. frust->makeClippedPlanes = false;
  869. for ( j = 0 ; j < 6 ; j++ ) {
  870. idPlane &plane = frust->planes[j];
  871. plane[0] = pointLightFrustums[i][j][0] / adjustedRadius[0];
  872. plane[1] = pointLightFrustums[i][j][1] / adjustedRadius[1];
  873. plane[2] = pointLightFrustums[i][j][2] / adjustedRadius[2];
  874. plane.Normalize();
  875. plane[3] = -( plane.Normal() * light->globalLightOrigin );
  876. if ( j == 5 ) {
  877. plane[3] += adjustedRadius[i>>1];
  878. }
  879. }
  880. light->numShadowFrustums++;
  881. }
  882. #else
  883. // exact projection,taking into account asymetric frustums when
  884. // globalLightOrigin isn't centered
  885. static int faceCorners[6][4] = {
  886. { 7, 5, 1, 3 }, // positive X side
  887. { 4, 6, 2, 0 }, // negative X side
  888. { 6, 7, 3, 2 }, // positive Y side
  889. { 5, 4, 0, 1 }, // negative Y side
  890. { 6, 4, 5, 7 }, // positive Z side
  891. { 3, 1, 0, 2 } // negative Z side
  892. };
  893. static int faceEdgeAdjacent[6][4] = {
  894. { 4, 4, 2, 2 }, // positive X side
  895. { 7, 7, 1, 1 }, // negative X side
  896. { 5, 5, 0, 0 }, // positive Y side
  897. { 6, 6, 3, 3 }, // negative Y side
  898. { 0, 0, 3, 3 }, // positive Z side
  899. { 5, 5, 6, 6 } // negative Z side
  900. };
  901. bool centerOutside = false;
  902. // if the light center of projection is outside the light bounds,
  903. // we will need to build the planes a little differently
  904. if ( fabs( light->parms.lightCenter[0] ) > light->parms.lightRadius[0]
  905. || fabs( light->parms.lightCenter[1] ) > light->parms.lightRadius[1]
  906. || fabs( light->parms.lightCenter[2] ) > light->parms.lightRadius[2] ) {
  907. centerOutside = true;
  908. }
  909. // make the corners
  910. idVec3 corners[8];
  911. for ( i = 0 ; i < 8 ; i++ ) {
  912. idVec3 temp;
  913. for ( j = 0 ; j < 3 ; j++ ) {
  914. if ( i & ( 1 << j ) ) {
  915. temp[j] = light->parms.lightRadius[j];
  916. } else {
  917. temp[j] = -light->parms.lightRadius[j];
  918. }
  919. }
  920. // transform to global space
  921. corners[i] = light->parms.origin + light->parms.axis * temp;
  922. }
  923. light->numShadowFrustums = 0;
  924. for ( int side = 0 ; side < 6 ; side++ ) {
  925. shadowFrustum_t *frust = &light->shadowFrustums[ light->numShadowFrustums ];
  926. idVec3 &p1 = corners[faceCorners[side][0]];
  927. idVec3 &p2 = corners[faceCorners[side][1]];
  928. idVec3 &p3 = corners[faceCorners[side][2]];
  929. idPlane backPlane;
  930. // plane will have positive side inward
  931. backPlane.FromPoints( p1, p2, p3 );
  932. // if center of projection is on the wrong side, skip
  933. float d = backPlane.Distance( light->globalLightOrigin );
  934. if ( d < 0 ) {
  935. continue;
  936. }
  937. frust->numPlanes = 6;
  938. frust->planes[5] = backPlane;
  939. frust->planes[4] = backPlane; // we don't really need the extra plane
  940. // make planes with positive side facing inwards in light local coordinates
  941. for ( int edge = 0 ; edge < 4 ; edge++ ) {
  942. idVec3 &p1 = corners[faceCorners[side][edge]];
  943. idVec3 &p2 = corners[faceCorners[side][(edge+1)&3]];
  944. // create a plane that goes through the center of projection
  945. frust->planes[edge].FromPoints( p2, p1, light->globalLightOrigin );
  946. // see if we should use an adjacent plane instead
  947. if ( centerOutside ) {
  948. idVec3 &p3 = corners[faceEdgeAdjacent[side][edge]];
  949. idPlane sidePlane;
  950. sidePlane.FromPoints( p2, p1, p3 );
  951. d = sidePlane.Distance( light->globalLightOrigin );
  952. if ( d < 0 ) {
  953. // use this plane instead of the edged plane
  954. frust->planes[edge] = sidePlane;
  955. }
  956. // we can't guarantee a neighbor, so add sill planes at edge
  957. light->shadowFrustums[ light->numShadowFrustums ].makeClippedPlanes = true;
  958. }
  959. }
  960. light->numShadowFrustums++;
  961. }
  962. #endif
  963. return;
  964. }
  965. // projected light
  966. light->numShadowFrustums = 1;
  967. shadowFrustum_t *frust = &light->shadowFrustums[ 0 ];
  968. // flip and transform the frustum planes so the positive side faces
  969. // inward in local coordinates
  970. // it is important to clip against even the near clip plane, because
  971. // many projected lights that are faking area lights will have their
  972. // origin behind solid surfaces.
  973. for ( i = 0 ; i < 6 ; i++ ) {
  974. idPlane &plane = frust->planes[i];
  975. plane.SetNormal( -light->frustum[i].Normal() );
  976. plane.SetDist( -light->frustum[i].Dist() );
  977. }
  978. frust->numPlanes = 6;
  979. frust->makeClippedPlanes = true;
  980. // projected lights don't have shared frustums, so any clipped edges
  981. // right on the planes must have a sil plane created for them
  982. }
  983. /*
  984. =================
  985. R_CreateShadowVolume
  986. The returned surface will have a valid bounds and radius for culling.
  987. Triangles are clipped to the light frustum before projecting.
  988. A single triangle can clip to as many as 7 vertexes, so
  989. the worst case expansion is 2*(numindexes/3)*7 verts when counting both
  990. the front and back caps, although it will usually only be a modest
  991. increase in vertexes for closed modesl
  992. The worst case index count is much larger, when the 7 vertex clipped triangle
  993. needs 15 indexes for the front, 15 for the back, and 42 (a quad on seven sides)
  994. for the sides, for a total of 72 indexes from the original 3. Ouch.
  995. NULL may be returned if the surface doesn't create a shadow volume at all,
  996. as with a single face that the light is behind.
  997. If an edge is within an epsilon of the border of the volume, it must be treated
  998. as if it is clipped for triangles, generating a new sil edge, and act
  999. as if it was culled for edges, because the sil edge will have been
  1000. generated by the triangle irregardless of if it actually was a sil edge.
  1001. =================
  1002. */
  1003. srfTriangles_t *R_CreateShadowVolume( const idRenderEntityLocal *ent,
  1004. const srfTriangles_t *tri, const idRenderLightLocal *light,
  1005. shadowGen_t optimize, srfCullInfo_t &cullInfo ) {
  1006. int i, j;
  1007. idVec3 lightOrigin;
  1008. srfTriangles_t *newTri;
  1009. int capPlaneBits;
  1010. if ( !r_shadows.GetBool() ) {
  1011. return NULL;
  1012. }
  1013. if ( tri->numSilEdges == 0 || tri->numIndexes == 0 || tri->numVerts == 0 ) {
  1014. return NULL;
  1015. }
  1016. if ( tri->numIndexes < 0 ) {
  1017. common->Error( "R_CreateShadowVolume: tri->numIndexes = %i", tri->numIndexes );
  1018. }
  1019. if ( tri->numVerts < 0 ) {
  1020. common->Error( "R_CreateShadowVolume: tri->numVerts = %i", tri->numVerts );
  1021. }
  1022. tr.pc.c_createShadowVolumes++;
  1023. // use the fast infinite projection in dynamic situations, which
  1024. // trades somewhat more overdraw and no cap optimizations for
  1025. // a very simple generation process
  1026. if ( optimize == SG_DYNAMIC && r_useTurboShadow.GetBool() ) {
  1027. if ( tr.backEndRendererHasVertexPrograms && r_useShadowVertexProgram.GetBool() ) {
  1028. return R_CreateVertexProgramTurboShadowVolume( ent, tri, light, cullInfo );
  1029. } else {
  1030. return R_CreateTurboShadowVolume( ent, tri, light, cullInfo );
  1031. }
  1032. }
  1033. R_CalcInteractionFacing( ent, tri, light, cullInfo );
  1034. int numFaces = tri->numIndexes / 3;
  1035. int allFront = 1;
  1036. for ( i = 0; i < numFaces && allFront; i++ ) {
  1037. allFront &= cullInfo.facing[i];
  1038. }
  1039. if ( allFront ) {
  1040. // if no faces are the right direction, don't make a shadow at all
  1041. return NULL;
  1042. }
  1043. // clear the shadow volume
  1044. numShadowIndexes = 0;
  1045. numShadowVerts = 0;
  1046. overflowed = false;
  1047. indexFrustumNumber = 0;
  1048. capPlaneBits = 0;
  1049. callOptimizer = (optimize == SG_OFFLINE);
  1050. // the facing information will be the same for all six projections
  1051. // from a point light, as well as for any directed lights
  1052. globalFacing = cullInfo.facing;
  1053. faceCastsShadow = (byte *)_alloca16( tri->numIndexes / 3 + 1 ); // + 1 for fake dangling edge face
  1054. remap = (int *)_alloca16( tri->numVerts * sizeof( remap[0] ) );
  1055. R_GlobalPointToLocal( ent->modelMatrix, light->globalLightOrigin, lightOrigin );
  1056. // run through all the shadow frustums, which is one for a projected light,
  1057. // and usually six for a point light, but point lights with centers outside
  1058. // the box may have less
  1059. for ( int frustumNum = 0 ; frustumNum < light->numShadowFrustums ; frustumNum++ ) {
  1060. const shadowFrustum_t *frust = &light->shadowFrustums[frustumNum];
  1061. ALIGN16( idPlane frustum[6] );
  1062. // transform the planes into entity space
  1063. // we could share and reverse some of the planes between frustums for a minor
  1064. // speed increase
  1065. // the cull test is redundant for a single shadow frustum projected light, because
  1066. // the surface has already been checked against the main light frustums
  1067. for ( j = 0 ; j < frust->numPlanes ; j++ ) {
  1068. R_GlobalPlaneToLocal( ent->modelMatrix, frust->planes[j], frustum[j] );
  1069. // try to cull the entire surface against this frustum
  1070. float d = tri->bounds.PlaneDistance( frustum[j] );
  1071. if ( d < -LIGHT_CLIP_EPSILON ) {
  1072. break;
  1073. }
  1074. }
  1075. if ( j != frust->numPlanes ) {
  1076. continue;
  1077. }
  1078. // we need to check all the triangles
  1079. int oldFrustumNumber = indexFrustumNumber;
  1080. R_CreateShadowVolumeInFrustum( ent, tri, light, lightOrigin, frustum, frustum[5], frust->makeClippedPlanes );
  1081. // if we couldn't make a complete shadow volume, it is better to
  1082. // not draw one at all, avoiding streamer problems
  1083. if ( overflowed ) {
  1084. return NULL;
  1085. }
  1086. if ( indexFrustumNumber != oldFrustumNumber ) {
  1087. // note that we have caps projected against this frustum,
  1088. // which may allow us to skip drawing the caps if all projected
  1089. // planes face away from the viewer and the viewer is outside the light volume
  1090. capPlaneBits |= 1<<frustumNum;
  1091. }
  1092. }
  1093. // if no faces have been defined for the shadow volume,
  1094. // there won't be anything at all
  1095. if ( numShadowIndexes == 0 ) {
  1096. return NULL;
  1097. }
  1098. // this should have been prevented by the overflowed flag, so if it ever happens,
  1099. // it is a code error
  1100. if ( numShadowVerts > MAX_SHADOW_VERTS || numShadowIndexes > MAX_SHADOW_INDEXES ) {
  1101. common->FatalError( "Shadow volume exceeded allocation" );
  1102. }
  1103. // allocate a new surface for the shadow volume
  1104. newTri = R_AllocStaticTriSurf();
  1105. // we might consider setting this, but it would only help for
  1106. // large lights that are partially off screen
  1107. newTri->bounds.Clear();
  1108. // copy off the verts and indexes
  1109. newTri->numVerts = numShadowVerts;
  1110. newTri->numIndexes = numShadowIndexes;
  1111. // the shadow verts will go into a main memory buffer as well as a vertex
  1112. // cache buffer, so they can be copied back if they are purged
  1113. R_AllocStaticTriSurfShadowVerts( newTri, newTri->numVerts );
  1114. SIMDProcessor->Memcpy( newTri->shadowVertexes, shadowVerts, newTri->numVerts * sizeof( newTri->shadowVertexes[0] ) );
  1115. R_AllocStaticTriSurfIndexes( newTri, newTri->numIndexes );
  1116. if ( 1 /* sortCapIndexes */ ) {
  1117. newTri->shadowCapPlaneBits = capPlaneBits;
  1118. // copy the sil indexes first
  1119. newTri->numShadowIndexesNoCaps = 0;
  1120. for ( i = 0 ; i < indexFrustumNumber ; i++ ) {
  1121. int c = indexRef[i].end - indexRef[i].silStart;
  1122. SIMDProcessor->Memcpy( newTri->indexes+newTri->numShadowIndexesNoCaps,
  1123. shadowIndexes+indexRef[i].silStart, c * sizeof( newTri->indexes[0] ) );
  1124. newTri->numShadowIndexesNoCaps += c;
  1125. }
  1126. // copy rear cap indexes next
  1127. newTri->numShadowIndexesNoFrontCaps = newTri->numShadowIndexesNoCaps;
  1128. for ( i = 0 ; i < indexFrustumNumber ; i++ ) {
  1129. int c = indexRef[i].silStart - indexRef[i].rearCapStart;
  1130. SIMDProcessor->Memcpy( newTri->indexes+newTri->numShadowIndexesNoFrontCaps,
  1131. shadowIndexes+indexRef[i].rearCapStart, c * sizeof( newTri->indexes[0] ) );
  1132. newTri->numShadowIndexesNoFrontCaps += c;
  1133. }
  1134. // copy front cap indexes last
  1135. newTri->numIndexes = newTri->numShadowIndexesNoFrontCaps;
  1136. for ( i = 0 ; i < indexFrustumNumber ; i++ ) {
  1137. int c = indexRef[i].rearCapStart - indexRef[i].frontCapStart;
  1138. SIMDProcessor->Memcpy( newTri->indexes+newTri->numIndexes,
  1139. shadowIndexes+indexRef[i].frontCapStart, c * sizeof( newTri->indexes[0] ) );
  1140. newTri->numIndexes += c;
  1141. }
  1142. } else {
  1143. newTri->shadowCapPlaneBits = 63; // we don't have optimized index lists
  1144. SIMDProcessor->Memcpy( newTri->indexes, shadowIndexes, newTri->numIndexes * sizeof( newTri->indexes[0] ) );
  1145. }
  1146. if ( optimize == SG_OFFLINE ) {
  1147. CleanupOptimizedShadowTris( newTri );
  1148. }
  1149. return newTri;
  1150. }