156 lines
4.6 KiB
JavaScript
156 lines
4.6 KiB
JavaScript
// This file is part of meshoptimizer library and is distributed under the terms of MIT License.
|
|
// Copyright (C) 2016-2023, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
|
|
var MeshoptDecoder = (function() {
|
|
"use strict";
|
|
|
|
var instance;
|
|
var supported = false;
|
|
|
|
var ready = (instantiateWasm = {}) => {
|
|
|
|
if (typeof instantiateWasm !== 'function') {
|
|
return Promise.reject(new Error('No wasm support detected'));
|
|
}
|
|
|
|
return instantiateWasm().then(function(result) {
|
|
supported = true;
|
|
instance = result.instance;
|
|
instance.exports.__wasm_call_ctors();
|
|
});
|
|
}
|
|
|
|
function decode(fun, target, count, size, source, filter) {
|
|
var sbrk = instance.exports.sbrk;
|
|
var count4 = (count + 3) & ~3;
|
|
var tp = sbrk(count4 * size);
|
|
var sp = sbrk(source.length);
|
|
var heap = new Uint8Array(instance.exports.memory.buffer);
|
|
heap.set(source, sp);
|
|
var res = fun(tp, count, size, sp, source.length);
|
|
if (res == 0 && filter) {
|
|
filter(tp, count4, size);
|
|
}
|
|
target.set(heap.subarray(tp, tp + count * size));
|
|
sbrk(tp - sbrk(0));
|
|
if (res != 0) {
|
|
throw new Error("Malformed buffer data: " + res);
|
|
}
|
|
}
|
|
|
|
var filters = {
|
|
NONE: "",
|
|
OCTAHEDRAL: "meshopt_decodeFilterOct",
|
|
QUATERNION: "meshopt_decodeFilterQuat",
|
|
EXPONENTIAL: "meshopt_decodeFilterExp",
|
|
};
|
|
|
|
var decoders = {
|
|
ATTRIBUTES: "meshopt_decodeVertexBuffer",
|
|
TRIANGLES: "meshopt_decodeIndexBuffer",
|
|
INDICES: "meshopt_decodeIndexSequence",
|
|
};
|
|
|
|
var workers = [];
|
|
var requestId = 0;
|
|
|
|
function createWorker(url) {
|
|
var worker = {
|
|
object: new Worker(url),
|
|
pending: 0,
|
|
requests: {}
|
|
};
|
|
|
|
worker.object.onmessage = function(event) {
|
|
var data = event.data;
|
|
|
|
worker.pending -= data.count;
|
|
worker.requests[data.id][data.action](data.value);
|
|
|
|
delete worker.requests[data.id];
|
|
};
|
|
|
|
return worker;
|
|
}
|
|
|
|
function initWorkers(count) {
|
|
var source =
|
|
"var instance; var ready = WebAssembly.instantiate(new Uint8Array([" + new Uint8Array(unpack(wasm)) + "]), {})" +
|
|
".then(function(result) { instance = result.instance; instance.exports.__wasm_call_ctors(); });" +
|
|
"self.onmessage = workerProcess;" +
|
|
decode.toString() + workerProcess.toString();
|
|
|
|
var blob = new Blob([source], {type: 'text/javascript'});
|
|
var url = URL.createObjectURL(blob);
|
|
|
|
for (var i = 0; i < count; ++i) {
|
|
workers[i] = createWorker(url);
|
|
}
|
|
|
|
URL.revokeObjectURL(url);
|
|
}
|
|
|
|
function decodeWorker(count, size, source, mode, filter) {
|
|
var worker = workers[0];
|
|
|
|
for (var i = 1; i < workers.length; ++i) {
|
|
if (workers[i].pending < worker.pending) {
|
|
worker = workers[i];
|
|
}
|
|
}
|
|
|
|
return new Promise(function (resolve, reject) {
|
|
var data = new Uint8Array(source);
|
|
var id = requestId++;
|
|
|
|
worker.pending += count;
|
|
worker.requests[id] = { resolve: resolve, reject: reject };
|
|
worker.object.postMessage({ id: id, count: count, size: size, source: data, mode: mode, filter: filter }, [ data.buffer ]);
|
|
});
|
|
}
|
|
|
|
function workerProcess(event) {
|
|
ready.then(function() {
|
|
var data = event.data;
|
|
try {
|
|
var target = new Uint8Array(data.count * data.size);
|
|
decode(instance.exports[data.mode], target, data.count, data.size, data.source, instance.exports[data.filter]);
|
|
self.postMessage({ id: data.id, count: data.count, action: "resolve", value: target }, [ target.buffer ]);
|
|
} catch (error) {
|
|
self.postMessage({ id: data.id, count: data.count, action: "reject", value: error });
|
|
}
|
|
});
|
|
}
|
|
|
|
return {
|
|
ready: ready,
|
|
supported: supported,
|
|
useWorkers: function(count) {
|
|
initWorkers(count);
|
|
},
|
|
decodeVertexBuffer: function(target, count, size, source, filter) {
|
|
decode(instance.exports.meshopt_decodeVertexBuffer, target, count, size, source, instance.exports[filters[filter]]);
|
|
},
|
|
decodeIndexBuffer: function(target, count, size, source) {
|
|
decode(instance.exports.meshopt_decodeIndexBuffer, target, count, size, source);
|
|
},
|
|
decodeIndexSequence: function(target, count, size, source) {
|
|
decode(instance.exports.meshopt_decodeIndexSequence, target, count, size, source);
|
|
},
|
|
decodeGltfBuffer: function(target, count, size, source, mode, filter) {
|
|
decode(instance.exports[decoders[mode]], target, count, size, source, instance.exports[filters[filter]]);
|
|
},
|
|
decodeGltfBufferAsync: function(count, size, source, mode, filter) {
|
|
if (workers.length > 0) {
|
|
return decodeWorker(count, size, source, decoders[mode], filters[filter]);
|
|
}
|
|
|
|
return ready.then(function() {
|
|
var target = new Uint8Array(count * size);
|
|
decode(instance.exports[decoders[mode]], target, count, size, source, instance.exports[filters[filter]]);
|
|
return target;
|
|
});
|
|
}
|
|
};
|
|
})();
|
|
|
|
export default MeshoptDecoder; |