texheaders

package module
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 17, 2026 License: MIT Imports: 12 Imported by: 0

README

texheaders

texheaders is a Go package for reading and writing DayZ/Arma texHeaders.bin files.

It supports two main flows:

  • decode/encode texHeaders.bin from/to streams or files;
  • build texHeaders.bin from a list of source texture files (.paa).

Install

go get github.com/woozymasta/texheaders

Usage

Decode
f, err := texheaders.ReadFile("testdata/texHeaders.bin")
if err != nil {
    return err
}

fmt.Println(f.Version, len(f.Textures))
Encode
if err := texheaders.WriteFile("out.bin", f); err != nil {
    return err
}
Build From .paa
baseDir := "P:/modsource"
b := texheaders.NewBuilder(texheaders.BuildOptions{
    BaseDir:        baseDir,
    LowercasePaths: true,
    BackslashPaths: true,
})

if err := b.AppendMany(
    "P:/modsource/data/test_co.paa",
    "P:/modsource/data/test_nohq.paa",
); err != nil {
    return err
}

if err := b.WriteFile("P:/modsource/texHeaders.bin"); err != nil {
    return err
}
Build With Skip Invalid Inputs
b := texheaders.NewBuilder(texheaders.BuildOptions{SkipInvalid: true})
_ = b.Append("ok_co.paa")
_ = b.Append("not_texture.txt")

f, err := b.Build()
if err != nil {
    return err
}

for _, issue := range b.Issues() {
    fmt.Println(issue.Path, issue.Error)
}

_ = f

Path Normalization

Builder stores TextureEntry.PAAFile as normalized relative path:

  • relative to BuildOptions.BaseDir when possible;
  • lowercase by default;
  • backslash separators by default.

Build Parallelism

BuildOptions.Workers controls build parallelism:

  • 0 or 1: serial build (default, no worker overhead);
  • >1: explicit worker count;
  • texheaders.WorkersAuto (-1): auto mode based on GOMAXPROCS/4, rounded down to nearest power of two and capped by input file count.

Known Unsupported

  • .pac source input is currently not supported (ErrPACUnsupported).

Compatibility

Current target is structural compatibility with official output. Exact byte parity is best-effort and depends on source metadata/tooling differences.

Documentation

Overview

Package texheaders reads and writes DayZ/Arma texHeaders.bin files.

The format stores texture metadata index entries (path, color tags, mip descriptors, pax format, and suffix type). The package provides stream/file APIs for decode/encode and a builder API for creating texHeaders models from source .paa files.

Basic read:

f, err := texheaders.ReadFile("texHeaders.bin")
if err != nil {
	return err
}

Basic write:

err := texheaders.WriteFile("out.bin", f)
if err != nil {
	return err
}

Build from textures:

b := texheaders.NewBuilder(texheaders.BuildOptions{BaseDir: "P:/mod"})
_ = b.AppendMany(
	"P:/mod/data/test_co.paa",
	"P:/mod/data/test_nohq.paa",
)
err = b.WriteFile("P:/mod/texHeaders.bin")
if err != nil {
	return err
}

Index

Constants

View Source
const (
	SuffixDiffuseSRGB           uint32 = 0
	SuffixDiffuseLinear         uint32 = 1
	SuffixDetailLinear          uint32 = 2
	SuffixNormalMap             uint32 = 3
	SuffixIrradianceMap         uint32 = 4
	SuffixRandom05To1           uint32 = 5
	SuffixTreeCrownCalc         uint32 = 6
	SuffixMacroObjectSRGB       uint32 = 7
	SuffixAmbientShadow         uint32 = 8
	SuffixSpecularAmount        uint32 = 9
	SuffixDitherTexture         uint32 = 10
	SuffixDetailSpecularAmount  uint32 = 11
	SuffixMultiShaderMask       uint32 = 12
	SuffixThermalImageTextureCA uint32 = 13
)

Known pax suffix kinds from available format docs.

View Source
const FileMagic = "0DHT"

FileMagic is the required 4-byte file signature.

View Source
const SupportedVersion uint32 = 1

SupportedVersion is the only currently supported file version.

View Source
const WorkersAuto = -1

WorkersAuto enables automatic worker selection for BuildOptions.Workers.

Variables

View Source
var (
	// ErrInvalidMagic means the file signature is not "0DHT".
	ErrInvalidMagic = errors.New("invalid texheaders magic")
	// ErrUnsupportedVersion means version is not supported by decoder.
	ErrUnsupportedVersion = errors.New("unsupported texheaders version")
	// ErrInvalidASCIIZ means string payload is missing zero terminator.
	ErrInvalidASCIIZ = errors.New("invalid ASCIIZ payload")
	// ErrTooManyTextures means texture count does not fit uint32 file field.
	ErrTooManyTextures = errors.New("too many texture entries")
	// ErrUnsupportedInputFormat means source texture extension is not supported.
	ErrUnsupportedInputFormat = errors.New("unsupported input texture format")
	// ErrPACUnsupported means .pac source support is not implemented yet.
	ErrPACUnsupported = errors.New(".pac source is not supported")
	// ErrEmptyInputPath means builder input path is empty or whitespace.
	ErrEmptyInputPath = errors.New("empty input path")
	// ErrNilFile means Write received a nil file model.
	ErrNilFile = errors.New("file is nil")
	// ErrValidation means semantic model validation failed.
	ErrValidation = errors.New("texheaders validation failed")
)

Functions

func GuessSuffixTypeFromPath

func GuessSuffixTypeFromPath(path string) (value uint32, ok bool)

GuessSuffixTypeFromPath tries to infer pax suffix type from texture file path.

This is heuristic mapping based on known DayZ/Arma naming conventions. Unknown patterns fall back to diffuse_srgb (0) and return ok=false.

func ValidateEntry

func ValidateEntry(entry *TextureEntry, entryIndex int) error

ValidateEntry validates one texture entry invariants.

func ValidateFile

func ValidateFile(f *File) error

ValidateFile validates file-level and entry-level invariants.

func Write

func Write(w io.Writer, f *File) error

Write encodes texHeaders.bin into stream.

func WriteFile

func WriteFile(path string, f *File) error

WriteFile encodes texHeaders.bin into file path.

Types

type BuildIssue

type BuildIssue struct {
	// Path is the path of the skipped input.
	Path string `json:"path,omitempty" yaml:"path,omitempty"`
	// Error is the error message of the skipped input.
	Error string `json:"error,omitempty" yaml:"error,omitempty"`
}

BuildIssue reports one skipped input in lenient mode.

type BuildOptions

type BuildOptions struct {
	// SuffixOverrides maps normalized path to forced suffix type value.
	SuffixOverrides map[string]uint32 `json:"suffix_overrides,omitempty" yaml:"suffix_overrides,omitempty"`
	// BaseDir is used for relative paths stored in PAAFile.
	// If empty, absolute input paths are made relative to current working dir when possible.
	BaseDir string `json:"base_dir,omitempty" yaml:"base_dir,omitempty"`
	// SkipInvalid keeps building when one input fails.
	SkipInvalid bool `json:"skip_invalid,omitempty" yaml:"skip_invalid,omitempty"`
	// LowercasePaths stores entry paths in lowercase.
	LowercasePaths bool `json:"lowercase_paths,omitempty" yaml:"lowercase_paths,omitempty"`
	// BackslashPaths stores entry paths with backslash separators.
	BackslashPaths bool `json:"backslash_paths,omitempty" yaml:"backslash_paths,omitempty"`
	// Workers controls parallelism in Build.
	//  - Workers <= 1 disables parallel build (default, no worker overhead).
	//  - Workers == WorkersAuto selects workers automatically from host CPU count.
	//  - Workers > 1 enables parallel entry build with that worker count.
	Workers int `json:"workers,omitempty" yaml:"workers,omitempty"`
}

BuildOptions controls builder behavior.

type Builder

type Builder struct {
	// contains filtered or unexported fields
}

Builder builds texheaders file from source texture files.

func NewBuilder

func NewBuilder(opts BuildOptions) *Builder

NewBuilder creates a new builder with options.

func (*Builder) Append

func (b *Builder) Append(path string) error

Append registers one source texture path for build.

func (*Builder) AppendMany

func (b *Builder) AppendMany(paths ...string) error

AppendMany registers multiple source texture paths for build.

func (*Builder) Build

func (b *Builder) Build() (*File, error)

Build compiles appended source files into texheaders model.

func (*Builder) Inputs

func (b *Builder) Inputs() []string

Inputs returns a copy of currently appended paths.

func (*Builder) Issues

func (b *Builder) Issues() []BuildIssue

Issues returns skipped input issues collected during Build with SkipInvalid=true.

func (*Builder) Write

func (b *Builder) Write(w io.Writer) error

Write builds and writes texheaders model to stream.

func (*Builder) WriteFile

func (b *Builder) WriteFile(path string) error

WriteFile builds and writes texheaders model to file.

type File

type File struct {
	// Magic is expected to be "0DHT".
	Magic string `json:"magic,omitempty" yaml:"magic,omitempty"`
	// Textures holds all texture entries in file order.
	Textures []TextureEntry `json:"textures,omitempty" yaml:"textures,omitempty"`
	// Version is expected to be 1.
	Version uint32 `json:"version,omitempty" yaml:"version,omitempty"`
}

File represents texHeaders.bin content.

func Read

func Read(r io.Reader) (*File, error)

Read decodes texHeaders.bin from stream.

func ReadFile

func ReadFile(path string) (*File, error)

ReadFile decodes texHeaders.bin from file path.

type MipMap

type MipMap struct {
	Width  uint16 `json:"width,omitempty" yaml:"width,omitempty"`
	Height uint16 `json:"height,omitempty" yaml:"height,omitempty"`
	// AlwaysZero is expected to be 0 in known files.
	AlwaysZero uint16 `json:"always_zero,omitempty" yaml:"always_zero,omitempty"`
	// PaxFormat usually matches entry PaxFormat.
	PaxFormat uint8 `json:"pax_format,omitempty" yaml:"pax_format,omitempty"`
	// AlwaysThree is expected to be 3 in known files.
	AlwaysThree uint8 `json:"always_three,omitempty" yaml:"always_three,omitempty"`
	// DataOffset points to mip payload inside source pax.
	DataOffset uint32 `json:"data_offset,omitempty" yaml:"data_offset,omitempty"`
}

MipMap describes one mipmap descriptor.

type TextureEntry

type TextureEntry struct {
	// PAAFile is a path relative to texHeaders.bin location.
	PAAFile string `json:"paa_file,omitempty" yaml:"paa_file,omitempty"`
	// MipMaps contains mip descriptors.
	MipMaps []MipMap `json:"mipmaps,omitempty" yaml:"mipmaps,omitempty"`

	// ColorPaletteCount is usually 1.
	ColorPaletteCount uint32 `json:"color_palette_count,omitempty" yaml:"color_palette_count,omitempty"`
	// PalettePtr is usually 0.
	PalettePtr uint32 `json:"palette_ptr,omitempty" yaml:"palette_ptr,omitempty"`

	// AverageColorF stores average color as float32 tuple.
	AverageColorF [4]float32 `json:"average_color_f,omitempty" yaml:"average_color_f,omitempty"`
	// AverageColor stores average color as byte tuple.
	AverageColor [4]byte `json:"average_color,omitempty" yaml:"average_color,omitempty"`
	// MaxColor stores max color as byte tuple.
	MaxColor [4]byte `json:"max_color,omitempty" yaml:"max_color,omitempty"`

	// ClampFlags is usually 0.
	ClampFlags uint32 `json:"clamp_flags,omitempty" yaml:"clamp_flags,omitempty"`
	// TransparentColor is usually 0xFFFFFFFF.
	TransparentColor uint32 `json:"transparent_color,omitempty" yaml:"transparent_color,omitempty"`

	// HasMaxCtagg means MaxColor was set by source paa.
	HasMaxCtagg bool `json:"has_max_ctagg,omitempty" yaml:"has_max_ctagg,omitempty"`
	// IsAlpha means FLAGTAG = 1 basic transparency.
	IsAlpha bool `json:"is_alpha,omitempty" yaml:"is_alpha,omitempty"`
	// IsTransparent means FLAGTAG = 2 non-interpolated alpha.
	IsTransparent bool `json:"is_transparent,omitempty" yaml:"is_transparent,omitempty"`
	// IsAlphaNonOpaque means IsAlpha and average alpha < 0x80.
	IsAlphaNonOpaque bool `json:"is_alpha_non_opaque,omitempty" yaml:"is_alpha_non_opaque,omitempty"`

	// MipMapCount is usually equal to MipMapCountCopy.
	MipMapCount uint32 `json:"mipmap_count,omitempty" yaml:"mipmap_count,omitempty"`
	// PaxFormat describes texture storage format.
	PaxFormat uint32 `json:"pax_format,omitempty" yaml:"pax_format,omitempty"`
	// LittleEndian is expected to be true.
	LittleEndian bool `json:"little_endian,omitempty" yaml:"little_endian,omitempty"`
	// IsPAA tells whether source file is .paa.
	IsPAA bool `json:"is_paa,omitempty" yaml:"is_paa,omitempty"`
	// PaxSuffixType is texture suffix class identifier.
	PaxSuffixType uint32 `json:"pax_suffix_type,omitempty" yaml:"pax_suffix_type,omitempty"`

	// MipMapCountCopy is usually equal to MipMapCount.
	MipMapCountCopy uint32 `json:"mipmap_count_copy,omitempty" yaml:"mipmap_count_copy,omitempty"`
	// PaxFileSize stores source pax file size in bytes.
	PaxFileSize uint32 `json:"pax_file_size,omitempty" yaml:"pax_file_size,omitempty"`
}

TextureEntry describes one texture metadata entry.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL