From 1504bcfe25012fdf70041355576ba25e0b4b8e6d Mon Sep 17 00:00:00 2001 From: Arseny Kapoulkine Date: Tue, 27 Jul 2021 20:12:46 -0700 Subject: [PATCH 01/11] js: Add meshopt_encoder module and tests This adds the entire encoder module and wrappers + tests for raw encoders (vertex, triangle and sequence data). We still need to implement mesh preparation and encoding filters. --- js/meshopt_encoder.js | 105 +++++++++++++++++++++++++++++++++ js/meshopt_encoder.module.d.ts | 10 ++++ js/meshopt_encoder.module.js | 95 +++++++++++++++++++++++++++++ js/meshopt_encoder.test.js | 80 +++++++++++++++++++++++++ 4 files changed, 290 insertions(+) create mode 100644 js/meshopt_encoder.js create mode 100644 js/meshopt_encoder.module.d.ts create mode 100644 js/meshopt_encoder.module.js create mode 100644 js/meshopt_encoder.test.js diff --git a/js/meshopt_encoder.js b/js/meshopt_encoder.js new file mode 100644 index 000000000..eb1d27928 --- /dev/null +++ b/js/meshopt_encoder.js @@ -0,0 +1,105 @@ +// This file is part of meshoptimizer library and is distributed under the terms of MIT License. +// Copyright (C) 2016-2021, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) +var MeshoptEncoder = (function() { + "use strict"; + + // Built with clang version 11.0.0 (https://github.com/llvm/llvm-project 176249bd6732a8044d457092ed932768724a6f06) + // Built from meshoptimizer 0.16 + var wasm = "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"; + + // Used to unpack wasm + var wasmpack = new Uint8Array([32,0,65,2,1,106,34,33,3,128,11,4,13,64,6,253,10,7,15,116,127,5,8,12,40,16,19,54,20,9,27,255,113,17,42,67,24,23,146,148,18,14,22,45,70,69,56,114,101,21,25,63,75,136,108,28,118,29,73,115]); + + if (typeof WebAssembly !== 'object') { + // This module requires WebAssembly to function + return { + supported: false, + }; + } + + var instance; + + var promise = + WebAssembly.instantiate(unpack(wasm), {}) + .then(function(result) { + instance = result.instance; + instance.exports.__wasm_call_ctors(); + instance.exports.meshopt_encodeVertexVersion(0); + instance.exports.meshopt_encodeIndexVersion(1); + }); + + function unpack(data) { + var result = new Uint8Array(data.length); + for (var i = 0; i < data.length; ++i) { + var ch = data.charCodeAt(i); + result[i] = ch > 96 ? ch - 71 : ch > 64 ? ch - 65 : ch > 47 ? ch + 4 : ch > 46 ? 63 : 62; + } + var write = 0; + for (var i = 0; i < data.length; ++i) { + result[write++] = (result[i] < 60) ? wasmpack[result[i]] : (result[i] - 60) * 64 + result[++i]; + } + return result.buffer.slice(0, write); + } + + function encode(fun, bound, source, count, size) { + var sbrk = instance.exports.sbrk; + var tp = sbrk(bound); + var sp = sbrk(count * size); + var heap = new Uint8Array(instance.exports.memory.buffer); + heap.set(new Uint8Array(source.buffer, source.byteOffset, source.byteLength), sp); + var res = fun(tp, bound, sp, count, size); + var target = new Uint8Array(res); + target.set(heap.subarray(tp, tp + res)); + sbrk(tp - sbrk(0)); + return target; + }; + + function maxindex(source) { + var result = 0; + for (var i = 0; i < source.length; ++i) { + var index = source[i]; + result = result < index ? index : result; + } + return result; + } + + function index32(source) { + if (source instanceof Uint32Array || source instanceof Int32Array) { + return source; + } + var result = new Uint32Array(source.length); + for (var i = 0; i < source.length; ++i) { + result[i] = source[i]; + } + return result; + } + + return { + ready: promise, + supported: true, + encodeVertexBuffer: function(source, count, size) { + var bound = instance.exports.meshopt_encodeVertexBufferBound(count, size); + return encode(instance.exports.meshopt_encodeVertexBuffer, bound, source, count, size); + }, + encodeIndexBuffer: function(source, count) { + var bound = instance.exports.meshopt_encodeIndexBufferBound(count, maxindex(source) + 1); + return encode(instance.exports.meshopt_encodeIndexBuffer, bound, index32(source), count, 4); + }, + encodeIndexSequence: function(source, count) { + var bound = instance.exports.meshopt_encodeIndexSequenceBound(count, maxindex(source) + 1); + return encode(instance.exports.meshopt_encodeIndexSequence, bound, index32(source), count, 4); + }, + }; +})(); + +// UMD-style export for MeshoptEncoder +if (typeof exports === 'object' && typeof module === 'object') + module.exports = MeshoptEncoder; +else if (typeof define === 'function' && define['amd']) + define([], function() { + return MeshoptEncoder; + }); +else if (typeof exports === 'object') + exports["MeshoptEncoder"] = MeshoptEncoder; +else + (typeof self !== 'undefined' ? self : this).MeshoptEncoder = MeshoptEncoder; diff --git a/js/meshopt_encoder.module.d.ts b/js/meshopt_encoder.module.d.ts new file mode 100644 index 000000000..1522cd108 --- /dev/null +++ b/js/meshopt_encoder.module.d.ts @@ -0,0 +1,10 @@ +// This file is part of meshoptimizer library and is distributed under the terms of MIT License. +// Copyright (C) 2016-2021, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) +export const MeshoptEncoder: { + supported: boolean; + ready: Promise; + + encodeVertexBuffer: (source: Uint8Array, count: number, size: number) => Uint8Array; + encodeIndexBuffer: (source: Uint32Array, count: number) => Uint8Array; + encodeIndexSequence: (source: Uint32Array, count: number) => Uint8Array; +}; diff --git a/js/meshopt_encoder.module.js b/js/meshopt_encoder.module.js new file mode 100644 index 000000000..d7b5b97e4 --- /dev/null +++ b/js/meshopt_encoder.module.js @@ -0,0 +1,95 @@ +// This file is part of meshoptimizer library and is distributed under the terms of MIT License. +// Copyright (C) 2016-2021, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) +var MeshoptEncoder = (function() { + "use strict"; + + // Built with clang version 11.0.0 (https://github.com/llvm/llvm-project 176249bd6732a8044d457092ed932768724a6f06) + // Built from meshoptimizer 0.16 + var wasm = "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"; + + // Used to unpack wasm + var wasmpack = new Uint8Array([32,0,65,2,1,106,34,33,3,128,11,4,13,64,6,253,10,7,15,116,127,5,8,12,40,16,19,54,20,9,27,255,113,17,42,67,24,23,146,148,18,14,22,45,70,69,56,114,101,21,25,63,75,136,108,28,118,29,73,115]); + + if (typeof WebAssembly !== 'object') { + // This module requires WebAssembly to function + return { + supported: false, + }; + } + + var instance; + + var promise = + WebAssembly.instantiate(unpack(wasm), {}) + .then(function(result) { + instance = result.instance; + instance.exports.__wasm_call_ctors(); + instance.exports.meshopt_encodeVertexVersion(0); + instance.exports.meshopt_encodeIndexVersion(1); + }); + + function unpack(data) { + var result = new Uint8Array(data.length); + for (var i = 0; i < data.length; ++i) { + var ch = data.charCodeAt(i); + result[i] = ch > 96 ? ch - 71 : ch > 64 ? ch - 65 : ch > 47 ? ch + 4 : ch > 46 ? 63 : 62; + } + var write = 0; + for (var i = 0; i < data.length; ++i) { + result[write++] = (result[i] < 60) ? wasmpack[result[i]] : (result[i] - 60) * 64 + result[++i]; + } + return result.buffer.slice(0, write); + } + + function encode(fun, bound, source, count, size) { + var sbrk = instance.exports.sbrk; + var tp = sbrk(bound); + var sp = sbrk(count * size); + var heap = new Uint8Array(instance.exports.memory.buffer); + heap.set(new Uint8Array(source.buffer, source.byteOffset, source.byteLength), sp); + var res = fun(tp, bound, sp, count, size); + var target = new Uint8Array(res); + target.set(heap.subarray(tp, tp + res)); + sbrk(tp - sbrk(0)); + return target; + }; + + function maxindex(source) { + var result = 0; + for (var i = 0; i < source.length; ++i) { + var index = source[i]; + result = result < index ? index : result; + } + return result; + } + + function index32(source) { + if (source instanceof Uint32Array || source instanceof Int32Array) { + return source; + } + var result = new Uint32Array(source.length); + for (var i = 0; i < source.length; ++i) { + result[i] = source[i]; + } + return result; + } + + return { + ready: promise, + supported: true, + encodeVertexBuffer: function(source, count, size) { + var bound = instance.exports.meshopt_encodeVertexBufferBound(count, size); + return encode(instance.exports.meshopt_encodeVertexBuffer, bound, source, count, size); + }, + encodeIndexBuffer: function(source, count) { + var bound = instance.exports.meshopt_encodeIndexBufferBound(count, maxindex(source) + 1); + return encode(instance.exports.meshopt_encodeIndexBuffer, bound, index32(source), count, 4); + }, + encodeIndexSequence: function(source, count) { + var bound = instance.exports.meshopt_encodeIndexSequenceBound(count, maxindex(source) + 1); + return encode(instance.exports.meshopt_encodeIndexSequence, bound, index32(source), count, 4); + }, + }; +})(); + +export { MeshoptEncoder }; diff --git a/js/meshopt_encoder.test.js b/js/meshopt_encoder.test.js new file mode 100644 index 000000000..25b75fc4d --- /dev/null +++ b/js/meshopt_encoder.test.js @@ -0,0 +1,80 @@ +var assert = require('assert').strict; +var encoder = require('./meshopt_encoder.js'); +var decoder = require('./meshopt_decoder.js'); + +process.on('unhandledRejection', error => { + console.log('unhandledRejection', error); + process.exit(1); +}); + +var tests = { + roundtripVertexBuffer: function() { + var data = new Uint8Array(16 * 4); + + // this tests 0/2/4/8 bit groups in one stream + for (var i = 0; i < 16; ++i) + { + data[i * 4 + 0] = 0; + data[i * 4 + 1] = i * 1; + data[i * 4 + 2] = i * 2; + data[i * 4 + 3] = i * 8; + } + + var encoded = encoder.encodeVertexBuffer(data, 16, 4); + var decoded = new Uint8Array(16 * 4); + decoder.decodeVertexBuffer(decoded, 16, 4, encoded); + + assert.deepEqual(decoded, data); + }, + + roundtripIndexBuffer: function() { + var data = new Uint32Array([0, 1, 2, 2, 1, 3, 4, 6, 5, 7, 8, 9]); + + var encoded = encoder.encodeIndexBuffer(data, data.length); + var decoded = new Uint32Array(data.length); + decoder.decodeIndexBuffer(new Uint8Array(decoded.buffer), data.length, 4, encoded); + + assert.deepEqual(decoded, data); + }, + + roundtripIndexBuffer16: function() { + var data = new Uint16Array([0, 1, 2, 2, 1, 3, 4, 6, 5, 7, 8, 9]); + + var encoded = encoder.encodeIndexBuffer(data, data.length); + var decoded = new Uint16Array(data.length); + decoder.decodeIndexBuffer(new Uint8Array(decoded.buffer), data.length, 2, encoded); + + assert.deepEqual(decoded, data); + }, + + roundtripIndexSequence: function() { + var data = new Uint32Array([0, 1, 51, 2, 49, 1000]); + + var encoded = encoder.encodeIndexSequence(data, data.length); + var decoded = new Uint32Array(data.length); + decoder.decodeIndexSequence(new Uint8Array(decoded.buffer), data.length, 4, encoded); + + assert.deepEqual(decoded, data); + }, + + roundtripIndexSequence16: function() { + var data = new Uint16Array([0, 1, 51, 2, 49, 1000]); + + var encoded = encoder.encodeIndexSequence(data, data.length); + var decoded = new Uint16Array(data.length); + decoder.decodeIndexSequence(new Uint8Array(decoded.buffer), data.length, 2, encoded); + + assert.deepEqual(decoded, data); + }, +}; + +Promise.all([encoder.ready, decoder.ready]).then(() => { + var count = 0; + + for (var key in tests) { + tests[key](); + count++; + } + + console.log(count, 'tests passed'); +}); From ea3a48b85d1549ae4630f7ea3b662d059dec0f55 Mon Sep 17 00:00:00 2001 From: Arseny Kapoulkine Date: Tue, 27 Jul 2021 20:14:45 -0700 Subject: [PATCH 02/11] js: encodeIndex* can accept either 32-bit or 16-bit inputs It should also technically work with signed index inputs but this is good enough for now. --- js/meshopt_encoder.module.d.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/meshopt_encoder.module.d.ts b/js/meshopt_encoder.module.d.ts index 1522cd108..baf1dc26b 100644 --- a/js/meshopt_encoder.module.d.ts +++ b/js/meshopt_encoder.module.d.ts @@ -5,6 +5,6 @@ export const MeshoptEncoder: { ready: Promise; encodeVertexBuffer: (source: Uint8Array, count: number, size: number) => Uint8Array; - encodeIndexBuffer: (source: Uint32Array, count: number) => Uint8Array; - encodeIndexSequence: (source: Uint32Array, count: number) => Uint8Array; + encodeIndexBuffer: (source: Uint32Array | Uint16Array, count: number) => Uint8Array; + encodeIndexSequence: (source: Uint32Array | Uint16Array, count: number) => Uint8Array; }; From 5b30411c96145eb77e5e7acdf43890d4505b77c1 Mon Sep 17 00:00:00 2001 From: Arseny Kapoulkine Date: Tue, 27 Jul 2021 20:42:57 -0700 Subject: [PATCH 03/11] js: Add filter encoders and tests The filter encoders take floating-point data as inputs and produce encoded byte arrays that can be concatenated when multiple different bit counts are required to use. --- js/meshopt_encoder.js | 24 ++++++++++- js/meshopt_encoder.module.d.ts | 4 ++ js/meshopt_encoder.module.js | 24 ++++++++++- js/meshopt_encoder.test.js | 78 ++++++++++++++++++++++++++++++++++ 4 files changed, 128 insertions(+), 2 deletions(-) diff --git a/js/meshopt_encoder.js b/js/meshopt_encoder.js index eb1d27928..ba830dfdd 100644 --- a/js/meshopt_encoder.js +++ b/js/meshopt_encoder.js @@ -52,7 +52,7 @@ var MeshoptEncoder = (function() { target.set(heap.subarray(tp, tp + res)); sbrk(tp - sbrk(0)); return target; - }; + } function maxindex(source) { var result = 0; @@ -74,6 +74,19 @@ var MeshoptEncoder = (function() { return result; } + function filter(fun, source, count, stride, bits, insize) { + var sbrk = instance.exports.sbrk; + var tp = sbrk(count * stride); + var sp = sbrk(count * insize); + var heap = new Uint8Array(instance.exports.memory.buffer); + heap.set(new Uint8Array(source.buffer, source.byteOffset, source.byteLength), sp); + fun(tp, count, stride, bits, sp); + var target = new Uint8Array(count * stride); + target.set(heap.subarray(tp, tp + count * stride)); + sbrk(tp - sbrk(0)); + return target; + } + return { ready: promise, supported: true, @@ -89,6 +102,15 @@ var MeshoptEncoder = (function() { var bound = instance.exports.meshopt_encodeIndexSequenceBound(count, maxindex(source) + 1); return encode(instance.exports.meshopt_encodeIndexSequence, bound, index32(source), count, 4); }, + encodeFilterOct: function(source, count, stride, bits) { + return filter(instance.exports.meshopt_encodeFilterOct, source, count, stride, bits, 4); + }, + encodeFilterQuat: function(source, count, stride, bits) { + return filter(instance.exports.meshopt_encodeFilterQuat, source, count, stride, bits, 4); + }, + encodeFilterExp: function(source, count, stride, bits) { + return filter(instance.exports.meshopt_encodeFilterExp, source, count, stride, bits, stride/4); + }, }; })(); diff --git a/js/meshopt_encoder.module.d.ts b/js/meshopt_encoder.module.d.ts index baf1dc26b..fd5eb1d86 100644 --- a/js/meshopt_encoder.module.d.ts +++ b/js/meshopt_encoder.module.d.ts @@ -7,4 +7,8 @@ export const MeshoptEncoder: { encodeVertexBuffer: (source: Uint8Array, count: number, size: number) => Uint8Array; encodeIndexBuffer: (source: Uint32Array | Uint16Array, count: number) => Uint8Array; encodeIndexSequence: (source: Uint32Array | Uint16Array, count: number) => Uint8Array; + + encodeFilterOct: (source: Float32Array, count: number, stride: number, bits: number) => Uint8Array; + encodeFilterQuat: (source: Float32Array, count: number, stride: number, bits: number) => Uint8Array; + encodeFilterExp: (source: Float32Array, count: number, stride: number, bits: number) => Uint8Array; }; diff --git a/js/meshopt_encoder.module.js b/js/meshopt_encoder.module.js index d7b5b97e4..9479edbd8 100644 --- a/js/meshopt_encoder.module.js +++ b/js/meshopt_encoder.module.js @@ -52,7 +52,7 @@ var MeshoptEncoder = (function() { target.set(heap.subarray(tp, tp + res)); sbrk(tp - sbrk(0)); return target; - }; + } function maxindex(source) { var result = 0; @@ -74,6 +74,19 @@ var MeshoptEncoder = (function() { return result; } + function filter(fun, source, count, stride, bits, insize) { + var sbrk = instance.exports.sbrk; + var tp = sbrk(count * stride); + var sp = sbrk(count * insize); + var heap = new Uint8Array(instance.exports.memory.buffer); + heap.set(new Uint8Array(source.buffer, source.byteOffset, source.byteLength), sp); + fun(tp, count, stride, bits, sp); + var target = new Uint8Array(count * stride); + target.set(heap.subarray(tp, tp + count * stride)); + sbrk(tp - sbrk(0)); + return target; + } + return { ready: promise, supported: true, @@ -89,6 +102,15 @@ var MeshoptEncoder = (function() { var bound = instance.exports.meshopt_encodeIndexSequenceBound(count, maxindex(source) + 1); return encode(instance.exports.meshopt_encodeIndexSequence, bound, index32(source), count, 4); }, + encodeFilterOct: function(source, count, stride, bits) { + return filter(instance.exports.meshopt_encodeFilterOct, source, count, stride, bits, 4); + }, + encodeFilterQuat: function(source, count, stride, bits) { + return filter(instance.exports.meshopt_encodeFilterQuat, source, count, stride, bits, 4); + }, + encodeFilterExp: function(source, count, stride, bits) { + return filter(instance.exports.meshopt_encodeFilterExp, source, count, stride, bits, stride/4); + }, }; })(); diff --git a/js/meshopt_encoder.test.js b/js/meshopt_encoder.test.js index 25b75fc4d..b2c3684c7 100644 --- a/js/meshopt_encoder.test.js +++ b/js/meshopt_encoder.test.js @@ -66,6 +66,84 @@ var tests = { assert.deepEqual(decoded, data); }, + + encodeFilterOct8: function() { + var data = new Float32Array([ + 1, 0, 0, 0, + 0, -1, 0, 0, + 0.7071068, 0, 0.707168, 1, + -0.7071068, 0, -0.707168, 1, + ]); + + var expected = new Uint8Array([ + 0x7f, 0, 0x7f, 0, + 0, 0x81, 0x7f, 0, + 0x3f, 0, 0x7f, 0x7f, + 0x81, 0x40, 0x7f, 0x7f, + ]); + + // 4 vectors, encode each vector into 4 bytes with 8 bits of precision/component + var encoded = encoder.encodeFilterOct(data, 4, 4, 8); + assert.deepEqual(encoded, expected); + }, + + encodeFilterOct12: function() { + var data = new Float32Array([ + 1, 0, 0, 0, + 0, -1, 0, 0, + 0.7071068, 0, 0.707168, 1, + -0.7071068, 0, -0.707168, 1, + ]); + + var expected = new Uint16Array([ + 0x7ff, 0, 0x7ff, 0, + 0x0, 0xf801, 0x7ff, 0, + 0x3ff, 0, 0x7ff, 0x7fff, + 0xf801, 0x400, 0x7ff, 0x7fff, + ]); + + // 4 vectors, encode each vector into 8 bytes with 12 bits of precision/component + var encoded = encoder.encodeFilterOct(data, 4, 8, 12); + assert.deepEqual(encoded, new Uint8Array(expected.buffer, expected.byteOffset, expected.byteLength)); + }, + + encodeFilterQuat12: function() { + var data = new Float32Array([ + 1, 0, 0, 0, + 0, -1, 0, 0, + 0.7071068, 0, 0, 0.707168, + -0.7071068, 0, 0, -0.707168, + ]); + + var expected = new Uint16Array([ + 0, 0, 0, 0x7fc, + 0, 0, 0, 0x7fd, + 0x7ff, 0, 0, 0x7ff, + 0x7ff, 0, 0, 0x7ff, + ]); + + // 4 quaternions, encode each quaternion into 8 bytes with 12 bits of precision/component + var encoded = encoder.encodeFilterQuat(data, 4, 8, 12); + assert.deepEqual(encoded, new Uint8Array(expected.buffer, expected.byteOffset, expected.byteLength)); + }, + + encodeFilterExp: function() { + var data = new Float32Array([ + 1, + -23.4, + -0.1, + ]); + + var expected = new Uint32Array([ + 0xf7000200, + 0xf7ffd133, + 0xf7ffffcd, + ]); + + // 1 vector with 3 components (12 bytes), encode each vector into 12 bytes with 15 bits of precision/component + var encoded = encoder.encodeFilterExp(data, 1, 12, 15); + assert.deepEqual(encoded, new Uint8Array(expected.buffer, expected.byteOffset, expected.byteLength)); + }, }; Promise.all([encoder.ready, decoder.ready]).then(() => { From 76f8de9ebbd8f8a2ae9e14cb3979262bd3639a08 Mon Sep 17 00:00:00 2001 From: Arseny Kapoulkine Date: Tue, 27 Jul 2021 21:11:56 -0700 Subject: [PATCH 04/11] js: Implement mesh reordering The function recomputes the index buffer using optimal index/vertex order and returns a remap table that can be used to reorder all attribute streams for the mesh. --- js/meshopt_encoder.js | 28 ++++++++++++++++++++++++++++ js/meshopt_encoder.module.d.ts | 2 ++ js/meshopt_encoder.module.js | 28 ++++++++++++++++++++++++++++ js/meshopt_encoder.test.js | 25 +++++++++++++++++++++++++ 4 files changed, 83 insertions(+) diff --git a/js/meshopt_encoder.js b/js/meshopt_encoder.js index ba830dfdd..51eb952af 100644 --- a/js/meshopt_encoder.js +++ b/js/meshopt_encoder.js @@ -41,6 +41,30 @@ var MeshoptEncoder = (function() { return result.buffer.slice(0, write); } + function reorder(indices, vertices, optf) { + var sbrk = instance.exports.sbrk; + var ip = sbrk(indices.length * 4); + var rp = sbrk(vertices * 4); + var heap = new Uint8Array(instance.exports.memory.buffer); + var indices8 =new Uint8Array(indices.buffer, indices.byteOffset, indices.byteLength); + heap.set(indices8, ip); + if (optf) { + optf(ip, ip, indices.length, vertices); + } + var unique = instance.exports.meshopt_optimizeVertexFetchRemap(rp, ip, indices.length, vertices); + // heap may have grown + heap = new Uint8Array(instance.exports.memory.buffer); + var remap = new Uint32Array(vertices); + new Uint8Array(remap.buffer).set(heap.subarray(rp, rp + vertices * 4)); + indices8.set(heap.subarray(ip, ip + indices.length * 4)); + sbrk(ip - sbrk(0)); + + for (var i = 0; i < indices.length; ++i) + indices[i] = remap[indices[i]]; + + return [remap, unique]; + } + function encode(fun, bound, source, count, size) { var sbrk = instance.exports.sbrk; var tp = sbrk(bound); @@ -90,6 +114,10 @@ var MeshoptEncoder = (function() { return { ready: promise, supported: true, + reorderMesh: function(indices, triangles, optsize) { + var optf = triangles ? (optsize ? instance.exports.meshopt_optimizeVertexCacheStrip : instance.exports.meshopt_optimizeVertexCache) : undefined; + return reorder(indices, maxindex(indices) + 1, optf); + }, encodeVertexBuffer: function(source, count, size) { var bound = instance.exports.meshopt_encodeVertexBufferBound(count, size); return encode(instance.exports.meshopt_encodeVertexBuffer, bound, source, count, size); diff --git a/js/meshopt_encoder.module.d.ts b/js/meshopt_encoder.module.d.ts index fd5eb1d86..3786a6727 100644 --- a/js/meshopt_encoder.module.d.ts +++ b/js/meshopt_encoder.module.d.ts @@ -3,6 +3,8 @@ export const MeshoptEncoder: { supported: boolean; ready: Promise; + + reorderMesh: (indices: Uint32Array, triangles: boolean, optsize: boolean) => [Uint32Array, number]; encodeVertexBuffer: (source: Uint8Array, count: number, size: number) => Uint8Array; encodeIndexBuffer: (source: Uint32Array | Uint16Array, count: number) => Uint8Array; diff --git a/js/meshopt_encoder.module.js b/js/meshopt_encoder.module.js index 9479edbd8..508caf468 100644 --- a/js/meshopt_encoder.module.js +++ b/js/meshopt_encoder.module.js @@ -41,6 +41,30 @@ var MeshoptEncoder = (function() { return result.buffer.slice(0, write); } + function reorder(indices, vertices, optf) { + var sbrk = instance.exports.sbrk; + var ip = sbrk(indices.length * 4); + var rp = sbrk(vertices * 4); + var heap = new Uint8Array(instance.exports.memory.buffer); + var indices8 =new Uint8Array(indices.buffer, indices.byteOffset, indices.byteLength); + heap.set(indices8, ip); + if (optf) { + optf(ip, ip, indices.length, vertices); + } + var unique = instance.exports.meshopt_optimizeVertexFetchRemap(rp, ip, indices.length, vertices); + // heap may have grown + heap = new Uint8Array(instance.exports.memory.buffer); + var remap = new Uint32Array(vertices); + new Uint8Array(remap.buffer).set(heap.subarray(rp, rp + vertices * 4)); + indices8.set(heap.subarray(ip, ip + indices.length * 4)); + sbrk(ip - sbrk(0)); + + for (var i = 0; i < indices.length; ++i) + indices[i] = remap[indices[i]]; + + return [remap, unique]; + } + function encode(fun, bound, source, count, size) { var sbrk = instance.exports.sbrk; var tp = sbrk(bound); @@ -90,6 +114,10 @@ var MeshoptEncoder = (function() { return { ready: promise, supported: true, + reorderMesh: function(indices, triangles, optsize) { + var optf = triangles ? (optsize ? instance.exports.meshopt_optimizeVertexCacheStrip : instance.exports.meshopt_optimizeVertexCache) : undefined; + return reorder(indices, maxindex(indices) + 1, optf); + }, encodeVertexBuffer: function(source, count, size) { var bound = instance.exports.meshopt_encodeVertexBufferBound(count, size); return encode(instance.exports.meshopt_encodeVertexBuffer, bound, source, count, size); diff --git a/js/meshopt_encoder.test.js b/js/meshopt_encoder.test.js index b2c3684c7..050bf1ee4 100644 --- a/js/meshopt_encoder.test.js +++ b/js/meshopt_encoder.test.js @@ -8,6 +8,31 @@ process.on('unhandledRejection', error => { }); var tests = { + reorderMesh: function() { + var indices = new Uint32Array([ + 4, 2, 5, + 3, 1, 4, + 0, 1, 3, + 1, 2, 4, + ]); + + var expected = new Uint32Array([ + 0, 1, 2, + 3, 1, 0, + 4, 3, 0, + 5, 3, 4, + ]); + + var remap = new Uint32Array([ + 5, 3, 1, 4, 0, 2 + ]); + + var res = encoder.reorderMesh(indices, /* triangles= */ true, /* optsize= */ true); + assert.deepEqual(indices, expected); + assert.deepEqual(res[0], remap); + assert.equal(res[1], 6); // unique + }, + roundtripVertexBuffer: function() { var data = new Uint8Array(16 * 4); From 8fe42603dea26c3ff756f6c16e7d2d060fe82be4 Mon Sep 17 00:00:00 2001 From: Arseny Kapoulkine Date: Mon, 2 Aug 2021 22:25:07 -0700 Subject: [PATCH 05/11] js: Add preconditions as assertions Also add bytes() to test code for clarity --- js/meshopt_encoder.js | 14 ++++++++++++++ js/meshopt_encoder.module.js | 14 ++++++++++++++ js/meshopt_encoder.test.js | 10 +++++++--- 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/js/meshopt_encoder.js b/js/meshopt_encoder.js index 51eb952af..4d27c542c 100644 --- a/js/meshopt_encoder.js +++ b/js/meshopt_encoder.js @@ -41,6 +41,12 @@ var MeshoptEncoder = (function() { return result.buffer.slice(0, write); } + function assert(cond) { + if (!cond) { + throw new Error("Assertion failed"); + } + } + function reorder(indices, vertices, optf) { var sbrk = instance.exports.sbrk; var ip = sbrk(indices.length * 4); @@ -119,6 +125,8 @@ var MeshoptEncoder = (function() { return reorder(indices, maxindex(indices) + 1, optf); }, encodeVertexBuffer: function(source, count, size) { + assert(size > 0 && size <= 256); + assert(size % 4 == 0); var bound = instance.exports.meshopt_encodeVertexBufferBound(count, size); return encode(instance.exports.meshopt_encodeVertexBuffer, bound, source, count, size); }, @@ -131,12 +139,18 @@ var MeshoptEncoder = (function() { return encode(instance.exports.meshopt_encodeIndexSequence, bound, index32(source), count, 4); }, encodeFilterOct: function(source, count, stride, bits) { + assert(stride == 4 || stride == 8); + assert(bits >= 1 && bits <= 16); return filter(instance.exports.meshopt_encodeFilterOct, source, count, stride, bits, 4); }, encodeFilterQuat: function(source, count, stride, bits) { + assert(stride == 8); + assert(bits >= 4 && bits <= 16); return filter(instance.exports.meshopt_encodeFilterQuat, source, count, stride, bits, 4); }, encodeFilterExp: function(source, count, stride, bits) { + assert(stride > 0 && stride % 4 == 0); + assert(bits >= 1 && bits <= 24); return filter(instance.exports.meshopt_encodeFilterExp, source, count, stride, bits, stride/4); }, }; diff --git a/js/meshopt_encoder.module.js b/js/meshopt_encoder.module.js index 508caf468..a4eb97ecb 100644 --- a/js/meshopt_encoder.module.js +++ b/js/meshopt_encoder.module.js @@ -41,6 +41,12 @@ var MeshoptEncoder = (function() { return result.buffer.slice(0, write); } + function assert(cond) { + if (!cond) { + throw new Error("Assertion failed"); + } + } + function reorder(indices, vertices, optf) { var sbrk = instance.exports.sbrk; var ip = sbrk(indices.length * 4); @@ -119,6 +125,8 @@ var MeshoptEncoder = (function() { return reorder(indices, maxindex(indices) + 1, optf); }, encodeVertexBuffer: function(source, count, size) { + assert(size > 0 && size <= 256); + assert(size % 4 == 0); var bound = instance.exports.meshopt_encodeVertexBufferBound(count, size); return encode(instance.exports.meshopt_encodeVertexBuffer, bound, source, count, size); }, @@ -131,12 +139,18 @@ var MeshoptEncoder = (function() { return encode(instance.exports.meshopt_encodeIndexSequence, bound, index32(source), count, 4); }, encodeFilterOct: function(source, count, stride, bits) { + assert(stride == 4 || stride == 8); + assert(bits >= 1 && bits <= 16); return filter(instance.exports.meshopt_encodeFilterOct, source, count, stride, bits, 4); }, encodeFilterQuat: function(source, count, stride, bits) { + assert(stride == 8); + assert(bits >= 4 && bits <= 16); return filter(instance.exports.meshopt_encodeFilterQuat, source, count, stride, bits, 4); }, encodeFilterExp: function(source, count, stride, bits) { + assert(stride > 0 && stride % 4 == 0); + assert(bits >= 1 && bits <= 24); return filter(instance.exports.meshopt_encodeFilterExp, source, count, stride, bits, stride/4); }, }; diff --git a/js/meshopt_encoder.test.js b/js/meshopt_encoder.test.js index 050bf1ee4..e2ec34c88 100644 --- a/js/meshopt_encoder.test.js +++ b/js/meshopt_encoder.test.js @@ -7,6 +7,10 @@ process.on('unhandledRejection', error => { process.exit(1); }); +function bytes(view) { + return new Uint8Array(view.buffer, view.byteOffset, view.byteLength); +} + var tests = { reorderMesh: function() { var indices = new Uint32Array([ @@ -129,7 +133,7 @@ var tests = { // 4 vectors, encode each vector into 8 bytes with 12 bits of precision/component var encoded = encoder.encodeFilterOct(data, 4, 8, 12); - assert.deepEqual(encoded, new Uint8Array(expected.buffer, expected.byteOffset, expected.byteLength)); + assert.deepEqual(encoded, bytes(expected)); }, encodeFilterQuat12: function() { @@ -149,7 +153,7 @@ var tests = { // 4 quaternions, encode each quaternion into 8 bytes with 12 bits of precision/component var encoded = encoder.encodeFilterQuat(data, 4, 8, 12); - assert.deepEqual(encoded, new Uint8Array(expected.buffer, expected.byteOffset, expected.byteLength)); + assert.deepEqual(encoded, bytes(expected)); }, encodeFilterExp: function() { @@ -167,7 +171,7 @@ var tests = { // 1 vector with 3 components (12 bytes), encode each vector into 12 bytes with 15 bits of precision/component var encoded = encoder.encodeFilterExp(data, 1, 12, 15); - assert.deepEqual(encoded, new Uint8Array(expected.buffer, expected.byteOffset, expected.byteLength)); + assert.deepEqual(encoded, bytes(expected)); }, }; From d8fdecdeeba230e4e1d409c63960e02d8fcecdb7 Mon Sep 17 00:00:00 2001 From: Arseny Kapoulkine Date: Mon, 2 Aug 2021 22:33:13 -0700 Subject: [PATCH 06/11] js: Rework encoder interface to accept uint8 index views This makes the code more consistent between encoder & decoder, and between different types of encoding. --- js/meshopt_encoder.js | 31 +++++++++++++++++-------------- js/meshopt_encoder.module.d.ts | 4 ++-- js/meshopt_encoder.module.js | 33 ++++++++++++++++++--------------- js/meshopt_encoder.test.js | 16 ++++++++-------- 4 files changed, 45 insertions(+), 39 deletions(-) diff --git a/js/meshopt_encoder.js b/js/meshopt_encoder.js index 4d27c542c..9ddf67f16 100644 --- a/js/meshopt_encoder.js +++ b/js/meshopt_encoder.js @@ -93,15 +93,14 @@ var MeshoptEncoder = (function() { return result; } - function index32(source) { - if (source instanceof Uint32Array || source instanceof Int32Array) { - return source; + function index32(source, size) { + assert(size == 2 || size == 4); + if (size == 4) { + return new Uint32Array(source.buffer, source.byteOffset, source.byteLength / 4); + } else { + var view = new Uint16Array(source.buffer, source.byteOffset, source.byteLength / 2); + return new Uint32Array(view); // copies each element } - var result = new Uint32Array(source.length); - for (var i = 0; i < source.length; ++i) { - result[i] = source[i]; - } - return result; } function filter(fun, source, count, stride, bits, insize) { @@ -130,13 +129,17 @@ var MeshoptEncoder = (function() { var bound = instance.exports.meshopt_encodeVertexBufferBound(count, size); return encode(instance.exports.meshopt_encodeVertexBuffer, bound, source, count, size); }, - encodeIndexBuffer: function(source, count) { - var bound = instance.exports.meshopt_encodeIndexBufferBound(count, maxindex(source) + 1); - return encode(instance.exports.meshopt_encodeIndexBuffer, bound, index32(source), count, 4); + encodeIndexBuffer: function(source, count, size) { + assert(size == 2 || size == 4); + var indices = index32(source, size); + var bound = instance.exports.meshopt_encodeIndexBufferBound(count, maxindex(indices) + 1); + return encode(instance.exports.meshopt_encodeIndexBuffer, bound, indices, count, 4); }, - encodeIndexSequence: function(source, count) { - var bound = instance.exports.meshopt_encodeIndexSequenceBound(count, maxindex(source) + 1); - return encode(instance.exports.meshopt_encodeIndexSequence, bound, index32(source), count, 4); + encodeIndexSequence: function(source, count, size) { + assert(size == 2 || size == 4); + var indices = index32(source, size); + var bound = instance.exports.meshopt_encodeIndexSequenceBound(count, maxindex(indices) + 1); + return encode(instance.exports.meshopt_encodeIndexSequence, bound, indices, count, 4); }, encodeFilterOct: function(source, count, stride, bits) { assert(stride == 4 || stride == 8); diff --git a/js/meshopt_encoder.module.d.ts b/js/meshopt_encoder.module.d.ts index 3786a6727..66dd4c080 100644 --- a/js/meshopt_encoder.module.d.ts +++ b/js/meshopt_encoder.module.d.ts @@ -7,8 +7,8 @@ export const MeshoptEncoder: { reorderMesh: (indices: Uint32Array, triangles: boolean, optsize: boolean) => [Uint32Array, number]; encodeVertexBuffer: (source: Uint8Array, count: number, size: number) => Uint8Array; - encodeIndexBuffer: (source: Uint32Array | Uint16Array, count: number) => Uint8Array; - encodeIndexSequence: (source: Uint32Array | Uint16Array, count: number) => Uint8Array; + encodeIndexBuffer: (source: Uint8Array, count: number, size: number) => Uint8Array; + encodeIndexSequence: (source: Uint8Array, count: number, size: number) => Uint8Array; encodeFilterOct: (source: Float32Array, count: number, stride: number, bits: number) => Uint8Array; encodeFilterQuat: (source: Float32Array, count: number, stride: number, bits: number) => Uint8Array; diff --git a/js/meshopt_encoder.module.js b/js/meshopt_encoder.module.js index a4eb97ecb..b04b4c701 100644 --- a/js/meshopt_encoder.module.js +++ b/js/meshopt_encoder.module.js @@ -43,7 +43,7 @@ var MeshoptEncoder = (function() { function assert(cond) { if (!cond) { - throw new Error("Assertion failed"); + throw new Error("Assertion failed"); } } @@ -93,15 +93,14 @@ var MeshoptEncoder = (function() { return result; } - function index32(source) { - if (source instanceof Uint32Array || source instanceof Int32Array) { - return source; + function index32(source, size) { + assert(size == 2 || size == 4); + if (size == 4) { + return new Uint32Array(source.buffer, source.byteOffset, source.byteLength / 4); + } else { + var view = new Uint16Array(source.buffer, source.byteOffset, source.byteLength / 2); + return new Uint32Array(view); // copies each element } - var result = new Uint32Array(source.length); - for (var i = 0; i < source.length; ++i) { - result[i] = source[i]; - } - return result; } function filter(fun, source, count, stride, bits, insize) { @@ -130,13 +129,17 @@ var MeshoptEncoder = (function() { var bound = instance.exports.meshopt_encodeVertexBufferBound(count, size); return encode(instance.exports.meshopt_encodeVertexBuffer, bound, source, count, size); }, - encodeIndexBuffer: function(source, count) { - var bound = instance.exports.meshopt_encodeIndexBufferBound(count, maxindex(source) + 1); - return encode(instance.exports.meshopt_encodeIndexBuffer, bound, index32(source), count, 4); + encodeIndexBuffer: function(source, count, size) { + assert(size == 2 || size == 4); + var indices = index32(source, size); + var bound = instance.exports.meshopt_encodeIndexBufferBound(count, maxindex(indices) + 1); + return encode(instance.exports.meshopt_encodeIndexBuffer, bound, indices, count, 4); }, - encodeIndexSequence: function(source, count) { - var bound = instance.exports.meshopt_encodeIndexSequenceBound(count, maxindex(source) + 1); - return encode(instance.exports.meshopt_encodeIndexSequence, bound, index32(source), count, 4); + encodeIndexSequence: function(source, count, size) { + assert(size == 2 || size == 4); + var indices = index32(source, size); + var bound = instance.exports.meshopt_encodeIndexSequenceBound(count, maxindex(indices) + 1); + return encode(instance.exports.meshopt_encodeIndexSequence, bound, indices, count, 4); }, encodeFilterOct: function(source, count, stride, bits) { assert(stride == 4 || stride == 8); diff --git a/js/meshopt_encoder.test.js b/js/meshopt_encoder.test.js index e2ec34c88..85630e5c2 100644 --- a/js/meshopt_encoder.test.js +++ b/js/meshopt_encoder.test.js @@ -59,9 +59,9 @@ var tests = { roundtripIndexBuffer: function() { var data = new Uint32Array([0, 1, 2, 2, 1, 3, 4, 6, 5, 7, 8, 9]); - var encoded = encoder.encodeIndexBuffer(data, data.length); + var encoded = encoder.encodeIndexBuffer(bytes(data), data.length, 4); var decoded = new Uint32Array(data.length); - decoder.decodeIndexBuffer(new Uint8Array(decoded.buffer), data.length, 4, encoded); + decoder.decodeIndexBuffer(bytes(decoded), data.length, 4, encoded); assert.deepEqual(decoded, data); }, @@ -69,9 +69,9 @@ var tests = { roundtripIndexBuffer16: function() { var data = new Uint16Array([0, 1, 2, 2, 1, 3, 4, 6, 5, 7, 8, 9]); - var encoded = encoder.encodeIndexBuffer(data, data.length); + var encoded = encoder.encodeIndexBuffer(bytes(data), data.length, 2); var decoded = new Uint16Array(data.length); - decoder.decodeIndexBuffer(new Uint8Array(decoded.buffer), data.length, 2, encoded); + decoder.decodeIndexBuffer(bytes(decoded), data.length, 2, encoded); assert.deepEqual(decoded, data); }, @@ -79,9 +79,9 @@ var tests = { roundtripIndexSequence: function() { var data = new Uint32Array([0, 1, 51, 2, 49, 1000]); - var encoded = encoder.encodeIndexSequence(data, data.length); + var encoded = encoder.encodeIndexSequence(bytes(data), data.length, 4); var decoded = new Uint32Array(data.length); - decoder.decodeIndexSequence(new Uint8Array(decoded.buffer), data.length, 4, encoded); + decoder.decodeIndexSequence(bytes(decoded), data.length, 4, encoded); assert.deepEqual(decoded, data); }, @@ -89,9 +89,9 @@ var tests = { roundtripIndexSequence16: function() { var data = new Uint16Array([0, 1, 51, 2, 49, 1000]); - var encoded = encoder.encodeIndexSequence(data, data.length); + var encoded = encoder.encodeIndexSequence(bytes(data), data.length, 2); var decoded = new Uint16Array(data.length); - decoder.decodeIndexSequence(new Uint8Array(decoded.buffer), data.length, 2, encoded); + decoder.decodeIndexSequence(bytes(decoded), data.length, 2, encoded); assert.deepEqual(decoded, data); }, From 41394ffbc67cffb19000e58589e77f1c2068cece Mon Sep 17 00:00:00 2001 From: Arseny Kapoulkine Date: Mon, 2 Aug 2021 22:40:04 -0700 Subject: [PATCH 07/11] js: Implement encodeGltfBuffer This function isn't perfectly symmetric wrt decoding because it assumes that the floating-point data has been already encoded using filters (if any), but for basic cases it's symmetrical wrt decoder's decodeGltfBuffer. --- js/meshopt_decoder.module.d.ts | 1 + js/meshopt_encoder.js | 5 +++++ js/meshopt_encoder.module.d.ts | 2 ++ js/meshopt_encoder.module.js | 5 +++++ js/meshopt_encoder.test.js | 10 ++++++++++ 5 files changed, 23 insertions(+) diff --git a/js/meshopt_decoder.module.d.ts b/js/meshopt_decoder.module.d.ts index 133fa7f3e..511593963 100644 --- a/js/meshopt_decoder.module.d.ts +++ b/js/meshopt_decoder.module.d.ts @@ -7,5 +7,6 @@ export const MeshoptDecoder: { decodeVertexBuffer: (target: Uint8Array, count: number, size: number, source: Uint8Array, filter?: string) => void; decodeIndexBuffer: (target: Uint8Array, count: number, size: number, source: Uint8Array) => void; decodeIndexSequence: (target: Uint8Array, count: number, size: number, source: Uint8Array) => void; + decodeGltfBuffer: (target: Uint8Array, count: number, size: number, source: Uint8Array, mode: string, filter?: string) => void; }; diff --git a/js/meshopt_encoder.js b/js/meshopt_encoder.js index 9ddf67f16..e17dee619 100644 --- a/js/meshopt_encoder.js +++ b/js/meshopt_encoder.js @@ -141,6 +141,11 @@ var MeshoptEncoder = (function() { var bound = instance.exports.meshopt_encodeIndexSequenceBound(count, maxindex(indices) + 1); return encode(instance.exports.meshopt_encodeIndexSequence, bound, indices, count, 4); }, + encodeGltfBuffer: function(source, count, size, mode) { + var table = { ATTRIBUTES: this.encodeVertexBuffer, TRIANGLES: this.encodeIndexBuffer, INDICES: this.encodeIndexSequence }; + assert(table[mode]); + return table[mode](source, count, size); + }, encodeFilterOct: function(source, count, stride, bits) { assert(stride == 4 || stride == 8); assert(bits >= 1 && bits <= 16); diff --git a/js/meshopt_encoder.module.d.ts b/js/meshopt_encoder.module.d.ts index 66dd4c080..53b735758 100644 --- a/js/meshopt_encoder.module.d.ts +++ b/js/meshopt_encoder.module.d.ts @@ -10,6 +10,8 @@ export const MeshoptEncoder: { encodeIndexBuffer: (source: Uint8Array, count: number, size: number) => Uint8Array; encodeIndexSequence: (source: Uint8Array, count: number, size: number) => Uint8Array; + encodeGltfBuffer: (source: Uint8Array, count: number, size: number, mode: string) => Uint8Array; + encodeFilterOct: (source: Float32Array, count: number, stride: number, bits: number) => Uint8Array; encodeFilterQuat: (source: Float32Array, count: number, stride: number, bits: number) => Uint8Array; encodeFilterExp: (source: Float32Array, count: number, stride: number, bits: number) => Uint8Array; diff --git a/js/meshopt_encoder.module.js b/js/meshopt_encoder.module.js index b04b4c701..5ab3ba86f 100644 --- a/js/meshopt_encoder.module.js +++ b/js/meshopt_encoder.module.js @@ -141,6 +141,11 @@ var MeshoptEncoder = (function() { var bound = instance.exports.meshopt_encodeIndexSequenceBound(count, maxindex(indices) + 1); return encode(instance.exports.meshopt_encodeIndexSequence, bound, indices, count, 4); }, + encodeGltfBuffer: function(source, count, size, mode) { + var table = { ATTRIBUTES: this.encodeVertexBuffer, TRIANGLES: this.encodeIndexBuffer, INDICES: this.encodeIndexSequence }; + assert(table[mode]); + return table[mode](source, count, size); + }, encodeFilterOct: function(source, count, stride, bits) { assert(stride == 4 || stride == 8); assert(bits >= 1 && bits <= 16); diff --git a/js/meshopt_encoder.test.js b/js/meshopt_encoder.test.js index 85630e5c2..dcde4d171 100644 --- a/js/meshopt_encoder.test.js +++ b/js/meshopt_encoder.test.js @@ -173,6 +173,16 @@ var tests = { var encoded = encoder.encodeFilterExp(data, 1, 12, 15); assert.deepEqual(encoded, bytes(expected)); }, + + encodeGltfBuffer: function() { + var data = new Uint32Array([0, 1, 2, 2, 1, 3, 4, 6, 5, 7, 8, 9]); + + var encoded = encoder.encodeGltfBuffer(bytes(data), data.length, 4, 'TRIANGLES'); + var decoded = new Uint32Array(data.length); + decoder.decodeGltfBuffer(bytes(decoded), data.length, 4, encoded, 'TRIANGLES'); + + assert.deepEqual(decoded, data); + }, }; Promise.all([encoder.ready, decoder.ready]).then(() => { From a566e9dd525679540d34fe6fa017c3cbe7e6ec70 Mon Sep 17 00:00:00 2001 From: Arseny Kapoulkine Date: Mon, 2 Aug 2021 22:49:45 -0700 Subject: [PATCH 08/11] js: Reformat code --- js/meshopt_encoder.js | 8 ++++++-- js/meshopt_encoder.module.js | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/js/meshopt_encoder.js b/js/meshopt_encoder.js index e17dee619..214f84681 100644 --- a/js/meshopt_encoder.js +++ b/js/meshopt_encoder.js @@ -52,7 +52,7 @@ var MeshoptEncoder = (function() { var ip = sbrk(indices.length * 4); var rp = sbrk(vertices * 4); var heap = new Uint8Array(instance.exports.memory.buffer); - var indices8 =new Uint8Array(indices.buffer, indices.byteOffset, indices.byteLength); + var indices8 = new Uint8Array(indices.buffer, indices.byteOffset, indices.byteLength); heap.set(indices8, ip); if (optf) { optf(ip, ip, indices.length, vertices); @@ -142,7 +142,11 @@ var MeshoptEncoder = (function() { return encode(instance.exports.meshopt_encodeIndexSequence, bound, indices, count, 4); }, encodeGltfBuffer: function(source, count, size, mode) { - var table = { ATTRIBUTES: this.encodeVertexBuffer, TRIANGLES: this.encodeIndexBuffer, INDICES: this.encodeIndexSequence }; + var table = { + ATTRIBUTES: this.encodeVertexBuffer, + TRIANGLES: this.encodeIndexBuffer, + INDICES: this.encodeIndexSequence, + }; assert(table[mode]); return table[mode](source, count, size); }, diff --git a/js/meshopt_encoder.module.js b/js/meshopt_encoder.module.js index 5ab3ba86f..cf2299d6d 100644 --- a/js/meshopt_encoder.module.js +++ b/js/meshopt_encoder.module.js @@ -52,7 +52,7 @@ var MeshoptEncoder = (function() { var ip = sbrk(indices.length * 4); var rp = sbrk(vertices * 4); var heap = new Uint8Array(instance.exports.memory.buffer); - var indices8 =new Uint8Array(indices.buffer, indices.byteOffset, indices.byteLength); + var indices8 = new Uint8Array(indices.buffer, indices.byteOffset, indices.byteLength); heap.set(indices8, ip); if (optf) { optf(ip, ip, indices.length, vertices); @@ -142,7 +142,11 @@ var MeshoptEncoder = (function() { return encode(instance.exports.meshopt_encodeIndexSequence, bound, indices, count, 4); }, encodeGltfBuffer: function(source, count, size, mode) { - var table = { ATTRIBUTES: this.encodeVertexBuffer, TRIANGLES: this.encodeIndexBuffer, INDICES: this.encodeIndexSequence }; + var table = { + ATTRIBUTES: this.encodeVertexBuffer, + TRIANGLES: this.encodeIndexBuffer, + INDICES: this.encodeIndexSequence, + }; assert(table[mode]); return table[mode](source, count, size); }, From aa9f948362cc477d05cd00b3c85fd9f7d77bfcc8 Mon Sep 17 00:00:00 2001 From: Arseny Kapoulkine Date: Tue, 3 Aug 2021 13:53:32 -0700 Subject: [PATCH 09/11] js: Add an assertion for index encoding This makes sure that the input is a triangle list. --- js/meshopt_encoder.js | 1 + js/meshopt_encoder.module.js | 1 + 2 files changed, 2 insertions(+) diff --git a/js/meshopt_encoder.js b/js/meshopt_encoder.js index 214f84681..d71b9ad4d 100644 --- a/js/meshopt_encoder.js +++ b/js/meshopt_encoder.js @@ -131,6 +131,7 @@ var MeshoptEncoder = (function() { }, encodeIndexBuffer: function(source, count, size) { assert(size == 2 || size == 4); + assert(count % 3 == 0); var indices = index32(source, size); var bound = instance.exports.meshopt_encodeIndexBufferBound(count, maxindex(indices) + 1); return encode(instance.exports.meshopt_encodeIndexBuffer, bound, indices, count, 4); diff --git a/js/meshopt_encoder.module.js b/js/meshopt_encoder.module.js index cf2299d6d..3f2430a2f 100644 --- a/js/meshopt_encoder.module.js +++ b/js/meshopt_encoder.module.js @@ -131,6 +131,7 @@ var MeshoptEncoder = (function() { }, encodeIndexBuffer: function(source, count, size) { assert(size == 2 || size == 4); + assert(count % 3 == 0); var indices = index32(source, size); var bound = instance.exports.meshopt_encodeIndexBufferBound(count, maxindex(indices) + 1); return encode(instance.exports.meshopt_encodeIndexBuffer, bound, indices, count, 4); From 17dc818296b043ae74b987b2d1382798799d92bd Mon Sep 17 00:00:00 2001 From: Arseny Kapoulkine Date: Tue, 3 Aug 2021 22:47:28 -0700 Subject: [PATCH 10/11] js: Add README.md This contains documentation of decoders and encoders. --- js/README.md | 106 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 js/README.md diff --git a/js/README.md b/js/README.md new file mode 100644 index 000000000..8b5b36f55 --- /dev/null +++ b/js/README.md @@ -0,0 +1,106 @@ +# meshoptimizer.js + +This folder contains JavaScript/WebAssembly modules that can be used to access parts of functionality of meshoptimizer library. While normally these would be used internally by glTF loaders, processors and other Web optimization tools, they can also be used directly if needed. + +## Structure + +Each component comes in two variants: + +- `meshopt_component.js` uses a UMD-style module declaration and can be used by a wide variety of JavaScript module loaders, including node.js require(), AMD, Common.JS, and can also be loaded into the web page directly via a `