@loaders.gl/textures
Version:
Framework-independent loaders for compressed and super compressed (basis) textures
370 lines (358 loc) • 12.9 kB
JavaScript
;
(() => {
// ../worker-utils/src/lib/env-utils/version.ts
function getVersion() {
if (!globalThis._loadersgl_?.version) {
globalThis._loadersgl_ = globalThis._loadersgl_ || {};
if (false) {
console.warn(
"loaders.gl: The __VERSION__ variable is not injected using babel plugin. Latest unstable workers would be fetched from the CDN."
);
globalThis._loadersgl_.version = NPM_TAG;
} else {
globalThis._loadersgl_.version = "4.3.2";
}
}
return globalThis._loadersgl_.version;
}
var VERSION = getVersion();
// ../worker-utils/src/lib/env-utils/assert.ts
function assert(condition, message) {
if (!condition) {
throw new Error(message || "loaders.gl assertion failed.");
}
}
// ../worker-utils/src/lib/env-utils/globals.ts
var globals = {
self: typeof self !== "undefined" && self,
window: typeof window !== "undefined" && window,
global: typeof global !== "undefined" && global,
document: typeof document !== "undefined" && document
};
var self_ = globals.self || globals.window || globals.global || {};
var window_ = globals.window || globals.self || globals.global || {};
var global_ = globals.global || globals.self || globals.window || {};
var document_ = globals.document || {};
var isBrowser = (
// @ts-ignore process.browser
typeof process !== "object" || String(process) !== "[object process]" || process.browser
);
var isWorker = typeof importScripts === "function";
var isMobile = typeof window !== "undefined" && typeof window.orientation !== "undefined";
var matches = typeof process !== "undefined" && process.version && /v([0-9]*)/.exec(process.version);
var nodeVersion = matches && parseFloat(matches[1]) || 0;
// ../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");
}
// ../worker-utils/src/lib/library-utils/library-utils.ts
var loadLibraryPromises = {};
async function loadLibrary(libraryUrl, moduleName = null, options = {}, libraryName = null) {
if (moduleName) {
libraryUrl = getLibraryUrl(libraryUrl, moduleName, options, libraryName);
}
loadLibraryPromises[libraryUrl] = // eslint-disable-next-line @typescript-eslint/no-misused-promises
loadLibraryPromises[libraryUrl] || loadLibraryFromFile(libraryUrl);
return await loadLibraryPromises[libraryUrl];
}
function getLibraryUrl(library, moduleName, options = {}, libraryName = null) {
if (!options.useLocalLibraries && library.startsWith("http")) {
return library;
}
libraryName = libraryName || library;
const modules = options.modules || {};
if (modules[libraryName]) {
return modules[libraryName];
}
if (!isBrowser) {
return `modules/${moduleName}/dist/libs/${libraryName}`;
}
if (options.CDN) {
assert(options.CDN.startsWith("http"));
return `${options.CDN}/${moduleName}@${VERSION}/dist/libs/${libraryName}`;
}
if (isWorker) {
return `../src/libs/${libraryName}`;
}
return `modules/${moduleName}/src/libs/${libraryName}`;
}
async function loadLibraryFromFile(libraryUrl) {
if (libraryUrl.endsWith("wasm")) {
return await loadAsArrayBuffer(libraryUrl);
}
if (!isBrowser) {
try {
const { requireFromFile } = globalThis.loaders || {};
return await requireFromFile?.(libraryUrl);
} catch (error) {
console.error(error);
return null;
}
}
if (isWorker) {
return importScripts(libraryUrl);
}
const scriptSource = await loadAsText(libraryUrl);
return loadLibraryFromString(scriptSource, libraryUrl);
}
function loadLibraryFromString(scriptSource, id) {
if (!isBrowser) {
const { requireFromString } = globalThis.loaders || {};
return requireFromString?.(scriptSource, id);
}
if (isWorker) {
eval.call(globalThis, scriptSource);
return null;
}
const script = document.createElement("script");
script.id = id;
try {
script.appendChild(document.createTextNode(scriptSource));
} catch (e) {
script.text = scriptSource;
}
document.body.appendChild(script);
return null;
}
async function loadAsArrayBuffer(url) {
const { readFileAsArrayBuffer } = globalThis.loaders || {};
if (isBrowser || !readFileAsArrayBuffer || url.startsWith("http")) {
const response = await fetch(url);
return await response.arrayBuffer();
}
return await readFileAsArrayBuffer(url);
}
async function loadAsText(url) {
const { readFileAsText } = globalThis.loaders || {};
if (isBrowser || !readFileAsText || url.startsWith("http")) {
const response = await fetch(url);
return await response.text();
}
return await readFileAsText(url);
}
// src/lib/utils/version.ts
var VERSION2 = true ? "4.3.2" : "latest";
// src/lib/parsers/basis-module-loader.ts
var BASIS_EXTERNAL_LIBRARIES = {
/** Basis transcoder, javascript wrapper part */
TRANSCODER: "basis_transcoder.js",
/** Basis transcoder, compiled web assembly part */
TRANSCODER_WASM: "basis_transcoder.wasm",
/** Basis encoder, javascript wrapper part */
ENCODER: "basis_encoder.js",
/** Basis encoder, compiled web assembly part */
ENCODER_WASM: "basis_encoder.wasm"
};
var loadBasisEncoderPromise;
async function loadBasisEncoderModule(options) {
const modules = options.modules || {};
if (modules.basisEncoder) {
return modules.basisEncoder;
}
loadBasisEncoderPromise = loadBasisEncoderPromise || loadBasisEncoder(options);
return await loadBasisEncoderPromise;
}
async function loadBasisEncoder(options) {
let BASIS_ENCODER = null;
let wasmBinary = null;
[BASIS_ENCODER, wasmBinary] = await Promise.all([
await loadLibrary(BASIS_EXTERNAL_LIBRARIES.ENCODER, "textures", options),
await loadLibrary(BASIS_EXTERNAL_LIBRARIES.ENCODER_WASM, "textures", options)
]);
BASIS_ENCODER = BASIS_ENCODER || globalThis.BASIS;
return await initializeBasisEncoderModule(BASIS_ENCODER, wasmBinary);
}
function initializeBasisEncoderModule(BasisEncoderModule, wasmBinary) {
const options = {};
if (wasmBinary) {
options.wasmBinary = wasmBinary;
}
return new Promise((resolve) => {
BasisEncoderModule(options).then((module) => {
const { BasisFile, KTX2File, initializeBasis, BasisEncoder } = module;
initializeBasis();
resolve({ BasisFile, KTX2File, BasisEncoder });
});
});
}
// src/lib/encoders/encode-ktx2-basis-texture.ts
async function encodeKTX2BasisTexture(image, options = {}) {
const {
useSRGB = false,
qualityLevel = 10,
encodeUASTC = false,
mipmaps = false
} = options?.["ktx2-basis-writer"] || {};
const { BasisEncoder } = await loadBasisEncoderModule(options);
const basisEncoder = new BasisEncoder();
try {
const basisFileData = new Uint8Array(image.width * image.height * 4);
basisEncoder.setCreateKTX2File(true);
basisEncoder.setKTX2UASTCSupercompression(true);
basisEncoder.setKTX2SRGBTransferFunc(true);
basisEncoder.setSliceSourceImage(0, image.data, image.width, image.height, false);
basisEncoder.setPerceptual(useSRGB);
basisEncoder.setMipSRGB(useSRGB);
basisEncoder.setQualityLevel(qualityLevel);
basisEncoder.setUASTC(encodeUASTC);
basisEncoder.setMipGen(mipmaps);
const numOutputBytes = basisEncoder.encode(basisFileData);
const actualKTX2FileData = basisFileData.subarray(0, numOutputBytes).buffer;
return actualKTX2FileData;
} catch (error) {
console.error("Basis Universal Supercompressed GPU Texture encoder Error: ", error);
throw error;
} finally {
basisEncoder.delete();
}
}
// src/ktx2-basis-writer.ts
var KTX2BasisWriter = {
name: "Basis Universal Supercompressed GPU Texture",
id: "ktx2-basis-writer",
module: "textures",
version: VERSION2,
extensions: ["ktx2"],
options: {
["ktx2-basis-writer"]: {
useSRGB: false,
qualityLevel: 10,
encodeUASTC: false,
mipmaps: false
}
},
encode: encodeKTX2BasisTexture
};
// src/workers/ktx2-basis-writer-worker.ts
(async () => {
if (!await WorkerBody.inWorkerThread()) {
return;
}
WorkerBody.onmessage = async (type, payload) => {
switch (type) {
case "process":
try {
const { input, options } = payload;
const result = await KTX2BasisWriter.encode?.(input, options);
WorkerBody.postMessage("done", { result });
} catch (error) {
const message = error instanceof Error ? error.message : "";
WorkerBody.postMessage("error", { error: message });
}
break;
default:
}
};
})();
})();