UNPKG

@loaders.gl/textures

Version:

Framework-independent loaders for compressed and super compressed (basis) textures

710 lines (691 loc) 26.2 kB
"use strict"; (() => { // ../loader-utils/src/lib/env-utils/assert.ts function assert(condition, message) { if (!condition) { throw new Error(message || "loader assertion failed."); } } // ../loader-utils/src/lib/module-utils/js-module-utils.ts function registerJSModules(modules) { globalThis.loaders ||= {}; globalThis.loaders.modules ||= {}; Object.assign(globalThis.loaders.modules, modules); } function getJSModuleOrNull(name) { const module = globalThis.loaders?.modules?.[name]; return module || null; } // ../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; warningIssued = true; } else { globalThis._loadersgl_.version = "4.4.2"; } } return globalThis._loadersgl_.version; } var VERSION = getVersion(); // ../worker-utils/src/lib/env-utils/assert.ts function assert2(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 = {}; function extractLoadLibraryOptions(options = {}) { const useLocalLibraries = options.useLocalLibraries ?? options.core?.useLocalLibraries; const CDN = options.CDN ?? options.core?.CDN; const modules = options.modules; return { ...useLocalLibraries !== void 0 ? { useLocalLibraries } : {}, ...CDN !== void 0 ? { CDN } : {}, ...modules !== void 0 ? { modules } : {} }; } 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?.core) { throw new Error("loadLibrary: options.core must be pre-normalized"); } 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) { assert2(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) { const { requireFromFile } = globalThis.loaders || {}; try { const result = await requireFromFile?.(libraryUrl); if (result || !libraryUrl.includes("/dist/libs/")) { return result; } return await requireFromFile?.(libraryUrl.replace("/dist/libs/", "/src/libs/")); } catch (error) { if (libraryUrl.includes("/dist/libs/")) { try { return await requireFromFile?.(libraryUrl.replace("/dist/libs/", "/src/libs/")); } catch { } } 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(); } try { return await readFileAsArrayBuffer(url); } catch { if (url.includes("/dist/libs/")) { return await readFileAsArrayBuffer(url.replace("/dist/libs/", "/src/libs/")); } throw new Error(`Failed to load ArrayBuffer from ${url}`); } } async function loadAsText(url) { const { readFileAsText } = globalThis.loaders || {}; if (isBrowser || !readFileAsText || url.startsWith("http")) { const response = await fetch(url); return await response.text(); } try { return await readFileAsText(url); } catch { if (url.includes("/dist/libs/")) { return await readFileAsText(url.replace("/dist/libs/", "/src/libs/")); } throw new Error(`Failed to load text from ${url}`); } } // ../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 || {}, core: { ...options.core, worker: false } }; return await parser(data, { ...options }, context, loader); } // src/lib/utils/version.ts var VERSION2 = true ? "4.4.2" : "latest"; // src/crunch-loader.ts var CrunchLoader = { dataType: null, batchType: null, id: "crunch", name: "Crunch", module: "textures", version: VERSION2, worker: true, extensions: ["crn"], mimeTypes: ["image/crn", "image/x-crn", "application/octet-stream"], binary: true, options: { crunch: {} } }; // src/lib/parsers/crunch-module-loader.ts var CRUNCH_EXTERNAL_LIBRARIES = { /** Crunch decoder library. It is used as dynamically imported script */ DECODER: "crunch.js" }; async function loadCrunchModule(options) { registerJSModules(options.modules); const crunch = getJSModuleOrNull("crunch"); if (crunch) { return crunch; } return loadCrunch(options); } var crunchModule; async function loadCrunch(options) { if (crunchModule) { return crunchModule; } let loadCrunchDecoder = await loadLibrary(CRUNCH_EXTERNAL_LIBRARIES.DECODER, "textures", options); loadCrunchDecoder ||= globalThis.LoadCrunchDecoder; crunchModule = loadCrunchDecoder(); return crunchModule; } // src/lib/gl-extensions.ts var GL_RGBA32F = 34836; var GL_COMPRESSED_RGB_S3TC_DXT1_EXT = 33776; var GL_COMPRESSED_RGBA_S3TC_DXT1_EXT = 33777; var GL_COMPRESSED_RGBA_S3TC_DXT3_EXT = 33778; var GL_COMPRESSED_RGBA_S3TC_DXT5_EXT = 33779; var GL_COMPRESSED_R11_EAC = 37488; var GL_COMPRESSED_SIGNED_R11_EAC = 37489; var GL_COMPRESSED_RG11_EAC = 37490; var GL_COMPRESSED_SIGNED_RG11_EAC = 37491; var GL_COMPRESSED_RGB8_ETC2 = 37492; var GL_COMPRESSED_RGBA8_ETC2_EAC = 37493; var GL_COMPRESSED_SRGB8_ETC2 = 37494; var GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC = 37495; var GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 = 37496; var GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 = 37497; var GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG = 35840; var GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG = 35841; var GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG = 35842; var GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG = 35843; var GL_COMPRESSED_RGB_ETC1_WEBGL = 36196; var GL_COMPRESSED_RGB_ATC_WEBGL = 35986; var GL_COMPRESSED_RGBA_ATC_EXPLICIT_ALPHA_WEBGL = 35987; var GL_COMPRESSED_RGBA_ATC_INTERPOLATED_ALPHA_WEBGL = 34798; var GL_COMPRESSED_RGBA_ASTC_4x4_KHR = 37808; var GL_COMPRESSED_RGBA_ASTC_5x4_KHR = 37809; var GL_COMPRESSED_RGBA_ASTC_5x5_KHR = 37810; var GL_COMPRESSED_RGBA_ASTC_6x5_KHR = 37811; var GL_COMPRESSED_RGBA_ASTC_6x6_KHR = 37812; var GL_COMPRESSED_RGBA_ASTC_8x5_KHR = 37813; var GL_COMPRESSED_RGBA_ASTC_8x6_KHR = 37814; var GL_COMPRESSED_RGBA_ASTC_8x8_KHR = 37815; var GL_COMPRESSED_RGBA_ASTC_10x5_KHR = 37816; var GL_COMPRESSED_RGBA_ASTC_10x6_KHR = 37817; var GL_COMPRESSED_RGBA_ASTC_10x8_KHR = 37818; var GL_COMPRESSED_RGBA_ASTC_10x10_KHR = 37819; var GL_COMPRESSED_RGBA_ASTC_12x10_KHR = 37820; var GL_COMPRESSED_RGBA_ASTC_12x12_KHR = 37821; var GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR = 37840; var GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR = 37841; var GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR = 37842; var GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR = 37843; var GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR = 37844; var GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR = 37845; var GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR = 37846; var GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR = 37847; var GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR = 37848; var GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR = 37849; var GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR = 37850; var GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR = 37851; var GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR = 37852; var GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR = 37853; var GL_COMPRESSED_RED_RGTC1_EXT = 36283; var GL_COMPRESSED_SIGNED_RED_RGTC1_EXT = 36284; var GL_COMPRESSED_RED_GREEN_RGTC2_EXT = 36285; var GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT = 36286; var GL_COMPRESSED_SRGB_S3TC_DXT1_EXT = 35916; var GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT = 35917; var GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT = 35918; var GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT = 35919; // src/lib/utils/texture-format-map.ts var WEBGL_TO_TEXTURE_FORMAT = { [GL_RGBA32F]: "rgba32float", [GL_COMPRESSED_RGB_S3TC_DXT1_EXT]: "bc1-rgb-unorm-webgl", [GL_COMPRESSED_SRGB_S3TC_DXT1_EXT]: "bc1-rgb-unorm-srgb-webgl", [GL_COMPRESSED_RGBA_S3TC_DXT1_EXT]: "bc1-rgba-unorm", [GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT]: "bc1-rgba-unorm-srgb", [GL_COMPRESSED_RGBA_S3TC_DXT3_EXT]: "bc2-rgba-unorm", [GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT]: "bc2-rgba-unorm-srgb", [GL_COMPRESSED_RGBA_S3TC_DXT5_EXT]: "bc3-rgba-unorm", [GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT]: "bc3-rgba-unorm-srgb", [GL_COMPRESSED_RED_RGTC1_EXT]: "bc4-r-unorm", [GL_COMPRESSED_SIGNED_RED_RGTC1_EXT]: "bc4-r-snorm", [GL_COMPRESSED_RED_GREEN_RGTC2_EXT]: "bc5-rg-unorm", [GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT]: "bc5-rg-snorm", [GL_COMPRESSED_RGB8_ETC2]: "etc2-rgb8unorm", [GL_COMPRESSED_SRGB8_ETC2]: "etc2-rgb8unorm-srgb", [GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2]: "etc2-rgb8a1unorm", [GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2]: "etc2-rgb8a1unorm-srgb", [GL_COMPRESSED_RGBA8_ETC2_EAC]: "etc2-rgba8unorm", [GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC]: "etc2-rgba8unorm-srgb", [GL_COMPRESSED_R11_EAC]: "eac-r11unorm", [GL_COMPRESSED_SIGNED_R11_EAC]: "eac-r11snorm", [GL_COMPRESSED_RG11_EAC]: "eac-rg11unorm", [GL_COMPRESSED_SIGNED_RG11_EAC]: "eac-rg11snorm", [GL_COMPRESSED_RGBA_ASTC_4x4_KHR]: "astc-4x4-unorm", [GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR]: "astc-4x4-unorm-srgb", [GL_COMPRESSED_RGBA_ASTC_5x4_KHR]: "astc-5x4-unorm", [GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR]: "astc-5x4-unorm-srgb", [GL_COMPRESSED_RGBA_ASTC_5x5_KHR]: "astc-5x5-unorm", [GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR]: "astc-5x5-unorm-srgb", [GL_COMPRESSED_RGBA_ASTC_6x5_KHR]: "astc-6x5-unorm", [GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR]: "astc-6x5-unorm-srgb", [GL_COMPRESSED_RGBA_ASTC_6x6_KHR]: "astc-6x6-unorm", [GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR]: "astc-6x6-unorm-srgb", [GL_COMPRESSED_RGBA_ASTC_8x5_KHR]: "astc-8x5-unorm", [GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR]: "astc-8x5-unorm-srgb", [GL_COMPRESSED_RGBA_ASTC_8x6_KHR]: "astc-8x6-unorm", [GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR]: "astc-8x6-unorm-srgb", [GL_COMPRESSED_RGBA_ASTC_8x8_KHR]: "astc-8x8-unorm", [GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR]: "astc-8x8-unorm-srgb", [GL_COMPRESSED_RGBA_ASTC_10x5_KHR]: "astc-10x5-unorm", [GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR]: "astc-10x5-unorm-srgb", [GL_COMPRESSED_RGBA_ASTC_10x6_KHR]: "astc-10x6-unorm", [GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR]: "astc-10x6-unorm-srgb", [GL_COMPRESSED_RGBA_ASTC_10x8_KHR]: "astc-10x8-unorm", [GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR]: "astc-10x8-unorm-srgb", [GL_COMPRESSED_RGBA_ASTC_10x10_KHR]: "astc-10x10-unorm", [GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR]: "astc-10x10-unorm-srgb", [GL_COMPRESSED_RGBA_ASTC_12x10_KHR]: "astc-12x10-unorm", [GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR]: "astc-12x10-unorm-srgb", [GL_COMPRESSED_RGBA_ASTC_12x12_KHR]: "astc-12x12-unorm", [GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR]: "astc-12x12-unorm-srgb", [GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG]: "pvrtc-rgb4unorm-webgl", [GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG]: "pvrtc-rgba4unorm-webgl", [GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG]: "pvrtc-rgb2unorm-webgl", [GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG]: "pvrtc-rgba2unorm-webgl", [GL_COMPRESSED_RGB_ETC1_WEBGL]: "etc1-rgb-unorm-webgl", [GL_COMPRESSED_RGB_ATC_WEBGL]: "atc-rgb-unorm-webgl", [GL_COMPRESSED_RGBA_ATC_EXPLICIT_ALPHA_WEBGL]: "atc-rgba-unorm-webgl", [GL_COMPRESSED_RGBA_ATC_INTERPOLATED_ALPHA_WEBGL]: "atc-rgbai-unorm-webgl" }; var TEXTURE_FORMAT_TO_WEBGL = Object.fromEntries( Object.entries(WEBGL_TO_TEXTURE_FORMAT).map(([format, textureFormat]) => [ textureFormat, Number(format) ]) ); function getTextureFormatFromWebGLFormat(format) { if (format === void 0) { return void 0; } return WEBGL_TO_TEXTURE_FORMAT[format]; } function getWebGLFormatFromTextureFormat(textureFormat) { if (textureFormat === void 0) { return void 0; } return TEXTURE_FORMAT_TO_WEBGL[textureFormat]; } // src/lib/utils/extract-mipmap-images.ts function extractMipmapImages(data, options) { const images = new Array(options.mipMapLevels); const textureFormat = options.textureFormat || getTextureFormatFromWebGLFormat(options.internalFormat); const format = options.internalFormat || getWebGLFormatFromTextureFormat(options.textureFormat); let levelWidth = options.width; let levelHeight = options.height; let offset = 0; for (let i = 0; i < options.mipMapLevels; ++i) { const levelSize = getLevelSize(options, levelWidth, levelHeight, data, i); const levelData = getLevelData(data, i, offset, levelSize); const image = { shape: "texture-level", compressed: true, data: levelData, width: levelWidth, height: levelHeight, levelSize }; if (format !== void 0) { image.format = format; } if (textureFormat) { image.textureFormat = textureFormat; } images[i] = image; levelWidth = Math.max(1, levelWidth >> 1); levelHeight = Math.max(1, levelHeight >> 1); offset += levelSize; } return images; } function getLevelData(data, index, offset, levelSize) { if (!Array.isArray(data)) { return new Uint8Array(data.buffer, data.byteOffset + offset, levelSize); } return data[index].levelData; } function getLevelSize(options, levelWidth, levelHeight, data, index) { if (!Array.isArray(data)) { return options.sizeFunction(levelWidth, levelHeight); } return options.sizeFunction(data[index]); } // src/lib/parsers/parse-dds.ts function getDxt1LevelSize(width, height) { return (width + 3 >> 2) * (height + 3 >> 2) * 8; } function getDxtXLevelSize(width, height) { return (width + 3 >> 2) * (height + 3 >> 2) * 16; } // src/lib/parsers/parse-crunch.ts var CRN_FORMAT = { cCRNFmtInvalid: -1, cCRNFmtDXT1: 0, // cCRNFmtDXT3 is not currently supported when writing to CRN - only DDS. cCRNFmtDXT3: 1, cCRNFmtDXT5: 2 // Crunch supports more formats than this. }; var DXT_FORMAT_MAP = { [CRN_FORMAT.cCRNFmtDXT1]: { textureFormat: "bc1-rgb-unorm-webgl", sizeFunction: getDxt1LevelSize }, [CRN_FORMAT.cCRNFmtDXT3]: { textureFormat: "bc2-rgba-unorm", sizeFunction: getDxtXLevelSize }, [CRN_FORMAT.cCRNFmtDXT5]: { textureFormat: "bc3-rgba-unorm", sizeFunction: getDxtXLevelSize } }; var cachedDstSize = 0; var dst; async function parseCrunch(data, options) { const crunchModule2 = await loadCrunchModule(extractLoadLibraryOptions(options)); const srcSize = data.byteLength; const bytes = new Uint8Array(data); const src = crunchModule2._malloc(srcSize); arrayBufferCopy(bytes, crunchModule2.HEAPU8, src, srcSize); const format = crunchModule2._crn_get_dxt_format(src, srcSize); assert(Boolean(DXT_FORMAT_MAP[format]), "Unsupported format"); const mipMapLevels = crunchModule2._crn_get_levels(src, srcSize); const width = crunchModule2._crn_get_width(src, srcSize); const height = crunchModule2._crn_get_height(src, srcSize); const sizeFunction = DXT_FORMAT_MAP[format].sizeFunction; let dstSize = 0; for (let i = 0; i < mipMapLevels; ++i) { dstSize += sizeFunction(width >> i, height >> i); } if (cachedDstSize < dstSize) { if (dst) { crunchModule2._free(dst); } dst = crunchModule2._malloc(dstSize); cachedDstSize = dstSize; } crunchModule2._crn_decompress(src, srcSize, dst, dstSize, 0, mipMapLevels); crunchModule2._free(src); const image = new Uint8Array(crunchModule2.HEAPU8.buffer, dst, dstSize).slice(); return extractMipmapImages(image, { mipMapLevels, width, height, sizeFunction, textureFormat: DXT_FORMAT_MAP[format].textureFormat }); } function arrayBufferCopy(srcData, dstData, dstByteOffset, numBytes) { let i; const dst32Offset = dstByteOffset / 4; const tail = numBytes % 4; const src32 = new Uint32Array(srcData.buffer, 0, (numBytes - tail) / 4); const dst32 = new Uint32Array(dstData.buffer); for (i = 0; i < src32.length; i++) { dst32[dst32Offset + i] = src32[i]; } for (i = numBytes - tail; i < numBytes; i++) { dstData[dstByteOffset + i] = srcData[i]; } } // src/workers/crunch-worker.ts var CrunchLoaderWithParser = { ...CrunchLoader, parse: parseCrunch }; createLoaderWorker(CrunchLoaderWithParser); })();