gaf

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Jun 14, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package gaf implements reading and writing of Total Annihilation and TA: Kingdoms GAF (Graphics Animation Format) files.

The on-disk binary layout is identical between both games; only palette resolution differs. See variant.go for how callers signal which game an asset belongs to.

Index

Constants

View Source
const (
	// HeaderSize is the size of the GAF header in bytes
	HeaderSize = 8

	// EntryHeaderSize is the size of a GAF entry header
	EntryHeaderSize = 32

	// FrameDataHeaderSize is the size of frame data header
	FrameDataHeaderSize = 32
)
View Source
const VersionTA = 0x00010100

VersionTA is the standard GAF header version word.

Variables

This section is empty.

Functions

func WriteGAF

func WriteGAF(w io.Writer, sequences []*Sequence) error

WriteGAF writes a complete GAF file containing the given sequences. Frame pixel data must already be palette indices ([]byte, one byte per pixel).

Types

type Frame

type Frame struct {
	Width             uint16
	Height            uint16
	OriginX           int16
	OriginY           int16
	TransparencyIndex uint8
	Duration          uint32 // In game ticks (1/30th second)
	Pixels            []byte // Palette indices
}

Frame represents a single animation frame.

func (*Frame) EffectiveTransparencyIndex

func (f *Frame) EffectiveTransparencyIndex() uint8

EffectiveTransparencyIndex returns the palette index that should be treated as transparent when this frame is rendered.

Most TA assets store an honest TransparencyIndex in the frame header — the artist used that exact palette index for transparent pixels and the renderer simply makes palette[TI] transparent. TA: Kingdoms texture-atlas GAFs frequently carry a TransparencyIndex that doesn't match the actual pixel value the artist used as the transparent fill (e.g. metadata claims 9, the on-disk pixels are 5). In that case TA-style rendering shows the background as an opaque dark teal rather than transparent.

The heuristic:

  1. If TransparencyIndex appears anywhere in the pixel data, trust it. This is the common case — the decompressor's "transparent run" opcode fills with TI, and TA assets where TI is correctly authored also have TI-valued pixels in the data.

  2. Otherwise sample the four corners; if they all agree on a value, use that. This rescues TAK uncompressed frames where TI is bogus but the artist painted a uniform border (the canonical "background" pixels).

  3. Otherwise fall back to TransparencyIndex.

The on-disk TransparencyIndex value is never overwritten — round-trip writers still see the original byte.

func (*Frame) ToImage

func (f *Frame) ToImage(palette *Palette) *image.Paletted

ToImage converts a frame to an image.Image using the given palette and the auto-resolved transparency index.

func (*Frame) ToImageWith

func (f *Frame) ToImageWith(palette *Palette, opts RenderOptions) *image.Paletted

ToImageWith renders a frame with explicit transparency handling.

func (*Frame) ToPNG

func (f *Frame) ToPNG(palette *Palette, w io.Writer) error

ToPNG converts a single frame to PNG with auto transparency.

func (*Frame) ToPNGWith

func (f *Frame) ToPNGWith(palette *Palette, opts RenderOptions, w io.Writer) error

ToPNGWith converts a single frame to PNG with explicit transparency options.

type FrameInfo

type FrameInfo struct {
	Width             uint16 // Frame width
	Height            uint16 // Frame height
	OriginX           int16  // X origin offset
	OriginY           int16  // Y origin offset
	TransparencyIndex uint8  // Transparent color index
	Compressed        uint8  // 0=uncompressed, 1=compressed
	LayerCount        uint16 // Number of subframes (0 for simple frames)
	Unknown2          uint32 // Unknown
	PtrFrameData      uint32 // Pointer to pixel data
	Unknown3          uint32 // Unknown
}

FrameInfo describes frame properties (24 bytes).

type FrameListItem

type FrameListItem struct {
	PtrFrameInfo uint32 // Pointer to frame info
	Duration     uint32 // Duration in game ticks (1/30th second)
}

FrameListItem describes a frame entry (8 bytes).

type Header struct {
	Version       uint32 // Always 0x00010100
	SequenceCount uint32 // Number of animation sequences
	Unknown1      uint32 // Always 0
}

Header represents the GAF file header (12 bytes).

type Palette

type Palette struct {
	Colors [256]color.RGBA
}

Palette represents a TA color palette

func FallbackPalette

func FallbackPalette() *Palette

FallbackPalette returns a greyscale palette for when no real palette is available.

func LoadPalette

func LoadPalette(path string) (*Palette, error)

LoadPalette loads a TA .PAL palette file

func LoadPaletteFromBytes

func LoadPaletteFromBytes(data []byte) (*Palette, error)

LoadPaletteFromBytes loads a palette from a byte slice.

func ReadPalette

func ReadPalette(r io.Reader) (*Palette, error)

ReadPalette reads a palette from an io.Reader

func (*Palette) ColorModel

func (p *Palette) ColorModel() color.Palette

ColorModel returns a color.Palette for this palette

type Reader

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

Reader reads GAF files.

func LoadFromFile

func LoadFromFile(path string) (*Reader, error)

LoadFromFile opens and validates a GAF file at path.

func LoadFromReader

func LoadFromReader(rs io.ReadSeeker) (*Reader, error)

LoadFromReader creates a new Reader from an io.ReadSeeker and validates the GAF header.

func (*Reader) Close

func (r *Reader) Close() error

Close closes the reader if its underlying source is an io.Closer.

func (*Reader) Header

func (r *Reader) Header() *Header

Header returns the file header.

func (*Reader) ReadSequences

func (r *Reader) ReadSequences() ([]*Sequence, error)

ReadSequences reads all animation sequences from the file.

type RenderOptions

type RenderOptions struct {
	Mode  TransparencyMode
	Index uint8 // honored when Mode == TransparencyModeIndex
}

RenderOptions controls per-render transparency choices. A zero-valued RenderOptions resolves to TransparencyModeAuto.

type Sequence

type Sequence struct {
	Name   string
	Frames []*Frame
}

Sequence represents a complete animation sequence.

func (*Sequence) ToAPNG

func (s *Sequence) ToAPNG(palette *Palette, w io.Writer) error

ToAPNG converts a sequence to an animated PNG (APNG) using auto transparency.

func (*Sequence) ToAPNGWith

func (s *Sequence) ToAPNGWith(palette *Palette, opts RenderOptions, w io.Writer) error

ToAPNGWith converts a sequence to an animated PNG (APNG) with explicit transparency options.

func (*Sequence) ToGIF

func (s *Sequence) ToGIF(palette *Palette) (*gif.GIF, error)

ToGIF converts a sequence to an animated GIF using auto transparency.

func (*Sequence) ToGIFWith

func (s *Sequence) ToGIFWith(palette *Palette, opts RenderOptions) (*gif.GIF, error)

ToGIFWith converts a sequence to an animated GIF using explicit transparency options.

func (*Sequence) WriteGIF

func (s *Sequence) WriteGIF(w io.Writer, palette *Palette) error

WriteGIF writes an animated GIF to the given writer using auto transparency.

func (*Sequence) WriteGIFWith

func (s *Sequence) WriteGIFWith(w io.Writer, palette *Palette, opts RenderOptions) error

WriteGIFWith writes an animated GIF using explicit transparency options.

type SequenceHeader

type SequenceHeader struct {
	FrameCount uint16   // Number of frames
	Unknown1   uint16   // Unknown
	Unknown2   uint32   // Unknown
	Name       [32]byte // Sequence name (null-terminated)
}

SequenceHeader represents an animation sequence header (40 bytes).

type TransparencyMode

type TransparencyMode int

TransparencyMode selects how a frame's transparency index is resolved at render time. The zero value is TransparencyModeAuto, which preserves the historical behavior callers got from Frame.TransparencyIndex.

const (
	// TransparencyModeAuto uses EffectiveTransparencyIndex (corner-detect
	// heuristic for TAK uncompressed frames, metadata otherwise).
	TransparencyModeAuto TransparencyMode = iota
	// TransparencyModeMetadata forces use of Frame.TransparencyIndex
	// exactly as stored on disk, bypassing the heuristic.
	TransparencyModeMetadata
	// TransparencyModeNone disables transparency for the render — every
	// palette entry stays opaque.
	TransparencyModeNone
	// TransparencyModeIndex uses a caller-supplied palette index.
	TransparencyModeIndex
)

type Variant

type Variant int

Variant identifies which game's colouring rules apply to a GAF's indexed pixels.

The on-disk GAF binary format is identical between Total Annihilation and TA: Kingdoms: the same version word, the same sequence/frame layout, and the same row RLE encoding. The games differ only in how the palette indices are coloured:

  • Total Annihilation uses a single shared 256-colour palette (palettes/PALETTE.PAL).
  • TA: Kingdoms stores palettes externally. Interface GAFs pair with a sibling .pcx of the same base name; unit and feature GAFs use a side-specific palette (Aramon, Taros, Veruna, Zhon).

Because the bytes are identical, the variant cannot be detected from a GAF file alone — callers supply it from context (which game or directory the asset came from). This type exists to make that decision explicit at call sites rather than leaving it implicit in whichever palette happens to be passed to the renderer.

const (
	// VariantUnknown is the zero value: the caller has not stated which game
	// the asset belongs to. Rendering still works; it simply uses whatever
	// palette is supplied.
	VariantUnknown Variant = iota
	// VariantTA is Total Annihilation (shared palette).
	VariantTA
	// VariantTAK is TA: Kingdoms (external / side-specific palette).
	VariantTAK
)

func (Variant) DefaultRenderOptions

func (v Variant) DefaultRenderOptions() RenderOptions

DefaultRenderOptions returns the transparency policy that best matches a variant's authored assets.

TA: Kingdoms texture-atlas GAFs frequently carry a TransparencyIndex that does not match the pixel value the artist used for the transparent fill, so the corner-detect heuristic (TransparencyModeAuto) gives the most faithful result. Total Annihilation assets store an honest TransparencyIndex, which the same Auto mode also handles, so both currently resolve to Auto; keeping the choice behind this helper lets the policies diverge later without touching call sites.

func (Variant) String

func (v Variant) String() string

String returns a short human-readable name for the variant.

Jump to

Keyboard shortcuts

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