Luxar Viewer API Documentation - v2026.9.22
    Preparing search index...

    Module data/mesh/texture-decode

    Mesh texture fetch + decode, and the Stage 2 check that the decoded surface is the one the store declared.

    Its own module rather than a branch of mesh-whole-node-loader.ts for the reason the writer split _write_mesh_texture_arrays out on the Python side: a texture is the only array in a mesh that is not per-vertex, so it shares none of the loader's nVertices-shaped machinery and every one of its steps is conditional on an encoding the other arrays do not have.

    raw is a numeric (h, w, c) array, so it goes through the normal Luxar decode stack — which matters, because the raw arm is the one that carries HDR and an HDR texture is stored as geolog_perchannel_u16 codes under AUTO. Reading its bytes directly would hand back quantization codes and render a garbage image.

    A codec arm (png / webp / jpeg) is an opaque blob no Luxar encoder touches, decoded by the browser via createImageBitmap — the same mechanism loaders/picking/image-label-loader.ts already uses for hover thumbnails.

    The ktx2 arm is also an opaque blob, but it must bypass browser image decode: the renderer-owned KTX2 decoder transcodes it directly to a native compressed GPU texture while preserving the authored mip chain.

    The preflight charges the decoded surface against the byte budget from the DECLARED texture_width/texture_height, because a compressed image's stored size says nothing about what it expands to. That admission is therefore only as true as the declaration. So the moment real dimensions exist — after createImageBitmap reports them — they are compared against what was declared and a mismatch rejects the node. Without that, a store declares 16 x 16, is admitted for 1 KB, and detonates a 30000 x 30000 decode.

    decodeMeshTexture