Vixen
dd8b0a81
csharp
public sealed class DdsDecoder

Reads a DDS, which is mostly a header over block-compressed data the engine already speaks.

Read the guide page for this →

Remarks

Doc 01 names Pfim for this and it turned out not to be needed. The plan's dependency table has carried a row for Pfim (MIT, DDS/TGA) since it was written, and neither half of that row survives contact with what got built: TGA has been read by StbImageDecoder since the ImageSharp swap, and DDS in this engine is a container rather than a codec. The payload a game ships in one is BCn, and Vixen.Core.Imaging has understood BC1 through BC7 and BC6H for as long as Ktx2 has. What was missing was header parsing and a format table — not a decoder, and not a package. Adding one would have bought a dependency, a licence line and a restore-graph change to do work the repository can already do.

Which way up. DDS has no origin flag: row zero is the top, in every file the format has ever described. That is already this pipeline's order — MinimalPng writes its rows top first and TextureImporter ships them unchanged, and SpriteRect.Y is measured down from the top of a sheet — so the bytes are copied straight through and nothing here flips anything. The engine's clip-space convention (y = +1 is the top, and the screen helpers negate y) is a statement about vertices, settled long after a texture is uploaded, and does not reach the import.

What it claims. A plain 2D texture: one array element, one face. A compressed payload passes through with its whole mip chain and its own format, so a BC7 file an artist encoded with a better tool than BlockCompressor ships exactly as it arrived — including whether its header said sRGB. An uncompressed payload comes back as level zero in Rgba8UNorm, which is what StbImageDecoder returns for a PNG and what TextureImporter's uncompressed path is written against; the mip chain is regenerated and the sRGB decision is the settings', exactly as it is for a PNG.

What it refuses, by name and out loud: cube maps, texture arrays, volumes, and every uncompressed format wider than eight bits a channel. VideoImporter's precedent, for its reason — an artist who drops a file in and finds it silently became something else has learned nothing. The first three have a concrete reason as well: DDS orders a cube map and an array element-major (every mip of face 0, then every mip of face 1) and TextureData and KTX2 order them level-major. Half-reading one does not give a slightly wrong texture, it gives six faces interleaved into the wrong levels, and that transpose is the work — so it waits for something that needs it instead of being guessed at.

Fields and properties (2)

  • public const string Extension

    The extension it reads.

  • public IReadOnlyList<string> Extensions

    Which extensions it reads, lowercase and with their leading dots.

Methods (2)

  • public TextureData Decode(Stream stream, string extension)

    Decodes an image.

  • public static TextureData Read(ReadOnlySpan<byte> file)

    Reads a DDS file's bytes.

Used by (2)

  • DdsImportTestsVixen.Editor.Assets.Tests
  • ImageDecodersVixen.Editor.Assets