indexcodec.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675
  1. // This file is part of meshoptimizer library; see meshoptimizer.h for version/license details
  2. #include "meshoptimizer.h"
  3. #include <assert.h>
  4. #include <string.h>
  5. // This work is based on:
  6. // Fabian Giesen. Simple lossless index buffer compression & follow-up. 2013
  7. // Conor Stokes. Vertex Cache Optimised Index Buffer Compression. 2014
  8. namespace meshopt
  9. {
  10. const unsigned char kIndexHeader = 0xe0;
  11. const unsigned char kSequenceHeader = 0xd0;
  12. static int gEncodeIndexVersion = 0;
  13. typedef unsigned int VertexFifo[16];
  14. typedef unsigned int EdgeFifo[16][2];
  15. static const unsigned int kTriangleIndexOrder[3][3] = {
  16. {0, 1, 2},
  17. {1, 2, 0},
  18. {2, 0, 1},
  19. };
  20. static const unsigned char kCodeAuxEncodingTable[16] = {
  21. 0x00, 0x76, 0x87, 0x56, 0x67, 0x78, 0xa9, 0x86, 0x65, 0x89, 0x68, 0x98, 0x01, 0x69,
  22. 0, 0, // last two entries aren't used for encoding
  23. };
  24. static int rotateTriangle(unsigned int a, unsigned int b, unsigned int c, unsigned int next)
  25. {
  26. (void)a;
  27. return (b == next) ? 1 : (c == next) ? 2 : 0;
  28. }
  29. static int getEdgeFifo(EdgeFifo fifo, unsigned int a, unsigned int b, unsigned int c, size_t offset)
  30. {
  31. for (int i = 0; i < 16; ++i)
  32. {
  33. size_t index = (offset - 1 - i) & 15;
  34. unsigned int e0 = fifo[index][0];
  35. unsigned int e1 = fifo[index][1];
  36. if (e0 == a && e1 == b)
  37. return (i << 2) | 0;
  38. if (e0 == b && e1 == c)
  39. return (i << 2) | 1;
  40. if (e0 == c && e1 == a)
  41. return (i << 2) | 2;
  42. }
  43. return -1;
  44. }
  45. static void pushEdgeFifo(EdgeFifo fifo, unsigned int a, unsigned int b, size_t& offset)
  46. {
  47. fifo[offset][0] = a;
  48. fifo[offset][1] = b;
  49. offset = (offset + 1) & 15;
  50. }
  51. static int getVertexFifo(VertexFifo fifo, unsigned int v, size_t offset)
  52. {
  53. for (int i = 0; i < 16; ++i)
  54. {
  55. size_t index = (offset - 1 - i) & 15;
  56. if (fifo[index] == v)
  57. return i;
  58. }
  59. return -1;
  60. }
  61. static void pushVertexFifo(VertexFifo fifo, unsigned int v, size_t& offset, int cond = 1)
  62. {
  63. fifo[offset] = v;
  64. offset = (offset + cond) & 15;
  65. }
  66. static void encodeVByte(unsigned char*& data, unsigned int v)
  67. {
  68. // encode 32-bit value in up to 5 7-bit groups
  69. do
  70. {
  71. *data++ = (v & 127) | (v > 127 ? 128 : 0);
  72. v >>= 7;
  73. } while (v);
  74. }
  75. static unsigned int decodeVByte(const unsigned char*& data)
  76. {
  77. unsigned char lead = *data++;
  78. // fast path: single byte
  79. if (lead < 128)
  80. return lead;
  81. // slow path: up to 4 extra bytes
  82. // note that this loop always terminates, which is important for malformed data
  83. unsigned int result = lead & 127;
  84. unsigned int shift = 7;
  85. for (int i = 0; i < 4; ++i)
  86. {
  87. unsigned char group = *data++;
  88. result |= unsigned(group & 127) << shift;
  89. shift += 7;
  90. if (group < 128)
  91. break;
  92. }
  93. return result;
  94. }
  95. static void encodeIndex(unsigned char*& data, unsigned int index, unsigned int last)
  96. {
  97. unsigned int d = index - last;
  98. unsigned int v = (d << 1) ^ (int(d) >> 31);
  99. encodeVByte(data, v);
  100. }
  101. static unsigned int decodeIndex(const unsigned char*& data, unsigned int last)
  102. {
  103. unsigned int v = decodeVByte(data);
  104. unsigned int d = (v >> 1) ^ -int(v & 1);
  105. return last + d;
  106. }
  107. static int getCodeAuxIndex(unsigned char v, const unsigned char* table)
  108. {
  109. for (int i = 0; i < 16; ++i)
  110. if (table[i] == v)
  111. return i;
  112. return -1;
  113. }
  114. static void writeTriangle(void* destination, size_t offset, size_t index_size, unsigned int a, unsigned int b, unsigned int c)
  115. {
  116. if (index_size == 2)
  117. {
  118. static_cast<unsigned short*>(destination)[offset + 0] = (unsigned short)(a);
  119. static_cast<unsigned short*>(destination)[offset + 1] = (unsigned short)(b);
  120. static_cast<unsigned short*>(destination)[offset + 2] = (unsigned short)(c);
  121. }
  122. else
  123. {
  124. static_cast<unsigned int*>(destination)[offset + 0] = a;
  125. static_cast<unsigned int*>(destination)[offset + 1] = b;
  126. static_cast<unsigned int*>(destination)[offset + 2] = c;
  127. }
  128. }
  129. } // namespace meshopt
  130. size_t meshopt_encodeIndexBuffer(unsigned char* buffer, size_t buffer_size, const unsigned int* indices, size_t index_count)
  131. {
  132. using namespace meshopt;
  133. assert(index_count % 3 == 0);
  134. // the minimum valid encoding is header, 1 byte per triangle and a 16-byte codeaux table
  135. if (buffer_size < 1 + index_count / 3 + 16)
  136. return 0;
  137. int version = gEncodeIndexVersion;
  138. buffer[0] = (unsigned char)(kIndexHeader | version);
  139. EdgeFifo edgefifo;
  140. memset(edgefifo, -1, sizeof(edgefifo));
  141. VertexFifo vertexfifo;
  142. memset(vertexfifo, -1, sizeof(vertexfifo));
  143. size_t edgefifooffset = 0;
  144. size_t vertexfifooffset = 0;
  145. unsigned int next = 0;
  146. unsigned int last = 0;
  147. unsigned char* code = buffer + 1;
  148. unsigned char* data = code + index_count / 3;
  149. unsigned char* data_safe_end = buffer + buffer_size - 16;
  150. int fecmax = version >= 1 ? 13 : 15;
  151. // use static encoding table; it's possible to pack the result and then build an optimal table and repack
  152. // for now we keep it simple and use the table that has been generated based on symbol frequency on a training mesh set
  153. const unsigned char* codeaux_table = kCodeAuxEncodingTable;
  154. for (size_t i = 0; i < index_count; i += 3)
  155. {
  156. // make sure we have enough space to write a triangle
  157. // each triangle writes at most 16 bytes: 1b for codeaux and 5b for each free index
  158. // after this we can be sure we can write without extra bounds checks
  159. if (data > data_safe_end)
  160. return 0;
  161. int fer = getEdgeFifo(edgefifo, indices[i + 0], indices[i + 1], indices[i + 2], edgefifooffset);
  162. if (fer >= 0 && (fer >> 2) < 15)
  163. {
  164. const unsigned int* order = kTriangleIndexOrder[fer & 3];
  165. unsigned int a = indices[i + order[0]], b = indices[i + order[1]], c = indices[i + order[2]];
  166. // encode edge index and vertex fifo index, next or free index
  167. int fe = fer >> 2;
  168. int fc = getVertexFifo(vertexfifo, c, vertexfifooffset);
  169. int fec = (fc >= 1 && fc < fecmax) ? fc : (c == next) ? (next++, 0) : 15;
  170. if (fec == 15 && version >= 1)
  171. {
  172. // encode last-1 and last+1 to optimize strip-like sequences
  173. if (c + 1 == last)
  174. fec = 13, last = c;
  175. if (c == last + 1)
  176. fec = 14, last = c;
  177. }
  178. *code++ = (unsigned char)((fe << 4) | fec);
  179. // note that we need to update the last index since free indices are delta-encoded
  180. if (fec == 15)
  181. encodeIndex(data, c, last), last = c;
  182. // we only need to push third vertex since first two are likely already in the vertex fifo
  183. if (fec == 0 || fec >= fecmax)
  184. pushVertexFifo(vertexfifo, c, vertexfifooffset);
  185. // we only need to push two new edges to edge fifo since the third one is already there
  186. pushEdgeFifo(edgefifo, c, b, edgefifooffset);
  187. pushEdgeFifo(edgefifo, a, c, edgefifooffset);
  188. }
  189. else
  190. {
  191. int rotation = rotateTriangle(indices[i + 0], indices[i + 1], indices[i + 2], next);
  192. const unsigned int* order = kTriangleIndexOrder[rotation];
  193. unsigned int a = indices[i + order[0]], b = indices[i + order[1]], c = indices[i + order[2]];
  194. // if a/b/c are 0/1/2, we emit a reset code
  195. bool reset = false;
  196. if (a == 0 && b == 1 && c == 2 && next > 0 && version >= 1)
  197. {
  198. reset = true;
  199. next = 0;
  200. // reset vertex fifo to make sure we don't accidentally reference vertices from that in the future
  201. // this makes sure next continues to get incremented instead of being stuck
  202. memset(vertexfifo, -1, sizeof(vertexfifo));
  203. }
  204. int fb = getVertexFifo(vertexfifo, b, vertexfifooffset);
  205. int fc = getVertexFifo(vertexfifo, c, vertexfifooffset);
  206. // after rotation, a is almost always equal to next, so we don't waste bits on FIFO encoding for a
  207. int fea = (a == next) ? (next++, 0) : 15;
  208. int feb = (fb >= 0 && fb < 14) ? (fb + 1) : (b == next) ? (next++, 0) : 15;
  209. int fec = (fc >= 0 && fc < 14) ? (fc + 1) : (c == next) ? (next++, 0) : 15;
  210. // we encode feb & fec in 4 bits using a table if possible, and as a full byte otherwise
  211. unsigned char codeaux = (unsigned char)((feb << 4) | fec);
  212. int codeauxindex = getCodeAuxIndex(codeaux, codeaux_table);
  213. // <14 encodes an index into codeaux table, 14 encodes fea=0, 15 encodes fea=15
  214. if (fea == 0 && codeauxindex >= 0 && codeauxindex < 14 && !reset)
  215. {
  216. *code++ = (unsigned char)((15 << 4) | codeauxindex);
  217. }
  218. else
  219. {
  220. *code++ = (unsigned char)((15 << 4) | 14 | fea);
  221. *data++ = codeaux;
  222. }
  223. // note that we need to update the last index since free indices are delta-encoded
  224. if (fea == 15)
  225. encodeIndex(data, a, last), last = a;
  226. if (feb == 15)
  227. encodeIndex(data, b, last), last = b;
  228. if (fec == 15)
  229. encodeIndex(data, c, last), last = c;
  230. // only push vertices that weren't already in fifo
  231. if (fea == 0 || fea == 15)
  232. pushVertexFifo(vertexfifo, a, vertexfifooffset);
  233. if (feb == 0 || feb == 15)
  234. pushVertexFifo(vertexfifo, b, vertexfifooffset);
  235. if (fec == 0 || fec == 15)
  236. pushVertexFifo(vertexfifo, c, vertexfifooffset);
  237. // all three edges aren't in the fifo; pushing all of them is important so that we can match them for later triangles
  238. pushEdgeFifo(edgefifo, b, a, edgefifooffset);
  239. pushEdgeFifo(edgefifo, c, b, edgefifooffset);
  240. pushEdgeFifo(edgefifo, a, c, edgefifooffset);
  241. }
  242. }
  243. // make sure we have enough space to write codeaux table
  244. if (data > data_safe_end)
  245. return 0;
  246. // add codeaux encoding table to the end of the stream; this is used for decoding codeaux *and* as padding
  247. // we need padding for decoding to be able to assume that each triangle is encoded as <= 16 bytes of extra data
  248. // this is enough space for aux byte + 5 bytes per varint index which is the absolute worst case for any input
  249. for (size_t i = 0; i < 16; ++i)
  250. {
  251. // decoder assumes that table entries never refer to separately encoded indices
  252. assert((codeaux_table[i] & 0xf) != 0xf && (codeaux_table[i] >> 4) != 0xf);
  253. *data++ = codeaux_table[i];
  254. }
  255. // since we encode restarts as codeaux without a table reference, we need to make sure 00 is encoded as a table reference
  256. assert(codeaux_table[0] == 0);
  257. assert(data >= buffer + index_count / 3 + 16);
  258. assert(data <= buffer + buffer_size);
  259. return data - buffer;
  260. }
  261. size_t meshopt_encodeIndexBufferBound(size_t index_count, size_t vertex_count)
  262. {
  263. assert(index_count % 3 == 0);
  264. // compute number of bits required for each index
  265. unsigned int vertex_bits = 1;
  266. while (vertex_bits < 32 && vertex_count > size_t(1) << vertex_bits)
  267. vertex_bits++;
  268. // worst-case encoding is 2 header bytes + 3 varint-7 encoded index deltas
  269. unsigned int vertex_groups = (vertex_bits + 1 + 6) / 7;
  270. return 1 + (index_count / 3) * (2 + 3 * vertex_groups) + 16;
  271. }
  272. void meshopt_encodeIndexVersion(int version)
  273. {
  274. assert(unsigned(version) <= 1);
  275. meshopt::gEncodeIndexVersion = version;
  276. }
  277. int meshopt_decodeIndexBuffer(void* destination, size_t index_count, size_t index_size, const unsigned char* buffer, size_t buffer_size)
  278. {
  279. using namespace meshopt;
  280. assert(index_count % 3 == 0);
  281. assert(index_size == 2 || index_size == 4);
  282. // the minimum valid encoding is header, 1 byte per triangle and a 16-byte codeaux table
  283. if (buffer_size < 1 + index_count / 3 + 16)
  284. return -2;
  285. if ((buffer[0] & 0xf0) != kIndexHeader)
  286. return -1;
  287. int version = buffer[0] & 0x0f;
  288. if (version > 1)
  289. return -1;
  290. EdgeFifo edgefifo;
  291. memset(edgefifo, -1, sizeof(edgefifo));
  292. VertexFifo vertexfifo;
  293. memset(vertexfifo, -1, sizeof(vertexfifo));
  294. size_t edgefifooffset = 0;
  295. size_t vertexfifooffset = 0;
  296. unsigned int next = 0;
  297. unsigned int last = 0;
  298. int fecmax = version >= 1 ? 13 : 15;
  299. // since we store 16-byte codeaux table at the end, triangle data has to begin before data_safe_end
  300. const unsigned char* code = buffer + 1;
  301. const unsigned char* data = code + index_count / 3;
  302. const unsigned char* data_safe_end = buffer + buffer_size - 16;
  303. const unsigned char* codeaux_table = data_safe_end;
  304. for (size_t i = 0; i < index_count; i += 3)
  305. {
  306. // make sure we have enough data to read for a triangle
  307. // each triangle reads at most 16 bytes of data: 1b for codeaux and 5b for each free index
  308. // after this we can be sure we can read without extra bounds checks
  309. if (data > data_safe_end)
  310. return -2;
  311. unsigned char codetri = *code++;
  312. if (codetri < 0xf0)
  313. {
  314. int fe = codetri >> 4;
  315. // fifo reads are wrapped around 16 entry buffer
  316. unsigned int a = edgefifo[(edgefifooffset - 1 - fe) & 15][0];
  317. unsigned int b = edgefifo[(edgefifooffset - 1 - fe) & 15][1];
  318. int fec = codetri & 15;
  319. // note: this is the most common path in the entire decoder
  320. // inside this if we try to stay branchless (by using cmov/etc.) since these aren't predictable
  321. if (fec < fecmax)
  322. {
  323. // fifo reads are wrapped around 16 entry buffer
  324. unsigned int cf = vertexfifo[(vertexfifooffset - 1 - fec) & 15];
  325. unsigned int c = (fec == 0) ? next : cf;
  326. int fec0 = fec == 0;
  327. next += fec0;
  328. // output triangle
  329. writeTriangle(destination, i, index_size, a, b, c);
  330. // push vertex/edge fifo must match the encoding step *exactly* otherwise the data will not be decoded correctly
  331. pushVertexFifo(vertexfifo, c, vertexfifooffset, fec0);
  332. pushEdgeFifo(edgefifo, c, b, edgefifooffset);
  333. pushEdgeFifo(edgefifo, a, c, edgefifooffset);
  334. }
  335. else
  336. {
  337. unsigned int c = 0;
  338. // fec - (fec ^ 3) decodes 13, 14 into -1, 1
  339. // note that we need to update the last index since free indices are delta-encoded
  340. last = c = (fec != 15) ? last + (fec - (fec ^ 3)) : decodeIndex(data, last);
  341. // output triangle
  342. writeTriangle(destination, i, index_size, a, b, c);
  343. // push vertex/edge fifo must match the encoding step *exactly* otherwise the data will not be decoded correctly
  344. pushVertexFifo(vertexfifo, c, vertexfifooffset);
  345. pushEdgeFifo(edgefifo, c, b, edgefifooffset);
  346. pushEdgeFifo(edgefifo, a, c, edgefifooffset);
  347. }
  348. }
  349. else
  350. {
  351. // fast path: read codeaux from the table
  352. if (codetri < 0xfe)
  353. {
  354. unsigned char codeaux = codeaux_table[codetri & 15];
  355. // note: table can't contain feb/fec=15
  356. int feb = codeaux >> 4;
  357. int fec = codeaux & 15;
  358. // fifo reads are wrapped around 16 entry buffer
  359. // also note that we increment next for all three vertices before decoding indices - this matches encoder behavior
  360. unsigned int a = next++;
  361. unsigned int bf = vertexfifo[(vertexfifooffset - feb) & 15];
  362. unsigned int b = (feb == 0) ? next : bf;
  363. int feb0 = feb == 0;
  364. next += feb0;
  365. unsigned int cf = vertexfifo[(vertexfifooffset - fec) & 15];
  366. unsigned int c = (fec == 0) ? next : cf;
  367. int fec0 = fec == 0;
  368. next += fec0;
  369. // output triangle
  370. writeTriangle(destination, i, index_size, a, b, c);
  371. // push vertex/edge fifo must match the encoding step *exactly* otherwise the data will not be decoded correctly
  372. pushVertexFifo(vertexfifo, a, vertexfifooffset);
  373. pushVertexFifo(vertexfifo, b, vertexfifooffset, feb0);
  374. pushVertexFifo(vertexfifo, c, vertexfifooffset, fec0);
  375. pushEdgeFifo(edgefifo, b, a, edgefifooffset);
  376. pushEdgeFifo(edgefifo, c, b, edgefifooffset);
  377. pushEdgeFifo(edgefifo, a, c, edgefifooffset);
  378. }
  379. else
  380. {
  381. // slow path: read a full byte for codeaux instead of using a table lookup
  382. unsigned char codeaux = *data++;
  383. int fea = codetri == 0xfe ? 0 : 15;
  384. int feb = codeaux >> 4;
  385. int fec = codeaux & 15;
  386. // reset: codeaux is 0 but encoded as not-a-table
  387. if (codeaux == 0)
  388. next = 0;
  389. // fifo reads are wrapped around 16 entry buffer
  390. // also note that we increment next for all three vertices before decoding indices - this matches encoder behavior
  391. unsigned int a = (fea == 0) ? next++ : 0;
  392. unsigned int b = (feb == 0) ? next++ : vertexfifo[(vertexfifooffset - feb) & 15];
  393. unsigned int c = (fec == 0) ? next++ : vertexfifo[(vertexfifooffset - fec) & 15];
  394. // note that we need to update the last index since free indices are delta-encoded
  395. if (fea == 15)
  396. last = a = decodeIndex(data, last);
  397. if (feb == 15)
  398. last = b = decodeIndex(data, last);
  399. if (fec == 15)
  400. last = c = decodeIndex(data, last);
  401. // output triangle
  402. writeTriangle(destination, i, index_size, a, b, c);
  403. // push vertex/edge fifo must match the encoding step *exactly* otherwise the data will not be decoded correctly
  404. pushVertexFifo(vertexfifo, a, vertexfifooffset);
  405. pushVertexFifo(vertexfifo, b, vertexfifooffset, (feb == 0) | (feb == 15));
  406. pushVertexFifo(vertexfifo, c, vertexfifooffset, (fec == 0) | (fec == 15));
  407. pushEdgeFifo(edgefifo, b, a, edgefifooffset);
  408. pushEdgeFifo(edgefifo, c, b, edgefifooffset);
  409. pushEdgeFifo(edgefifo, a, c, edgefifooffset);
  410. }
  411. }
  412. }
  413. // we should've read all data bytes and stopped at the boundary between data and codeaux table
  414. if (data != data_safe_end)
  415. return -3;
  416. return 0;
  417. }
  418. size_t meshopt_encodeIndexSequence(unsigned char* buffer, size_t buffer_size, const unsigned int* indices, size_t index_count)
  419. {
  420. using namespace meshopt;
  421. // the minimum valid encoding is header, 1 byte per index and a 4-byte tail
  422. if (buffer_size < 1 + index_count + 4)
  423. return 0;
  424. int version = gEncodeIndexVersion;
  425. buffer[0] = (unsigned char)(kSequenceHeader | version);
  426. unsigned int last[2] = {};
  427. unsigned int current = 0;
  428. unsigned char* data = buffer + 1;
  429. unsigned char* data_safe_end = buffer + buffer_size - 4;
  430. for (size_t i = 0; i < index_count; ++i)
  431. {
  432. // make sure we have enough data to write
  433. // each index writes at most 5 bytes of data; there's a 4 byte tail after data_safe_end
  434. // after this we can be sure we can write without extra bounds checks
  435. if (data >= data_safe_end)
  436. return 0;
  437. unsigned int index = indices[i];
  438. // this is a heuristic that switches between baselines when the delta grows too large
  439. // we want the encoded delta to fit into one byte (7 bits), but 2 bits are used for sign and baseline index
  440. // for now we immediately switch the baseline when delta grows too large - this can be adjusted arbitrarily
  441. int cd = int(index - last[current]);
  442. current ^= ((cd < 0 ? -cd : cd) >= 30);
  443. // encode delta from the last index
  444. unsigned int d = index - last[current];
  445. unsigned int v = (d << 1) ^ (int(d) >> 31);
  446. // note: low bit encodes the index of the last baseline which will be used for reconstruction
  447. encodeVByte(data, (v << 1) | current);
  448. // update last for the next iteration that uses it
  449. last[current] = index;
  450. }
  451. // make sure we have enough space to write tail
  452. if (data > data_safe_end)
  453. return 0;
  454. for (int k = 0; k < 4; ++k)
  455. *data++ = 0;
  456. return data - buffer;
  457. }
  458. size_t meshopt_encodeIndexSequenceBound(size_t index_count, size_t vertex_count)
  459. {
  460. // compute number of bits required for each index
  461. unsigned int vertex_bits = 1;
  462. while (vertex_bits < 32 && vertex_count > size_t(1) << vertex_bits)
  463. vertex_bits++;
  464. // worst-case encoding is 1 varint-7 encoded index delta for a K bit value and an extra bit
  465. unsigned int vertex_groups = (vertex_bits + 1 + 1 + 6) / 7;
  466. return 1 + index_count * vertex_groups + 4;
  467. }
  468. int meshopt_decodeIndexSequence(void* destination, size_t index_count, size_t index_size, const unsigned char* buffer, size_t buffer_size)
  469. {
  470. using namespace meshopt;
  471. // the minimum valid encoding is header, 1 byte per index and a 4-byte tail
  472. if (buffer_size < 1 + index_count + 4)
  473. return -2;
  474. if ((buffer[0] & 0xf0) != kSequenceHeader)
  475. return -1;
  476. int version = buffer[0] & 0x0f;
  477. if (version > 1)
  478. return -1;
  479. const unsigned char* data = buffer + 1;
  480. const unsigned char* data_safe_end = buffer + buffer_size - 4;
  481. unsigned int last[2] = {};
  482. for (size_t i = 0; i < index_count; ++i)
  483. {
  484. // make sure we have enough data to read
  485. // each index reads at most 5 bytes of data; there's a 4 byte tail after data_safe_end
  486. // after this we can be sure we can read without extra bounds checks
  487. if (data >= data_safe_end)
  488. return -2;
  489. unsigned int v = decodeVByte(data);
  490. // decode the index of the last baseline
  491. unsigned int current = v & 1;
  492. v >>= 1;
  493. // reconstruct index as a delta
  494. unsigned int d = (v >> 1) ^ -int(v & 1);
  495. unsigned int index = last[current] + d;
  496. // update last for the next iteration that uses it
  497. last[current] = index;
  498. if (index_size == 2)
  499. {
  500. static_cast<unsigned short*>(destination)[i] = (unsigned short)(index);
  501. }
  502. else
  503. {
  504. static_cast<unsigned int*>(destination)[i] = index;
  505. }
  506. }
  507. // we should've read all data bytes and stopped at the boundary between data and tail
  508. if (data != data_safe_end)
  509. return -3;
  510. return 0;
  511. }