meshopt_decoder_reference.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. // This file is part of meshoptimizer library and is distributed under the terms of MIT License.
  2. // Copyright (C) 2016-2022, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
  3. // This is the reference decoder implementation by Jasper St. Pierre.
  4. // It follows the decoder interface and should be a drop-in replacement for the actual decoder from meshopt_decoder.js
  5. // It is provided for educational value and is not recommended for use in production because it's not performance-optimized.
  6. const MeshoptDecoder = {};
  7. MeshoptDecoder.supported = true;
  8. MeshoptDecoder.ready = Promise.resolve();
  9. function assert(cond) {
  10. if (!cond) {
  11. throw new Error("Assertion failed");
  12. }
  13. }
  14. function dezig(v) {
  15. return ((v & 1) !== 0) ? ~(v >>> 1) : v >>> 1;
  16. }
  17. MeshoptDecoder.decodeVertexBuffer = (target, elementCount, byteStride, source, filter) => {
  18. assert(source[0] === 0xA0);
  19. const maxBlockElements = Math.min((0x2000 / byteStride) & ~0x000F, 0x100);
  20. const deltas = new Uint8Array(0x10);
  21. const tailDataOffs = source.length - byteStride;
  22. // What deltas are stored relative to
  23. const tempData = source.slice(tailDataOffs, tailDataOffs + byteStride);
  24. let srcOffs = 0x01;
  25. // Attribute Blocks
  26. for (let dstElemBase = 0; dstElemBase < elementCount; dstElemBase += maxBlockElements) {
  27. const attrBlockElementCount = Math.min(elementCount - dstElemBase, maxBlockElements);
  28. const groupCount = ((attrBlockElementCount + 0x0F) & ~0x0F) >>> 4;
  29. const headerByteCount = ((groupCount + 0x03) & ~0x03) >>> 2;
  30. // Data blocks
  31. for (let byte = 0; byte < byteStride; byte++) {
  32. let headerBitsOffs = srcOffs;
  33. srcOffs += headerByteCount;
  34. for (let group = 0; group < groupCount; group++) {
  35. const mode = (source[headerBitsOffs] >>> ((group & 0x03) << 1)) & 0x03;
  36. // If this is the last group, move to the next byte of header bits.
  37. if ((group & 0x03) === 0x03)
  38. headerBitsOffs++;
  39. const dstElemGroup = dstElemBase + (group << 4);
  40. if (mode === 0) {
  41. // bits 0: All 16 byte deltas are 0; the size of the encoded block is 0 bytes
  42. deltas.fill(0x00);
  43. } else if (mode === 1) {
  44. // bits 1: Deltas are using 2-bit sentinel encoding; the size of the encoded block is [4..20] bytes
  45. const srcBase = srcOffs;
  46. srcOffs += 0x04;
  47. for (let m = 0; m < 0x10; m++) {
  48. // 0 = >>> 6, 1 = >>> 4, 2 = >>> 2, 3 = >>> 0
  49. const shift = (6 - ((m & 0x03) << 1));
  50. let delta = (source[srcBase + (m >>> 2)] >>> shift) & 0x03;
  51. if (delta === 3)
  52. delta = source[srcOffs++];
  53. deltas[m] = delta;
  54. }
  55. } else if (mode === 2) {
  56. // bits 2: Deltas are using 4-bit sentinel encoding; the size of the encoded block is [8..24] bytes
  57. const srcBase = srcOffs;
  58. srcOffs += 0x08;
  59. for (let m = 0; m < 0x10; m++) {
  60. // 0 = >>> 6, 1 = >>> 4, 2 = >>> 2, 3 = >>> 0
  61. const shift = (m & 0x01) ? 0 : 4;
  62. let delta = (source[srcBase + (m >>> 1)] >>> shift) & 0x0f;
  63. if (delta === 0xf)
  64. delta = source[srcOffs++];
  65. deltas[m] = delta;
  66. }
  67. } else {
  68. // bits 3: All 16 byte deltas are stored verbatim; the size of the encoded block is 16 bytes
  69. deltas.set(source.subarray(srcOffs, srcOffs + 0x10));
  70. srcOffs += 0x10;
  71. }
  72. // Go through and apply deltas to data
  73. for (let m = 0; m < 0x10; m++) {
  74. const dstElem = dstElemGroup + m;
  75. if (dstElem >= elementCount)
  76. break;
  77. const delta = dezig(deltas[m]);
  78. const dstOffs = dstElem * byteStride + byte;
  79. target[dstOffs] = (tempData[byte] += delta);
  80. }
  81. }
  82. }
  83. }
  84. // Filters - only applied if filter isn't undefined or NONE
  85. if (filter === 'OCTAHEDRAL') {
  86. assert(byteStride === 4 || byteStride === 8);
  87. let dst, maxInt;
  88. if (byteStride === 4) {
  89. dst = new Int8Array(target.buffer);
  90. maxInt = 127;
  91. } else {
  92. dst = new Int16Array(target.buffer);
  93. maxInt = 32767;
  94. }
  95. for (let i = 0; i < 4 * elementCount; i += 4) {
  96. let x = dst[i + 0], y = dst[i + 1], one = dst[i + 2];
  97. x /= one;
  98. y /= one;
  99. const z = 1.0 - Math.abs(x) - Math.abs(y);
  100. const t = Math.max(-z, 0.0);
  101. x -= (x >= 0) ? t : -t;
  102. y -= (y >= 0) ? t : -t;
  103. const h = maxInt / Math.hypot(x, y, z);
  104. dst[i + 0] = Math.round(x * h);
  105. dst[i + 1] = Math.round(y * h);
  106. dst[i + 2] = Math.round(z * h);
  107. // keep dst[i + 3] as is
  108. }
  109. } else if (filter === 'QUATERNION') {
  110. assert(byteStride === 8);
  111. const dst = new Int16Array(target.buffer);
  112. for (let i = 0; i < 4 * elementCount; i += 4) {
  113. const inputW = dst[i + 3];
  114. const maxComponent = inputW & 0x03;
  115. const s = Math.SQRT1_2 / (inputW | 0x03);
  116. let x = dst[i + 0] * s;
  117. let y = dst[i + 1] * s;
  118. let z = dst[i + 2] * s;
  119. let w = Math.sqrt(Math.max(0.0, 1.0 - x**2 - y**2 - z**2));
  120. dst[i + (maxComponent + 1) % 4] = Math.round(x * 32767);
  121. dst[i + (maxComponent + 2) % 4] = Math.round(y * 32767);
  122. dst[i + (maxComponent + 3) % 4] = Math.round(z * 32767);
  123. dst[i + (maxComponent + 0) % 4] = Math.round(w * 32767);
  124. }
  125. } else if (filter === 'EXPONENTIAL') {
  126. assert((byteStride & 0x03) === 0x00);
  127. const src = new Int32Array(target.buffer);
  128. const dst = new Float32Array(target.buffer);
  129. for (let i = 0; i < (byteStride * elementCount) / 4; i++) {
  130. const v = src[i], exp = v >> 24, mantissa = (v << 8) >> 8;
  131. dst[i] = 2.0**exp * mantissa;
  132. }
  133. }
  134. };
  135. function pushfifo(fifo, n) {
  136. for (let i = fifo.length - 1; i > 0; i--)
  137. fifo[i] = fifo[i - 1];
  138. fifo[0] = n;
  139. }
  140. MeshoptDecoder.decodeIndexBuffer = (target, count, byteStride, source) => {
  141. assert(source[0] === 0xE1);
  142. assert(count % 3 === 0);
  143. assert(byteStride === 2 || byteStride === 4);
  144. let dst;
  145. if (byteStride === 2)
  146. dst = new Uint16Array(target.buffer);
  147. else
  148. dst = new Uint32Array(target.buffer);
  149. const triCount = count / 3;
  150. let codeOffs = 0x01;
  151. let dataOffs = codeOffs + triCount;
  152. let codeauxOffs = source.length - 0x10;
  153. function readLEB128() {
  154. let n = 0;
  155. for (let i = 0; ; i += 7) {
  156. const b = source[dataOffs++];
  157. n |= (b & 0x7F) << i;
  158. if (b < 0x80)
  159. return n;
  160. }
  161. }
  162. let next = 0, last = 0;
  163. const edgefifo = new Uint32Array(32);
  164. const vertexfifo = new Uint32Array(16);
  165. function decodeIndex(v) {
  166. return (last += dezig(v));
  167. }
  168. let dstOffs = 0;
  169. for (let i = 0; i < triCount; i++) {
  170. const code = source[codeOffs++];
  171. const b0 = code >>> 4, b1 = code & 0x0F;
  172. if (b0 < 0x0F) {
  173. const a = edgefifo[(b0 << 1) + 0], b = edgefifo[(b0 << 1) + 1];
  174. let c = -1;
  175. if (b1 === 0x00) {
  176. c = next++;
  177. pushfifo(vertexfifo, c);
  178. } else if (b1 < 0x0D) {
  179. c = vertexfifo[b1];
  180. } else if (b1 === 0x0D) {
  181. c = --last;
  182. pushfifo(vertexfifo, c);
  183. } else if (b1 === 0x0E) {
  184. c = ++last;
  185. pushfifo(vertexfifo, c);
  186. } else if (b1 === 0x0F) {
  187. const v = readLEB128();
  188. c = decodeIndex(v);
  189. pushfifo(vertexfifo, c);
  190. }
  191. // fifo pushes happen backwards
  192. pushfifo(edgefifo, b); pushfifo(edgefifo, c);
  193. pushfifo(edgefifo, c); pushfifo(edgefifo, a);
  194. dst[dstOffs++] = a;
  195. dst[dstOffs++] = b;
  196. dst[dstOffs++] = c;
  197. } else { // b0 === 0x0F
  198. let a = -1, b = -1, c = -1;
  199. if (b1 < 0x0E) {
  200. const e = source[codeauxOffs + b1];
  201. const z = e >>> 4, w = e & 0x0F;
  202. a = next++;
  203. if (z === 0x00)
  204. b = next++;
  205. else
  206. b = vertexfifo[z - 1];
  207. if (w === 0x00)
  208. c = next++;
  209. else
  210. c = vertexfifo[w - 1];
  211. pushfifo(vertexfifo, a);
  212. if (z === 0x00)
  213. pushfifo(vertexfifo, b);
  214. if (w === 0x00)
  215. pushfifo(vertexfifo, c);
  216. } else {
  217. const e = source[dataOffs++];
  218. if (e === 0x00)
  219. next = 0;
  220. const z = e >>> 4, w = e & 0x0F;
  221. if (b1 === 0x0E)
  222. a = next++;
  223. else
  224. a = decodeIndex(readLEB128());
  225. if (z === 0x00)
  226. b = next++;
  227. else if (z === 0x0F)
  228. b = decodeIndex(readLEB128());
  229. else
  230. b = vertexfifo[z - 1];
  231. if (w === 0x00)
  232. c = next++;
  233. else if (w === 0x0F)
  234. c = decodeIndex(readLEB128());
  235. else
  236. c = vertexfifo[w - 1];
  237. pushfifo(vertexfifo, a);
  238. if (z === 0x00 || z === 0x0F)
  239. pushfifo(vertexfifo, b);
  240. if (w === 0x00 || w === 0x0F)
  241. pushfifo(vertexfifo, c);
  242. }
  243. pushfifo(edgefifo, a); pushfifo(edgefifo, b);
  244. pushfifo(edgefifo, b); pushfifo(edgefifo, c);
  245. pushfifo(edgefifo, c); pushfifo(edgefifo, a);
  246. dst[dstOffs++] = a;
  247. dst[dstOffs++] = b;
  248. dst[dstOffs++] = c;
  249. }
  250. }
  251. };
  252. MeshoptDecoder.decodeIndexSequence = (target, count, byteStride, source) => {
  253. assert(source[0] === 0xD1);
  254. assert(byteStride === 2 || byteStride === 4);
  255. let dst;
  256. if (byteStride === 2)
  257. dst = new Uint16Array(target.buffer);
  258. else
  259. dst = new Uint32Array(target.buffer);
  260. let dataOffs = 0x01;
  261. function readLEB128() {
  262. let n = 0;
  263. for (let i = 0; ; i += 7) {
  264. const b = source[dataOffs++];
  265. n |= (b & 0x7F) << i;
  266. if (b < 0x80)
  267. return n;
  268. }
  269. }
  270. const last = new Uint32Array(2);
  271. for (let i = 0; i < count; i++) {
  272. const v = readLEB128();
  273. const b = (v & 0x01);
  274. const delta = dezig(v >>> 1);
  275. dst[i] = (last[b] += delta);
  276. }
  277. };
  278. MeshoptDecoder.decodeGltfBuffer = (target, count, size, source, mode, filter) => {
  279. var table = {
  280. ATTRIBUTES: MeshoptDecoder.decodeVertexBuffer,
  281. TRIANGLES: MeshoptDecoder.decodeIndexBuffer,
  282. INDICES: MeshoptDecoder.decodeIndexSequence,
  283. };
  284. assert(table[mode] !== undefined);
  285. table[mode](target, count, size, source, filter);
  286. };
  287. // node.js interface:
  288. // for (let k in MeshoptDecoder) { exports[k] = MeshoptDecoder[k]; }
  289. export { MeshoptDecoder };