ModelDecal.cpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809
  1. /*
  2. ===========================================================================
  3. Doom 3 BFG Edition GPL Source Code
  4. Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
  6. Doom 3 BFG Edition 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 BFG Edition 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 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 BFG Edition 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 BFG Edition 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. #pragma hdrstop
  21. #include "../idlib/precompiled.h"
  22. #include "tr_local.h"
  23. #include "Model_local.h"
  24. #include "../idlib/geometry/DrawVert_intrinsics.h"
  25. // decalFade filter 5 0.1
  26. // polygonOffset
  27. // {
  28. // map invertColor( textures/splat )
  29. // blend GL_ZERO GL_ONE_MINUS_SRC
  30. // vertexColor
  31. // clamp
  32. // }
  33. /*
  34. ==================
  35. idRenderModelDecal::idRenderModelDecal
  36. ==================
  37. */
  38. idRenderModelDecal::idRenderModelDecal() :
  39. firstDecal( 0 ),
  40. nextDecal( 0 ),
  41. firstDeferredDecal( 0 ),
  42. nextDeferredDecal( 0 ),
  43. numDecalMaterials( 0 ) {
  44. }
  45. /*
  46. ==================
  47. idRenderModelDecal::~idRenderModelDecal
  48. ==================
  49. */
  50. idRenderModelDecal::~idRenderModelDecal() {
  51. }
  52. /*
  53. =================
  54. idRenderModelDecal::CreateProjectionParms
  55. =================
  56. */
  57. bool idRenderModelDecal::CreateProjectionParms( decalProjectionParms_t &parms, const idFixedWinding &winding, const idVec3 &projectionOrigin, const bool parallel, const float fadeDepth, const idMaterial *material, const int startTime ) {
  58. if ( winding.GetNumPoints() != NUM_DECAL_BOUNDING_PLANES - 2 ) {
  59. common->Printf( "idRenderModelDecal::CreateProjectionInfo: winding must have %d points\n", NUM_DECAL_BOUNDING_PLANES - 2 );
  60. return false;
  61. }
  62. assert( material != NULL );
  63. parms.projectionOrigin = projectionOrigin;
  64. parms.material = material;
  65. parms.parallel = parallel;
  66. parms.fadeDepth = fadeDepth;
  67. parms.startTime = startTime;
  68. parms.force = false;
  69. // get the winding plane and the depth of the projection volume
  70. idPlane windingPlane;
  71. winding.GetPlane( windingPlane );
  72. float depth = windingPlane.Distance( projectionOrigin );
  73. // find the bounds for the projection
  74. winding.GetBounds( parms.projectionBounds );
  75. if ( parallel ) {
  76. parms.projectionBounds.ExpandSelf( depth );
  77. } else {
  78. parms.projectionBounds.AddPoint( projectionOrigin );
  79. }
  80. // calculate the world space projection volume bounding planes, positive sides face outside the decal
  81. if ( parallel ) {
  82. for ( int i = 0; i < winding.GetNumPoints(); i++ ) {
  83. idVec3 edge = winding[( i + 1 ) % winding.GetNumPoints()].ToVec3() - winding[i].ToVec3();
  84. parms.boundingPlanes[i].Normal().Cross( windingPlane.Normal(), edge );
  85. parms.boundingPlanes[i].Normalize();
  86. parms.boundingPlanes[i].FitThroughPoint( winding[i].ToVec3() );
  87. }
  88. } else {
  89. for ( int i = 0; i < winding.GetNumPoints(); i++ ) {
  90. parms.boundingPlanes[i].FromPoints( projectionOrigin, winding[i].ToVec3(), winding[(i+1)%winding.GetNumPoints()].ToVec3() );
  91. }
  92. }
  93. parms.boundingPlanes[NUM_DECAL_BOUNDING_PLANES - 2] = windingPlane;
  94. parms.boundingPlanes[NUM_DECAL_BOUNDING_PLANES - 2][3] -= depth;
  95. parms.boundingPlanes[NUM_DECAL_BOUNDING_PLANES - 1] = -windingPlane;
  96. // fades will be from these plane
  97. parms.fadePlanes[0] = windingPlane;
  98. parms.fadePlanes[0][3] -= fadeDepth;
  99. parms.fadePlanes[1] = -windingPlane;
  100. parms.fadePlanes[1][3] += depth - fadeDepth;
  101. // calculate the texture vectors for the winding
  102. float len, texArea, inva;
  103. idVec3 temp;
  104. idVec5 d0, d1;
  105. const idVec5 &a = winding[0];
  106. const idVec5 &b = winding[1];
  107. const idVec5 &c = winding[2];
  108. d0 = b.ToVec3() - a.ToVec3();
  109. d0.s = b.s - a.s;
  110. d0.t = b.t - a.t;
  111. d1 = c.ToVec3() - a.ToVec3();
  112. d1.s = c.s - a.s;
  113. d1.t = c.t - a.t;
  114. texArea = ( d0[3] * d1[4] ) - ( d0[4] * d1[3] );
  115. inva = 1.0f / texArea;
  116. temp[0] = ( d0[0] * d1[4] - d0[4] * d1[0] ) * inva;
  117. temp[1] = ( d0[1] * d1[4] - d0[4] * d1[1] ) * inva;
  118. temp[2] = ( d0[2] * d1[4] - d0[4] * d1[2] ) * inva;
  119. len = temp.Normalize();
  120. parms.textureAxis[0].Normal() = temp * ( 1.0f / len );
  121. parms.textureAxis[0][3] = winding[0].s - ( winding[0].ToVec3() * parms.textureAxis[0].Normal() );
  122. temp[0] = ( d0[3] * d1[0] - d0[0] * d1[3] ) * inva;
  123. temp[1] = ( d0[3] * d1[1] - d0[1] * d1[3] ) * inva;
  124. temp[2] = ( d0[3] * d1[2] - d0[2] * d1[3] ) * inva;
  125. len = temp.Normalize();
  126. parms.textureAxis[1].Normal() = temp * ( 1.0f / len );
  127. parms.textureAxis[1][3] = winding[0].t - ( winding[0].ToVec3() * parms.textureAxis[1].Normal() );
  128. return true;
  129. }
  130. /*
  131. =================
  132. idRenderModelDecal::GlobalProjectionParmsToLocal
  133. =================
  134. */
  135. void idRenderModelDecal::GlobalProjectionParmsToLocal( decalProjectionParms_t &localParms, const decalProjectionParms_t &globalParms, const idVec3 &origin, const idMat3 &axis ) {
  136. float modelMatrix[16];
  137. R_AxisToModelMatrix( axis, origin, modelMatrix );
  138. for ( int j = 0; j < NUM_DECAL_BOUNDING_PLANES; j++ ) {
  139. R_GlobalPlaneToLocal( modelMatrix, globalParms.boundingPlanes[j], localParms.boundingPlanes[j] );
  140. }
  141. R_GlobalPlaneToLocal( modelMatrix, globalParms.fadePlanes[0], localParms.fadePlanes[0] );
  142. R_GlobalPlaneToLocal( modelMatrix, globalParms.fadePlanes[1], localParms.fadePlanes[1] );
  143. R_GlobalPlaneToLocal( modelMatrix, globalParms.textureAxis[0], localParms.textureAxis[0] );
  144. R_GlobalPlaneToLocal( modelMatrix, globalParms.textureAxis[1], localParms.textureAxis[1] );
  145. R_GlobalPointToLocal( modelMatrix, globalParms.projectionOrigin, localParms.projectionOrigin );
  146. localParms.projectionBounds = globalParms.projectionBounds;
  147. localParms.projectionBounds.TranslateSelf( -origin );
  148. localParms.projectionBounds.RotateSelf( axis.Transpose() );
  149. localParms.material = globalParms.material;
  150. localParms.parallel = globalParms.parallel;
  151. localParms.fadeDepth = globalParms.fadeDepth;
  152. localParms.startTime = globalParms.startTime;
  153. localParms.force = globalParms.force;
  154. }
  155. /*
  156. =================
  157. idRenderModelDecal::ReUse
  158. =================
  159. */
  160. void idRenderModelDecal::ReUse() {
  161. firstDecal = 0;
  162. nextDecal = 0;
  163. firstDeferredDecal = 0;
  164. nextDeferredDecal = 0;
  165. numDecalMaterials = 0;
  166. }
  167. /*
  168. =================
  169. idRenderModelDecal::CreateDecalFromWinding
  170. =================
  171. */
  172. void idRenderModelDecal::CreateDecalFromWinding( const idWinding &w, const idMaterial *decalMaterial, const idPlane fadePlanes[2], float fadeDepth, int startTime ) {
  173. // Often we are appending a new triangle to an existing decal, so merge with the previous decal if possible
  174. int decalIndex = ( nextDecal - 1 ) & ( MAX_DECALS - 1 );
  175. if ( decalIndex >= 0
  176. && decals[decalIndex].material == decalMaterial
  177. && decals[decalIndex].startTime == startTime
  178. && decals[decalIndex].numVerts + w.GetNumPoints() <= MAX_DECAL_VERTS
  179. && decals[decalIndex].numIndexes + 3 * ( w.GetNumPoints() - 2 ) <= MAX_DECAL_INDEXES ) {
  180. } else {
  181. decalIndex = nextDecal++ & ( MAX_DECALS - 1 );
  182. decals[decalIndex].material = decalMaterial;
  183. decals[decalIndex].startTime = startTime;
  184. decals[decalIndex].numVerts = 0;
  185. decals[decalIndex].numIndexes = 0;
  186. assert( w.GetNumPoints() <= MAX_DECAL_VERTS );
  187. if ( nextDecal - firstDecal > MAX_DECALS ) {
  188. firstDecal = nextDecal - MAX_DECALS;
  189. }
  190. }
  191. decal_t & decal = decals[decalIndex];
  192. const float invFadeDepth = -1.0f / fadeDepth;
  193. int firstVert = decal.numVerts;
  194. // create the vertices
  195. for ( int i = 0; i < w.GetNumPoints(); i++ ) {
  196. float depthFade = fadePlanes[0].Distance( w[i].ToVec3() ) * invFadeDepth;
  197. if ( depthFade < 0.0f ) {
  198. depthFade = fadePlanes[1].Distance( w[i].ToVec3() ) * invFadeDepth;
  199. }
  200. if ( depthFade < 0.0f ) {
  201. depthFade = 0.0f;
  202. } else if ( depthFade > 0.99f ) {
  203. depthFade = 1.0f;
  204. }
  205. decal.vertDepthFade[decal.numVerts] = 1.0f - depthFade;
  206. decal.verts[decal.numVerts].Clear();
  207. decal.verts[decal.numVerts].xyz = w[i].ToVec3();
  208. decal.verts[decal.numVerts].SetTexCoord( w[i].s, w[i].t );
  209. decal.numVerts++;
  210. }
  211. // create the indexes
  212. for ( int i = 2; i < w.GetNumPoints(); i++ ) {
  213. assert( decal.numIndexes + 3 <= MAX_DECAL_INDEXES );
  214. decal.indexes[decal.numIndexes + 0] = firstVert;
  215. decal.indexes[decal.numIndexes + 1] = firstVert + i - 1;
  216. decal.indexes[decal.numIndexes + 2] = firstVert + i;
  217. decal.numIndexes += 3;
  218. }
  219. // add degenerate triangles until the index size is a multiple of 16 bytes
  220. for ( ; ( ( ( decal.numIndexes * sizeof( triIndex_t ) ) & 15 ) != 0 ); decal.numIndexes += 3 ) {
  221. assert( decal.numIndexes + 3 <= MAX_DECAL_INDEXES );
  222. decal.indexes[decal.numIndexes + 0] = 0;
  223. decal.indexes[decal.numIndexes + 1] = 0;
  224. decal.indexes[decal.numIndexes + 2] = 0;
  225. }
  226. }
  227. /*
  228. ============
  229. R_DecalPointCullStatic
  230. ============
  231. */
  232. static void R_DecalPointCullStatic( byte * cullBits, const idPlane * planes, const idDrawVert * verts, const int numVerts ) {
  233. assert_16_byte_aligned( cullBits );
  234. assert_16_byte_aligned( verts );
  235. #ifdef ID_WIN_X86_SSE2_INTRIN
  236. idODSStreamedArray< idDrawVert, 16, SBT_DOUBLE, 4 > vertsODS( verts, numVerts );
  237. const __m128 vector_float_zero = { 0.0f, 0.0f, 0.0f, 0.0f };
  238. const __m128i vector_int_mask0 = _mm_set1_epi32( 1 << 0 );
  239. const __m128i vector_int_mask1 = _mm_set1_epi32( 1 << 1 );
  240. const __m128i vector_int_mask2 = _mm_set1_epi32( 1 << 2 );
  241. const __m128i vector_int_mask3 = _mm_set1_epi32( 1 << 3 );
  242. const __m128i vector_int_mask4 = _mm_set1_epi32( 1 << 4 );
  243. const __m128i vector_int_mask5 = _mm_set1_epi32( 1 << 5 );
  244. const __m128 p0 = _mm_loadu_ps( planes[0].ToFloatPtr() );
  245. const __m128 p1 = _mm_loadu_ps( planes[1].ToFloatPtr() );
  246. const __m128 p2 = _mm_loadu_ps( planes[2].ToFloatPtr() );
  247. const __m128 p3 = _mm_loadu_ps( planes[3].ToFloatPtr() );
  248. const __m128 p4 = _mm_loadu_ps( planes[4].ToFloatPtr() );
  249. const __m128 p5 = _mm_loadu_ps( planes[5].ToFloatPtr() );
  250. const __m128 p0X = _mm_splat_ps( p0, 0 );
  251. const __m128 p0Y = _mm_splat_ps( p0, 1 );
  252. const __m128 p0Z = _mm_splat_ps( p0, 2 );
  253. const __m128 p0W = _mm_splat_ps( p0, 3 );
  254. const __m128 p1X = _mm_splat_ps( p1, 0 );
  255. const __m128 p1Y = _mm_splat_ps( p1, 1 );
  256. const __m128 p1Z = _mm_splat_ps( p1, 2 );
  257. const __m128 p1W = _mm_splat_ps( p1, 3 );
  258. const __m128 p2X = _mm_splat_ps( p2, 0 );
  259. const __m128 p2Y = _mm_splat_ps( p2, 1 );
  260. const __m128 p2Z = _mm_splat_ps( p2, 2 );
  261. const __m128 p2W = _mm_splat_ps( p2, 3 );
  262. const __m128 p3X = _mm_splat_ps( p3, 0 );
  263. const __m128 p3Y = _mm_splat_ps( p3, 1 );
  264. const __m128 p3Z = _mm_splat_ps( p3, 2 );
  265. const __m128 p3W = _mm_splat_ps( p3, 3 );
  266. const __m128 p4X = _mm_splat_ps( p4, 0 );
  267. const __m128 p4Y = _mm_splat_ps( p4, 1 );
  268. const __m128 p4Z = _mm_splat_ps( p4, 2 );
  269. const __m128 p4W = _mm_splat_ps( p4, 3 );
  270. const __m128 p5X = _mm_splat_ps( p5, 0 );
  271. const __m128 p5Y = _mm_splat_ps( p5, 1 );
  272. const __m128 p5Z = _mm_splat_ps( p5, 2 );
  273. const __m128 p5W = _mm_splat_ps( p5, 3 );
  274. for ( int i = 0; i < numVerts; ) {
  275. const int nextNumVerts = vertsODS.FetchNextBatch() - 4;
  276. for ( ; i <= nextNumVerts; i += 4 ) {
  277. const __m128 v0 = _mm_load_ps( vertsODS[i + 0].xyz.ToFloatPtr() );
  278. const __m128 v1 = _mm_load_ps( vertsODS[i + 1].xyz.ToFloatPtr() );
  279. const __m128 v2 = _mm_load_ps( vertsODS[i + 2].xyz.ToFloatPtr() );
  280. const __m128 v3 = _mm_load_ps( vertsODS[i + 3].xyz.ToFloatPtr() );
  281. const __m128 r0 = _mm_unpacklo_ps( v0, v2 ); // v0.x, v2.x, v0.z, v2.z
  282. const __m128 r1 = _mm_unpackhi_ps( v0, v2 ); // v0.y, v2.y, v0.w, v2.w
  283. const __m128 r2 = _mm_unpacklo_ps( v1, v3 ); // v1.x, v3.x, v1.z, v3.z
  284. const __m128 r3 = _mm_unpackhi_ps( v1, v3 ); // v1.y, v3.y, v1.w, v3.w
  285. const __m128 vX = _mm_unpacklo_ps( r0, r2 ); // v0.x, v1.x, v2.x, v3.x
  286. const __m128 vY = _mm_unpackhi_ps( r0, r2 ); // v0.y, v1.y, v2.y, v3.y
  287. const __m128 vZ = _mm_unpacklo_ps( r1, r3 ); // v0.z, v1.z, v2.z, v3.z
  288. const __m128 d0 = _mm_madd_ps( vX, p0X, _mm_madd_ps( vY, p0Y, _mm_madd_ps( vZ, p0Z, p0W ) ) );
  289. const __m128 d1 = _mm_madd_ps( vX, p1X, _mm_madd_ps( vY, p1Y, _mm_madd_ps( vZ, p1Z, p1W ) ) );
  290. const __m128 d2 = _mm_madd_ps( vX, p2X, _mm_madd_ps( vY, p2Y, _mm_madd_ps( vZ, p2Z, p2W ) ) );
  291. const __m128 d3 = _mm_madd_ps( vX, p3X, _mm_madd_ps( vY, p3Y, _mm_madd_ps( vZ, p3Z, p3W ) ) );
  292. const __m128 d4 = _mm_madd_ps( vX, p4X, _mm_madd_ps( vY, p4Y, _mm_madd_ps( vZ, p4Z, p4W ) ) );
  293. const __m128 d5 = _mm_madd_ps( vX, p5X, _mm_madd_ps( vY, p5Y, _mm_madd_ps( vZ, p5Z, p5W ) ) );
  294. __m128i c0 = __m128c( _mm_cmpgt_ps( d0, vector_float_zero ) );
  295. __m128i c1 = __m128c( _mm_cmpgt_ps( d1, vector_float_zero ) );
  296. __m128i c2 = __m128c( _mm_cmpgt_ps( d2, vector_float_zero ) );
  297. __m128i c3 = __m128c( _mm_cmpgt_ps( d3, vector_float_zero ) );
  298. __m128i c4 = __m128c( _mm_cmpgt_ps( d4, vector_float_zero ) );
  299. __m128i c5 = __m128c( _mm_cmpgt_ps( d5, vector_float_zero ) );
  300. c0 = _mm_and_si128( c0, vector_int_mask0 );
  301. c1 = _mm_and_si128( c1, vector_int_mask1 );
  302. c2 = _mm_and_si128( c2, vector_int_mask2 );
  303. c3 = _mm_and_si128( c3, vector_int_mask3 );
  304. c4 = _mm_and_si128( c4, vector_int_mask4 );
  305. c5 = _mm_and_si128( c5, vector_int_mask5 );
  306. c0 = _mm_or_si128( c0, c1 );
  307. c2 = _mm_or_si128( c2, c3 );
  308. c4 = _mm_or_si128( c4, c5 );
  309. c0 = _mm_or_si128( c0, c2 );
  310. c0 = _mm_or_si128( c0, c4 );
  311. __m128i s0 = _mm_packs_epi32( c0, c0 );
  312. __m128i b0 = _mm_packus_epi16( s0, s0 );
  313. *(unsigned int *)&cullBits[i] = _mm_cvtsi128_si32( b0 );
  314. }
  315. }
  316. #else
  317. idODSStreamedArray< idDrawVert, 16, SBT_DOUBLE, 1 > vertsODS( verts, numVerts );
  318. for ( int i = 0; i < numVerts; ) {
  319. const int nextNumVerts = vertsODS.FetchNextBatch() - 1;
  320. for ( ; i <= nextNumVerts; i++ ) {
  321. const idVec3 & v = vertsODS[i].xyz;
  322. const float d0 = planes[0].Distance( v );
  323. const float d1 = planes[1].Distance( v );
  324. const float d2 = planes[2].Distance( v );
  325. const float d3 = planes[3].Distance( v );
  326. const float d4 = planes[4].Distance( v );
  327. const float d5 = planes[5].Distance( v );
  328. byte bits;
  329. bits = IEEE_FLT_SIGNBITNOTSET( d0 ) << 0;
  330. bits |= IEEE_FLT_SIGNBITNOTSET( d1 ) << 1;
  331. bits |= IEEE_FLT_SIGNBITNOTSET( d2 ) << 2;
  332. bits |= IEEE_FLT_SIGNBITNOTSET( d3 ) << 3;
  333. bits |= IEEE_FLT_SIGNBITNOTSET( d4 ) << 4;
  334. bits |= IEEE_FLT_SIGNBITNOTSET( d5 ) << 5;
  335. cullBits[i] = bits;
  336. }
  337. }
  338. #endif
  339. }
  340. /*
  341. =================
  342. idRenderModelDecal::CreateDecal
  343. =================
  344. */
  345. void idRenderModelDecal::CreateDecal( const idRenderModel *model, const decalProjectionParms_t &localParms ) {
  346. int maxVerts = 0;
  347. for ( int surfNum = 0; surfNum < model->NumSurfaces(); surfNum++ ) {
  348. const modelSurface_t *surf = model->Surface( surfNum );
  349. if ( surf->geometry != NULL && surf->shader != NULL ) {
  350. maxVerts = Max( maxVerts, surf->geometry->numVerts );
  351. }
  352. }
  353. idTempArray< byte > cullBits( ALIGN( maxVerts, 4 ) );
  354. // check all model surfaces
  355. for ( int surfNum = 0; surfNum < model->NumSurfaces(); surfNum++ ) {
  356. const modelSurface_t *surf = model->Surface( surfNum );
  357. // if no geometry or no shader
  358. if ( surf->geometry == NULL || surf->shader == NULL ) {
  359. continue;
  360. }
  361. // decals and overlays use the same rules
  362. if ( !localParms.force && !surf->shader->AllowOverlays() ) {
  363. continue;
  364. }
  365. srfTriangles_t *tri = surf->geometry;
  366. // if the triangle bounds do not overlap with the projection bounds
  367. if ( !localParms.projectionBounds.IntersectsBounds( tri->bounds ) ) {
  368. continue;
  369. }
  370. // decals don't work on animated models
  371. assert( tri->staticModelWithJoints == NULL );
  372. // catagorize all points by the planes
  373. R_DecalPointCullStatic( cullBits.Ptr(), localParms.boundingPlanes, tri->verts, tri->numVerts );
  374. // start streaming the indexes
  375. idODSStreamedArray< triIndex_t, 256, SBT_QUAD, 3 > indexesODS( tri->indexes, tri->numIndexes );
  376. // find triangles inside the projection volume
  377. for ( int i = 0; i < tri->numIndexes; ) {
  378. const int nextNumIndexes = indexesODS.FetchNextBatch() - 3;
  379. for ( ; i <= nextNumIndexes; i += 3 ) {
  380. const int i0 = indexesODS[i + 0];
  381. const int i1 = indexesODS[i + 1];
  382. const int i2 = indexesODS[i + 2];
  383. // skip triangles completely off one side
  384. if ( cullBits[i0] & cullBits[i1] & cullBits[i2] ) {
  385. continue;
  386. }
  387. const idDrawVert * verts[3] = {
  388. &tri->verts[i0],
  389. &tri->verts[i1],
  390. &tri->verts[i2]
  391. };
  392. // skip back facing triangles
  393. const idPlane plane( verts[0]->xyz, verts[1]->xyz, verts[2]->xyz );
  394. if ( plane.Normal() * localParms.boundingPlanes[NUM_DECAL_BOUNDING_PLANES - 2].Normal() < -0.1f ) {
  395. continue;
  396. }
  397. // create a winding with texture coordinates for the triangle
  398. idFixedWinding fw;
  399. fw.SetNumPoints( 3 );
  400. if ( localParms.parallel ) {
  401. for ( int j = 0; j < 3; j++ ) {
  402. fw[j] = verts[j]->xyz;
  403. fw[j].s = localParms.textureAxis[0].Distance( verts[j]->xyz );
  404. fw[j].t = localParms.textureAxis[1].Distance( verts[j]->xyz );
  405. }
  406. } else {
  407. for ( int j = 0; j < 3; j++ ) {
  408. const idVec3 dir = verts[j]->xyz - localParms.projectionOrigin;
  409. float scale;
  410. localParms.boundingPlanes[NUM_DECAL_BOUNDING_PLANES - 1].RayIntersection( verts[j]->xyz, dir, scale );
  411. const idVec3 intersection = verts[j]->xyz + scale * dir;
  412. fw[j] = verts[j]->xyz;
  413. fw[j].s = localParms.textureAxis[0].Distance( intersection );
  414. fw[j].t = localParms.textureAxis[1].Distance( intersection );
  415. }
  416. }
  417. const int orBits = cullBits[i0] | cullBits[i1] | cullBits[i2];
  418. // clip the exact surface triangle to the projection volume
  419. for ( int j = 0; j < NUM_DECAL_BOUNDING_PLANES; j++ ) {
  420. if ( ( orBits & ( 1 << j ) ) != 0 ) {
  421. if ( !fw.ClipInPlace( -localParms.boundingPlanes[j] ) ) {
  422. break;
  423. }
  424. }
  425. }
  426. // if there is a part of the triangle between the bounding planes then clip
  427. // the triangle based on depth and add decals for the depth faded parts
  428. if ( fw.GetNumPoints() != 0 ) {
  429. idFixedWinding back;
  430. if ( fw.Split( &back, localParms.fadePlanes[0], 0.1f ) == SIDE_CROSS ) {
  431. CreateDecalFromWinding( back, localParms.material, localParms.fadePlanes, localParms.fadeDepth, localParms.startTime );
  432. }
  433. if ( fw.Split( &back, localParms.fadePlanes[1], 0.1f ) == SIDE_CROSS ) {
  434. CreateDecalFromWinding( back, localParms.material, localParms.fadePlanes, localParms.fadeDepth, localParms.startTime );
  435. }
  436. CreateDecalFromWinding( fw, localParms.material, localParms.fadePlanes, localParms.fadeDepth, localParms.startTime );
  437. }
  438. }
  439. }
  440. }
  441. }
  442. /*
  443. =====================
  444. idRenderModelDecal::CreateDeferredDecals
  445. =====================
  446. */
  447. void idRenderModelDecal::CreateDeferredDecals( const idRenderModel *model ) {
  448. for ( unsigned int i = firstDeferredDecal; i < nextDeferredDecal; i++ ) {
  449. decalProjectionParms_t & parms = deferredDecals[i & ( MAX_DEFERRED_DECALS - 1 )];
  450. if ( parms.startTime > tr.viewDef->renderView.time[0] - DEFFERED_DECAL_TIMEOUT ) {
  451. CreateDecal( model, parms );
  452. }
  453. }
  454. firstDeferredDecal = 0;
  455. nextDeferredDecal = 0;
  456. }
  457. /*
  458. =====================
  459. idRenderModelDecal::AddDeferredDecal
  460. =====================
  461. */
  462. void idRenderModelDecal::AddDeferredDecal( const decalProjectionParms_t &localParms ) {
  463. deferredDecals[nextDeferredDecal++ & ( MAX_DEFERRED_DECALS - 1 )] = localParms;
  464. if ( nextDeferredDecal - firstDeferredDecal > MAX_DEFERRED_DECALS ) {
  465. firstDeferredDecal = nextDeferredDecal - MAX_DEFERRED_DECALS;
  466. }
  467. }
  468. /*
  469. =====================
  470. idRenderModelDecal::RemoveFadedDecals
  471. =====================
  472. */
  473. void idRenderModelDecal::RemoveFadedDecals( int time ) {
  474. for ( unsigned int i = firstDecal; i < nextDecal; i++ ) {
  475. decal_t & decal = decals[i & ( MAX_DECALS - 1 )];
  476. const decalInfo_t decalInfo = decal.material->GetDecalInfo();
  477. const int minTime = time - ( decalInfo.stayTime + decalInfo.fadeTime );
  478. if ( decal.startTime <= minTime ) {
  479. decal.numVerts = 0;
  480. decal.numIndexes = 0;
  481. if ( i == firstDecal ) {
  482. firstDecal++;
  483. }
  484. }
  485. }
  486. if ( firstDecal == nextDecal ) {
  487. firstDecal = 0;
  488. nextDecal = 0;
  489. }
  490. }
  491. /*
  492. =====================
  493. R_CopyDecalSurface
  494. =====================
  495. */
  496. static void R_CopyDecalSurface( idDrawVert * verts, int numVerts, triIndex_t * indexes, int numIndexes,
  497. const decal_t * decal, const float fadeColor[4] ) {
  498. assert_16_byte_aligned( &verts[numVerts] );
  499. assert_16_byte_aligned( &indexes[numIndexes] );
  500. assert_16_byte_aligned( decal->indexes );
  501. assert_16_byte_aligned( decal->verts );
  502. assert( ( ( decal->numVerts * sizeof( idDrawVert ) ) & 15 ) == 0 );
  503. assert( ( ( decal->numIndexes * sizeof( triIndex_t ) ) & 15 ) == 0 );
  504. assert_16_byte_aligned( fadeColor );
  505. #ifdef ID_WIN_X86_SSE2_INTRIN
  506. const __m128i vector_int_num_verts = _mm_shuffle_epi32( _mm_cvtsi32_si128( numVerts ), 0 );
  507. const __m128i vector_short_num_verts = _mm_packs_epi32( vector_int_num_verts, vector_int_num_verts );
  508. const __m128 vector_fade_color = _mm_load_ps( fadeColor );
  509. const __m128i vector_color_mask = _mm_set_epi32( 0, -1, 0, 0 );
  510. // copy vertices and apply depth/time based fading
  511. assert_offsetof( idDrawVert, color, 6 * 4 );
  512. for ( int i = 0; i < decal->numVerts; i++ ) {
  513. const idDrawVert &srcVert = decal->verts[i];
  514. idDrawVert &dstVert = verts[numVerts + i];
  515. __m128i v0 = _mm_load_si128( (const __m128i *)( (byte *)&srcVert + 0 ) );
  516. __m128i v1 = _mm_load_si128( (const __m128i *)( (byte *)&srcVert + 16 ) );
  517. __m128 depthFade = _mm_splat_ps( _mm_load_ss( decal->vertDepthFade + i ), 0 );
  518. __m128 timeDepthFade = _mm_mul_ps( depthFade, vector_fade_color );
  519. __m128i colorInt = _mm_cvtps_epi32( timeDepthFade );
  520. __m128i colorShort = _mm_packs_epi32( colorInt, colorInt );
  521. __m128i colorByte = _mm_packus_epi16( colorShort, colorShort );
  522. v1 = _mm_or_si128( v1, _mm_and_si128( colorByte, vector_color_mask ) );
  523. _mm_stream_si128( (__m128i *)( (byte *)&dstVert + 0 ), v0 );
  524. _mm_stream_si128( (__m128i *)( (byte *)&dstVert + 16 ), v1 );
  525. }
  526. // copy indexes
  527. assert( ( decal->numIndexes & 7 ) == 0 );
  528. assert( sizeof( triIndex_t ) == 2 );
  529. for ( int i = 0; i < decal->numIndexes; i += 8 ) {
  530. __m128i vi = _mm_load_si128( (const __m128i *)&decal->indexes[i] );
  531. vi = _mm_add_epi16( vi, vector_short_num_verts );
  532. _mm_stream_si128( (__m128i *)&indexes[numIndexes + i], vi );
  533. }
  534. _mm_sfence();
  535. #else
  536. // copy vertices and apply depth/time based fading
  537. for ( int i = 0; i < decal->numVerts; i++ ) {
  538. // NOTE: bad out-of-order write-combined write, SIMD code does the right thing
  539. verts[numVerts + i] = decal->verts[i];
  540. for ( int j = 0; j < 4; j++ ) {
  541. verts[numVerts + i].color[j] = idMath::Ftob( fadeColor[j] * decal->vertDepthFade[i] );
  542. }
  543. }
  544. // copy indices
  545. assert( ( decal->numIndexes & 1 ) == 0 );
  546. for ( int i = 0; i < decal->numIndexes; i += 2 ) {
  547. assert( decal->indexes[i + 0] < decal->numVerts && decal->indexes[i + 1] < decal->numVerts );
  548. WriteIndexPair( &indexes[numIndexes + i], numVerts + decal->indexes[i + 0], numVerts + decal->indexes[i + 1] );
  549. }
  550. #endif
  551. }
  552. /*
  553. =====================
  554. idRenderModelDecal::GetNumDecalDrawSurfs
  555. =====================
  556. */
  557. unsigned int idRenderModelDecal::GetNumDecalDrawSurfs() {
  558. numDecalMaterials = 0;
  559. for ( unsigned int i = firstDecal; i < nextDecal; i++ ) {
  560. const decal_t & decal = decals[i & ( MAX_DECALS - 1 )];
  561. unsigned int j = 0;
  562. for ( ; j < numDecalMaterials; j++ ) {
  563. if ( decalMaterials[j] == decal.material ) {
  564. break;
  565. }
  566. }
  567. if ( j >= numDecalMaterials ) {
  568. decalMaterials[numDecalMaterials++] = decal.material;
  569. }
  570. }
  571. return numDecalMaterials;
  572. }
  573. /*
  574. =====================
  575. idRenderModelDecal::CreateDecalDrawSurf
  576. =====================
  577. */
  578. drawSurf_t * idRenderModelDecal::CreateDecalDrawSurf( const viewEntity_t *space, unsigned int index ) {
  579. if ( index < 0 || index >= numDecalMaterials ) {
  580. return NULL;
  581. }
  582. const idMaterial * material = decalMaterials[index];
  583. int maxVerts = 0;
  584. int maxIndexes = 0;
  585. for ( unsigned int i = firstDecal; i < nextDecal; i++ ) {
  586. const decal_t & decal = decals[i & ( MAX_DECALS - 1 )];
  587. if ( decal.material == material ) {
  588. maxVerts += decal.numVerts;
  589. maxIndexes += decal.numIndexes;
  590. }
  591. }
  592. if ( maxVerts == 0 || maxIndexes == 0 ) {
  593. return NULL;
  594. }
  595. // create a new triangle surface in frame memory so it gets automatically disposed of
  596. srfTriangles_t *newTri = (srfTriangles_t *)R_ClearedFrameAlloc( sizeof( *newTri ), FRAME_ALLOC_SURFACE_TRIANGLES );
  597. newTri->numVerts = maxVerts;
  598. newTri->numIndexes = maxIndexes;
  599. newTri->ambientCache = vertexCache.AllocVertex( NULL, ALIGN( maxVerts * sizeof( idDrawVert ), VERTEX_CACHE_ALIGN ) );
  600. newTri->indexCache = vertexCache.AllocIndex( NULL, ALIGN( maxIndexes * sizeof( triIndex_t ), INDEX_CACHE_ALIGN ) );
  601. idDrawVert * mappedVerts = (idDrawVert *)vertexCache.MappedVertexBuffer( newTri->ambientCache );
  602. triIndex_t * mappedIndexes = (triIndex_t *)vertexCache.MappedIndexBuffer( newTri->indexCache );
  603. const decalInfo_t decalInfo = material->GetDecalInfo();
  604. const int maxTime = decalInfo.stayTime + decalInfo.fadeTime;
  605. const int time = tr.viewDef->renderView.time[0];
  606. int numVerts = 0;
  607. int numIndexes = 0;
  608. for ( unsigned int i = firstDecal; i < nextDecal; i++ ) {
  609. const decal_t & decal = decals[i & ( MAX_DECALS - 1 )];
  610. if ( decal.numVerts == 0 ) {
  611. if ( i == firstDecal ) {
  612. firstDecal++;
  613. }
  614. continue;
  615. }
  616. if ( decal.material != material ) {
  617. continue;
  618. }
  619. const int deltaTime = time - decal.startTime;
  620. const int fadeTime = deltaTime - decalInfo.stayTime;
  621. if ( deltaTime > maxTime ) {
  622. continue; // already completely faded away, but not yet removed
  623. }
  624. const float f = ( deltaTime > decalInfo.stayTime ) ? ( (float) fadeTime / decalInfo.fadeTime ) : 0.0f;
  625. ALIGNTYPE16 float fadeColor[4];
  626. for ( int j = 0; j < 4; j++ ) {
  627. fadeColor[j] = 255.0f * ( decalInfo.start[j] + ( decalInfo.end[j] - decalInfo.start[j] ) * f );
  628. }
  629. // use SIMD optimized routine to copy the vertices and indices directly to write-combined memory
  630. // this also applies any depth/time based fading while copying
  631. R_CopyDecalSurface( mappedVerts, numVerts, mappedIndexes, numIndexes, &decal, fadeColor );
  632. numVerts += decal.numVerts;
  633. numIndexes += decal.numIndexes;
  634. }
  635. newTri->numVerts = numVerts;
  636. newTri->numIndexes = numIndexes;
  637. // create the drawsurf
  638. drawSurf_t * drawSurf = (drawSurf_t *)R_FrameAlloc( sizeof( *drawSurf ), FRAME_ALLOC_DRAW_SURFACE );
  639. drawSurf->frontEndGeo = newTri;
  640. drawSurf->numIndexes = newTri->numIndexes;
  641. drawSurf->ambientCache = newTri->ambientCache;
  642. drawSurf->indexCache = newTri->indexCache;
  643. drawSurf->shadowCache = 0;
  644. drawSurf->jointCache = 0;
  645. drawSurf->space = space;
  646. drawSurf->scissorRect = space->scissorRect;
  647. drawSurf->extraGLState = 0;
  648. drawSurf->renderZFail = 0;
  649. R_SetupDrawSurfShader( drawSurf, material, &space->entityDef->parms );
  650. return drawSurf;
  651. }
  652. /*
  653. ====================
  654. idRenderModelDecal::ReadFromDemoFile
  655. ====================
  656. */
  657. void idRenderModelDecal::ReadFromDemoFile( idDemoFile *f ) {
  658. // FIXME: implement
  659. }
  660. /*
  661. ====================
  662. idRenderModelDecal::WriteToDemoFile
  663. ====================
  664. */
  665. void idRenderModelDecal::WriteToDemoFile( idDemoFile *f ) const {
  666. // FIXME: implement
  667. }