render

package
v0.0.37 Latest Latest
Warning

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

Go to latest
Published: Aug 2, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package render draws Linefire assets with the ebiten vector package. The same code is used by the editor canvas (zoomed) and the real-size preview, and is intended to be reusable by the future game.

Index

Constants

View Source
const CamScale = 0.6

CamScale is Linefire's world-to-logical-pixel factor: how big a world unit is drawn. Every dimension in the game is authored in world units and lands on screen through this, which is why the art, the rings and the hitboxes all agree there. Anything drawing Linefire assets should scale by it rather than invent its own factor.

Variables

This section is empty.

Functions

func DrawAsset

func DrawAsset(dst *ebiten.Image, a *asset.Asset, v View, antialias bool)

DrawAsset renders every layer of the asset into dst using the given view. Filled shapes are drawn first, then strokes on top. It draws the crisp geometry only; the additive bloom that uses the per-layer glow field is applied separately by Glow (see glow.go).

func DrawLayers

func DrawLayers(dst *ebiten.Image, layers []asset.Layer, v View, antialias bool)

DrawLayers renders a slice of styled layers (used for both assets and map walls, which share the layer format).

func FillCircle added in v0.0.6

func FillCircle(dst *ebiten.Image, cx, cy, r float64, col color.RGBA)

FillCircle draws a tinted disc of radius r (device px) centered at (cx, cy).

func FillCircleAdd added in v0.0.6

func FillCircleAdd(dst *ebiten.Image, cx, cy, r float64, col color.RGBA, gain float64)

FillCircleAdd is FillCircle with ADDITIVE blending, scaled by gain — the same light-adding draw the bolts use. Note that a caller fades an additive mark with gain, NOT with the color's alpha: additive blending ignores the destination, so a lower alpha alone would leave the mark just as bright.

func ParseColor

func ParseColor(s string) (col color.RGBA, visible bool)

ParseColor parses a color string. It accepts "#rgb", "#rrggbb" and "#rrggbbaa". An empty string or "transparent" reports visible == false so the caller can skip drawing that stroke or fill.

func StrokeLine added in v0.0.6

func StrokeLine(dst *ebiten.Image, x0, y0, x1, y1, width float64, col color.RGBA)

StrokeLine draws a tinted straight streak of the given width (device px) from (x0, y0) to (x1, y1), butt-capped like the vector StrokeLine it replaces.

func StrokeLineAdd added in v0.0.6

func StrokeLineAdd(dst *ebiten.Image, x0, y0, x1, y1, width float64, col color.RGBA, gain float64)

StrokeLineAdd is StrokeLine with ADDITIVE blending, scaled by gain: the streak adds light to whatever lies under it instead of covering it. That is how kutta composites its glowing smoke, and it is what makes a mark read as hot — the same stroke drawn over-and-over blows out to white where it overlaps.

Types

type CRT

type CRT struct{}

CRT applies the CRT post-process shader.

func NewCRT

func NewCRT() *CRT

NewCRT returns a CRT post-processor.

func (*CRT) Present

func (c *CRT) Present(dst, src *ebiten.Image, geo ebiten.GeoM, opts CRTOptions)

Present draws src onto dst through the CRT shader, positioned by geo. If the shader is unavailable it copies src across unchanged so the editor still works.

type CRTOptions

type CRTOptions struct {
	Curvature     float64
	ScanIntensity float64
	Aberration    float64 // pixels
	Vignette      float64
}

CRTOptions are the tunable parameters of the CRT post-process.

func DefaultCRTOptions

func DefaultCRTOptions() CRTOptions

DefaultCRTOptions returns a subtle CRT look — gentle curvature and faint scanlines/aberration, meant to suggest a CRT rather than distort heavily.

type Glow

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

Glow renders an asset's strokes with an additive bloom. It owns offscreen buffers sized to the region it is used for; use one Glow per region (e.g. one for the canvas and one for the preview) so the buffers stay a stable size.

func NewGlow

func NewGlow() *Glow

NewGlow returns an empty glow renderer; buffers are created on first use.

func (*Glow) Apply

func (g *Glow) Apply(dst *ebiten.Image, layers []asset.Layer, view View, region image.Rectangle, opts GlowOptions)

Apply adds a bloom for the given layers into dst, confined to region, using the screen-space view (the editors' CPU-transform path). The crisp geometry should already be drawn; this only adds the additive glow on top.

func (*Glow) Bloom

func (g *Glow) Bloom(dst *ebiten.Image, region image.Rectangle, opts GlowOptions, fillEmissive func(emissive *ebiten.Image))

Bloom blurs whatever fillEmissive draws into the (cleared) emissive buffer and adds it to dst with the variant's intensity. This decouples the bloom from how the bright source is produced: the editors fill it via a View; the game draws a world mesh with the camera GeoM (so the GPU does the transform). It is a no-op if the shader is unavailable.

func (*Glow) Deallocate

func (g *Glow) Deallocate()

Deallocate returns the offscreen buffers' textures to the GPU immediately — otherwise they wait on Go FINALIZERS, which lag far behind on wasm (the iOS tab-kill ratchet). The Glow stays usable: the next Bloom recreates them.

type GlowOptions

type GlowOptions struct {
	Variant    GlowVariant
	Time       float64 // seconds, for the pulse variant
	Intensity  float64 // base multiplier; 0 is treated as 1
	Spread     float64 // blur step in target pixels; 0 uses the variant default
	Iterations int     // separable blur iterations; 0 uses the variant default
	AntiAlias  bool
}

GlowOptions controls a glow pass.

type GlowVariant

type GlowVariant int

GlowVariant selects the look of the bloom.

const (
	GlowStable GlowVariant = iota // steady halo
	GlowPulse                     // halo pulses over time
	GlowLaser                     // bright tight core plus a wide soft halo
)

func (GlowVariant) String

func (v GlowVariant) String() string

String names the variant for the UI.

type Mesh

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

Mesh is cached vector path data in world/asset coordinates. Draw transforms only visible paths and lets Ebitengine's modern vector renderer handle the final stroke/fill quality, avoiding rotated bitmap artifacts.

func BuildGlowMesh

func BuildGlowMesh(layers []asset.Layer) *Mesh

BuildGlowMesh caches only glowing strokes for the bloom emissive source.

func BuildLayersMesh

func BuildLayersMesh(layers []asset.Layer) *Mesh

BuildLayersMesh caches the crisp geometry of layers: fills for closed paths and strokes for visible strokes.

func (*Mesh) Draw

func (m *Mesh) Draw(dst *ebiten.Image, geo ebiten.GeoM, smooth bool)

Draw renders cached geometry into dst, transformed by geo.

func (*Mesh) DrawTinted

func (m *Mesh) DrawTinted(dst *ebiten.Image, geo ebiten.GeoM, smooth bool, tint ebiten.ColorScale)

DrawTinted renders the cached geometry like Draw, but multiplies every path color by tint — e.g. a dimmed, translucent scale to draw a faded ghost. The zero ColorScale is identity, so Draw is just DrawTinted with no tint.

func (*Mesh) Empty

func (m *Mesh) Empty() bool

Empty reports whether the mesh has nothing to draw.

func (*Mesh) Retinted added in v0.0.25

func (m *Mesh) Retinted(target color.RGBA) *Mesh

Retinted returns a copy of the mesh with every path's fill and stroke moved to the target's hue, keeping each color's own saturation, value and alpha — so a faction can own a hull without flattening the art's shading. A straight blend toward the faction color drags saturation with it and washes the art out; moving only the hue keeps every highlight and shadow where the artist put it. An achromatic target (white or grey) has no hue to move to, so the copy desaturates instead, which reads as that faction's scheme.

The vector geometry is shared with the original, not copied: paths are immutable at runtime, and only the color table is new.

type View

type View struct {
	OffsetX float64
	OffsetY float64
	Scale   float64
}

View describes how asset-space coordinates map to screen pixels: a uniform scale plus a translation. ScreenX = OffsetX + assetX*Scale. It is used by the editors (small assets, CPU transform). The game instead caches world geometry once and applies the camera to visible batches before drawing (see mesh.go).

func (View) Project

func (v View) Project(x, y float64) (float32, float32)

Project converts an asset-space coordinate to screen pixels.

func (View) Unproject

func (v View) Unproject(sx, sy float64) (float64, float64)

Unproject converts a screen pixel back to an asset-space coordinate.

Jump to

Keyboard shortcuts

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