tsf

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: 17 Imported by: 0

Documentation

Overview

Package tsf implements reading, writing, compiling and decompiling of Total Annihilation: Kingdoms truecolor animation files.

TA: Kingdoms stores animations in two related forms:

  • TAF: a compiled binary container. It reuses the Total Annihilation GAF layout (version 0x00010100, an entry-pointer table, per-frame info records and a frame list) but stores 16-bit truecolor pixels instead of 8-bit palette indices. Each frame carries a pixel-format flag selecting ARGB4444 or ARGB1555.

  • TSF: the human-readable text form of the same data. It is a brace delimited, INI-like document describing an animation as a tree of frames and layers, where each layer references an external image file. The game's GUI loader consumes TSF directly for menu backgrounds.

This package can parse and re-emit both forms byte-for-byte, decompile a binary TAF into a TSF document plus extracted layer images, and compile a TSF document plus its images back into a binary TAF.

Index

Constants

View Source
const Version uint32 = 0x00010100

Version is the format version stored in every TA: Kingdoms TAF header. It is identical to the Total Annihilation GAF version.

Variables

This section is empty.

Functions

func Decompile

func Decompile(t *TAF, baseName string) (*Document, []ImageFile, error)

Decompile converts a binary TAF into an equivalent TSF document plus one PNG per frame. The document records every detail needed to recompile the exact original bytes: per-frame pixel format, placement, duration and the preserved frame flag. Compiling the returned document with an ImageResolver backed by the returned images reproduces the original TAF byte-for-byte.

baseName is used to derive image filenames (baseName_<frame>.png). When empty, the TAF's sequence name is used, falling back to "frame".

func PixelsFromNRGBA

func PixelsFromNRGBA(img *image.NRGBA, format PixelFormat) ([]byte, error)

PixelsFromNRGBA encodes a non-premultiplied RGBA image into packed 16-bit pixels in the requested format. It is the exact inverse of ToNRGBA for any image that ToNRGBA produced.

Types

type Assignment

type Assignment struct {
	Key   string
	Value string
}

Assignment is a "Key = Value;" statement.

type DirResolver

type DirResolver string

DirResolver resolves filenames against a directory on disk. Lookups are case-insensitive to match the game's tolerant filename handling.

func (DirResolver) Resolve

func (d DirResolver) Resolve(filename string) (*image.NRGBA, error)

Resolve implements ImageResolver.

type Document

type Document struct {
	// Leading holds verbatim lines that appear before the first section
	// (typically a comment and a blank line).
	Leading []string
	// Sections holds the top-level sections in order.
	Sections []*Section
	// Trailing holds verbatim lines that appear after the last section.
	Trailing []string
	// LineEnding is the terminator used between lines ("\r\n" or "\n").
	LineEnding string
}

Document is a parsed TSF text file: an optional block of leading trivia (comments and blank lines), one or more top-level sections, and any trailing trivia. Re-serializing a parsed Document reproduces the original bytes.

func ParseTSF

func ParseTSF(text string) (*Document, error)

ParseTSF parses TSF text into a Document.

func (*Document) String

func (d *Document) String() string

String renders the document back to text. For a Document produced by ParseTSF the output is byte-identical to the input.

type Frame

type Frame struct {
	Width    uint16
	Height   uint16
	OriginX  int16
	OriginY  int16
	Format   PixelFormat
	Duration uint32 // playback duration in game ticks (1/30th second)

	// Pixels holds Width*Height little-endian 16-bit values in the frame's
	// PixelFormat.
	Pixels []byte
	// contains filtered or unexported fields
}

Frame is a single animation frame: a rectangle of 16-bit truecolor pixels plus placement and timing metadata.

func (*Frame) FlagByte

func (f *Frame) FlagByte() uint8

FlagByte returns the preserved frame-info byte at offset 0x0B (0x00 or 0xFF across the retail asset set). Its meaning is unconfirmed; it is exposed for inspection and lint tooling.

func (*Frame) ToNRGBA

func (f *Frame) ToNRGBA() (*image.NRGBA, error)

ToNRGBA decodes the frame's 16-bit pixels into a non-premultiplied RGBA image. Channels are expanded to 8 bits by bit replication, which makes the inverse (PixelsFromNRGBA) exactly reversible.

type ImageFile

type ImageFile struct {
	Name string
	Data []byte
}

ImageFile is a layer image produced when decompiling a TAF. Name is the filename referenced from the TSF document; Data is the encoded PNG.

type ImageResolver

type ImageResolver interface {
	Resolve(filename string) (*image.NRGBA, error)
}

ImageResolver loads a layer image referenced by a TSF Filename and returns it as a non-premultiplied RGBA image.

type LintDiagnostic

type LintDiagnostic struct {
	Level   LintLevel
	Frame   int
	Message string
}

LintDiagnostic is a single finding from Lint or LintDocument. Frame is the zero-based frame index, or -1 for a file-level finding.

func LintDocument

func LintDocument(doc *Document) []LintDiagnostic

LintDocument checks that a TSF document matches the animation shape the compiler expects: one animation section, each frame holding exactly one layer with a Filename. It does not load the referenced images.

type LintLevel

type LintLevel int

LintLevel classifies the seriousness of a lint finding.

const (
	// LintError marks a problem that makes the file unusable or unserializable.
	LintError LintLevel = iota
	// LintWarning marks a suspicious-but-tolerated condition.
	LintWarning
	// LintInfo records a noteworthy, harmless observation.
	LintInfo
)

func (LintLevel) String

func (l LintLevel) String() string

String returns the lowercase label for the level.

type MemoryResolver

type MemoryResolver map[string][]byte

MemoryResolver resolves filenames against an in-memory map of PNG bytes.

func NewMemoryResolver

func NewMemoryResolver(files []ImageFile) MemoryResolver

NewMemoryResolver builds a MemoryResolver from decompiled image files.

func (MemoryResolver) Resolve

func (m MemoryResolver) Resolve(filename string) (*image.NRGBA, error)

Resolve implements ImageResolver.

type Node

type Node interface {
	// contains filtered or unexported methods
}

Node is one element of a section body: either an *Assignment or a *Section.

type PixelFormat

type PixelFormat uint8

PixelFormat selects the 16-bit encoding used for a frame's pixels.

const (
	// FormatARGB4444 packs each pixel as 4 bits of alpha, red, green and blue.
	FormatARGB4444 PixelFormat = 4
	// FormatARGB1555 packs each pixel as 1 bit of alpha and 5 bits each of
	// red, green and blue.
	FormatARGB1555 PixelFormat = 5
)

func ParsePixelFormat

func ParsePixelFormat(s string) (PixelFormat, error)

ParsePixelFormat maps a case-insensitive format name ("ARGB4444"/"4444" or "ARGB1555"/"1555") to its PixelFormat. It is the public entry point used by import tooling.

func (PixelFormat) BytesPerPixel

func (p PixelFormat) BytesPerPixel() int

BytesPerPixel is always 2 for the truecolor TAF formats.

func (PixelFormat) String

func (p PixelFormat) String() string

String returns a stable textual name for the pixel format, used in TSF documents.

type Section

type Section struct {
	Name string
	Body []Node
}

Section is a named brace-delimited block. Its body is an ordered list of assignments and nested sections.

func (*Section) Get

func (s *Section) Get(key string) (string, bool)

Get returns the value of the first assignment with the given key and whether it was found. Section nodes are ignored.

func (*Section) Subsections

func (s *Section) Subsections() []*Section

Subsections returns the nested sections of s in order.

type TAF

type TAF struct {
	// Name is the sequence name as stored in the 32-byte name field.
	Name string
	// Frames holds the animation frames in playback order.
	Frames []*Frame
	// contains filtered or unexported fields
}

TAF is a parsed TA: Kingdoms animation file. Every retail TAF contains a single animation sequence, which this type models directly.

func Compile

func Compile(doc *Document, res ImageResolver) (*TAF, error)

Compile builds a binary TAF from a TSF document, loading each layer image through res. The document's first section is treated as the animation.

The per-frame pixel format is taken from a "Format" assignment in the frame section (defaulting to ARGB4444), the duration from "Delay", and the placement from the layer's "AnchorX"/"AnchorY". A "Flags" assignment, when present, restores the preserved frame-info byte so a decompiled animation can be recompiled byte-for-byte.

func FromGIF

func FromGIF(g *gif.GIF, format PixelFormat, name string) (*TAF, error)

FromGIF builds a TAF from a decoded animated GIF. Every GIF frame is flattened against the running canvas (honouring background/none disposal) so each TAF frame is a full-size truecolor image in the requested format. GIF delays (1/100s) are converted back to TA: Kingdoms ticks.

func FromSheet

func FromSheet(img image.Image, frameW, frameH, count int, format PixelFormat, name string, duration uint32) (*TAF, error)

FromSheet slices a sprite-sheet image into frames of frameW×frameH, walking left-to-right then top-to-bottom. When count is zero every full cell is taken; otherwise the first count cells are used. Each frame is given the same duration (in ticks).

func ParseTAF

func ParseTAF(data []byte) (*TAF, error)

ParseTAF parses a TAF file from a byte slice. The format is pointer-based, so the whole file must be available.

func ReadTAF

func ReadTAF(r io.Reader) (*TAF, error)

ReadTAF reads and parses a TAF from r.

func (*TAF) Bytes

func (t *TAF) Bytes() ([]byte, error)

Bytes serializes the TAF back into its binary form. For any TAF produced by ParseTAF the result is byte-identical to the original file.

func (*TAF) CanvasBounds

func (t *TAF) CanvasBounds() (image.Rectangle, error)

CanvasBounds returns the bounding box that contains every frame once each is positioned by its origin. The rectangle is expressed in origin space, so its Min may be negative; its width and height give the canvas size an animation renders into.

func (*TAF) FrameImage

func (t *TAF) FrameImage(i int) (*image.NRGBA, error)

FrameImage decodes frame i to a non-premultiplied RGBA image at its own dimensions (origin ignored).

func (*TAF) Lint

func (t *TAF) Lint() []LintDiagnostic

Lint inspects a parsed TAF for structural problems and curiosities. An empty result means the animation is clean and will serialize byte-cleanly.

func (*TAF) RenderSheet

func (t *TAF) RenderSheet(cols int, bg color.Color) (*image.NRGBA, error)

RenderSheet lays every frame out in a grid sprite sheet with cols columns. Each cell is sized to the largest frame; smaller frames are anchored top-left. When bg is nil the sheet background stays transparent.

func (*TAF) ToAPNG

func (t *TAF) ToAPNG(w io.Writer) error

ToAPNG renders the animation to an animated PNG, preserving the full RGBA channels (including partial alpha). A single-frame animation is written as a plain PNG.

func (*TAF) ToGIF

func (t *TAF) ToGIF() (*gif.GIF, error)

ToGIF renders the animation to an animated GIF. The truecolor frames are quantised to a 255-colour adaptive table plus a transparent slot, so alpha is reduced to a 1-bit cutout — adequate for previews; use ToAPNG to keep the full alpha channel.

Jump to

Keyboard shortcuts

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