indexbuffercompression.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791
  1. /*
  2. Copyright (c) 2014, Conor Stokes
  3. All rights reserved.
  4. Redistribution and use in source and binary forms, with or without
  5. modification, are permitted provided that the following conditions are met:
  6. 1. Redistributions of source code must retain the above copyright notice, this
  7. list of conditions and the following disclaimer.
  8. 2. Redistributions in binary form must reproduce the above copyright notice,
  9. this list of conditions and the following disclaimer in the documentation
  10. and/or other materials provided with the distribution.
  11. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  12. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  13. WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  14. DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
  15. ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  16. (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  17. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  18. ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  19. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  20. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  21. */
  22. #include "indexbuffercompression.h"
  23. #include "writebitstream.h"
  24. #include "indexcompressionconstants.h"
  25. #include <assert.h>
  26. #ifdef _MSC_VER
  27. #define IBC_INLINE __forceinline
  28. #else
  29. #define IBC_INLINE inline
  30. #endif
  31. // Individual vertex type classifications.
  32. enum VertexClassification
  33. {
  34. NEW_VERTEX = 0,
  35. CACHED_VERTEX = 1,
  36. FREE_VERTEX = 2
  37. };
  38. // Individual case for handling a combination of vertice classifications.
  39. struct VertexCompressionCase
  40. {
  41. IndexBufferTriangleCodes code;
  42. uint32_t vertexOrder[ 3 ];
  43. };
  44. // This is a table for looking up the appropriate code and rotation for a set of vertex classifications.
  45. const VertexCompressionCase CompressionCase[3][3][3] =
  46. {
  47. { // new
  48. { // new new
  49. { // new new new
  50. IB_NEW_NEW_NEW, { 0, 1, 2 }
  51. },
  52. { // new new cached
  53. IB_NEW_NEW_CACHED, { 0, 1, 2 }
  54. },
  55. { // new new free
  56. IB_NEW_NEW_FREE, { 0, 1, 2 }
  57. }
  58. },
  59. { // new cached
  60. { // new cached new
  61. IB_NEW_NEW_CACHED, { 2, 0, 1 }
  62. },
  63. { // new cached cached
  64. IB_NEW_CACHED_CACHED, { 0, 1, 2 }
  65. },
  66. { // new cached free
  67. IB_NEW_CACHED_FREE, { 0, 1, 2 }
  68. }
  69. },
  70. { // new free
  71. { // new free new
  72. IB_NEW_NEW_FREE, { 2, 0, 1 }
  73. },
  74. { // new free cached
  75. IB_NEW_FREE_CACHED, { 0, 1, 2 }
  76. },
  77. { // new free free
  78. IB_NEW_FREE_FREE, { 0, 1, 2 }
  79. }
  80. }
  81. },
  82. { // cached
  83. { // cached new
  84. { // cached new new
  85. IB_NEW_NEW_CACHED, { 1, 2, 0 }
  86. },
  87. { // cached new cached
  88. IB_NEW_CACHED_CACHED, { 1, 2, 0 }
  89. },
  90. { // cached new free
  91. IB_NEW_FREE_CACHED, { 1, 2, 0 }
  92. }
  93. },
  94. { // cached cached
  95. { // cached cached new
  96. IB_NEW_CACHED_CACHED, { 2, 0, 1 }
  97. },
  98. { // cached cached cached
  99. IB_CACHED_CACHED_CACHED, { 0, 1, 2 }
  100. },
  101. { // cached cached free
  102. IB_CACHED_CACHED_FREE, { 0, 1, 2 }
  103. }
  104. },
  105. { // cached free
  106. { // cached free new
  107. IB_NEW_CACHED_FREE, { 2, 0, 1 }
  108. },
  109. { // cached free cached
  110. IB_CACHED_CACHED_FREE, { 2, 0, 1 }
  111. },
  112. { // cached free free
  113. IB_CACHED_FREE_FREE, { 0, 1, 2 }
  114. }
  115. }
  116. },
  117. { // free
  118. { // free new
  119. { // free new new
  120. IB_NEW_NEW_FREE, { 1, 2, 0 }
  121. },
  122. { // free new cached
  123. IB_NEW_CACHED_FREE, { 1, 2, 0 }
  124. },
  125. { // free new free
  126. IB_NEW_FREE_FREE, { 1, 2, 0 }
  127. }
  128. },
  129. { // free cached
  130. { // free cached new
  131. IB_NEW_FREE_CACHED, { 2, 0, 1 }
  132. },
  133. { // free cached cached
  134. IB_CACHED_CACHED_FREE, { 1, 2, 0 }
  135. },
  136. { // free cached free
  137. IB_CACHED_FREE_FREE, { 1, 2, 0 }
  138. }
  139. },
  140. { // free free
  141. { // free free new
  142. IB_NEW_FREE_FREE, { 2, 0, 1 }
  143. },
  144. { // free free cached
  145. IB_CACHED_FREE_FREE, { 2, 0, 1 }
  146. },
  147. { // free free free
  148. IB_FREE_FREE_FREE, { 0, 1, 2 }
  149. }
  150. }
  151. }
  152. };
  153. const uint32_t VERTEX_NOT_MAPPED = 0xFFFFFFFF;
  154. // Classify a vertex as new, cached or free, outputting the relative position in the vertex indice cache FIFO.
  155. static IBC_INLINE VertexClassification ClassifyVertex( uint32_t vertex, const uint32_t* vertexRemap, const uint32_t* vertexFifo, uint32_t verticesRead, uint32_t& cachedVertexIndex )
  156. {
  157. if ( vertexRemap[ vertex ] == VERTEX_NOT_MAPPED )
  158. {
  159. return NEW_VERTEX;
  160. }
  161. else
  162. {
  163. int32_t lowestVertexCursor = verticesRead >= VERTEX_FIFO_SIZE ? verticesRead - VERTEX_FIFO_SIZE : 0;
  164. // Probe backwards in the vertex FIFO for a cached vertex
  165. for ( int32_t vertexCursor = verticesRead - 1; vertexCursor >= lowestVertexCursor; --vertexCursor )
  166. {
  167. if ( vertexFifo[ vertexCursor & VERTEX_FIFO_MASK ] == vertex )
  168. {
  169. cachedVertexIndex = ( verticesRead - 1 ) - vertexCursor;
  170. return CACHED_VERTEX;
  171. }
  172. }
  173. return FREE_VERTEX;
  174. }
  175. }
  176. template <typename Ty>
  177. void CompressTriangleCodes1( const Ty* triangles,
  178. uint32_t triangleCount,
  179. uint32_t* vertexRemap,
  180. uint32_t vertexCount,
  181. WriteBitstream& output )
  182. {
  183. Edge edgeFifo[ EDGE_FIFO_SIZE ];
  184. uint32_t vertexFifo[ VERTEX_FIFO_SIZE ];
  185. uint32_t edgesRead = 0;
  186. uint32_t verticesRead = 0;
  187. uint32_t newVertices = 0;
  188. const Ty* triangleEnd = triangles + ( triangleCount * 3 );
  189. assert( vertexCount < 0xFFFFFFFF );
  190. uint32_t* vertexRemapEnd = vertexRemap + vertexCount;
  191. // clear the vertex remapping to "not found" value of 0xFFFFFFFF - dirty, but low overhead.
  192. for ( uint32_t* remappedVertex = vertexRemap; remappedVertex < vertexRemapEnd; ++remappedVertex )
  193. {
  194. *remappedVertex = VERTEX_NOT_MAPPED;
  195. }
  196. // iterate through the triangles
  197. for ( const Ty* triangle = triangles; triangle < triangleEnd; triangle += 3 )
  198. {
  199. int32_t lowestEdgeCursor = edgesRead >= EDGE_FIFO_SIZE ? edgesRead - EDGE_FIFO_SIZE : 0;
  200. int32_t edgeCursor = edgesRead - 1;
  201. bool foundEdge = false;
  202. int32_t spareVertex = 0;
  203. // check to make sure that there are no degenerate triangles.
  204. assert( triangle[ 0 ] != triangle[ 1 ] && triangle[ 1 ] != triangle[ 2 ] && triangle[ 2 ] != triangle[ 0 ] );
  205. // Probe back through the edge fifo to see if one of the triangle edges is in the FIFO
  206. for ( ; edgeCursor >= lowestEdgeCursor; --edgeCursor )
  207. {
  208. const Edge& edge = edgeFifo[ edgeCursor & EDGE_FIFO_MASK ];
  209. // check all the edges in order and save the free vertex.
  210. if ( edge.second == triangle[ 0 ] && edge.first == triangle[ 1 ] )
  211. {
  212. foundEdge = true;
  213. spareVertex = 2;
  214. break;
  215. }
  216. else if ( edge.second == triangle[ 1 ] && edge.first == triangle[ 2 ] )
  217. {
  218. foundEdge = true;
  219. spareVertex = 0;
  220. break;
  221. }
  222. else if ( edge.second == triangle[ 2 ] && edge.first == triangle[ 0 ] )
  223. {
  224. foundEdge = true;
  225. spareVertex = 1;
  226. break;
  227. }
  228. }
  229. // we found an edge so write it out, so classify a vertex and then write out the correct code.
  230. if ( foundEdge )
  231. {
  232. uint32_t cachedVertex;
  233. uint32_t spareVertexIndice = triangle[ spareVertex ];
  234. VertexClassification freeVertexClass = ClassifyVertex( spareVertexIndice, vertexRemap, vertexFifo, verticesRead, cachedVertex );
  235. uint32_t relativeEdge = ( edgesRead - 1 ) - edgeCursor;
  236. switch ( freeVertexClass )
  237. {
  238. case NEW_VERTEX:
  239. switch ( relativeEdge )
  240. {
  241. case 0:
  242. output.Write( IB_EDGE_0_NEW, IB_TRIANGLE_CODE_BITS );
  243. break;
  244. case 1:
  245. output.Write( IB_EDGE_1_NEW, IB_TRIANGLE_CODE_BITS );
  246. break;
  247. default:
  248. output.Write( IB_EDGE_NEW, IB_TRIANGLE_CODE_BITS );
  249. output.Write( relativeEdge, CACHED_EDGE_BITS );
  250. break;
  251. }
  252. vertexFifo[ verticesRead & VERTEX_FIFO_MASK ] = spareVertexIndice;
  253. vertexRemap[ spareVertexIndice ] = newVertices;
  254. ++verticesRead;
  255. ++newVertices;
  256. break;
  257. case CACHED_VERTEX:
  258. output.Write( IB_EDGE_CACHED, IB_TRIANGLE_CODE_BITS );
  259. output.Write( relativeEdge, CACHED_EDGE_BITS );
  260. output.Write( cachedVertex, CACHED_VERTEX_BITS );
  261. break;
  262. case FREE_VERTEX:
  263. output.Write( IB_EDGE_FREE, IB_TRIANGLE_CODE_BITS );
  264. output.Write( relativeEdge, CACHED_EDGE_BITS );
  265. vertexFifo[ verticesRead & VERTEX_FIFO_MASK ] = spareVertexIndice;
  266. ++verticesRead;
  267. output.WriteVInt( ( newVertices - 1 ) - vertexRemap[ spareVertexIndice ] );
  268. break;
  269. }
  270. // Populate the edge fifo with the the remaining edges
  271. // Note - the winding order is important as we'll need to re-produce this on decompression.
  272. // The edges are put in as if the found edge is the first edge in the triangle (which it will be when we
  273. // reconstruct).
  274. switch ( spareVertex )
  275. {
  276. case 0:
  277. edgeFifo[ edgesRead & EDGE_FIFO_MASK ].set( triangle[ 2 ], triangle[ 0 ] );
  278. ++edgesRead;
  279. edgeFifo[ edgesRead & EDGE_FIFO_MASK ].set( triangle[ 0 ], triangle[ 1 ] );
  280. ++edgesRead;
  281. break;
  282. case 1:
  283. edgeFifo[ edgesRead & EDGE_FIFO_MASK ].set( triangle[ 0 ], triangle[ 1 ] );
  284. ++edgesRead;
  285. edgeFifo[ edgesRead & EDGE_FIFO_MASK ].set( triangle[ 1 ], triangle[ 2 ] );
  286. ++edgesRead;
  287. break;
  288. case 2:
  289. edgeFifo[ edgesRead & EDGE_FIFO_MASK ].set( triangle[ 1 ], triangle[ 2 ] );
  290. ++edgesRead;
  291. edgeFifo[ edgesRead & EDGE_FIFO_MASK ].set( triangle[ 2 ], triangle[ 0 ] );
  292. ++edgesRead;
  293. break;
  294. }
  295. }
  296. else
  297. {
  298. VertexClassification classifications[ 3 ];
  299. uint32_t cachedVertexIndices[ 3 ];
  300. // classify each vertex as new, cached or free, potentially extracting a cached indice.
  301. classifications[ 0 ] = ClassifyVertex( triangle[ 0 ], vertexRemap, vertexFifo, verticesRead, cachedVertexIndices[ 0 ] );
  302. classifications[ 1 ] = ClassifyVertex( triangle[ 1 ], vertexRemap, vertexFifo, verticesRead, cachedVertexIndices[ 1 ] );
  303. classifications[ 2 ] = ClassifyVertex( triangle[ 2 ], vertexRemap, vertexFifo, verticesRead, cachedVertexIndices[ 2 ] );
  304. // use the classifications to lookup the matching compression code and potentially rotate the order of the vertices.
  305. const VertexCompressionCase& compressionCase = CompressionCase[ classifications[ 0 ] ][ classifications[ 1 ] ][ classifications[ 2 ] ];
  306. // rotate the order of the vertices based on the compression classification.
  307. uint32_t reorderedTriangle[ 3 ];
  308. reorderedTriangle[ 0 ] = triangle[ compressionCase.vertexOrder[ 0 ] ];
  309. reorderedTriangle[ 1 ] = triangle[ compressionCase.vertexOrder[ 1 ] ];
  310. reorderedTriangle[ 2 ] = triangle[ compressionCase.vertexOrder[ 2 ] ];
  311. output.Write( compressionCase.code, IB_TRIANGLE_CODE_BITS );
  312. switch ( compressionCase.code )
  313. {
  314. case IB_NEW_NEW_NEW:
  315. {
  316. vertexFifo[ verticesRead & VERTEX_FIFO_MASK ] = triangle[ 0 ];
  317. vertexFifo[ ( verticesRead + 1 ) & VERTEX_FIFO_MASK ] = triangle[ 1 ];
  318. vertexFifo[ ( verticesRead + 2 ) & VERTEX_FIFO_MASK ] = triangle[ 2 ];
  319. vertexRemap[ triangle[ 0 ] ] = newVertices;
  320. vertexRemap[ triangle[ 1 ] ] = newVertices + 1;
  321. vertexRemap[ triangle[ 2 ] ] = newVertices + 2;
  322. verticesRead += 3;
  323. newVertices += 3;
  324. break;
  325. }
  326. case IB_NEW_NEW_CACHED:
  327. {
  328. vertexFifo[ verticesRead & VERTEX_FIFO_MASK ] = reorderedTriangle[ 0 ];
  329. vertexFifo[ ( verticesRead + 1 ) & VERTEX_FIFO_MASK ] = reorderedTriangle[ 1 ];
  330. output.Write( cachedVertexIndices[ compressionCase.vertexOrder[ 2 ] ], CACHED_VERTEX_BITS );
  331. vertexRemap[ reorderedTriangle[ 0 ] ] = newVertices;
  332. vertexRemap[ reorderedTriangle[ 1 ] ] = newVertices + 1;
  333. verticesRead += 2;
  334. newVertices += 2;
  335. break;
  336. }
  337. case IB_NEW_NEW_FREE:
  338. {
  339. vertexFifo[ verticesRead & VERTEX_FIFO_MASK ] = reorderedTriangle[ 0 ];
  340. vertexFifo[ ( verticesRead + 1 ) & VERTEX_FIFO_MASK ] = reorderedTriangle[ 1 ];
  341. vertexFifo[ ( verticesRead + 2 ) & VERTEX_FIFO_MASK ] = reorderedTriangle[ 2 ];
  342. output.WriteVInt( ( newVertices - 1 ) - vertexRemap[ reorderedTriangle[ 2 ] ] );
  343. vertexRemap[ reorderedTriangle[ 0 ] ] = newVertices;
  344. vertexRemap[ reorderedTriangle[ 1 ] ] = newVertices + 1;
  345. verticesRead += 3;
  346. newVertices += 2;
  347. break;
  348. }
  349. case IB_NEW_CACHED_CACHED:
  350. {
  351. vertexFifo[ verticesRead & VERTEX_FIFO_MASK ] = reorderedTriangle[ 0 ];
  352. output.Write( cachedVertexIndices[ compressionCase.vertexOrder[ 1 ] ], CACHED_VERTEX_BITS );
  353. output.Write( cachedVertexIndices[ compressionCase.vertexOrder[ 2 ] ], CACHED_VERTEX_BITS );
  354. vertexRemap[ reorderedTriangle[ 0 ] ] = newVertices;
  355. verticesRead += 1;
  356. newVertices += 1;
  357. break;
  358. }
  359. case IB_NEW_CACHED_FREE:
  360. {
  361. vertexFifo[ verticesRead & VERTEX_FIFO_MASK ] = reorderedTriangle[ 0 ];
  362. vertexFifo[ ( verticesRead + 1 ) & VERTEX_FIFO_MASK ] = reorderedTriangle[ 2 ];
  363. output.Write( cachedVertexIndices[ compressionCase.vertexOrder[ 1 ] ], CACHED_VERTEX_BITS );
  364. output.WriteVInt( ( newVertices - 1 ) - vertexRemap[ reorderedTriangle[ 2 ] ] );
  365. vertexRemap[ reorderedTriangle[ 0 ] ] = newVertices;
  366. verticesRead += 2;
  367. newVertices += 1;
  368. break;
  369. }
  370. case IB_NEW_FREE_CACHED:
  371. {
  372. vertexFifo[ verticesRead & VERTEX_FIFO_MASK ] = reorderedTriangle[ 0 ];
  373. vertexFifo[ ( verticesRead + 1 ) & VERTEX_FIFO_MASK ] = reorderedTriangle[ 1 ];
  374. output.WriteVInt( ( newVertices - 1 ) - vertexRemap[ reorderedTriangle[ 1 ] ] );
  375. output.Write( cachedVertexIndices[ compressionCase.vertexOrder[ 2 ] ], CACHED_VERTEX_BITS );
  376. vertexRemap[ reorderedTriangle[ 0 ] ] = newVertices;
  377. verticesRead += 2;
  378. newVertices += 1;
  379. break;
  380. }
  381. case IB_NEW_FREE_FREE:
  382. {
  383. vertexFifo[ verticesRead & VERTEX_FIFO_MASK ] = reorderedTriangle[ 0 ];
  384. vertexFifo[ ( verticesRead + 1 ) & VERTEX_FIFO_MASK ] = reorderedTriangle[ 1 ];
  385. vertexFifo[ ( verticesRead + 2 ) & VERTEX_FIFO_MASK ] = reorderedTriangle[ 2 ];
  386. output.WriteVInt( ( newVertices - 1 ) - vertexRemap[ reorderedTriangle[ 1 ] ] );
  387. output.WriteVInt( ( newVertices - 1 ) - vertexRemap[ reorderedTriangle[ 2 ] ] );
  388. vertexRemap[ reorderedTriangle[ 0 ] ] = newVertices;
  389. verticesRead += 3;
  390. newVertices += 1;
  391. break;
  392. }
  393. case IB_CACHED_CACHED_CACHED:
  394. {
  395. output.Write( cachedVertexIndices[ compressionCase.vertexOrder[ 0 ] ], CACHED_VERTEX_BITS );
  396. output.Write( cachedVertexIndices[ compressionCase.vertexOrder[ 1 ] ], CACHED_VERTEX_BITS );
  397. output.Write( cachedVertexIndices[ compressionCase.vertexOrder[ 2 ] ], CACHED_VERTEX_BITS );
  398. break;
  399. }
  400. case IB_CACHED_CACHED_FREE:
  401. {
  402. vertexFifo[ verticesRead & VERTEX_FIFO_MASK ] = reorderedTriangle[ 2 ];
  403. output.Write( cachedVertexIndices[ compressionCase.vertexOrder[ 0 ] ], CACHED_VERTEX_BITS );
  404. output.Write( cachedVertexIndices[ compressionCase.vertexOrder[ 1 ] ], CACHED_VERTEX_BITS );
  405. output.WriteVInt( ( newVertices - 1 ) - vertexRemap[ reorderedTriangle[ 2 ] ] );
  406. verticesRead += 1;
  407. break;
  408. }
  409. case IB_CACHED_FREE_FREE:
  410. {
  411. vertexFifo[ verticesRead & VERTEX_FIFO_MASK ] = reorderedTriangle[ 1 ];
  412. vertexFifo[ ( verticesRead + 1 ) & VERTEX_FIFO_MASK ] = reorderedTriangle[ 2 ];
  413. output.Write( cachedVertexIndices[ compressionCase.vertexOrder[ 0 ] ], CACHED_VERTEX_BITS );
  414. output.WriteVInt( ( newVertices - 1 ) - vertexRemap[ reorderedTriangle[ 1 ] ] );
  415. output.WriteVInt( ( newVertices - 1 ) - vertexRemap[ reorderedTriangle[ 2 ] ] );
  416. verticesRead += 2;
  417. break;
  418. }
  419. case IB_FREE_FREE_FREE:
  420. {
  421. vertexFifo[ verticesRead & VERTEX_FIFO_MASK ] = reorderedTriangle[ 0 ];
  422. vertexFifo[ ( verticesRead + 1 ) & VERTEX_FIFO_MASK ] = reorderedTriangle[ 1 ];
  423. vertexFifo[ ( verticesRead + 2 ) & VERTEX_FIFO_MASK ] = reorderedTriangle[ 2 ];
  424. output.WriteVInt( ( newVertices - 1 ) - vertexRemap[ reorderedTriangle[ 0 ] ] );
  425. output.WriteVInt( ( newVertices - 1 ) - vertexRemap[ reorderedTriangle[ 1 ] ] );
  426. output.WriteVInt( ( newVertices - 1 ) - vertexRemap[ reorderedTriangle[ 2 ] ] );
  427. verticesRead += 3;
  428. break;
  429. }
  430. }
  431. // populate the edge fifo with the 3 most recent edges
  432. edgeFifo[ edgesRead & EDGE_FIFO_MASK ].set( reorderedTriangle[ 0 ], reorderedTriangle[ 1 ] );
  433. ++edgesRead;
  434. edgeFifo[ edgesRead & EDGE_FIFO_MASK ].set( reorderedTriangle[ 1 ], reorderedTriangle[ 2 ] );
  435. ++edgesRead;
  436. edgeFifo[ edgesRead & EDGE_FIFO_MASK ].set( reorderedTriangle[ 2 ], reorderedTriangle[ 0 ] );
  437. ++edgesRead;
  438. }
  439. }
  440. }
  441. // Output the compression information for a single vertex, remapping any new vertices and updating the vertex fifo where needed.
  442. static IBC_INLINE void OutputVertex( uint32_t vertex,
  443. uint32_t* vertexRemap,
  444. uint32_t& newVertexCount,
  445. uint32_t* vertexFifo,
  446. uint32_t& verticesRead,
  447. WriteBitstream& output )
  448. {
  449. // Check if a vertex hasn't been remapped,
  450. if ( vertexRemap[ vertex ] == VERTEX_NOT_MAPPED )
  451. {
  452. // no remap, so remap to the current high watermark and output a new vertex code.
  453. vertexRemap[ vertex ] = newVertexCount;
  454. output.Write( IB_NEW_VERTEX, IB_VERTEX_CODE_BITS );
  455. ++newVertexCount;
  456. // new vertices go into the vertex FIFO
  457. vertexFifo[ verticesRead & VERTEX_FIFO_MASK ] = vertex;
  458. ++verticesRead;
  459. }
  460. else
  461. {
  462. int32_t lowestVertexCursor = verticesRead >= VERTEX_FIFO_SIZE ? verticesRead - VERTEX_FIFO_SIZE : 0;
  463. // Probe backwards in the vertex FIFO for a cached vertex
  464. for ( int32_t vertexCursor = verticesRead - 1; vertexCursor >= lowestVertexCursor; --vertexCursor )
  465. {
  466. if ( vertexFifo[ vertexCursor & VERTEX_FIFO_MASK ] == vertex )
  467. {
  468. // found a cached vertex, so write out the code for a cached vertex, as the relative index into the fifo.
  469. output.Write( IB_CACHED_VERTEX, IB_VERTEX_CODE_BITS );
  470. output.Write( ( verticesRead - 1 ) - vertexCursor, CACHED_VERTEX_BITS );
  471. return;
  472. }
  473. }
  474. // no cached vertex found, so write out a free vertex
  475. output.Write( IB_FREE_VERTEX, IB_VERTEX_CODE_BITS );
  476. // free vertices are relative to the latest new vertex.
  477. uint32_t vertexOutput = ( newVertexCount - 1 ) - vertexRemap[ vertex ];
  478. // v-int encode the free vertex index.
  479. output.WriteVInt( vertexOutput );
  480. // free vertices go back into the vertex cache.
  481. vertexFifo[ verticesRead & VERTEX_FIFO_MASK ] = vertex;
  482. ++verticesRead;
  483. }
  484. }
  485. template <typename Ty>
  486. void CompressIndiceCodes1( const Ty* triangles,
  487. uint32_t triangleCount,
  488. uint32_t* vertexRemap,
  489. uint32_t vertexCount,
  490. WriteBitstream& output )
  491. {
  492. Edge edgeFifo[ EDGE_FIFO_SIZE ];
  493. uint32_t vertexFifo[ VERTEX_FIFO_SIZE ];
  494. uint32_t edgesRead = 0;
  495. uint32_t verticesRead = 0;
  496. uint32_t newVertices = 0;
  497. const Ty* triangleEnd = triangles + ( triangleCount * 3 );
  498. assert( vertexCount < 0xFFFFFFFF );
  499. uint32_t* vertexRemapEnd = vertexRemap + vertexCount;
  500. // clear the vertex remapping to "not found" value of 0xFFFFFFFF - dirty, but low overhead.
  501. for ( uint32_t* remappedVertex = vertexRemap; remappedVertex < vertexRemapEnd; ++remappedVertex )
  502. {
  503. *remappedVertex = VERTEX_NOT_MAPPED;
  504. }
  505. // iterate through the triangles
  506. for ( const Ty* triangle = triangles; triangle < triangleEnd; triangle += 3 )
  507. {
  508. int32_t lowestEdgeCursor = edgesRead >= EDGE_FIFO_SIZE ? edgesRead - EDGE_FIFO_SIZE : 0;
  509. int32_t edgeCursor = edgesRead - 1;
  510. bool foundEdge = false;
  511. int32_t freeVertex = -1; // should not be negative 1 if found, this is not used as a signal, but for debugging.
  512. // Probe back through the edge fifo to see if one of the triangle edges is in the FIFO
  513. for ( ; edgeCursor >= lowestEdgeCursor; --edgeCursor )
  514. {
  515. const Edge& edge = edgeFifo[ edgeCursor & VERTEX_FIFO_MASK ];
  516. // check all the edges in order and save the free vertex.
  517. if ( edge.second == triangle[ 0 ] && edge.first == triangle[ 1 ] )
  518. {
  519. foundEdge = true;
  520. freeVertex = 2;
  521. break;
  522. }
  523. else if ( edge.second == triangle[ 1 ] && edge.first == triangle[ 2 ] )
  524. {
  525. foundEdge = true;
  526. freeVertex = 0;
  527. break;
  528. }
  529. else if ( edge.second == triangle[ 2 ] && edge.first == triangle[ 0 ] )
  530. {
  531. foundEdge = true;
  532. freeVertex = 1;
  533. break;
  534. }
  535. }
  536. // we found an edge so write it out, then output the vertex
  537. if ( foundEdge )
  538. {
  539. output.Write( IB_CACHED_EDGE, IB_VERTEX_CODE_BITS );
  540. output.Write( ( edgesRead - 1 ) - edgeCursor, CACHED_EDGE_BITS );
  541. const Edge& edge = edgeFifo[ edgeCursor & EDGE_FIFO_MASK ];
  542. OutputVertex( triangle[ freeVertex ], vertexRemap, newVertices, vertexFifo, verticesRead, output );
  543. // edge is in reverse order to last triangle it occured on (and it will only be a match if this is the case).
  544. // so put the vertices into the fifo in that order.
  545. vertexFifo[ verticesRead & VERTEX_FIFO_MASK ] = edge.second;
  546. ++verticesRead;
  547. vertexFifo[ verticesRead & VERTEX_FIFO_MASK ] = edge.first;
  548. ++verticesRead;
  549. // Populate the edge fifo with the the remaining edges
  550. // Note - the winding order is important as we'll need to re-produce this on decompression.
  551. // The edges are put in as if the found edge is the first edge in the triangle (which it will be when we
  552. // reconstruct).
  553. switch ( freeVertex )
  554. {
  555. case 0:
  556. edgeFifo[ edgesRead & EDGE_FIFO_MASK ].set( triangle[ 2 ], triangle[ 0 ] );
  557. ++edgesRead;
  558. edgeFifo[ edgesRead & EDGE_FIFO_MASK ].set( triangle[ 0 ], triangle[ 1 ] );
  559. ++edgesRead;
  560. break;
  561. case 1:
  562. edgeFifo[ edgesRead & EDGE_FIFO_MASK ].set( triangle[ 0 ], triangle[ 1 ] );
  563. ++edgesRead;
  564. edgeFifo[ edgesRead & EDGE_FIFO_MASK ].set( triangle[ 1 ], triangle[ 2 ] );
  565. ++edgesRead;
  566. break;
  567. case 2:
  568. edgeFifo[ edgesRead & EDGE_FIFO_MASK ].set( triangle[ 1 ], triangle[ 2 ] );
  569. ++edgesRead;
  570. edgeFifo[ edgesRead & EDGE_FIFO_MASK ].set( triangle[ 2 ], triangle[ 0 ] );
  571. ++edgesRead;
  572. break;
  573. }
  574. }
  575. else
  576. {
  577. // no edge, so we need to output all the vertices.
  578. OutputVertex( triangle[ 0 ], vertexRemap, newVertices, vertexFifo, verticesRead, output );
  579. OutputVertex( triangle[ 1 ], vertexRemap, newVertices, vertexFifo, verticesRead, output );
  580. OutputVertex( triangle[ 2 ], vertexRemap, newVertices, vertexFifo, verticesRead, output );
  581. // populate the edge fifo with the 3 most recent edges
  582. edgeFifo[ edgesRead & EDGE_FIFO_MASK ].set( triangle[ 0 ], triangle[ 1 ] );
  583. ++edgesRead;
  584. edgeFifo[ edgesRead & EDGE_FIFO_MASK ].set( triangle[ 1 ], triangle[ 2 ] );
  585. ++edgesRead;
  586. edgeFifo[ edgesRead & EDGE_FIFO_MASK ].set( triangle[ 2 ], triangle[ 0 ] );
  587. ++edgesRead;
  588. }
  589. }
  590. }
  591. template <typename Ty>
  592. void CompressIndexBuffer( const Ty* triangles,
  593. uint32_t triangleCount,
  594. uint32_t* vertexRemap,
  595. uint32_t vertexCount,
  596. IndexBufferCompressionFormat format,
  597. WriteBitstream& output )
  598. {
  599. output.WriteVInt( format );
  600. switch ( format )
  601. {
  602. case IBCF_PER_INDICE_1:
  603. CompressIndiceCodes1<Ty>( triangles, triangleCount, vertexRemap, vertexCount, output );
  604. break;
  605. case IBCF_PER_TRIANGLE_1:
  606. CompressTriangleCodes1<Ty>( triangles, triangleCount, vertexRemap, vertexCount, output );
  607. break;
  608. }
  609. }
  610. void CompressIndexBuffer( const uint16_t* triangles,
  611. uint32_t triangleCount,
  612. uint32_t* vertexRemap,
  613. uint32_t vertexCount,
  614. IndexBufferCompressionFormat format,
  615. WriteBitstream& output )
  616. {
  617. CompressIndexBuffer<uint16_t>( triangles, triangleCount, vertexRemap, vertexCount, format, output );
  618. }
  619. void CompressIndexBuffer( const uint32_t* triangles,
  620. uint32_t triangleCount,
  621. uint32_t* vertexRemap,
  622. uint32_t vertexCount,
  623. IndexBufferCompressionFormat format,
  624. WriteBitstream& output )
  625. {
  626. CompressIndexBuffer<uint32_t>( triangles, triangleCount, vertexRemap, vertexCount, format, output );
  627. }