@loaders.gl/textures
Version:
Framework-independent loaders for compressed and super compressed (basis) textures
290 lines (282 loc) • 9.18 kB
JavaScript
;
(() => {
// src/lib/utils/version.ts
var VERSION = true ? "4.3.2" : "latest";
// src/lib/parsers/parse-npy.ts
var a = new Uint32Array([305419896]);
var b = new Uint8Array(a.buffer, a.byteOffset, a.byteLength);
var isLittleEndian = !(b[0] === 18);
var LITTLE_ENDIAN_OS = isLittleEndian;
var DTYPES = {
u1: Uint8Array,
i1: Int8Array,
u2: Uint16Array,
i2: Int16Array,
u4: Uint32Array,
i4: Int32Array,
f4: Float32Array,
f8: Float64Array
};
function parseNPY(arrayBuffer, options) {
const view = new DataView(arrayBuffer);
const { header, headerEndOffset } = parseHeader(view);
const numpyType = header.descr;
const ArrayType = DTYPES[numpyType.slice(1, 3)];
if (!ArrayType) {
throw new Error(`Unimplemented type ${numpyType}`);
}
const nArrayElements = header.shape?.reduce((a2, b2) => a2 * b2);
const arrayByteLength = nArrayElements * ArrayType.BYTES_PER_ELEMENT;
if (arrayBuffer.byteLength < headerEndOffset + arrayByteLength) {
throw new Error("Buffer overflow");
}
const data = new ArrayType(arrayBuffer.slice(headerEndOffset, headerEndOffset + arrayByteLength));
if (numpyType[0] === ">" && LITTLE_ENDIAN_OS || numpyType[0] === "<" && !LITTLE_ENDIAN_OS) {
throw new Error("Incorrect endianness");
}
return {
data,
header
};
}
function parseHeader(view) {
const majorVersion = view.getUint8(6);
let offset = 8;
let headerLength;
if (majorVersion >= 2) {
headerLength = view.getUint32(offset, true);
offset += 4;
} else {
headerLength = view.getUint16(offset, true);
offset += 2;
}
const encoding = majorVersion <= 2 ? "latin1" : "utf-8";
const decoder = new TextDecoder(encoding);
const headerArray = new Uint8Array(view.buffer, offset, headerLength);
const headerText = decoder.decode(headerArray);
offset += headerLength;
const header = JSON.parse(
headerText.replace(/'/g, '"').replace("False", "false").replace("(", "[").replace(/,*\),*/g, "]")
);
return { header, headerEndOffset: offset };
}
// src/npy-loader.ts
var NPY_MAGIC_NUMBER = new Uint8Array([147, 78, 85, 77, 80, 89]);
var NPYWorkerLoader = {
dataType: null,
batchType: null,
name: "NPY",
id: "npy",
module: "textures",
version: VERSION,
worker: true,
extensions: ["npy"],
mimeTypes: [],
tests: [NPY_MAGIC_NUMBER.buffer],
options: {
npy: {}
}
};
var NPYLoader = {
...NPYWorkerLoader,
parseSync: parseNPY,
parse: async (arrayBuffer, options) => parseNPY(arrayBuffer, options)
};
// ../worker-utils/src/lib/node/worker_threads-browser.ts
var parentPort = null;
// ../worker-utils/src/lib/worker-utils/get-transfer-list.ts
function getTransferList(object, recursive = true, transfers) {
const transfersSet = transfers || /* @__PURE__ */ new Set();
if (!object) {
} else if (isTransferable(object)) {
transfersSet.add(object);
} else if (isTransferable(object.buffer)) {
transfersSet.add(object.buffer);
} else if (ArrayBuffer.isView(object)) {
} else if (recursive && typeof object === "object") {
for (const key in object) {
getTransferList(object[key], recursive, transfersSet);
}
}
return transfers === void 0 ? Array.from(transfersSet) : [];
}
function isTransferable(object) {
if (!object) {
return false;
}
if (object instanceof ArrayBuffer) {
return true;
}
if (typeof MessagePort !== "undefined" && object instanceof MessagePort) {
return true;
}
if (typeof ImageBitmap !== "undefined" && object instanceof ImageBitmap) {
return true;
}
if (typeof OffscreenCanvas !== "undefined" && object instanceof OffscreenCanvas) {
return true;
}
return false;
}
// ../worker-utils/src/lib/worker-farm/worker-body.ts
async function getParentPort() {
return parentPort;
}
var onMessageWrapperMap = /* @__PURE__ */ new Map();
var WorkerBody = class {
/** Check that we are actually in a worker thread */
static async inWorkerThread() {
return typeof self !== "undefined" || Boolean(await getParentPort());
}
/*
* (type: WorkerMessageType, payload: WorkerMessagePayload) => any
*/
static set onmessage(onMessage) {
async function handleMessage(message) {
const parentPort2 = await getParentPort();
const { type, payload } = parentPort2 ? message : message.data;
onMessage(type, payload);
}
getParentPort().then((parentPort2) => {
if (parentPort2) {
parentPort2.on("message", (message) => {
handleMessage(message);
});
parentPort2.on("exit", () => console.debug("Node worker closing"));
} else {
globalThis.onmessage = handleMessage;
}
});
}
static async addEventListener(onMessage) {
let onMessageWrapper = onMessageWrapperMap.get(onMessage);
if (!onMessageWrapper) {
onMessageWrapper = async (message) => {
if (!isKnownMessage(message)) {
return;
}
const parentPort3 = await getParentPort();
const { type, payload } = parentPort3 ? message : message.data;
onMessage(type, payload);
};
}
const parentPort2 = await getParentPort();
if (parentPort2) {
console.error("not implemented");
} else {
globalThis.addEventListener("message", onMessageWrapper);
}
}
static async removeEventListener(onMessage) {
const onMessageWrapper = onMessageWrapperMap.get(onMessage);
onMessageWrapperMap.delete(onMessage);
const parentPort2 = await getParentPort();
if (parentPort2) {
console.error("not implemented");
} else {
globalThis.removeEventListener("message", onMessageWrapper);
}
}
/**
* Send a message from a worker to creating thread (main thread)
* @param type
* @param payload
*/
static async postMessage(type, payload) {
const data = { source: "loaders.gl", type, payload };
const transferList = getTransferList(payload);
const parentPort2 = await getParentPort();
if (parentPort2) {
parentPort2.postMessage(data, transferList);
} else {
globalThis.postMessage(data, transferList);
}
}
};
function isKnownMessage(message) {
const { type, data } = message;
return type === "message" && data && typeof data.source === "string" && data.source.startsWith("loaders.gl");
}
// ../loader-utils/src/lib/worker-loader-utils/create-loader-worker.ts
var requestId = 0;
async function createLoaderWorker(loader) {
if (!await WorkerBody.inWorkerThread()) {
return;
}
WorkerBody.onmessage = async (type, payload) => {
switch (type) {
case "process":
try {
const { input, options = {}, context = {} } = payload;
const result = await parseData({
loader,
arrayBuffer: input,
options,
// @ts-expect-error fetch missing
context: {
...context,
_parse: parseOnMainThread
}
});
WorkerBody.postMessage("done", { result });
} catch (error) {
const message = error instanceof Error ? error.message : "";
WorkerBody.postMessage("error", { error: message });
}
break;
default:
}
};
}
function parseOnMainThread(arrayBuffer, loader, options, context) {
return new Promise((resolve, reject) => {
const id = requestId++;
const onMessage = (type, payload2) => {
if (payload2.id !== id) {
return;
}
switch (type) {
case "done":
WorkerBody.removeEventListener(onMessage);
resolve(payload2.result);
break;
case "error":
WorkerBody.removeEventListener(onMessage);
reject(payload2.error);
break;
default:
}
};
WorkerBody.addEventListener(onMessage);
const payload = { id, input: arrayBuffer, options };
WorkerBody.postMessage("process", payload);
});
}
async function parseData({
loader,
arrayBuffer,
options,
context
}) {
let data;
let parser;
if (loader.parseSync || loader.parse) {
data = arrayBuffer;
parser = loader.parseSync || loader.parse;
} else if (loader.parseTextSync) {
const textDecoder = new TextDecoder();
data = textDecoder.decode(arrayBuffer);
parser = loader.parseTextSync;
} else {
throw new Error(`Could not load data with ${loader.name} loader`);
}
options = {
...options,
modules: loader && loader.options && loader.options.modules || {},
worker: false
};
return await parser(data, { ...options }, context, loader);
}
// src/workers/npy-worker.ts
createLoaderWorker(NPYLoader);
})();