Skip to content

Texture Formats Decoding and Writing

off-cmd edited this page Sep 16, 2026 · 1 revision

Texture Formats: Decoding and Writing

Relevant source files

The following files were used as context for generating this wiki page:

Purpose and Scope

This section covers the low-level binary format layer for FINAL FANTASY XIV textures within XIVUpscaler. Specifically, it documents the file header structures (tex.py), the multi-backend surface decoding engine (texdecode.py), the .tex serialization and box-filtered mip chain generation utilities (texwrite.py), and the pure-Python NumPy-based BC7 block compressor (bc7enc.py). Together, these modules allow the pipeline to read vanilla game assets from sqpack archives, decode compressed or raw graphic surfaces into standard NumPy arrays, process/upscale them, and write valid block-compressed or uncompressed .tex files ready for Penumbra packaging.

Sources: clarity/ffxiv/init.py:1-11, clarity/ffxiv/texwrite.py:1-21


1. Texture Headers and Format Specifications (tex.py)

FFXIV texture files (.tex) begin with an 80-byte header that defines dimensionality, surface attributes, pixel formats, and mipmap offsets. The format architecture supports both uncompressed layouts (such as B8G8R8A8, format code 0x1450) and block-compressed layouts (BC7 code 0x6432, BC5 code 0x6230, BC3 code 0x3431) clarity/ffxiv/texwrite.py:27-31.

The header structure is parsed via tex.TexHeader (shared via texfile aliases) clarity/ffxiv/init.py:15, exposing properties like width, height, mip_count, format_name, surface_offsets, and mip_dimensions. Unused surface offset slots in the 13-element offset array are explicitly zeroed out tests/test_texwrite.py:36.

Sources: clarity/ffxiv/tex.py:1-10, clarity/ffxiv/texwrite.py:27-63, tests/test_texwrite.py:23-37


2. Decoding Mips and Raw Surfaces (texdecode.py)

The texdecode.py module transforms compressed or raw binary texture payloads into standard (H, W, 4) uint8 NumPy arrays in RGBA order clarity/ffxiv/texdecode.py:1-6.

Decoding Pipeline and Code Mapping

graph TD
    A[""DecodeRequest(tex_bytes, mip)""] --> B[""tex.TexHeader(tex_bytes)""]
    B --> C[""decode(tex_bytes, mip)""]
    C --> D[""decode_raw(format_name, data, w, ht)""]
    D --> E{"Format Type"}
    E -->|BC7/BC6H| F[""_t2d.decode_bc7(data, w, ht)""]
    E -->|BC1| G[""_bc1_blocks(data, w, ht)""]
    E -->|BC2| H[""_t2d.decode_bc2 or _bc1_blocks(..., four_colour=True)""]
    E -->|BC3| I[""_t2d.decode_bc3 or _bc_alpha_plane + _bc1_blocks""]
    F --> J[""BGRA to RGBA Swizzle & Copy""]
    G --> J
    H --> J
    I --> J
Loading

Figure 1: Natural Language Space to Code Entity Space mapping for clarity.ffxiv.texdecode surface decoding routines.

Implementation Details

  • Validation & Dispatch: decode(tex_bytes, mip) checks that requested mips fall within valid bounds and have non-zero surface offsets before extracting the buffer slice clarity/ffxiv/texdecode.py:86-96. It delegates format-specific decoding to decode_raw() clarity/ffxiv/texdecode.py:99-104.
  • External Acceleration (texture2ddecoder): If the optional dependency texture2ddecoder (_t2d) is available, block compression formats such as BC7, BC6H, BC2, BC1, and BC3 are decoded via optimized native wrappers clarity/ffxiv/texdecode.py:12-16, followed by BGRA-to-RGBA channel swizzling ([..., [2, 1, 0, 3]]) clarity/ffxiv/texdecode.py:115-117. If BC7 or BC6H is requested without texture2ddecoder installed, a RuntimeError is raised indicating the required Python environment flags clarity/ffxiv/texdecode.py:105-114.
  • Pure-Python Fallbacks: For systems lacking native libraries, pure-Python decoders handle common formats:

Sources: clarity/ffxiv/texdecode.py:1-147, tests/test_texwrite.py:1-22


3. Texture Serialization and Writing (texwrite.py)

texwrite.py provides builders for uncompressed and compressed .tex payloads. It enforces BGRA byte ordering during serialization since the game loader expects blue-first channels clarity/ffxiv/texwrite.py:20-21.

Core Serialization Functions

  • write(rgba, attributes, mips): Converts an (H, W, 4) uint8 array (or converts RGB/greyscale inputs) into an 80-byte header followed by box-filtered mip levels clarity/ffxiv/texwrite.py:36-62. Grayscale inputs are expanded to multi-channel representations clarity/ffxiv/texwrite.py:46-47.
  • write_like(rgba, reference_tex, mips): Inherits header attribute bitmasks from an existing vanilla reference texture of the same processing role clarity/ffxiv/texwrite.py:65-68.
  • mip_chain(rgba, mips): Generates box-filtered RGBA mipmap chains where each dimension halves independently down to 1x1 clarity/ffxiv/texwrite.py:71-86. The downsampling operation _box_down() performs 2x2 spatial averaging (degrading to 2x1 or 1x2 when an edge reaches 1) followed by rounding and clipping to uint8 clarity/ffxiv/texwrite.py:89-100.
  • write_blocks(fmt, levels_blocks, w, h, attributes): Lays out block-compressed mip levels, verifying that the byte size of each compressed mip matches expected block dimensions (ceil(w/4) * ceil(h/4) * block_bytes) clarity/ffxiv/texwrite.py:103-127.
  • write_bc7(rgba, mips, attributes, modes): Computes a full mip chain using the pure-Python BC7 encoder (bc7enc.py) clarity/ffxiv/texwrite.py:130-142.

Sources: clarity/ffxiv/texwrite.py:1-142, tests/test_texwrite.py:39-110


4. Pure-Python BC7 Block Encoder (bc7enc.py)

Because standard image libraries lack complete BC7 encoders on non-Windows platforms, XIVUpscaler implements a pure-Python and NumPy-vectorized BC7 encoder focusing primarily on Mode 6 (single subset, RGBA 7-bit endpoints + p-bit, 4-bit indices) with Mode 5 (RGB line + separate alpha line) evaluated per-block for difficult regions clarity/ffxiv/bc7enc.py:1-11.

Encoding Architecture and Code Entities

graph TD
    A[""Input RGBA Array (h, w, 4)""] --> B[""_blocks(rgba) -> (B, 16, 4)""""]
    B --> C[""_mode6(X) & _mode5(X)""]
    subgraph Mode_6_Pipeline
        D1[""_fit_line(X) via np.linalg.eigh""] --> D2[""_refine(X, W4)""]
        D2 --> D3[""_assign(X, e0, e1, W4)""]
        D3 --> D4[""_lsq(X, idx, W4)""]
    end
    C -->|Compare MSE| E[""Select Best Block Encoding""]
    E --> F[""write_blocks(BC7, ...)""]
Loading

Figure 2: Code Entity Space mapping for the pure-Python BC7 encoding workflow in clarity.ffxiv.bc7enc and clarity.ffxiv.texwrite.

Implementation Functions

  • _blocks(rgba): Reshapes input images into raster-ordered 4x4 blocks of shape (B, 16, 4), padding edges by replication if dimensions are not multiples of 4 clarity/ffxiv/bc7enc.py:29-40.
  • _fit_line(X): Computes principal component axes of each block using covariance matrix eigenvalue decomposition (np.linalg.eigh) on centered texels, avoiding eigenvalue collapse issues associated with simple power-iteration methods clarity/ffxiv/bc7enc.py:43-58.
  • _assign(X, e0, e1, weights): Evaluates squared Euclidean distances across weight palettes to find nearest interpolation levels per texel clarity/ffxiv/bc7enc.py:61-66.
  • _lsq(X, idx, weights): Solves least-squares endpoint adjustments for fixed index assignments, falling back to block means if matrix determinants approach zero clarity/ffxiv/bc7enc.py:69-88.
  • _refine(X, weights, iters): Iteratively refines endpoints over multiple passes to minimize reconstruction error clarity/ffxiv/bc7enc.py:90-99.

Sources: clarity/ffxiv/bc7enc.py:1-173, clarity/ffxiv/texwrite.py:130-142

Clone this wiki locally