scene

package
v0.32.1 Latest Latest
Warning

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

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

Documentation

Overview

Package scene provides blend mode integration with internal/blend package.

Package scene provides a retained-mode scene graph encoding system for efficient GPU rendering.

The encoding system uses a dual-stream architecture inspired by vello:

  • A compact tags stream (1 byte per command)
  • Separate data streams for paths, draws, and transforms

This design is cache-friendly and GPU-ready, minimizing memory bandwidth and enabling efficient batched rendering.

Index

Constants

View Source
const (
	// DefaultMaxSizeMB is the default maximum cache size in megabytes.
	DefaultMaxSizeMB = 64
)

Default cache configuration constants.

Variables

View Source
var DefaultPool = NewEncodingPool()

DefaultPool is a global encoding pool for convenience. For performance-critical code, consider creating dedicated pools.

Functions

func PutEncoding

func PutEncoding(enc *Encoding)

PutEncoding returns an encoding to the default pool.

func TextAdvance added in v0.11.0

func TextAdvance(glyphs []*RenderedGlyph) float32

TextAdvance returns the total advance width of rendered glyphs.

Types

type Affine

type Affine struct {
	A, B, C float32
	D, E, F float32
}

Affine represents a 2D affine transformation matrix. The matrix is stored in row-major order as:

| A  B  C |
| D  E  F |

Where a point (x, y) is transformed to:

x' = A*x + B*y + C
y' = D*x + E*y + F

func AffineFromMatrix

func AffineFromMatrix(m gg.Matrix) Affine

AffineFromMatrix converts a gg.Matrix to an Affine.

func IdentityAffine

func IdentityAffine() Affine

IdentityAffine returns the identity transformation.

func RotateAffine

func RotateAffine(angle float32) Affine

RotateAffine creates a rotation transformation (angle in radians).

func ScaleAffine

func ScaleAffine(x, y float32) Affine

ScaleAffine creates a scaling transformation.

func TranslateAffine

func TranslateAffine(x, y float32) Affine

TranslateAffine creates a translation transformation.

func (Affine) IsIdentity

func (a Affine) IsIdentity() bool

IsIdentity returns true if this is the identity transformation.

func (Affine) Multiply

func (a Affine) Multiply(b Affine) Affine

Multiply returns the product of two affine transformations.

func (Affine) TransformPoint

func (a Affine) TransformPoint(x, y float32) (float32, float32)

TransformPoint transforms a point by the affine matrix.

type ArcShape

type ArcShape struct {
	CX, CY         float32 // Center
	RX, RY         float32 // Radii
	StartAngle     float32 // Start angle in radians
	EndAngle       float32 // End angle in radians
	SweepClockwise bool    // Direction
}

ArcShape represents an arc (portion of an ellipse outline).

func NewArcShape

func NewArcShape(cx, cy, rx, ry, startAngle, endAngle float32, sweepClockwise bool) *ArcShape

NewArcShape creates a new arc shape.

func (*ArcShape) Bounds

func (a *ArcShape) Bounds() Rect

Bounds returns a conservative bounding rectangle.

func (*ArcShape) ToPath

func (a *ArcShape) ToPath() *Path

ToPath converts the arc to a Path.

type BlendMode

type BlendMode uint32

BlendMode represents a compositing blend mode.

const (
	BlendNormal BlendMode = iota
	BlendMultiply
	BlendScreen
	BlendOverlay
	BlendDarken
	BlendLighten
	BlendColorDodge
	BlendColorBurn
	BlendHardLight
	BlendSoftLight
	BlendDifference
	BlendExclusion
	BlendHue
	BlendSaturation
	BlendColor
	BlendLuminosity
	// Porter-Duff modes
	BlendClear
	BlendCopy
	BlendDestination
	BlendSourceOver
	BlendDestinationOver
	BlendSourceIn
	BlendDestinationIn
	BlendSourceOut
	BlendDestinationOut
	BlendSourceAtop
	BlendDestinationAtop
	BlendXor
	BlendPlus
)

Blend mode constants following Porter-Duff and advanced blend modes.

func AdvancedModes

func AdvancedModes() []BlendMode

AdvancedModes returns a slice of advanced separable blend modes.

func AllBlendModes

func AllBlendModes() []BlendMode

AllBlendModes returns a slice of all supported blend modes. This is useful for testing and iteration.

func BlendModeFromInternal

func BlendModeFromInternal(internal blend.BlendMode) BlendMode

BlendModeFromInternal converts an internal blend.BlendMode to scene.BlendMode. This is the reverse mapping for cases where you need to convert from internal representation back to the scene graph representation.

func HSLModes

func HSLModes() []BlendMode

HSLModes returns a slice of HSL-based non-separable blend modes.

func PorterDuffModes

func PorterDuffModes() []BlendMode

PorterDuffModes returns a slice of Porter-Duff compositing modes.

func (BlendMode) GetBlendFunc

func (mode BlendMode) GetBlendFunc() blend.BlendFunc

GetBlendFunc returns the internal blend function for this mode. This is a convenience method that combines ToInternalBlendMode with blend.GetBlendFunc.

Usage:

blendFn := scene.BlendMultiply.GetBlendFunc()
r, g, b, a := blendFn(sr, sg, sb, sa, dr, dg, db, da)

func (BlendMode) IsAdvanced

func (mode BlendMode) IsAdvanced() bool

IsAdvanced returns true if this is an advanced separable blend mode.

func (BlendMode) IsHSL

func (mode BlendMode) IsHSL() bool

IsHSL returns true if this is an HSL-based non-separable blend mode.

func (BlendMode) IsPorterDuff

func (mode BlendMode) IsPorterDuff() bool

IsPorterDuff returns true if this is a Porter-Duff compositing mode.

func (BlendMode) String

func (mode BlendMode) String() string

String returns a human-readable name for the blend mode.

func (BlendMode) ToInternalBlendMode

func (mode BlendMode) ToInternalBlendMode() blend.BlendMode

ToInternalBlendMode converts scene.BlendMode to internal blend.BlendMode. This provides the mapping between the scene graph blend modes and the low-level pixel blending implementation.

The internal blend.BlendMode uses a different enumeration order, so this function provides the translation.

type Brush

type Brush struct {
	Kind  BrushKind
	Color gg.RGBA // For solid brushes

}

Brush represents a paint source for fill/stroke operations.

func SolidBrush

func SolidBrush(c gg.RGBA) Brush

SolidBrush creates a solid color brush.

type BrushKind

type BrushKind uint32

BrushKind identifies the type of brush.

const (
	BrushSolid BrushKind = iota
	BrushLinearGradient
	BrushRadialGradient
	BrushImage
)

type CacheEntry

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

CacheEntry represents a single cached pixmap with metadata.

type CacheStats

type CacheStats struct {
	// Size is the current memory usage in bytes.
	Size int64
	// MaxSize is the memory budget in bytes.
	MaxSize int64
	// Entries is the number of cached entries.
	Entries int
	// Hits is the number of cache hits.
	Hits uint64
	// Misses is the number of cache misses.
	Misses uint64
	// HitRate is the cache hit rate (0.0 to 1.0).
	HitRate float64
	// Evictions is the number of entries evicted.
	Evictions uint64
}

CacheStats contains cache statistics for monitoring.

type CircleShape

type CircleShape struct {
	CX, CY float32 // Center
	R      float32 // Radius
}

CircleShape represents a circle.

func NewCircleShape

func NewCircleShape(cx, cy, r float32) *CircleShape

NewCircleShape creates a new circle shape.

func (*CircleShape) Bounds

func (c *CircleShape) Bounds() Rect

Bounds returns the bounding rectangle.

func (*CircleShape) Contains

func (c *CircleShape) Contains(px, py float32) bool

Contains returns true if the point (px, py) is inside the circle.

func (*CircleShape) ToPath

func (c *CircleShape) ToPath() *Path

ToPath converts the circle to a Path.

type ClipStack

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

ClipStack manages a stack of clip regions.

func NewClipStack

func NewClipStack() *ClipStack

NewClipStack creates a new empty clip stack.

func (*ClipStack) CombinedBounds

func (s *ClipStack) CombinedBounds() Rect

CombinedBounds returns the intersection of all clip bounds. Returns an empty rect if any clip is empty.

func (*ClipStack) Contains

func (s *ClipStack) Contains(x, y float32) bool

Contains returns true if the point is inside all clip regions.

func (*ClipStack) Depth

func (s *ClipStack) Depth() int

Depth returns the current stack depth.

func (*ClipStack) Intersects

func (s *ClipStack) Intersects(r Rect) bool

Intersects returns true if the rectangle intersects all clip regions.

func (*ClipStack) IsEmpty

func (s *ClipStack) IsEmpty() bool

IsEmpty returns true if there are no clips on the stack.

func (*ClipStack) Pop

func (s *ClipStack) Pop() *ClipState

Pop removes and returns the top clip region.

func (*ClipStack) Push

func (s *ClipStack) Push(clip *ClipState)

Push adds a clip region to the stack.

func (*ClipStack) Reset

func (s *ClipStack) Reset()

Reset clears the clip stack.

func (*ClipStack) Top

func (s *ClipStack) Top() *ClipState

Top returns the current clip region without removing it.

type ClipState

type ClipState struct {
	// Shape is the clip shape
	Shape Shape

	// Bounds is the clip bounds (for quick rejection)
	Bounds Rect

	// Transform is the transform that was active when clip was pushed
	Transform Affine
}

ClipState represents a clip region on the clip stack.

func NewClipState

func NewClipState(shape Shape, transform Affine) *ClipState

NewClipState creates a new clip state.

func (*ClipState) Contains

func (cs *ClipState) Contains(x, y float32) bool

Contains returns true if the point is inside the clip region. This is a conservative test using the bounding box.

func (*ClipState) Intersects

func (cs *ClipState) Intersects(r Rect) bool

Intersects returns true if the rectangle intersects the clip region. This is a conservative test using bounding boxes.

type CompositeShape

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

CompositeShape combines multiple shapes into one.

func NewCompositeShape

func NewCompositeShape(shapes ...Shape) *CompositeShape

NewCompositeShape creates a new composite shape.

func (*CompositeShape) AddShape

func (cs *CompositeShape) AddShape(shape Shape)

AddShape adds a shape to the composite.

func (*CompositeShape) Bounds

func (cs *CompositeShape) Bounds() Rect

Bounds returns the union of all shape bounds.

func (*CompositeShape) ShapeCount

func (cs *CompositeShape) ShapeCount() int

ShapeCount returns the number of shapes in the composite.

func (*CompositeShape) ToPath

func (cs *CompositeShape) ToPath() *Path

ToPath converts all shapes to a single Path.

type Decoder

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

Decoder provides sequential decoding of an Encoding's command stream. It tracks position indices across all data streams (tags, paths, draws, transforms) and provides methods to read each command type's associated data.

The decoder is designed for efficient rendering playback, supporting both full traversal and selective decoding for tile-based rendering.

Example usage:

dec := NewDecoder(encoding)
for dec.Next() {
    switch dec.Tag() {
    case TagMoveTo:
        x, y := dec.MoveTo()
        // handle move
    case TagLineTo:
        x, y := dec.LineTo()
        // handle line
    case TagFill:
        brush, style := dec.Fill()
        // handle fill
    }
}

func NewDecoder

func NewDecoder(enc *Encoding) *Decoder

NewDecoder creates a new decoder for the given encoding. Returns nil if encoding is nil.

func (*Decoder) Brush

func (d *Decoder) Brush() (r, g, b, a float32)

Brush reads the current Brush command data. Returns the RGBA color values. Only valid when Tag() == TagBrush.

func (*Decoder) CollectPath

func (d *Decoder) CollectPath() *Path

CollectPath collects all path commands until EndPath into a new Path. Returns the collected path. The decoder is advanced past the path data. Returns nil if not currently at the start of a path.

func (*Decoder) CubicTo

func (d *Decoder) CubicTo() (c1x, c1y, c2x, c2y, x, y float32)

CubicTo reads the current CubicTo command data. Returns control point 1 (c1x, c1y), control point 2 (c2x, c2y), and destination (x, y). Only valid when Tag() == TagCubicTo.

func (*Decoder) Encoding

func (d *Decoder) Encoding() *Encoding

Encoding returns the encoding being decoded.

func (*Decoder) Fill

func (d *Decoder) Fill() (brush Brush, style FillStyle)

Fill reads the current Fill command data. Returns the brush and fill style. Only valid when Tag() == TagFill.

func (*Decoder) HasMore

func (d *Decoder) HasMore() bool

HasMore returns true if there are more commands to decode.

func (*Decoder) Image

func (d *Decoder) Image() (imageIndex uint32, transform Affine)

Image reads the current Image command data. Returns the image index and transform. Only valid when Tag() == TagImage.

func (*Decoder) LineTo

func (d *Decoder) LineTo() (x, y float32)

LineTo reads the current LineTo command data. Returns the destination point (x, y). Only valid when Tag() == TagLineTo.

func (*Decoder) MoveTo

func (d *Decoder) MoveTo() (x, y float32)

MoveTo reads the current MoveTo command data. Returns the destination point (x, y). Only valid when Tag() == TagMoveTo.

func (*Decoder) Next

func (d *Decoder) Next() bool

Next advances to the next command in the stream. Returns true if there is another command, false when iteration is complete. After calling Next, use Tag() to get the current command type, then call the appropriate method (MoveTo, LineTo, Fill, etc.) to get the data.

func (*Decoder) Peek

func (d *Decoder) Peek() Tag

Peek returns the next tag without advancing the decoder. Returns 0 if at end of stream.

func (*Decoder) Position

func (d *Decoder) Position() int

Position returns the current position in the tag stream.

func (*Decoder) PushLayer

func (d *Decoder) PushLayer() (blend BlendMode, alpha float32)

PushLayer reads the current PushLayer command data. Returns the blend mode and alpha value. Only valid when Tag() == TagPushLayer.

func (*Decoder) QuadTo

func (d *Decoder) QuadTo() (cx, cy, x, y float32)

QuadTo reads the current QuadTo command data. Returns the control point (cx, cy) and destination point (x, y). Only valid when Tag() == TagQuadTo.

func (*Decoder) Reset

func (d *Decoder) Reset(enc *Encoding)

Reset resets the decoder to the beginning of the encoding. This allows reusing the decoder for multiple passes.

func (*Decoder) SkipPath

func (d *Decoder) SkipPath()

SkipPath advances past all path commands until EndPath is found. This is useful for quickly skipping paths that are outside the clip region.

func (*Decoder) Stroke

func (d *Decoder) Stroke() (brush Brush, style *StrokeStyle)

Stroke reads the current Stroke command data. Returns the brush and stroke style. Only valid when Tag() == TagStroke.

func (*Decoder) Tag

func (d *Decoder) Tag() Tag

Tag returns the current command tag. Call this after Next() returns true to determine which data method to call.

func (*Decoder) Transform

func (d *Decoder) Transform() Affine

Transform reads the current Transform command data. Returns the affine transformation matrix. Only valid when Tag() == TagTransform.

type EllipseShape

type EllipseShape struct {
	CX, CY float32 // Center
	RX, RY float32 // Radii
}

EllipseShape represents an axis-aligned ellipse.

func NewEllipseShape

func NewEllipseShape(cx, cy, rx, ry float32) *EllipseShape

NewEllipseShape creates a new ellipse shape.

func (*EllipseShape) Bounds

func (e *EllipseShape) Bounds() Rect

Bounds returns the bounding rectangle.

func (*EllipseShape) Contains

func (e *EllipseShape) Contains(px, py float32) bool

Contains returns true if the point (px, py) is inside the ellipse.

func (*EllipseShape) ToPath

func (e *EllipseShape) ToPath() *Path

ToPath converts the ellipse to a Path.

type Encoding

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

Encoding holds the dual-stream encoded representation of drawing commands. It uses separate streams for tags (1 byte each), path data, draw data, and transforms to maximize cache efficiency and GPU compatibility.

func GetEncoding

func GetEncoding() *Encoding

GetEncoding retrieves an encoding from the default pool.

func NewEncoding

func NewEncoding() *Encoding

NewEncoding creates a new empty encoding.

func (*Encoding) Append

func (e *Encoding) Append(other *Encoding)

Append merges another encoding into this one. The other encoding's content is appended after the current content.

func (*Encoding) Bounds

func (e *Encoding) Bounds() Rect

Bounds returns the cumulative bounding box of all encoded content.

func (*Encoding) Brushes

func (e *Encoding) Brushes() []Brush

Brushes returns the brush definitions.

func (*Encoding) Capacity

func (e *Encoding) Capacity() int

Capacity returns the total allocated capacity in bytes.

func (*Encoding) Clone

func (e *Encoding) Clone() *Encoding

Clone creates a deep copy of the encoding.

func (*Encoding) DrawData

func (e *Encoding) DrawData() []uint32

DrawData returns the draw data stream.

func (*Encoding) EncodeBeginClip

func (e *Encoding) EncodeBeginClip()

EncodeBeginClip begins a clipping region.

func (*Encoding) EncodeBrush

func (e *Encoding) EncodeBrush(brush Brush) int

EncodeBrush encodes a brush definition.

func (*Encoding) EncodeEndClip

func (e *Encoding) EncodeEndClip()

EncodeEndClip ends the current clipping region.

func (*Encoding) EncodeFill

func (e *Encoding) EncodeFill(brush Brush, style FillStyle)

EncodeFill adds a fill command with the given brush and fill style.

func (*Encoding) EncodeImage

func (e *Encoding) EncodeImage(imageIndex uint32, transform Affine)

EncodeImage encodes an image reference.

func (*Encoding) EncodePath

func (e *Encoding) EncodePath(p *gg.Path)

EncodePath encodes a complete path from a gg.Path.

func (*Encoding) EncodePopLayer

func (e *Encoding) EncodePopLayer()

EncodePopLayer pops the current compositing layer.

func (*Encoding) EncodePushLayer

func (e *Encoding) EncodePushLayer(blend BlendMode, alpha float32)

EncodePushLayer pushes a new compositing layer.

func (*Encoding) EncodeStroke

func (e *Encoding) EncodeStroke(brush Brush, style *StrokeStyle)

EncodeStroke adds a stroke command with the given brush and stroke style.

func (*Encoding) EncodeTransform

func (e *Encoding) EncodeTransform(t Affine)

EncodeTransform adds a transform command.

func (*Encoding) EncodeTransformFromMatrix

func (e *Encoding) EncodeTransformFromMatrix(m gg.Matrix)

EncodeTransformFromMatrix adds a transform from a gg.Matrix.

func (*Encoding) Hash

func (e *Encoding) Hash() uint64

Hash computes a 64-bit FNV-1a hash of the encoding for cache keys. The hash includes all stream data to ensure uniqueness.

func (*Encoding) IsEmpty

func (e *Encoding) IsEmpty() bool

IsEmpty returns true if the encoding contains no commands.

func (*Encoding) NewIterator

func (e *Encoding) NewIterator() *Iterator

NewIterator creates an iterator for the encoding.

func (*Encoding) PathCount

func (e *Encoding) PathCount() int

PathCount returns the number of paths encoded.

func (*Encoding) PathData

func (e *Encoding) PathData() []float32

PathData returns the path data stream.

func (*Encoding) Reset

func (e *Encoding) Reset()

Reset clears the encoding for reuse without deallocating memory. This is the key method for zero-allocation pooling.

func (*Encoding) ShapeCount

func (e *Encoding) ShapeCount() int

ShapeCount returns the number of shapes (fills + strokes) encoded.

func (*Encoding) Size

func (e *Encoding) Size() int

Size returns the approximate memory size in bytes.

func (*Encoding) Tags

func (e *Encoding) Tags() []Tag

Tags returns the tag stream (read-only access for iteration).

func (*Encoding) Transforms

func (e *Encoding) Transforms() []Affine

Transforms returns the transform stream.

func (*Encoding) UpdateBounds added in v0.29.0

func (e *Encoding) UpdateBounds(bounds Rect)

UpdateBounds expands the encoding's bounding box to include the given rect. This is used to propagate transformed bounds from Scene to Encoding, ensuring that the tile-based renderer's early-out intersection test uses correct post-transform coordinates.

type EncodingPool

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

EncodingPool manages a pool of reusable Encoding objects. After warmup, allocations are minimized by reusing encodings.

Usage:

pool := NewEncodingPool()
enc := pool.Get()
defer pool.Put(enc)
// use enc...

func NewEncodingPool

func NewEncodingPool() *EncodingPool

NewEncodingPool creates a new encoding pool.

func (*EncodingPool) Get

func (p *EncodingPool) Get() *Encoding

Get retrieves an encoding from the pool. The encoding is reset and ready for use.

func (*EncodingPool) Put

func (p *EncodingPool) Put(enc *Encoding)

Put returns an encoding to the pool for reuse. The encoding will be reset on the next Get.

func (*EncodingPool) Warmup

func (p *EncodingPool) Warmup(count int)

Warmup pre-allocates encodings to avoid allocation during critical paths. Call this during initialization if allocation-free operation is required.

type FillStyle

type FillStyle uint32

FillStyle represents the fill rule for paths.

const (
	// FillNonZero uses the non-zero winding rule.
	FillNonZero FillStyle = 0
	// FillEvenOdd uses the even-odd rule.
	FillEvenOdd FillStyle = 1
)

type Filter

type Filter interface {
	// Apply processes src pixmap and writes result to dst.
	// bounds specifies the affected region in pixel coordinates.
	// The filter may read pixels outside bounds but only writes within bounds.
	Apply(src, dst *gg.Pixmap, bounds Rect)

	// ExpandBounds returns the expanded bounds after filter application.
	// This is used for buffer allocation:
	// - Blur expands by radius in all directions
	// - Shadow expands by offset + blur radius
	// - Color matrix does not expand
	ExpandBounds(input Rect) Rect
}

Filter applies visual effects to rendered layers. Filters are applied during layer pop when LayerFiltered is used.

The filter interface supports both in-place and copy operations: - If src == dst, the filter operates in-place when possible - Some filters (like blur) may require temporary buffers internally

Bounds handling: - Input bounds specify the region to process - ExpandBounds returns how much the output grows (e.g., blur radius)

type FilterChain

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

FilterChain represents multiple filters applied in sequence. Filters are applied in order from first to last.

func NewFilterChain

func NewFilterChain(filters ...Filter) *FilterChain

NewFilterChain creates a new filter chain from the given filters.

func (*FilterChain) Add

func (fc *FilterChain) Add(f Filter)

Add appends a filter to the chain.

func (*FilterChain) Apply

func (fc *FilterChain) Apply(src, dst *gg.Pixmap, bounds Rect)

Apply processes src through all filters in sequence. For chains with more than one filter, temporary buffers are used.

func (*FilterChain) ExpandBounds

func (fc *FilterChain) ExpandBounds(input Rect) Rect

ExpandBounds returns the combined expansion of all filters.

func (*FilterChain) IsEmpty

func (fc *FilterChain) IsEmpty() bool

IsEmpty returns true if the chain has no filters.

func (*FilterChain) Len

func (fc *FilterChain) Len() int

Len returns the number of filters in the chain.

type FilterType

type FilterType uint8

FilterType identifies the type of filter for serialization and debugging.

const (
	// FilterNone represents no filter (identity).
	FilterNone FilterType = iota

	// FilterBlur represents Gaussian blur filter.
	FilterBlur

	// FilterDropShadow represents drop shadow filter.
	FilterDropShadow

	// FilterColorMatrix represents color matrix transformation.
	FilterColorMatrix
)

Filter type constants.

func (FilterType) ExpandsOutput

func (ft FilterType) ExpandsOutput() bool

ExpandsOutput returns true if this filter type typically expands output bounds.

func (FilterType) String

func (ft FilterType) String() string

String returns a human-readable name for the filter type.

type Image

type Image struct {
	// Width is the image width in pixels
	Width int

	// Height is the image height in pixels
	Height int

	// Data holds the pixel data (RGBA format)
	// This will be populated during integration phase
	Data []byte
}

Image represents an image resource for drawing. This is a placeholder that will be expanded during integration.

func NewImage

func NewImage(width, height int) *Image

NewImage creates a new image with the given dimensions.

func (*Image) Bounds

func (img *Image) Bounds() Rect

Bounds returns the image bounds as a Rect.

func (*Image) IsEmpty

func (img *Image) IsEmpty() bool

IsEmpty returns true if the image has no dimensions.

type Iterator

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

Iterator provides sequential access to encoded commands.

func (*Iterator) GetBrush

func (it *Iterator) GetBrush(idx uint32) (Brush, bool)

GetBrush returns the brush at the given index.

func (*Iterator) Next

func (it *Iterator) Next() (Tag, bool)

Next advances to the next command and returns its tag. Returns false when iteration is complete.

func (*Iterator) ReadDrawData

func (it *Iterator) ReadDrawData(n int) []uint32

ReadDrawData reads n uint32 values from the draw data stream.

func (*Iterator) ReadPathData

func (it *Iterator) ReadPathData(n int) []float32

ReadPathData reads n float32 values from the path data stream.

func (*Iterator) ReadTransform

func (it *Iterator) ReadTransform() (Affine, bool)

ReadTransform reads the next transform from the stream.

func (*Iterator) Reset

func (it *Iterator) Reset()

Reset resets the iterator to the beginning.

type LayerCache

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

LayerCache provides an LRU cache for rendered layer pixmaps. It is thread-safe and uses atomic counters for statistics.

The cache evicts least recently used entries when the memory limit is exceeded. Cache entries are keyed by a 64-bit hash computed from the encoding content.

func DefaultLayerCache

func DefaultLayerCache() *LayerCache

DefaultLayerCache creates a new layer cache with the default 64MB limit.

func NewLayerCache

func NewLayerCache(maxSizeMB int) *LayerCache

NewLayerCache creates a new layer cache with the specified maximum size. The maxSizeMB parameter sets the memory budget in megabytes.

func (*LayerCache) Contains

func (c *LayerCache) Contains(hash uint64) bool

Contains checks if an entry with the given hash exists in the cache. This does not update the LRU order.

func (*LayerCache) EntryCount

func (c *LayerCache) EntryCount() int

EntryCount returns the number of entries in the cache.

func (*LayerCache) Get

func (c *LayerCache) Get(hash uint64) (*gg.Pixmap, bool)

Get retrieves a cached pixmap by its hash. Returns the pixmap and true if found, nil and false otherwise. On cache hit, the entry is moved to the front of the LRU list.

func (*LayerCache) GetVersion

func (c *LayerCache) GetVersion(hash uint64) (uint64, bool)

GetVersion returns the version of a cached entry if it exists. Returns 0 and false if the entry is not found.

func (*LayerCache) Invalidate

func (c *LayerCache) Invalidate(hash uint64)

Invalidate removes a specific entry from the cache by hash.

func (*LayerCache) InvalidateAll

func (c *LayerCache) InvalidateAll()

InvalidateAll clears the entire cache.

func (*LayerCache) MaxSize

func (c *LayerCache) MaxSize() int64

MaxSize returns the memory budget in bytes.

func (*LayerCache) Put

func (c *LayerCache) Put(hash uint64, pixmap *gg.Pixmap, version uint64)

Put stores a pixmap in the cache with the given hash and version. If the cache exceeds its memory budget, least recently used entries are evicted. If an entry with the same hash exists, it is replaced.

func (*LayerCache) ResetStats

func (c *LayerCache) ResetStats()

ResetStats resets the hit, miss, and eviction counters to zero.

func (*LayerCache) SetMaxSize

func (c *LayerCache) SetMaxSize(mb int)

SetMaxSize updates the memory budget. If the new budget is smaller than current usage, entries are evicted. The mb parameter is the new budget in megabytes.

func (*LayerCache) Size

func (c *LayerCache) Size() int64

Size returns the current memory usage in bytes.

func (*LayerCache) Stats

func (c *LayerCache) Stats() CacheStats

Stats returns current cache statistics. This operation is lock-free for the atomic counters.

func (*LayerCache) Trim

func (c *LayerCache) Trim(targetSize int64)

Trim evicts entries until the cache size is at or below the target size. The targetSize parameter is in bytes.

type LayerKind

type LayerKind uint8

LayerKind identifies the type of compositing layer.

const (
	// LayerRegular is a normal blend layer with alpha and blend mode.
	LayerRegular LayerKind = iota

	// LayerFiltered is a layer that will have filter effects applied.
	// This layer's contents are rendered to an offscreen buffer for processing.
	LayerFiltered

	// LayerClip is a clip-only layer that masks subsequent content.
	// No rendering is done to this layer; it only defines a clip region.
	LayerClip
)

Layer kind constants.

func (LayerKind) IsClipOnly

func (k LayerKind) IsClipOnly() bool

IsClipOnly returns true if this layer is only for clipping (no rendering).

func (LayerKind) NeedsOffscreen

func (k LayerKind) NeedsOffscreen() bool

NeedsOffscreen returns true if this layer kind requires an offscreen buffer.

func (LayerKind) String

func (k LayerKind) String() string

String returns a human-readable name for the layer kind.

type LayerStack

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

LayerStack manages a stack of active layers. The stack always has at least one layer (the root layer).

func NewLayerStack

func NewLayerStack() *LayerStack

NewLayerStack creates a new layer stack with a root layer.

func (*LayerStack) AcquireLayer

func (s *LayerStack) AcquireLayer() *LayerState

AcquireLayer gets a layer from the pool.

func (*LayerStack) All

func (s *LayerStack) All() []*LayerState

All returns all layers in the stack (bottom to top).

func (*LayerStack) Depth

func (s *LayerStack) Depth() int

Depth returns the current stack depth (1 = only root).

func (*LayerStack) IsRoot

func (s *LayerStack) IsRoot() bool

IsRoot returns true if only the root layer is on the stack.

func (*LayerStack) Pop

func (s *LayerStack) Pop() *LayerState

Pop removes and returns the top layer. Returns nil if only the root layer remains.

func (*LayerStack) Push

func (s *LayerStack) Push(layer *LayerState)

Push adds a new layer to the stack.

func (*LayerStack) ReleaseLayer

func (s *LayerStack) ReleaseLayer(layer *LayerState)

ReleaseLayer returns a layer to the pool.

func (*LayerStack) Reset

func (s *LayerStack) Reset()

Reset clears the stack, returning to just the root layer.

func (*LayerStack) Root

func (s *LayerStack) Root() *LayerState

Root returns the root (bottom) layer.

func (*LayerStack) Top

func (s *LayerStack) Top() *LayerState

Top returns the current (topmost) layer without removing it.

type LayerState

type LayerState struct {
	// Kind identifies the type of layer
	Kind LayerKind

	// BlendMode specifies how this layer composites with layers below
	BlendMode BlendMode

	// Alpha is the layer opacity (0.0 to 1.0)
	Alpha float32

	// Clip is the optional clip shape for this layer.
	// If nil, the layer has no clip (infinite bounds).
	Clip Shape

	// Encoding holds the layer's drawing commands.
	// This is populated as drawing commands are added to the scene
	// while this layer is active.
	Encoding *Encoding

	// Bounds tracks the cumulative bounding box of layer content.
	// This is updated as content is added.
	Bounds Rect

	// Transform is the transform active when the layer was pushed.
	// Used to restore transform state on pop.
	Transform Affine

	// ClipStackDepth records the clip stack depth when layer was pushed.
	// Used to restore clip state on pop.
	ClipStackDepth int
}

LayerState represents the state of an active compositing layer. Each layer has its own encoding for isolated rendering.

func NewClipLayer

func NewClipLayer(clip Shape) *LayerState

NewClipLayer creates a new clip-only layer.

func NewFilteredLayer

func NewFilteredLayer(blend BlendMode, alpha float32) *LayerState

NewFilteredLayer creates a new layer for filter effects.

func NewLayerState

func NewLayerState(kind LayerKind, blend BlendMode, alpha float32) *LayerState

NewLayerState creates a new layer state with default values.

func (*LayerState) HasClip

func (ls *LayerState) HasClip() bool

HasClip returns true if the layer has a clip shape.

func (*LayerState) IsEmpty

func (ls *LayerState) IsEmpty() bool

IsEmpty returns true if the layer has no content.

func (*LayerState) Reset

func (ls *LayerState) Reset()

Reset clears the layer state for reuse.

func (*LayerState) UpdateBounds

func (ls *LayerState) UpdateBounds(r Rect)

UpdateBounds expands the layer bounds to include the given rectangle.

type LineCap

type LineCap uint32

LineCap represents line endpoint shapes.

const (
	LineCapButt LineCap = iota
	LineCapRound
	LineCapSquare
)

type LineJoin

type LineJoin uint32

LineJoin represents line join shapes.

const (
	LineJoinMiter LineJoin = iota
	LineJoinRound
	LineJoinBevel
)

type LineShape

type LineShape struct {
	X1, Y1 float32 // Start point
	X2, Y2 float32 // End point
}

LineShape represents a line segment.

func NewLineShape

func NewLineShape(x1, y1, x2, y2 float32) *LineShape

NewLineShape creates a new line shape.

func (*LineShape) Bounds

func (l *LineShape) Bounds() Rect

Bounds returns the bounding rectangle.

func (*LineShape) Length

func (l *LineShape) Length() float32

Length returns the length of the line segment.

func (*LineShape) ToPath

func (l *LineShape) ToPath() *Path

ToPath converts the line to a Path.

type Path

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

Path represents a vector path for encoding. It stores path commands (verbs) and coordinate data separately for efficient processing and encoding.

func NewPath

func NewPath() *Path

NewPath creates a new empty path.

func (*Path) Arc

func (p *Path) Arc(cx, cy, rx, ry, startAngle, endAngle float32, sweepClockwise bool) *Path

Arc adds an arc path (portion of an ellipse). The arc is drawn from startAngle to endAngle (in radians). If sweepClockwise is true, the arc is drawn clockwise.

func (*Path) Bounds

func (p *Path) Bounds() Rect

Bounds returns the bounding rectangle of the path. Note: This is a conservative approximation that includes control points.

func (*Path) Circle

func (p *Path) Circle(cx, cy, r float32) *Path

Circle adds a circle path.

func (*Path) Clone

func (p *Path) Clone() *Path

Clone creates a deep copy of the path.

func (*Path) Close

func (p *Path) Close() *Path

Close closes the current subpath by drawing a line back to its start.

func (*Path) Contains

func (p *Path) Contains(px, py float32) bool

Contains returns true if the point (px, py) is inside the path. This uses the non-zero winding rule to determine containment. The test is performed by casting a ray from the point to infinity and counting the number of times the path crosses the ray.

func (*Path) CubicTo

func (p *Path) CubicTo(c1x, c1y, c2x, c2y, x, y float32) *Path

CubicTo draws a cubic Bezier curve. The curve goes from the current point to (x, y) using (c1x, c1y) and (c2x, c2y) as control points.

func (*Path) Elements added in v0.13.0

func (p *Path) Elements() iter.Seq[PathElement]

Elements returns an iterator over all path elements. This uses Go 1.25+ iter.Seq for efficient, zero-allocation iteration when used with a for-range loop.

Example:

for elem := range path.Elements() {
    switch elem.Verb {
    case VerbMoveTo:
        fmt.Printf("Move to %v\n", elem.Points[0])
    case VerbLineTo:
        fmt.Printf("Line to %v\n", elem.Points[0])
    case VerbQuadTo:
        fmt.Printf("Quad to %v via %v\n", elem.Points[1], elem.Points[0])
    case VerbCubicTo:
        fmt.Printf("Cubic to %v\n", elem.Points[2])
    case VerbClose:
        fmt.Println("Close")
    }
}

func (*Path) ElementsWithCursor added in v0.13.0

func (p *Path) ElementsWithCursor() iter.Seq2[Point, PathElement]

ElementsWithCursor returns an iterator that includes the current cursor position. This is useful when you need to know the starting point of each segment.

func (*Path) Ellipse

func (p *Path) Ellipse(cx, cy, rx, ry float32) *Path

Ellipse adds an ellipse path.

func (*Path) IsEmpty

func (p *Path) IsEmpty() bool

IsEmpty returns true if the path has no commands.

func (*Path) LineTo

func (p *Path) LineTo(x, y float32) *Path

LineTo draws a line from the current point to (x, y).

func (*Path) MoveTo

func (p *Path) MoveTo(x, y float32) *Path

MoveTo begins a new subpath at the specified point.

func (*Path) PointCount

func (p *Path) PointCount() int

PointCount returns the number of float32 values in the point stream.

func (*Path) Points

func (p *Path) Points() []float32

Points returns the point data stream.

func (*Path) QuadTo

func (p *Path) QuadTo(cx, cy, x, y float32) *Path

QuadTo draws a quadratic Bezier curve. The curve goes from the current point to (x, y) using (cx, cy) as control point.

func (*Path) Rectangle

func (p *Path) Rectangle(x, y, w, h float32) *Path

Rectangle adds a rectangle path.

func (*Path) Reset

func (p *Path) Reset()

Reset clears the path for reuse without deallocating memory.

func (*Path) Reverse

func (p *Path) Reverse() *Path

Reverse returns a new path with the direction reversed. This is useful for creating cut-out shapes.

func (*Path) RoundedRectangle

func (p *Path) RoundedRectangle(x, y, w, h, r float32) *Path

RoundedRectangle adds a rounded rectangle path.

func (*Path) Transform

func (p *Path) Transform(t Affine) *Path

Transform returns a new path with all points transformed by the affine matrix.

func (*Path) VerbCount

func (p *Path) VerbCount() int

VerbCount returns the number of verbs in the path.

func (*Path) Verbs

func (p *Path) Verbs() []PathVerb

Verbs returns the verb stream.

type PathElement added in v0.13.0

type PathElement struct {
	// Verb is the path command type.
	Verb PathVerb

	// Points contains the coordinates for this element.
	// The number of points depends on the verb:
	//   - MoveTo: 1 point (destination)
	//   - LineTo: 1 point (destination)
	//   - QuadTo: 2 points (control, destination)
	//   - CubicTo: 3 points (control1, control2, destination)
	//   - Close: 0 points
	Points []Point
}

PathElement represents a single path command with its associated points. This type is used by the Elements() iterator for ergonomic path traversal.

type PathPool

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

PathPool manages a pool of reusable Path objects.

func NewPathPool

func NewPathPool() *PathPool

NewPathPool creates a new path pool.

func (*PathPool) Get

func (pp *PathPool) Get() *Path

Get retrieves a path from the pool or creates a new one.

func (*PathPool) Put

func (pp *PathPool) Put(p *Path)

Put returns a path to the pool for reuse.

type PathShape

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

PathShape wraps a Path as a Shape.

func NewPathShape

func NewPathShape(path *Path) *PathShape

NewPathShape creates a new path shape.

func (*PathShape) Bounds

func (ps *PathShape) Bounds() Rect

Bounds returns the bounding rectangle of the path.

func (*PathShape) ToPath

func (ps *PathShape) ToPath() *Path

ToPath returns the underlying path.

type PathVerb

type PathVerb uint8

PathVerb represents a path construction command.

const (
	// VerbMoveTo moves the current point without drawing.
	VerbMoveTo PathVerb = iota
	// VerbLineTo draws a line to the specified point.
	VerbLineTo
	// VerbQuadTo draws a quadratic Bezier curve.
	VerbQuadTo
	// VerbCubicTo draws a cubic Bezier curve.
	VerbCubicTo
	// VerbClose closes the current subpath.
	VerbClose
)

Path verb constants.

func (PathVerb) PointCount

func (v PathVerb) PointCount() int

PointCount returns the number of points this verb consumes.

func (PathVerb) String

func (v PathVerb) String() string

String returns a human-readable name for the verb.

type PieShape

type PieShape struct {
	CX, CY         float32 // Center
	R              float32 // Radius
	StartAngle     float32 // Start angle in radians
	EndAngle       float32 // End angle in radians
	SweepClockwise bool    // Direction
}

PieShape represents a pie slice (wedge).

func NewPieShape

func NewPieShape(cx, cy, r, startAngle, endAngle float32, sweepClockwise bool) *PieShape

NewPieShape creates a new pie shape.

func (*PieShape) Bounds

func (p *PieShape) Bounds() Rect

Bounds returns a conservative bounding rectangle.

func (*PieShape) ToPath

func (p *PieShape) ToPath() *Path

ToPath converts the pie to a Path.

type Point added in v0.13.0

type Point struct {
	X, Y float32
}

Point represents a 2D point with float32 coordinates. This is used by PathElement for iterator-based path traversal.

type PolygonShape

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

PolygonShape represents a closed polygon.

func NewPolygonShape

func NewPolygonShape(points ...float32) *PolygonShape

NewPolygonShape creates a new polygon shape from a list of points. Points should be provided as x, y pairs.

func (*PolygonShape) Bounds

func (p *PolygonShape) Bounds() Rect

Bounds returns the bounding rectangle.

func (*PolygonShape) Point

func (p *PolygonShape) Point(i int) (x, y float32, ok bool)

Point returns the i-th vertex of the polygon.

func (*PolygonShape) PointCount

func (p *PolygonShape) PointCount() int

PointCount returns the number of vertices in the polygon.

func (*PolygonShape) ToPath

func (p *PolygonShape) ToPath() *Path

ToPath converts the polygon to a Path.

type Rect

type Rect struct {
	MinX, MinY float32
	MaxX, MaxY float32
}

Rect represents a bounding rectangle.

func EmptyRect

func EmptyRect() Rect

EmptyRect returns an empty rectangle (inverted bounds for union operations).

func TextBounds added in v0.11.0

func TextBounds(glyphs []*RenderedGlyph) Rect

TextBounds computes the bounding box for rendered text.

func (Rect) Height

func (r Rect) Height() float32

Height returns the height of the rectangle.

func (Rect) IsEmpty

func (r Rect) IsEmpty() bool

IsEmpty returns true if the rectangle has no area.

func (Rect) Union

func (r Rect) Union(other Rect) Rect

Union returns the smallest rectangle containing both r and other.

func (Rect) UnionPoint

func (r Rect) UnionPoint(x, y float32) Rect

UnionPoint expands the rectangle to include the point.

func (Rect) Width

func (r Rect) Width() float32

Width returns the width of the rectangle.

type RectShape

type RectShape struct {
	X, Y          float32 // Top-left corner
	Width, Height float32 // Dimensions
}

RectShape represents an axis-aligned rectangle.

func NewRectShape

func NewRectShape(x, y, width, height float32) *RectShape

NewRectShape creates a new rectangle shape.

func (*RectShape) Bounds

func (r *RectShape) Bounds() Rect

Bounds returns the bounding rectangle.

func (*RectShape) Contains

func (r *RectShape) Contains(px, py float32) bool

Contains returns true if the point (px, py) is inside the rectangle.

func (*RectShape) ToPath

func (r *RectShape) ToPath() *Path

ToPath converts the rectangle to a Path.

type RegularPolygonShape

type RegularPolygonShape struct {
	CX, CY   float32 // Center
	R        float32 // Radius (distance from center to vertices)
	Sides    int     // Number of sides
	Rotation float32 // Rotation angle in radians
}

RegularPolygonShape represents a regular polygon (all sides equal length).

func NewRegularPolygonShape

func NewRegularPolygonShape(cx, cy, r float32, sides int, rotation float32) *RegularPolygonShape

NewRegularPolygonShape creates a new regular polygon shape.

func (*RegularPolygonShape) Bounds

func (rp *RegularPolygonShape) Bounds() Rect

Bounds returns the bounding rectangle.

func (*RegularPolygonShape) ToPath

func (rp *RegularPolygonShape) ToPath() *Path

ToPath converts the regular polygon to a Path.

type RenderStats

type RenderStats struct {
	// Tile statistics
	TilesTotal    int
	TilesDirty    int
	TilesRendered int

	// Layer statistics
	LayersCached   int
	LayersRendered int

	// Timing (durations for the last render)
	TimeEncode    time.Duration
	TimeRaster    time.Duration
	TimeComposite time.Duration
	TimeTotal     time.Duration

	// Frame timing
	FrameTime time.Duration
	FPS       float64
}

RenderStats contains performance statistics for a render operation.

type RenderedGlyph added in v0.11.0

type RenderedGlyph struct {
	// Path is the vector path representing the glyph outline.
	// May be nil for non-outline glyphs (bitmap, empty).
	Path *Path

	// Bounds is the bounding box of the rendered glyph.
	Bounds Rect

	// Advance is the distance to the next glyph position.
	Advance float32

	// Position is the glyph position relative to the text origin.
	X, Y float32

	// GID is the glyph ID.
	GID text.GlyphID

	// Type indicates the glyph type.
	Type text.GlyphType

	// Cluster is the source character index.
	Cluster int
}

RenderedGlyph represents a glyph that has been converted to a path.

type Renderer

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

Renderer renders Scene content to a target Pixmap using parallel tile-based processing. It integrates with TileGrid for spatial subdivision and WorkerPool for concurrent execution.

The renderer supports:

  • Full scene rendering (all tiles)
  • Incremental rendering (dirty tiles only)
  • Layer caching for static content
  • Performance statistics collection

Thread safety: Renderer methods are safe for concurrent use after initialization.

func NewRenderer

func NewRenderer(width, height int, opts ...RendererOption) *Renderer

NewRenderer creates a new scene renderer for the given dimensions. Options can be used to configure caching, parallelism, and other settings.

func (*Renderer) Cache

func (r *Renderer) Cache() *LayerCache

Cache returns the layer cache.

func (*Renderer) CacheStats

func (r *Renderer) CacheStats() CacheStats

CacheStats returns the layer cache statistics.

func (*Renderer) Close

func (r *Renderer) Close()

Close releases all resources used by the renderer. The renderer should not be used after Close is called.

func (*Renderer) DirtyTileCount

func (r *Renderer) DirtyTileCount() int

DirtyTileCount returns the number of dirty tiles.

func (*Renderer) Height

func (r *Renderer) Height() int

Height returns the renderer height in pixels.

func (*Renderer) MarkAllDirty

func (r *Renderer) MarkAllDirty()

MarkAllDirty marks all tiles as needing redraw.

func (*Renderer) MarkDirty

func (r *Renderer) MarkDirty(x, y, w, h int)

MarkDirty marks the specified rectangle as needing redraw. Coordinates are in pixel space.

func (*Renderer) Render

func (r *Renderer) Render(target *gg.Pixmap, scene *Scene) error

Render renders the entire scene to the target pixmap. This processes all tiles regardless of dirty state.

For cancellable rendering, use RenderWithContext.

func (*Renderer) RenderDirty

func (r *Renderer) RenderDirty(target *gg.Pixmap, scene *Scene, dirty *parallel.DirtyRegion) error

RenderDirty renders only the dirty regions of the scene. This is more efficient when only parts of the scene have changed. The dirty parameter specifies which tiles need re-rendering.

For cancellable rendering, use RenderDirtyWithContext.

func (*Renderer) RenderDirtyWithContext added in v0.13.0

func (r *Renderer) RenderDirtyWithContext(ctx context.Context, target *gg.Pixmap, scene *Scene, dirty *parallel.DirtyRegion) error

RenderDirtyWithContext renders only the dirty regions of the scene with cancellation support. This is more efficient when only parts of the scene have changed. The dirty parameter specifies which tiles need re-rendering.

The context can be used to cancel long-running renders. When canceled, the function returns ctx.Err() and the target may contain partial results.

func (*Renderer) RenderWithContext added in v0.13.0

func (r *Renderer) RenderWithContext(ctx context.Context, target *gg.Pixmap, scene *Scene) error

RenderWithContext renders the entire scene to the target pixmap with cancellation support. This processes all tiles regardless of dirty state.

The context can be used to cancel long-running renders. When canceled, the function returns ctx.Err() and the target may contain partial results.

func (*Renderer) Resize

func (r *Renderer) Resize(width, height int)

Resize updates the renderer dimensions. All tiles will be marked dirty after resize.

func (*Renderer) Stats

func (r *Renderer) Stats() RenderStats

Stats returns the current render statistics.

func (*Renderer) TileCount

func (r *Renderer) TileCount() int

TileCount returns the total number of tiles.

func (*Renderer) Width

func (r *Renderer) Width() int

Width returns the renderer width in pixels.

func (*Renderer) Workers

func (r *Renderer) Workers() int

Workers returns the number of worker goroutines used for parallel rendering.

type RendererOption

type RendererOption func(*Renderer)

RendererOption configures a Renderer.

func WithCache

func WithCache(cache *LayerCache) RendererOption

WithCache sets a custom layer cache. If nil, a default cache is created.

func WithCacheSize

func WithCacheSize(mb int) RendererOption

WithCacheSize sets the layer cache size in megabytes. Default is 64MB.

func WithTileSize

func WithTileSize(size int) RendererOption

WithTileSize sets the tile size for rendering. This is informational only; actual tile size is fixed at 64x64.

func WithWorkers

func WithWorkers(n int) RendererOption

WithWorkers sets the number of worker goroutines for parallel rendering. If n <= 0, GOMAXPROCS is used.

type RoundedRectShape

type RoundedRectShape struct {
	X, Y          float32 // Top-left corner
	Width, Height float32 // Dimensions
	Radius        float32 // Corner radius (same for all corners)
}

RoundedRectShape represents a rectangle with rounded corners.

func NewRoundedRectShape

func NewRoundedRectShape(x, y, width, height, radius float32) *RoundedRectShape

NewRoundedRectShape creates a new rounded rectangle shape.

func (*RoundedRectShape) Bounds

func (r *RoundedRectShape) Bounds() Rect

Bounds returns the bounding rectangle.

func (*RoundedRectShape) ToPath

func (r *RoundedRectShape) ToPath() *Path

ToPath converts the rounded rectangle to a Path.

type Scene

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

Scene is the main retained mode container for accumulating drawing operations. It builds an Encoding that can be efficiently rendered or cached.

Scene provides a familiar drawing API with Fill, Stroke, layers, clips, and transforms. All operations are recorded into an internal Encoding for later playback or GPU submission.

Example:

scene := NewScene()
scene.Fill(FillNonZero, IdentityAffine(), SolidBrush(gg.Red), circle)
scene.PushLayer(BlendMultiply, 0.5, nil)
scene.Stroke(DefaultStrokeStyle(), IdentityAffine(), SolidBrush(gg.Blue), rect)
scene.PopLayer()
enc := scene.Encoding()

func NewScene

func NewScene() *Scene

NewScene creates a new empty scene.

func (*Scene) Bounds

func (s *Scene) Bounds() Rect

Bounds returns the cumulative bounding box of all scene content.

func (*Scene) ClipBounds

func (s *Scene) ClipBounds() Rect

ClipBounds returns the intersection of all active clip regions.

func (*Scene) ClipDepth

func (s *Scene) ClipDepth() int

ClipDepth returns the current clip stack depth.

func (*Scene) DrawGlyphs added in v0.11.0

func (s *Scene) DrawGlyphs(glyphs []text.ShapedGlyph, face text.Face, brush Brush) error

DrawGlyphs draws pre-shaped glyphs directly to the scene.

func (*Scene) DrawImage

func (s *Scene) DrawImage(img *Image, transform Affine)

DrawImage draws an image at the given transform.

func (*Scene) DrawText added in v0.11.0

func (s *Scene) DrawText(str string, face text.Face, x, y float32, brush Brush) error

DrawText is a convenience method on Scene to draw text directly. It creates a temporary TextRenderer, renders the text, and adds it to the scene.

func (*Scene) Encoding

func (s *Scene) Encoding() *Encoding

Encoding returns the root encoding containing all scene commands. This encoding can be used for rendering or caching.

func (*Scene) Fill

func (s *Scene) Fill(style FillStyle, transform Affine, brush Brush, shape Shape)

Fill fills a shape with the given style, transform, and brush.

func (*Scene) Flatten

func (s *Scene) Flatten() *Encoding

Flatten composites all layers into a single encoding. This is useful for rendering the complete scene as a single flattened representation.

Unlike Encoding(), this method returns a new cloned encoding that is independent of the scene's internal state. This allows the scene to be modified after calling Flatten() without affecting the returned encoding.

The flattening process:

  1. All open layers are popped and composited
  2. Layer blend modes and alpha values are applied
  3. The result is a single encoding with all content merged

Example:

scene := NewScene()
scene.Fill(FillNonZero, IdentityAffine(), SolidBrush(gg.Red), rect)
scene.PushLayer(BlendMultiply, 0.5, nil)
scene.Fill(FillNonZero, IdentityAffine(), SolidBrush(gg.Blue), circle)
flat := scene.Flatten()
// flat contains both shapes with layer compositing applied

func (*Scene) Images

func (s *Scene) Images() []*Image

Images returns all registered images.

func (*Scene) IsEmpty

func (s *Scene) IsEmpty() bool

IsEmpty returns true if the scene has no content.

func (*Scene) LayerDepth

func (s *Scene) LayerDepth() int

LayerDepth returns the current layer stack depth.

func (*Scene) PopClip

func (s *Scene) PopClip() bool

PopClip pops the current clip region. Returns false if there's no clip to pop.

func (*Scene) PopLayer

func (s *Scene) PopLayer() bool

PopLayer pops the current layer and composites it with the content below. Returns false if there's no layer to pop (only root layer remains).

func (*Scene) PopTransform

func (s *Scene) PopTransform() bool

PopTransform pops the current transform from the stack. Returns false if there's no transform to pop.

func (*Scene) PushClip

func (s *Scene) PushClip(shape Shape)

PushClip pushes a clip region. All subsequent drawing operations will be clipped to this shape until PopClip is called.

func (*Scene) PushLayer

func (s *Scene) PushLayer(blend BlendMode, alpha float32, clip Shape)

PushLayer pushes a new compositing layer. All subsequent drawing operations will be rendered to this layer. Call PopLayer to composite the layer with the content below.

func (*Scene) PushTransform

func (s *Scene) PushTransform(t Affine)

PushTransform pushes a transform onto the transform stack. The transform is concatenated with the current transform.

func (*Scene) Reset

func (s *Scene) Reset()

Reset clears the scene for reuse without deallocating memory.

func (*Scene) Rotate

func (s *Scene) Rotate(angle float32)

Rotate applies a rotation to the current transform (angle in radians).

func (*Scene) Scale

func (s *Scene) Scale(x, y float32)

Scale applies a scale to the current transform.

func (*Scene) SetTransform

func (s *Scene) SetTransform(t Affine)

SetTransform sets the current transform, replacing the existing one. This does not affect the transform stack.

func (*Scene) Stroke

func (s *Scene) Stroke(style *StrokeStyle, transform Affine, brush Brush, shape Shape)

Stroke strokes a shape with the given style, transform, and brush.

func (*Scene) Transform

func (s *Scene) Transform() Affine

Transform returns the current transform.

func (*Scene) TransformDepth

func (s *Scene) TransformDepth() int

TransformDepth returns the current transform stack depth.

func (*Scene) Translate

func (s *Scene) Translate(x, y float32)

Translate applies a translation to the current transform.

func (*Scene) Version

func (s *Scene) Version() uint64

Version returns the scene version number. This is incremented on each modification and can be used for cache invalidation.

type SceneBuilder

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

SceneBuilder provides a fluent API for constructing scenes ergonomically. It wraps a Scene and provides chainable methods for drawing operations, transform management, and layer composition.

The builder maintains its own transform state that accumulates with each transform operation. Use ResetTransform to clear the accumulated transform.

Example:

scene := NewSceneBuilder().
    Fill(NewRectShape(0, 0, 800, 600), SolidBrush(White)).
    Translate(100, 100).
    Layer(BlendMultiply, 0.8, nil, func(b *SceneBuilder) {
        b.Fill(NewCircleShape(0, 0, 50), SolidBrush(Red)).
          Stroke(NewCircleShape(0, 0, 50), SolidBrush(Black), 2)
    }).
    Build()

func NewSceneBuilder

func NewSceneBuilder() *SceneBuilder

NewSceneBuilder creates a new scene builder with an empty scene.

func NewSceneBuilderFrom

func NewSceneBuilderFrom(scene *Scene) *SceneBuilder

NewSceneBuilderFrom creates a scene builder wrapping an existing scene. This is useful for adding to a scene that already has content.

func (*SceneBuilder) Build

func (b *SceneBuilder) Build() *Scene

Build returns the constructed scene and resets the builder for reuse. The builder is left in a clean state with a new empty scene.

func (*SceneBuilder) Clip

func (b *SceneBuilder) Clip(shape Shape, fn func(*SceneBuilder)) *SceneBuilder

Clip creates a clipping region from the given shape. The callback receives the same builder to add clipped content.

Example:

builder.Clip(circle, func(b *SceneBuilder) {
    b.Fill(largeRect, SolidBrush(Blue)) // clipped to circle
})

func (*SceneBuilder) CurrentTransform

func (b *SceneBuilder) CurrentTransform() Affine

CurrentTransform returns the builder's current transform.

func (*SceneBuilder) DrawLine

func (b *SceneBuilder) DrawLine(x1, y1, x2, y2 float32, brush Brush, lineWidth float32) *SceneBuilder

DrawLine is a convenience method to draw a line.

func (*SceneBuilder) Fill

func (b *SceneBuilder) Fill(shape Shape, brush Brush) *SceneBuilder

Fill fills a shape with the given brush using the non-zero winding rule.

func (*SceneBuilder) FillCircle

func (b *SceneBuilder) FillCircle(cx, cy, r float32, brush Brush) *SceneBuilder

FillCircle is a convenience method to fill a circle.

func (*SceneBuilder) FillPath

func (b *SceneBuilder) FillPath(path *Path, brush Brush) *SceneBuilder

FillPath is a convenience method to fill a path wrapped as a shape.

func (*SceneBuilder) FillRect

func (b *SceneBuilder) FillRect(x, y, width, height float32, brush Brush) *SceneBuilder

FillRect is a convenience method to fill a rectangle.

func (*SceneBuilder) FillWith

func (b *SceneBuilder) FillWith(shape Shape, brush Brush, style FillStyle) *SceneBuilder

FillWith fills a shape with the given brush and fill style.

func (*SceneBuilder) Group

func (b *SceneBuilder) Group(fn func(*SceneBuilder)) *SceneBuilder

Group creates a logical grouping of drawing operations. This is primarily for organizational purposes; no blending or clipping is applied. The callback receives the same builder.

Example:

builder.Group(func(b *SceneBuilder) {
    b.Fill(rect1, SolidBrush(Red))
    b.Fill(rect2, SolidBrush(Blue))
})

func (*SceneBuilder) Image

func (b *SceneBuilder) Image(img *Image, rect Rect) *SceneBuilder

Image draws an image at the given rectangle. The image is scaled to fit the rectangle bounds.

func (*SceneBuilder) Layer

func (b *SceneBuilder) Layer(blend BlendMode, alpha float32, clip Shape, fn func(*SceneBuilder)) *SceneBuilder

Layer creates a compositing layer with the given blend mode and alpha. The callback receives the same builder to add content to the layer. If clip is not nil, the layer content is clipped to that shape.

Example:

builder.Layer(BlendMultiply, 0.8, nil, func(b *SceneBuilder) {
    b.Fill(circle, SolidBrush(Red))
})

func (*SceneBuilder) Reset

func (b *SceneBuilder) Reset() *SceneBuilder

Reset clears the builder's scene and transform for reuse. Unlike Build(), this does not return the scene.

func (*SceneBuilder) ResetTransform

func (b *SceneBuilder) ResetTransform() *SceneBuilder

ResetTransform resets the current transform to identity.

func (*SceneBuilder) Rotate

func (b *SceneBuilder) Rotate(angle float32) *SceneBuilder

Rotate applies a rotation to the current transform (angle in radians). Rotations accumulate - use ResetTransform to clear.

func (*SceneBuilder) Scale

func (b *SceneBuilder) Scale(x, y float32) *SceneBuilder

Scale applies a scale to the current transform. Scales accumulate - use ResetTransform to clear.

func (*SceneBuilder) Scene

func (b *SceneBuilder) Scene() *Scene

Scene returns the current scene without resetting the builder. Use this to inspect the scene during construction.

func (*SceneBuilder) Stroke

func (b *SceneBuilder) Stroke(shape Shape, brush Brush, width float32) *SceneBuilder

Stroke strokes a shape with the given brush and line width.

func (*SceneBuilder) StrokeCircle

func (b *SceneBuilder) StrokeCircle(cx, cy, r float32, brush Brush, lineWidth float32) *SceneBuilder

StrokeCircle is a convenience method to stroke a circle.

func (*SceneBuilder) StrokePath

func (b *SceneBuilder) StrokePath(path *Path, brush Brush, lineWidth float32) *SceneBuilder

StrokePath is a convenience method to stroke a path wrapped as a shape.

func (*SceneBuilder) StrokeRect

func (b *SceneBuilder) StrokeRect(x, y, width, height float32, brush Brush, lineWidth float32) *SceneBuilder

StrokeRect is a convenience method to stroke a rectangle.

func (*SceneBuilder) StrokeWith

func (b *SceneBuilder) StrokeWith(shape Shape, brush Brush, style *StrokeStyle) *SceneBuilder

StrokeWith strokes a shape with the given brush and stroke style.

func (*SceneBuilder) Transform

func (b *SceneBuilder) Transform(t Affine) *SceneBuilder

Transform sets the current transform, replacing any existing transform.

func (*SceneBuilder) Translate

func (b *SceneBuilder) Translate(x, y float32) *SceneBuilder

Translate applies a translation to the current transform. Translations accumulate - use ResetTransform to clear.

func (*SceneBuilder) WithTransform

func (b *SceneBuilder) WithTransform(t Affine, fn func(*SceneBuilder)) *SceneBuilder

WithTransform executes the callback with a temporary transform applied. The transform is reset after the callback completes.

Example:

builder.WithTransform(TranslateAffine(100, 100), func(b *SceneBuilder) {
    b.Fill(shape, brush) // drawn at (100, 100)
})

type ScenePool

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

ScenePool manages a pool of reusable Scene objects.

func NewScenePool

func NewScenePool() *ScenePool

NewScenePool creates a new scene pool.

func (*ScenePool) Get

func (sp *ScenePool) Get() *Scene

Get retrieves a scene from the pool or creates a new one.

func (*ScenePool) Put

func (sp *ScenePool) Put(scene *Scene)

Put returns a scene to the pool for reuse.

func (*ScenePool) Warmup

func (sp *ScenePool) Warmup(count int)

Warmup pre-allocates scenes to avoid allocation during critical paths.

type Shape

type Shape interface {
	// ToPath converts the shape to a Path for encoding.
	ToPath() *Path

	// Bounds returns the bounding rectangle of the shape.
	Bounds() Rect
}

Shape is the interface for geometric shapes that can be converted to paths. All shapes must be able to provide a path representation and their bounds.

type StarShape

type StarShape struct {
	CX, CY      float32 // Center
	OuterRadius float32 // Outer radius (points)
	InnerRadius float32 // Inner radius (valleys)
	Points      int     // Number of points
	Rotation    float32 // Rotation angle in radians
}

StarShape represents a star shape.

func NewStarShape

func NewStarShape(cx, cy, outerRadius, innerRadius float32, points int, rotation float32) *StarShape

NewStarShape creates a new star shape.

func (*StarShape) Bounds

func (s *StarShape) Bounds() Rect

Bounds returns the bounding rectangle.

func (*StarShape) ToPath

func (s *StarShape) ToPath() *Path

ToPath converts the star to a Path.

type StrokeStyle

type StrokeStyle struct {
	Width      float32
	MiterLimit float32
	Cap        LineCap
	Join       LineJoin
}

StrokeStyle contains stroke parameters.

func DefaultStrokeStyle

func DefaultStrokeStyle() *StrokeStyle

DefaultStrokeStyle returns default stroke parameters.

type Tag

type Tag byte

Tag represents a single-byte command identifier in the encoding stream. Tags are organized into groups by their high nibble:

0x0X: Transform operations
0x1X: Path commands
0x2X: Fill/Stroke operations
0x3X: Layer operations
0x4X: Clip operations
0x5X: Brush/Image operations
const (
	// TagTransform encodes an affine transformation.
	// Data: 6 float32 values [a, b, c, d, e, f] representing the matrix:
	//   | a  b  c |
	//   | d  e  f |
	TagTransform Tag = 0x01

	// TagBeginPath marks the start of a new path.
	// Data: none (marker only)
	TagBeginPath Tag = 0x10

	// TagMoveTo moves the current point without drawing.
	// Data: 2 float32 values [x, y]
	TagMoveTo Tag = 0x11

	// TagLineTo draws a line to the specified point.
	// Data: 2 float32 values [x, y]
	TagLineTo Tag = 0x12

	// TagQuadTo draws a quadratic Bezier curve.
	// Data: 4 float32 values [cx, cy, x, y] (control point, end point)
	TagQuadTo Tag = 0x13

	// TagCubicTo draws a cubic Bezier curve.
	// Data: 6 float32 values [c1x, c1y, c2x, c2y, x, y] (control1, control2, end)
	TagCubicTo Tag = 0x14

	// TagClosePath closes the current subpath.
	// Data: none (uses implicit return to subpath start)
	TagClosePath Tag = 0x16

	// TagEndPath marks the end of a path definition.
	// Data: none (marker only)
	TagEndPath Tag = 0x17

	// TagFill fills the current path.
	// Data: 1 uint32 for brush index, 1 uint32 for fill style (NonZero=0, EvenOdd=1)
	TagFill Tag = 0x20

	// TagStroke strokes the current path.
	// Data: 1 uint32 for brush index, then stroke style:
	//   4 float32: [lineWidth, miterLimit, lineCap, lineJoin]
	TagStroke Tag = 0x21

	// TagPushLayer pushes a new compositing layer.
	// Data: 1 uint32 for blend mode, 1 float32 for alpha
	TagPushLayer Tag = 0x30

	// TagPopLayer pops the current compositing layer.
	// Data: none
	TagPopLayer Tag = 0x31

	// TagBeginClip begins a clipping region using the current path.
	// Data: none (uses current path as clip)
	TagBeginClip Tag = 0x40

	// TagEndClip ends the current clipping region.
	// Data: none
	TagEndClip Tag = 0x41

	// TagBrush defines a brush (solid color, gradient, etc.).
	// Data: variable depending on brush type
	//   Solid: 4 float32 [r, g, b, a]
	TagBrush Tag = 0x50

	// TagImage references an image resource.
	// Data: 1 uint32 for image index, 6 float32 for transform
	TagImage Tag = 0x51
)

Tag constants define all encoding commands. Each tag has a fixed data layout documented in its comment.

func (Tag) DataSize

func (t Tag) DataSize() int

DataSize returns the number of float32 values this tag consumes from pathData. Returns -1 for tags that don't use pathData.

func (Tag) IsClipCommand

func (t Tag) IsClipCommand() bool

IsClipCommand returns true if the tag is a clip command.

func (Tag) IsDrawCommand

func (t Tag) IsDrawCommand() bool

IsDrawCommand returns true if the tag is a draw command (fill/stroke).

func (Tag) IsLayerCommand

func (t Tag) IsLayerCommand() bool

IsLayerCommand returns true if the tag is a layer command.

func (Tag) IsPathCommand

func (t Tag) IsPathCommand() bool

IsPathCommand returns true if the tag is a path construction command.

func (Tag) String

func (t Tag) String() string

String returns a human-readable name for the tag.

type TextRenderer added in v0.11.0

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

TextRenderer converts shaped text to scene paths for GPU rendering. It supports glyph outlines and handles positioning, transforms, and caching.

TextRenderer is safe for concurrent use.

func NewTextRenderer added in v0.11.0

func NewTextRenderer() *TextRenderer

NewTextRenderer creates a new text renderer with default configuration.

func NewTextRendererWithConfig added in v0.11.0

func NewTextRendererWithConfig(config TextRendererConfig) *TextRenderer

NewTextRendererWithConfig creates a new text renderer with the given configuration.

func (*TextRenderer) Config added in v0.11.0

func (r *TextRenderer) Config() TextRendererConfig

Config returns the current configuration.

func (*TextRenderer) RenderGlyph added in v0.11.0

func (r *TextRenderer) RenderGlyph(glyph text.ShapedGlyph, face text.Face) (*RenderedGlyph, error)

RenderGlyph converts a single shaped glyph to a renderable path. The path is positioned at the glyph's location and scaled appropriately.

func (*TextRenderer) RenderGlyphs added in v0.11.0

func (r *TextRenderer) RenderGlyphs(glyphs []text.ShapedGlyph, face text.Face) ([]*RenderedGlyph, error)

RenderGlyphs converts multiple shaped glyphs to renderable paths. Returns a slice of rendered glyphs in the same order as input.

func (*TextRenderer) RenderRun added in v0.11.0

func (r *TextRenderer) RenderRun(run *text.ShapedRun) ([]*RenderedGlyph, error)

RenderRun converts a shaped run to renderable glyphs.

func (*TextRenderer) RenderText added in v0.11.0

func (r *TextRenderer) RenderText(str string, face text.Face) ([]*RenderedGlyph, error)

RenderText shapes and renders text in one operation. Uses the global shaper for text shaping.

func (*TextRenderer) RenderTextToScene added in v0.11.0

func (r *TextRenderer) RenderTextToScene(s *Scene, str string, face text.Face, x, y float32, brush Brush) error

RenderTextToScene shapes and renders text directly into a scene.

func (*TextRenderer) RenderToScene added in v0.11.0

func (r *TextRenderer) RenderToScene(s *Scene, glyphs []text.ShapedGlyph, face text.Face, brush Brush) error

RenderToScene renders shaped glyphs directly into a scene. This is the primary method for GPU text rendering.

func (*TextRenderer) SetConfig added in v0.11.0

func (r *TextRenderer) SetConfig(config TextRendererConfig)

SetConfig updates the configuration.

func (*TextRenderer) ToCompositePath added in v0.11.0

func (r *TextRenderer) ToCompositePath(glyphs []*RenderedGlyph) *Path

ToCompositePath combines multiple rendered glyphs into a single path. This is useful for text that will be rendered as a single unit.

type TextRendererConfig added in v0.11.0

type TextRendererConfig struct {
	// FlipY inverts the Y-axis for glyph outlines (default: false).
	// Our OutlineExtractor preserves sfnt's Y-down convention
	// (Y=0 at baseline, Y<0 above, Y>0 below), which matches
	// screen coordinates directly. Set to true only if your
	// coordinate system has Y increasing upward.
	FlipY bool

	// SubpixelPositioning enables fractional glyph positioning.
	// When false, glyphs are snapped to integer pixel positions.
	SubpixelPositioning bool

	// HintingEnabled enables font hinting for sharper rendering at small sizes.
	HintingEnabled bool
}

TextRendererConfig holds configuration for TextRenderer.

func DefaultTextRendererConfig added in v0.11.0

func DefaultTextRendererConfig() TextRendererConfig

DefaultTextRendererConfig returns the default configuration.

type TextRendererPool added in v0.11.0

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

TextRendererPool manages a pool of TextRenderers for concurrent use.

func NewTextRendererPool added in v0.11.0

func NewTextRendererPool() *TextRendererPool

NewTextRendererPool creates a new pool of text renderers.

func (*TextRendererPool) Get added in v0.11.0

func (p *TextRendererPool) Get() *TextRenderer

Get retrieves a renderer from the pool.

func (*TextRendererPool) Put added in v0.11.0

func (p *TextRendererPool) Put(r *TextRenderer)

Put returns a renderer to the pool.

type TextShape added in v0.11.0

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

TextShape represents a shaped text string as a scene Shape. This allows text to be used with fill/stroke operations.

func NewTextShape added in v0.11.0

func NewTextShape(str string, face text.Face, x, y float32) (*TextShape, error)

NewTextShape creates a TextShape from text. The text is shaped and converted to a path at the specified position.

func (*TextShape) Bounds added in v0.11.0

func (ts *TextShape) Bounds() Rect

Bounds returns the bounding rectangle of the text.

func (*TextShape) ToPath added in v0.11.0

func (ts *TextShape) ToPath() *Path

ToPath returns the path representation of the text.

type TransformShape

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

TransformShape wraps a shape with a transformation.

func NewTransformShape

func NewTransformShape(shape Shape, transform Affine) *TransformShape

NewTransformShape creates a transformed shape.

func (*TransformShape) Bounds

func (ts *TransformShape) Bounds() Rect

Bounds returns the transformed bounding rectangle. Note: This is a conservative approximation.

func (*TransformShape) ToPath

func (ts *TransformShape) ToPath() *Path

ToPath converts the shape to a transformed Path.

Jump to

Keyboard shortcuts

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