gfx

package
v0.0.0-...-11816a6 Latest Latest
Warning

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

Go to latest
Published: Sep 25, 2026 License: MIT Imports: 53 Imported by: 0

Documentation

Overview

Package gfx draws a game's 2D and 3D graphics. A Graphics is the drawing context for one window. Every Draw* call queues work for the frame the engine has open, and the engine submits it. 2D and 3D share a frame. The 3D scene renders first into a high dynamic range image, the post pass tone-maps it, and sprites, text and paths draw over the top in layer order, preserving submission order within each layer.

GPU resources belong to the Graphics that created them. Different windows use independent devices, so upload resources separately for each output. Drawing and state methods panic before using foreign GPU resources; constructors and transfers with error results return errors. Text drawing reports invalid font ownership through frame submission. See Graphics.

2D

Textures come from images (NewTexture), pixel writes (Texture.Write) or render targets (NewRenderTexture with DrawTo). Sprites are drawn with DrawTexture, DrawSprite and DrawRegion, in the units set by SetView with the origin at the top-left and +Y down. Consecutive sprites with one texture, blend mode and shader become one draw. A Camera2D pans, zooms and rotates them, and a Tilemap draws a grid of regions with culling and animated tiles. Paths (Path, FillPath, StrokePath) draw vector shapes, gradients and dashes anti-aliased. Fonts shape text with HarfBuzz (DrawText, TextOptions, RichText, Hyphenator) and rasterise glyphs, colour emoji included, into an atlas. An Atlas names packed frames from a TexturePacker or Aseprite JSON export (ParseAtlas) or from Aseprite's own file (ParseAseprite), and plays its tags with the timings they were authored at. SetShader, SetBlend, SetColorMatrix and SetLights2D change how later sprites are drawn; DrawLit lights a sprite through a normal map, and AddOccluder2D casts shadows from the lights that want them. PushTransform and PushClip nest.

3D

A Mesh is indexed geometry from NewMesh, the shape functions (CubeMesh, SphereMesh, PlaneMesh, HeightfieldMesh and more) or a glTF Model loaded with LoadModel. Mesh.Update replaces geometry that changes. A Material is metallic-roughness PBR with textures, clearcoat, sheen, subsurface, transmission, outlines and x-ray, or a game's own mesh Shader. A Model's clips play through an AnimPlayer with crossfades, layers and masks, events, root motion, morph targets and node overrides for IK. DrawMesh, DrawModel and DrawSkinned queue draws that are instanced when they share a mesh and material, culled against the camera's Frustum (a skinned mesh by the boxes of its joints under the pose, and a mesh whose shape leaves its geometry by Mesh.SetBounds or Shader.VertexBounds), sorted for blending and lit by SetLight's directional light with cascaded shadows, AddPoint and AddSpot, whose lights cast shadows of their own and which a cluster grid sorts over the view, the procedural Sky or an Environment map, and Fog. Parts of a scene get their own light from a ReflectionProbe baked with BakeProbe and added with AddProbe, a LightProbeGrid baked with BakeLightProbes and set with SetLightProbes, and the screen-space reflections PostSettings.Reflections turns on. DrawLOD picks a mesh by distance. DrawBillboard and DrawText3D put camera-facing quads and labels in the scene, and DrawDecal projects a texture onto geometry. SetPost sets exposure, bloom, ambient occlusion, vignette and anti-aliasing. Project, ScreenRay and Mesh.Intersect convert between the view and the world. DrawLine3D and the DrawWire* helpers draw debug lines over everything.

Conventions

Option and material fields follow "zero means the default". A zero Roughness is 0.6, a zero IOR is 1.5, a zero Color where a tint is expected is white, and a zero Camera field of view is 60 degrees. A field whose zero must mean something of its own is named for that zero (NoMipmaps, NoDepthTest, Sky.Vacuum), so an empty struct is always a valid starting point. 2D sizes and positions use float32 view units; 3D uses game-defined world units. Texture dimensions use pixels. Rectangles are lin.Rect, and angles are radians. Colours are linear, non-premultiplied floats (RGB and Hex convert from sRGB bytes). Graphics owns the GPU resources it creates and releases them at shutdown, including after setup or drawing fails. Call Destroy to release a resource earlier. Create, update and destroy resources on the game goroutine in Init, Update, Draw or Shutdown. Destruction during Draw is deferred until queued work finishes; outside a frame it waits for the GPU. Stats reports what the last frame cost.

Index

Examples

Constants

View Source
const (
	TileFlipX    = 1 << 28
	TileFlipY    = 1 << 29
	TileFlipDiag = 1 << 30 // swap the axes: with FlipX a quarter turn clockwise

)

Tile flip bits, stored above the frame index in a Tilemap cell so a tile can be mirrored or turned without another sheet frame. They match the Tiled map editor's convention.

View Source
const MaxGPUMorphTargets = 8

MaxGPUMorphTargets is how many of a mesh's morph targets can carry a weight at once before the blend moves back to the processor. Eight is what the instance record holds, and more than a face usually needs at one time: a mesh with twenty targets is fine so long as no more than eight of them are open.

View Source
const MaxImpostorViews = 64

MaxImpostorViews is the most views one impostor may hold.

View Source
const MaxLights = maxPointLights

MaxLights is how many point and spot lights a frame keeps. The lights are sorted into a grid of clusters over the view, and a fragment is lit by its own cluster's lights alone, so a scene may add hundreds without every one costing every pixel. A cluster keeps 64 lights, and a light past that in a crowded part of the view does not light it.

View Source
const MaxOccluderTriangles = 4096

MaxOccluderTriangles is the most triangles an occluder mesh may have before AddOccluder3D ignores it. Occluders are rasterised on the CPU, so a blocking volume should be a box or a few quads, not the detailed geometry it stands for.

View Source
const MaxPointShadows = maxPointShadows

MaxPointShadows is how many point lights cast shadows in one frame. Each one costs six depth passes, one for each face of its cube.

View Source
const MaxProbes = maxProbes

MaxProbes is how many reflection probes a frame keeps.

View Source
const MaxSpotShadows = maxSpotShadows

MaxSpotShadows is how many spot lights cast shadows in one frame.

Variables

View Source
var (
	White       = Color{1, 1, 1, 1}
	Black       = Color{0, 0, 0, 1}
	Transparent = Color{}
)

Functions

func ComputeNormals

func ComputeNormals(verts []Vertex, indices []uint32)

ComputeNormals sets every vertex's normal to the average of its triangles' face normals, for geometry built without them: terrain, marching cubes, meshes edited in code.

func FrustumCorners

func FrustumCorners(viewProj lin.Mat4) [8]lin.Vec3

Corners returns the frustum's eight corners for a view-projection matrix: the near plane's four then the far plane's, each as bottom-left, bottom-right, top-right, top-left.

func NeutralLUT

func NeutralLUT(n int) *image.RGBA

NeutralLUT returns an identity colour lookup table of n slices (16 or 32 are usual): grade a screenshot with it pasted in the corner, crop it back out, and every frame gets the same grade through PostSettings.LUT.

func TileFlipped

func TileFlipped(frame int, flipX, flipY, diagonal bool) int

TileFlipped combines a frame index with flip bits for Tilemap.Set.

func TileFrame

func TileFrame(cell int) (frame int, flipX, flipY, diagonal bool)

TileFrame splits a cell value into its frame and flips.

Types

type Align

type Align uint8

Align positions lines within a text block.

const (
	AlignLeft Align = iota
	AlignCenter
	AlignRight
	// AlignJustify widens the spaces of every wrapped line but a
	// paragraph's last so both edges are straight; it needs a Width.
	AlignJustify
)

type AnimBlend

type AnimBlend struct {
	Clip   string
	Weight float32
	Time   float64 // sample time in seconds, supplied by the blend controller
}

AnimBlend is one clip's share of a blended pose, for SetBlend: the clip, its weight against the others and the time to sample it at.

type AnimEvent

type AnimEvent struct {
	Clip string
	Time float32 // event's position in the clip, in seconds
	Name string
}

AnimEvent is a moment in a clip that playback crossed: a footstep, a hit frame, a spawn point.

type AnimLayer

type AnimLayer struct {
	Weight float32 // how much of the layer shows, 0..1
	// Additive adds the clip's difference from the rest pose to the pose
	// underneath (a breathing motion over anything, a recoil); off, the
	// layer replaces the pose of the nodes it covers (a wave over a walk).
	Additive bool
	// Loop starts the clip over at its end; off, the layer holds the last
	// frame. Layer sets it.
	Loop bool
	// Mask is the set of nodes the layer affects; nil means every node.
	Mask AnimMask
	// contains filtered or unexported fields
}

AnimLayer plays a clip over part of the skeleton on top of the main clip. Get one from Layer.

func (*AnimLayer) Clip

func (l *AnimLayer) Clip() string

Clip is the layer's clip name.

func (*AnimLayer) Finished

func (l *AnimLayer) Finished() bool

Finished reports whether a non-looping layer has reached its clip's end.

func (*AnimLayer) Time

func (l *AnimLayer) Time() float64

Time is the layer's clip time in seconds.

type AnimMask

type AnimMask []bool

AnimMask is the set of nodes an animation layer affects, one flag per node; nil means every node. Build one with MaskNodes or MaskSubtree.

type AnimPlayer

type AnimPlayer struct {
	// OnEvent, when set, is called from Advance for every event playback
	// crosses; Events lists the same after Advance returns.
	OnEvent func(AnimEvent)
	// PostPose, when set, runs at the end of every Advance with the pose
	// built, before joint matrices are made: the place for inverse
	// kinematics, look-at and any other node override.
	PostPose func(p *AnimPlayer)
	// contains filtered or unexported fields
}

AnimPlayer plays a model's animation clips over its node hierarchy. One player per animated instance; it holds the current pose. Play and CrossFade choose the main clip, SetBlend mixes several clips in its place, Layer plays more clips over parts of the skeleton, AddEvent marks moments to be told about, SetRootMotion hands the root's movement to the game, and PostPose with the node setters adjusts the pose before it is drawn. Create one with Model.NewAnimPlayer; the zero value has no model or pose storage. Times and Advance deltas are seconds.

func (*AnimPlayer) AddEvent

func (p *AnimPlayer) AddEvent(clip string, time float32, name string) bool

AddEvent marks a time in a clip; Advance reports crossing it through OnEvent and Events, on every loop and while the clip blends in, out or on a layer. Unknown clips return false.

func (*AnimPlayer) Advance

func (p *AnimPlayer) Advance(dt float64)

Advance moves playback forward by dt seconds and rebuilds the pose: the main clip or blend, its crossfade, the layers, root motion, events and PostPose, in that order.

func (*AnimPlayer) Blend

func (p *AnimPlayer) Blend() []AnimBlend

Blend lists the clips SetBlend is playing with their weights as given and their times, in a new slice; nil when no blend plays.

func (*AnimPlayer) Clip

func (p *AnimPlayer) Clip() string

Clip is the name of the main clip, or "" when none plays.

func (*AnimPlayer) CrossFade

func (p *AnimPlayer) CrossFade(name string, loop bool, seconds float64) bool

CrossFade starts a clip while the current one blends out over the given seconds, so a run does not snap out of a walk. With nothing playing, a blend playing, or a zero fade, it is Play.

func (*AnimPlayer) Events

func (p *AnimPlayer) Events() []AnimEvent

Events lists the events the last Advance crossed, in clip order; the slice is reused by the next Advance.

func (*AnimPlayer) Finished

func (p *AnimPlayer) Finished() bool

Finished reports whether a non-looping main clip has reached its end.

func (*AnimPlayer) Layer

func (p *AnimPlayer) Layer(clip string, weight float32, mask AnimMask) *AnimLayer

Layer plays a clip on top of the main one over the nodes in the mask (nil for all of them), looping, at the given weight: a wave over the arms while the legs walk. Change the returned layer's fields at any time; RemoveLayer takes it off. Unknown clips return nil.

func (*AnimPlayer) Layers

func (p *AnimPlayer) Layers() []*AnimLayer

Layers lists the playing layers in the order they blend, first to last.

func (*AnimPlayer) Model

func (p *AnimPlayer) Model() *Model

Model is the model the player animates.

func (*AnimPlayer) MorphWeights

func (p *AnimPlayer) MorphWeights(node int) []float32

MorphWeights returns a node's morph target weights in the current pose, one per target; nil when the node has none.

func (*AnimPlayer) NodeLocal

func (p *AnimPlayer) NodeLocal(node int) (t lin.Vec3, r lin.Quat, s lin.Vec3)

NodeLocal returns a node's current local translation, rotation and scale, relative to its parent.

func (*AnimPlayer) NodeMatrix

func (p *AnimPlayer) NodeMatrix(node int) lin.Mat4

NodeMatrix returns a node's current world matrix (in model space).

func (*AnimPlayer) NodePosition

func (p *AnimPlayer) NodePosition(node int) lin.Vec3

NodePosition returns a node's position in model space.

func (*AnimPlayer) NodeRotation

func (p *AnimPlayer) NodeRotation(node int) lin.Quat

NodeRotation returns a node's rotation in model space.

func (*AnimPlayer) Play

func (p *AnimPlayer) Play(name string, loop bool) bool

Play starts a clip by name from its beginning, dropping any crossfade or blend; unknown names return false.

func (*AnimPlayer) PlayIndex

func (p *AnimPlayer) PlayIndex(i int, loop bool)

PlayIndex starts a clip by index.

func (*AnimPlayer) RemoveLayer

func (p *AnimPlayer) RemoveLayer(l *AnimLayer)

RemoveLayer stops a layer.

func (*AnimPlayer) RootMotion

func (p *AnimPlayer) RootMotion() (delta lin.Vec3, yaw float32)

RootMotion returns how far the root node moved during the last Advance, in model space, and how much it turned about +Y in radians. Apply them to the entity's transform: position += rotation.Rotate(delta), then turn by yaw. Both are zero unless SetRootMotion is on.

func (*AnimPlayer) RotateNode

func (p *AnimPlayer) RotateNode(node int, q lin.Quat)

RotateNode turns a node by a rotation given in model space, about its own position, so its children follow: what an inverse kinematics or look-at solver produces.

func (*AnimPlayer) SetBlend

func (p *AnimPlayer) SetBlend(clips []AnimBlend)

SetBlend plays a weighted mix of clips in place of the main clip, each sampled at its own time: what a blend space produces. The weights are scaled to sum to 1; entries with no weight, or an unknown clip, are skipped, and an empty list stops the blend. The caller owns the times and sets them again before every Advance; a time that moved backwards counts as having looped. Events fire and root motion accrues for every clip in the blend by its weight. Play, CrossFade and Stop drop the blend; layers play over it as they do over a clip.

func (*AnimPlayer) SetMorphWeights

func (p *AnimPlayer) SetMorphWeights(node int, weights []float32)

SetMorphWeights sets the weights a node's morph targets start from on every Advance, until a playing clip's weights channel replaces them: a smile held while the body animates. Weights beyond the target count are ignored.

func (*AnimPlayer) SetNodeLocal

func (p *AnimPlayer) SetNodeLocal(node int, t lin.Vec3, r lin.Quat, s lin.Vec3)

SetNodeLocal replaces a node's local transform in the current pose: an aimed turret, a procedural tail. The next Advance samples the clips again, so call it after Advance or from PostPose each frame.

func (*AnimPlayer) SetNodeRotation

func (p *AnimPlayer) SetNodeRotation(node int, r lin.Quat)

SetNodeRotation replaces a node's local rotation in the current pose.

func (*AnimPlayer) SetRootMotion

func (p *AnimPlayer) SetRootMotion(node string) bool

SetRootMotion names the node whose movement the game applies to the entity instead of the animation sliding it in place: usually the skeleton's root or hips. From then on the node's translation and its yaw (rotation about +Y) are held at the rest pose and their change per Advance is reported by RootMotion. "" turns root motion off; an unknown name returns false.

func (*AnimPlayer) SetSpeed

func (p *AnimPlayer) SetSpeed(s float64)

SetSpeed scales playback; 1 is normal, negative runs clips backwards.

func (*AnimPlayer) SetTime

func (p *AnimPlayer) SetTime(t float64)

SetTime moves the main clip to a time in seconds, as scrubbing does; events between the old and new times do not fire.

func (*AnimPlayer) Speed

func (p *AnimPlayer) Speed() float64

Speed is the playback scale set by SetSpeed; 1 by default.

func (*AnimPlayer) Stop

func (p *AnimPlayer) Stop()

Stop drops the main clip or blend, leaving the pose where it is; layers keep playing.

func (*AnimPlayer) Time

func (p *AnimPlayer) Time() float64

Time is the main clip's current time in seconds.

type AnimState

type AnimState struct {
	Anim *Animation
	Time float64
	Done bool
}

AnimState plays an Animation over time.

func (*AnimState) Advance

func (s *AnimState) Advance(dt float64)

Advance moves time forward by dt seconds.

func (*AnimState) Frame

func (s *AnimState) Frame() int

Frame returns the sheet frame to draw now.

func (*AnimState) Play

func (s *AnimState) Play(a *Animation)

Play restarts the state on an animation.

type Animation

type Animation struct {
	Frames []int
	FPS    float32 // zero means 10
	Loop   bool
}

Animation is a sequence of sheet frames at a frame rate.

type Aseprite

type Aseprite struct {
	Width, Height int // one frame, in pixels
	Frames        []AsepriteFrame
	Layers        []AsepriteLayer
	Tags          []AsepriteTag
	Slices        []AsepriteSlice
	Palette       []color.RGBA // empty for a file with no palette chunk
	Image         *image.RGBA  // every packed frame, premultiplied
	Data          *AtlasData   // the frames and tag animations of Image
	Atlas         *Atlas       // the bound atlas, once Upload has run
}

Aseprite is a parsed .aseprite or .ase file: every frame composited from its visible layers into one packed image, an AtlasData that names the packed frames and carries the file's tags as animations, and the pieces the editor keeps beside the pixels. ParseAseprite reads it and Upload puts it on the GPU.

Frames are named by their number, "0" upwards, in the order they play. With AsepriteOptions.Layers a layer's own frames are named "<layer>/<number>", where a layer inside a group carries the group's name first, so a hat drawn on its own is atlas.Region("gear/hat/3").

func ParseAseprite

func ParseAseprite(data []byte, opts AsepriteOptions) (*Aseprite, error)

ParseAseprite reads an Aseprite file: its header, frames, layers, cels, palette, tags and slices. It composites each frame's visible layers into one image, packs the frames into a grid and describes them in an AtlasData, so Atlas.Animation plays a tag with the timings the editor gave it. RGBA, greyscale and indexed files all read; layers blend as normal with their opacity, whatever mode the editor set.

func (*Aseprite) Slice

func (a *Aseprite) Slice(name string) (lin.Rect, bool)

Slice returns a slice's rectangle on its first key, which is what a slice that never moves has.

func (*Aseprite) Upload

func (a *Aseprite) Upload(g *Graphics, opts TextureOptions) (*Atlas, error)

Upload puts the packed image on the GPU and binds the atlas, which it also stores in Atlas. Destroy the atlas's texture when the game is done with it.

type AsepriteFrame

type AsepriteFrame struct {
	Duration float32 // seconds, as the editor timed it
}

AsepriteFrame is one frame of the file.

type AsepriteLayer

type AsepriteLayer struct {
	// Name is the layer's path: its own name, with the names of the
	// groups it sits in before it, separated by slashes.
	Name string
	// Visible is the layer's own visibility in the editor. A layer inside
	// a hidden group is left out of the composite even when this is set.
	Visible bool
	Opacity uint8 // 255 unless the file records layer opacity
	Group   bool  // a group, which holds no pixels of its own
	Level   int   // how deep in the group tree, zero at the top
	// Blend names the layer's blend mode ("normal", "multiply", and the
	// rest of the editor's list). Only normal is composited; a layer in
	// any other mode is drawn as normal.
	Blend     string
	UserData  string     // the note the editor keeps on the layer
	UserColor color.RGBA // its colour, zero when it has none
}

AsepriteLayer is one layer, in the order the file stacks them from the bottom.

type AsepriteOptions

type AsepriteOptions struct {
	// Layers packs each layer's own frames beside the composited ones,
	// for a game that draws a layer alone: a hat, a damage overlay, a
	// mask. Hidden layers are packed too, because a layer hidden in the
	// editor is often the one a game wants. It costs a packed frame per
	// layer per frame.
	Layers bool
}

AsepriteOptions selects what ParseAseprite packs.

type AsepriteSlice

type AsepriteSlice struct {
	Name      string
	Keys      []AsepriteSliceKey
	UserData  string
	UserColor color.RGBA
}

AsepriteSlice is a named rectangle drawn in the editor's slice tool, with one key per frame it changes on.

type AsepriteSliceKey

type AsepriteSliceKey struct {
	Frame  int      // the first frame the key applies to
	Bounds lin.Rect // in the sprite's pixels
	// Center is the nine-slice middle, relative to Bounds; it is zero
	// when the slice is not a nine-patch.
	Center lin.Rect
	// Pivot is the slice's pivot, relative to Bounds; it is zero when the
	// slice has none.
	Pivot lin.Vec2
}

AsepriteSliceKey is a slice's rectangle from one frame onwards.

type AsepriteTag

type AsepriteTag struct {
	Name     string
	From, To int
	// Direction is "forward", "reverse", "pingpong" or
	// "pingpong_reverse", the same names the JSON export uses.
	Direction string
	Repeat    int // how many times the editor plays it; zero means forever
	UserData  string
	UserColor color.RGBA
}

AsepriteTag is one animation tag: a range of frames and how it plays.

type Atlas

type Atlas struct {
	Tex  *Texture
	Data *AtlasData
	// contains filtered or unexported fields
}

Atlas is a texture with named regions and animation tags.

func (*Atlas) Animation

func (a *Atlas) Animation(tag string) RegionAnimation

Animation returns a tag's frames and durations as an animation that loops. An unknown tag gives an animation with no frames.

func (*Atlas) Durations

func (a *Atlas) Durations(name string) []float32

Durations returns a tag's frame durations in seconds, matching Tag.

func (*Atlas) Names

func (a *Atlas) Names() []string

Names lists the frames in file order.

func (*Atlas) Region

func (a *Atlas) Region(name string) (Region, bool)

Region returns a frame's region by name.

func (*Atlas) Tag

func (a *Atlas) Tag(name string) []Region

Tag returns a tag's frames as regions in play order, or nil for an unknown tag.

type AtlasData

type AtlasData struct {
	Frames map[string]AtlasFrame
	Order  []string            // frame names in file order
	Tags   map[string][]string // frame names per animation tag, in play order
	Image  string              // meta.image, the texture file the atlas expects
	Size   lin.Vec2            // meta.size, the texture size; zero if absent
}

AtlasData is a parsed atlas description before it is tied to a texture: TexturePacker JSON (hash or array) or Aseprite's JSON export.

func ParseAtlas

func ParseAtlas(data []byte) (*AtlasData, error)

ParseAtlas reads a TexturePacker or Aseprite JSON atlas.

func (*AtlasData) Bind

func (d *AtlasData) Bind(tex *Texture) *Atlas

Bind ties the atlas to the texture its frames index.

type AtlasFrame

type AtlasFrame struct {
	Rect     lin.Rect // pixels in the texture; for a rotated frame the packed size
	Duration float32  // seconds, from Aseprite exports; zero otherwise
	// Rotated frames are stored turned a quarter turn clockwise; Rect is
	// the packed rectangle and SourceSize the upright one.
	Rotated bool
	Trimmed bool
	// Offset is where the packed pixels sit within the untrimmed source.
	Offset     lin.Vec2
	SourceSize lin.Vec2
}

AtlasFrame is one named rectangle of a packed texture.

type Atmosphere

type Atmosphere struct {
	// Height is how deep the air is in world units. Zero means no
	// atmosphere: the sky keeps its Zenith and Horizon gradient. Density
	// falls to 1/e at a seventh of it for air and a fiftieth for haze.
	Height float32
	// PlanetRadius is the ground's distance from the planet's centre in
	// world units. It sets how far the horizon is and how long a grazing
	// ray runs through the air; zero means a hundred times Height, which
	// is Earth's proportion.
	PlanetRadius float32
	// Altitude is how far the camera is above the ground in world units.
	// Set it from the camera each frame: the air below the camera stops
	// scattering into the view as it climbs, so the sky darkens with
	// height and the horizon drops away. Zero is the ground.
	Altitude float32
	// Rayleigh is how much the air scatters per world unit at the ground,
	// by wavelength. Its zero is Earth's air scaled to Height, which is
	// what makes the sky blue and the sunset red.
	Rayleigh Color
	// Mie is how much haze scatters per world unit at the ground, the same
	// at every wavelength. It is the white glare around the sun and the
	// milkiness of a humid day; zero means Earth's haze scaled to Height.
	Mie float32
	// Forward is how strongly haze scatters along the light rather than
	// across it, 0 for even and towards 1 for a tight glare around the
	// sun; zero means 0.76.
	Forward float32
	// Intensity is the radiance of the sunlight the scattering divides up.
	// Raise it for a brighter sky without touching Light.Color; zero
	// means 22.
	Intensity float32
}

Atmosphere is the sky computed rather than described: single scattering of sunlight by air (Rayleigh) and by haze (Mie) through a shell around a planet. To use it, set Height to how deep the air is in world units and leave the rest at zero for Earth's air scaled to that depth. The sky then reddens along the horizon as the sun sets, keeps its blue overhead at noon, goes dark when the sun is below the horizon, and thins to black as Altitude climbs out of the shell, so a ship can fly from the ground to space with no seam. Distant geometry takes the same scattered light through Light.Fog's aerial perspective. Sky.Vacuum still scales the result, and Sky.Ground still lights the half below the horizon.

The model is integrated per pixel, eight samples along the view ray and four towards the sun at each, so a sky pixel costs about eighty exponentials. There is no precomputed table to load or keep in step.

type BatchItem

type BatchItem struct {
	Mesh     *Mesh
	Material Material
	Model    lin.Mat4
}

BatchItem is one draw of a static batch: a mesh, its material and where it sits in the world, exactly what DrawMesh takes.

type Billboard

type Billboard struct {
	Texture  *Texture // nil draws a flat colour
	Region   Region   // a part of the texture, for atlases and sprite sheets; zero means all of it
	Position lin.Vec3 // where the quad's centre sits, before Offset
	Size     lin.Vec2 // width and height in world units; zero means 1 by 1
	// Offset moves the quad in its own plane in units of its size: (0,
	// 0.5) puts Position at the bottom edge, for a sprite standing on
	// the ground.
	Offset lin.Vec2
	Color  Color // tint; zero means white
	// Upright turns the quad about the world's up axis only, so it stays
	// vertical when the camera looks down on it: trees, characters.
	Upright bool
	// Lit shades the quad with the scene's lights; otherwise it shows
	// its texture as it is.
	Lit bool
	// Cutout draws hard edges: alpha under half is discarded, the rest
	// writes depth and casts shadows. Otherwise the quad blends its
	// alpha over the scene, after the opaque draws.
	Cutout bool
	// OnTop draws over everything, for labels that must not be hidden.
	OnTop bool
}

Billboard is a textured quad in the 3D scene that turns to face the camera: a health bar over a unit, a name over a player, a tree or a bush in a scene that cannot afford a model, a glow around a star, a puff of smoke. It draws through the mesh path, so it is lit, fogged and shadowed like any mesh when asked to be, and many billboards with one texture become one instanced draw.

type Blend

type Blend uint8

Blend is how a draw combines with what is already there. Colours are premultiplied throughout, so these are the premultiplied equations.

const (
	BlendAlpha    Blend = iota // source over: the default
	BlendAdd                   // add light: glows, fire, particles
	BlendMultiply              // darken by the source: shadows, tinting
	BlendScreen                // the inverse of multiply: brighten
	BlendLighten               // keep the brighter of the two
	BlendDarken                // keep the darker of the two
	BlendReplace               // copy the source, ignoring what was there
	BlendErase                 // cut the source's shape out of what was there

)

func ParseBlend

func ParseBlend(s string) (Blend, bool)

ParseBlend reads a blend mode written the way String spells it, so a mode can be named in an asset file or on a console line. It reports false for anything else, leaving the caller to keep its default.

func (Blend) Options

func (b Blend) Options() BlendOptions

Options returns the equations of a built-in blend mode. The result is independent and can be edited before passing it to CustomBlended.

func (Blend) String

func (b Blend) String() string

String names the blend mode.

type BlendEquation

type BlendEquation uint8

BlendEquation combines the scaled source and destination components. Min and Max ignore their factors, as required by the graphics API.

const (
	EquationAdd             BlendEquation = iota // source plus destination
	EquationSubtract                             // source minus destination
	EquationReverseSubtract                      // destination minus source
	EquationMin                                  // smaller source/destination component
	EquationMax                                  // larger source/destination component

)

type BlendFactor

type BlendFactor uint8

BlendFactor scales a source or destination component before blending.

const (
	FactorZero             BlendFactor = iota // discard the input
	FactorOne                                 // use the input unchanged
	FactorSrcColor                            // multiply by the source colour
	FactorOneMinusSrcColor                    // multiply by one minus source colour
	FactorDstColor                            // multiply by the destination colour
	FactorOneMinusDstColor                    // multiply by one minus destination colour
	FactorSrcAlpha                            // multiply by source alpha
	FactorOneMinusSrcAlpha                    // multiply by one minus source alpha
	FactorDstAlpha                            // multiply by destination alpha
	FactorOneMinusDstAlpha                    // multiply by one minus destination alpha
	FactorSrcAlphaSaturate                    // min(source alpha, 1-destination alpha); one for alpha

)

type BlendOptions

type BlendOptions struct {
	SrcColor, DstColor BlendFactor
	ColorOp            BlendEquation
	SrcAlpha, DstAlpha BlendFactor
	AlphaOp            BlendEquation
}

BlendOptions controls colour and alpha independently. Values are literal: zero factors discard both inputs. Start with BlendAlpha.Options() for source-over defaults, then change the fields your effect needs. Colours supplied to the blend stage are premultiplied.

type Camera

type Camera struct {
	Position lin.Vec3
	Target   lin.Vec3
	Up       lin.Vec3 // zero means +Y
	FovY     float32  // radians; zero means 60 degrees
	Near     float32  // zero means 0.1
	Far      float32  // zero means 1000
	// Ortho is half the view's height in world units for an orthographic
	// camera; zero means perspective.
	Ortho float32
}

Camera looks from Position at Target: perspective with FovY, or orthographic when Ortho is set, for isometric and strategy views where distance does not shrink things.

func OrbitCamera

func OrbitCamera(target lin.Vec3, yaw, pitch, distance float32) Camera

OrbitCamera makes a camera looking at target from yaw and pitch radians at a distance, the usual control scheme for strategy and viewer cameras.

func (Camera) Frustum

func (c Camera) Frustum(aspect float32) Frustum

Frustum returns the camera's frustum for a view of the given aspect ratio (width over height).

func (Camera) Project

func (c Camera) Project(p lin.Vec3, viewW, viewH float32) (x, y float32, ok bool)

Project maps a world point to a view of the given size: where a label or a health bar for it belongs. ok is false when the point is behind the camera; a point outside the view still projects, off the edges. The view size is what Graphics.View reports, so this answers from Update as well as from Draw.

func (Camera) Projection

func (c Camera) Projection(aspect float32) lin.Mat4

Projection returns the projection matrix alone.

func (Camera) ScreenRay

func (c Camera) ScreenRay(x, y, viewW, viewH float32) Ray

ScreenRay returns the world-space ray under a point of a view of the given size (the units the mouse reports), for picking from Update.

func (Camera) ViewProj

func (c Camera) ViewProj(aspect float32) lin.Mat4

ViewProj returns the combined matrix for the given aspect ratio.

type Camera2D

type Camera2D struct {
	Position lin.Vec2
	Zoom     float32 // zero means 1
	Rotation float32
	// contains filtered or unexported fields
}

Camera2D frames a region of a 2D world: Position is the world point at the centre of the view, Zoom scales world units to view units (2 shows half as much), Rotation is radians anticlockwise. Follow, Clamp and Shake move it over time; a camera used by value is still valid, it just has no motion of its own.

func (*Camera2D) Advance

func (c *Camera2D) Advance(dt float64)

Advance steps the camera's shake by dt seconds; call it once per update. Without a shake in progress it does nothing.

func (*Camera2D) Clamp

func (c *Camera2D) Clamp(bounds lin.Rect, viewW, viewH float32)

Clamp keeps the view inside a world rectangle, so the camera stops at the edge of a level rather than showing what lies beyond it. Where the rectangle is narrower or shorter than the view, the view is centred on it along that axis. Rotation is ignored.

func (*Camera2D) Follow

func (c *Camera2D) Follow(target lin.Vec2, rate float32, dt float64)

Follow moves the camera towards a target, closing the gap at rate per second: 5 trails the player softly, 20 keeps close, and zero snaps. The motion is the same at any frame rate. Call it from Update with the step, or from Draw with the frame's time.

func (Camera2D) Matrix

func (c Camera2D) Matrix(viewW, viewH float32) lin.Mat4

Matrix returns the world-to-view transform for a view of the given size.

func (*Camera2D) Shake

func (c *Camera2D) Shake(amplitude, seconds float32)

Shake throws the view about by up to amplitude world units, fading out over seconds: an explosion, a heavy landing. A shake started while one is running takes the larger amplitude and the longer time left. Advance runs it.

func (*Camera2D) Shaking

func (c *Camera2D) Shaking() bool

Shaking reports whether a shake is in progress.

func (Camera2D) ViewToWorld

func (c Camera2D) ViewToWorld(p lin.Vec2, viewW, viewH float32) lin.Vec2

ViewToWorld maps a view point (for example the mouse) back to the world.

func (Camera2D) VisibleRect

func (c Camera2D) VisibleRect(viewW, viewH float32) lin.Rect

VisibleRect is the world-space box the camera can see, conservatively enlarged when rotated.

func (Camera2D) WorldToView

func (c Camera2D) WorldToView(p lin.Vec2, viewW, viewH float32) lin.Vec2

WorldToView maps a world point through the camera.

type CaretAffinity

type CaretAffinity uint8

CaretAffinity chooses the side of a source boundary at a wrap or bidi transition. Leading follows the next cluster; Trailing follows the previous.

const (
	CaretLeading CaretAffinity = iota
	CaretTrailing
)

type Color

type Color struct{ R, G, B, A float32 }

Color is a straight (non-premultiplied) RGBA colour in linear light, with alpha in 0..1. RGB values above 1 represent HDR radiance in lights, emissive materials and other HDR inputs; sprite colours are clamped.

func FromHSV

func FromHSV(h, s, v float32) Color

FromHSV makes an opaque colour in linear light from a hue in degrees, saturation and value in 0..1: the easy way to pick distinct team or debug colours.

func Hex

func Hex(rgb uint32) Color

Hex makes an opaque colour from 0xRRGGBB.

func RGB

func RGB(r, g, b uint8) Color

RGB makes an opaque colour from 8-bit sRGB channels.

func RGBA

func RGBA(r, g, b, a uint8) Color

RGBA makes a colour from 8-bit sRGB channels and straight alpha.

func (Color) HSV

func (c Color) HSV() (h, s, v float32)

HSV returns the hue in degrees (0..360), saturation and value (0..1) of the colour in linear light.

func (Color) Lerp

func (c Color) Lerp(d Color, t float32) Color

Lerp interpolates from c (t 0) to d (t 1), channel by channel.

func (Color) Mul

func (c Color) Mul(d Color) Color

Mul tints c by d, channel by channel: a sprite's colour times a team colour.

func (Color) Premultiplied

func (c Color) Premultiplied() Color

Premultiplied returns the colour with RGB scaled by alpha, the form the blend modes and DrawTriangles vertices use.

func (Color) Scale

func (c Color) Scale(s float32) Color

Scale brightens or darkens the colour, leaving alpha alone; values above 1 make emissive colours for bloom.

func (Color) Vec4

func (c Color) Vec4() lin.Vec4

Vec4 returns the channels as a vector, for shader uniforms.

func (Color) WithAlpha

func (c Color) WithAlpha(a float32) Color

WithAlpha returns the colour with a different alpha.

type ColorFormat

type ColorFormat int

ColorFormat is the pixel format of a render texture's colour image.

const (
	// ColorScreen is the window's own format, eight bits a channel with
	// sRGB encoding. It is the default and what a texture drawn back onto
	// the screen wants.
	ColorScreen ColorFormat = iota
	// ColorHDR is sixteen-bit floating point RGBA: values above 1 survive,
	// so a render texture can hold light rather than a tone-mapped
	// picture. Feed one to a material or grade it later.
	ColorHDR
	// ColorMask is one eight-bit channel, for a mask, a height field or a
	// coverage buffer. Only the red channel is stored; sampling it gives
	// that value in red and one in alpha.
	ColorMask
)

type ColorMatrix

type ColorMatrix struct {
	M      lin.Mat4
	Offset lin.Vec4
}

ColorMatrix recolours sprites: the straight colour goes through M and gains Offset before the alpha is put back. Build one with the constructors, compose with Mul, and set it with SetColorMatrix or ColorMatrixed; the standard sprite shader applies it. It is laid out as the shader's uniform block.

func Brightness

func Brightness(b float32) ColorMatrix

Brightness scales colours: below 1 darkens, above 1 brightens.

func ColorIdentity

func ColorIdentity() ColorMatrix

ColorIdentity leaves colours alone.

func Contrast

func Contrast(c float32) ColorMatrix

Contrast stretches colours about mid grey: 0 is flat grey, 1 unchanged.

func Grayscale

func Grayscale() ColorMatrix

Grayscale drops all colour.

func HueRotate

func HueRotate(angle float32) ColorMatrix

HueRotate turns every hue by angle radians around the grey axis.

func Invert

func Invert() ColorMatrix

Invert makes a negative.

func Saturation

func Saturation(s float32) ColorMatrix

Saturation scales colourfulness: 0 is greyscale, 1 unchanged, above 1 more vivid.

func Sepia

func Sepia() ColorMatrix

Sepia gives an old photograph's brown.

func Tint

func Tint(c Color) ColorMatrix

Tint scales each channel by a colour, like a sprite tint but after the matrix stack.

func (ColorMatrix) Apply

func (m ColorMatrix) Apply(c Color) Color

Apply runs a colour through the matrix on the CPU, for previews.

func (ColorMatrix) Mul

Mul composes matrices so that m.Mul(n) applies n first, then m.

type CompiledPath

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

CompiledPath is a path's tessellated fill and stroke stored on the GPU. It captures the path, paint coordinates and colours at compilation time, and borrows any paint textures. Keep those textures alive while drawing it. Later changes to the source Path or paint options do not change the result. Graphics owns the compiled geometry; Destroy releases it early.

func (*CompiledPath) Bounds

func (c *CompiledPath) Bounds() lin.Rect

Bounds returns the local bounds of the compiled triangles, including stroke and antialias fringes. It excludes the drawing transform and camera.

func (*CompiledPath) Destroy

func (c *CompiledPath) Destroy()

Destroy releases the compiled geometry after queued GPU work finishes. Paint textures remain owned by their creators. Repeated calls do nothing.

type Direction

type Direction uint8

Direction is the direction text runs in.

const (
	// DirectionAuto reads the text: right to left when it starts with a
	// right-to-left script (Arabic, Hebrew), left to right otherwise.
	DirectionAuto Direction = iota
	DirectionLTR
	DirectionRTL
	// DirectionTTB lays glyphs top to bottom in columns that step from
	// right to left, for vertical Japanese and Chinese.
	DirectionTTB
)

type Environment

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

Environment is distant light from every direction, for image-based lighting: metals reflect it, rough surfaces are tinted by it, and it can be drawn as the sky behind the scene. Build one from an equirectangular panorama with NewEnvironment or NewEnvironmentHDR and set it on the Light; without one the light's procedural Sky does the same job from parameters alone.

func (*Environment) Destroy

func (env *Environment) Destroy()

Destroy frees the environment. Called inside a frame it costs no wait: the cube map and its descriptor set go on the frame slot's retire list and are freed once that frame has finished.

type EnvironmentOptions

type EnvironmentOptions struct {
	// Intensity multiplies the environment's light; zero means 1. A photo
	// of an overcast day is around 1; a bright sky panorama may need more.
	Intensity float32
	// Size is the cube map's side in texels; zero means 128. Larger is
	// sharper in mirror-like reflections and slower to prepare.
	Size int
}

EnvironmentOptions tunes an environment.

type FillOptions

type FillOptions struct {
	Rule FillRule
	// Texture maps an image over the path: view point p gets texture
	// coordinate (p - TextureOrigin) / TextureSize. Zero size means the
	// path's bounds.
	Texture       *Texture
	TextureOrigin lin.Vec2
	TextureSize   lin.Vec2
	// Gradient colours the fill by position instead of a texture; the
	// colour argument then tints it.
	Gradient    *Gradient
	NoAntiAlias bool
}

FillOptions controls FillPath.

type FillRule

type FillRule uint8

FillRule decides which regions of a self-overlapping path are inside.

const (
	// FillNonZero fills where the winding number is not zero: a shape
	// drawn twice the same way stays filled.
	FillNonZero FillRule = iota
	// FillEvenOdd fills where an odd number of edges are crossed: a shape
	// inside another becomes a hole.
	FillEvenOdd
)

type Filter

type Filter uint8

Filter is how a draw samples its texture.

const (
	FilterDefault Filter = iota // the texture's own choice
	FilterNearest               // sharp pixels
	FilterLinear                // smooth
)

type Fog

type Fog struct {
	Color         Color
	Start, End    float32
	Density       float32
	Height        float32
	HeightFalloff float32
}

Fog fades geometry into a colour with distance from the camera: the cheapest way to give a scene depth and to hide the far plane. Linear fog ramps from Start to full at End; exponential fog thickens with Density (1 - exp(-(distance * Density)^2)); when both are set the denser wins. Height and HeightFalloff make ground fog: full at and below Height, thinning above it by exp(-(y - Height) * HeightFalloff), along the world's y axis. A zero End and Density means no fog. The sky is not fogged, so pick a colour near the horizon's for outdoor scenes.

type Font

type Font struct {
	Size       float32 // em size in view units
	LineHeight float32 // baseline to baseline
	Ascent     float32 // baseline to the top of the tallest glyph
	Descent    float32 // baseline to the bottom of the deepest glyph, positive
	// contains filtered or unexported fields
}

Font is an OpenType face (with optional fallbacks) rasterised into a glyph atlas at one size. Text is shaped with HarfBuzz, so kerning, ligatures, mark placement, Arabic joining and right-to-left order all come out right; glyphs are rendered from the font's outlines at the framebuffer's pixel density and drawn in view units, so text is crisp on high-DPI displays. Create fonts with NewFont or NewSDFFont; Graphics releases their atlases at shutdown, or Destroy releases one earlier. The base atlas has fixed capacity: Layout and Shape report glyphs that cannot fit. Choose FontOptions.AtlasSize for the character set and raster size the game needs. Lazy outline atlases are also owned by the font.

func (*Font) Destroy

func (f *Font) Destroy()

Destroy frees the atlas.

func (*Font) Layout

func (f *Font) Layout(text string, opts TextOptions) (*TextLayout, error)

Layout shapes and wraps text once for drawing, measurement and caret queries. Indices always address the original UTF-8 string, including paragraphs and wrapping with generated hyphens. Invalid options, exhausted atlas capacity and GPU allocation/upload failures are returned to the caller. A layout of the same text and options made recently is returned from the font's cache without laying the text out again or allocating.

func (*Font) Measure

func (f *Font) Measure(text string, opts TextOptions) (w, h float32)

Measure returns the size text takes when drawn with the options: one line with the zero options, or wrapped, spaced and sized as they say. The width is the widest line's advance and the height is the line height times the line spacing for every line; vertical text swaps the two. Measure shares the layout Layout and DrawTextBlock use, so text measured and then drawn with the same options is shaped once, and measuring the same static label every frame costs a map lookup. Text that cannot be laid out (a destroyed font, a full atlas) is measured by shaping alone.

func (*Font) Shape

func (f *Font) Shape(text string, opts TextOptions) ([]Glyph, error)

Shape lays out one line of text and returns its glyphs in visual order, for drawing them yourself with Draw and the font's Texture, or for hit-testing. This low-level operation ignores block alignment, wrapping and decorations; Layout handles those. Rasterization and upload errors are returned explicitly. The source must be one valid UTF-8 line.

func (*Font) Texture

func (f *Font) Texture() *Texture

Texture returns the glyph atlas, for drawing glyphs from Shape by hand. The atlas is written in place as glyphs are added, so the texture stays the same for the life of the font.

type FontOptions

type FontOptions struct {
	// OutlinePages limits lazy outline-atlas pages; zero allows 16. Pages
	// reuse power-of-two distance spreads, so animating width reuses them.
	OutlinePages int
	AtlasSize    int       // texture side in pixels; default 1024
	Preload      []rune    // glyphs rendered up front; ASCII is always included
	Ranges       [][2]rune // inclusive ranges rendered up front

	// Fallbacks are further TTF/OTF fonts consulted, in order, for runs of
	// text the main font has no glyphs for: a CJK or Arabic font behind a
	// Latin one, for example.
	Fallbacks [][]byte
	// Features turns OpenType features on ("smcp", "frac", "ss01") or off
	// ("-liga", "-kern") for all text drawn with the font.
	Features []string
	// Variations sets variable font axes, such as "wght": 650 or "wdth": 90.
	Variations map[string]float32
}

FontOptions tunes a font.

type FrameStats

type FrameStats struct {
	Draws2D    int // 2D draw calls after batching
	Vertices2D int // 2D vertices drawn
	Draws3D    int // mesh draw calls after instancing, all passes
	Instances  int // mesh instances drawn in the main pass
	Culled     int // mesh draws outside the camera's view, skipped in the main pass
	// Occluded counts the mesh draws inside the camera's view that the
	// software occlusion buffer found behind an occluder, which is a
	// subset of Culled. It is zero in a frame with no AddOccluder3D.
	Occluded int
	// CullTests counts the bounding volume tests culling ran: one per
	// queued draw, plus one per hierarchy node a static batch visited.
	// A batch shows up as far fewer tests than it holds items.
	CullTests int
	// ShadowDraws counts the mesh instances recorded into the shadow maps,
	// summed over the cascades, the shadowed spot lights and the cube
	// faces of the shadowed point lights. A caster is only recorded into
	// the maps its bounds reach, so this falls as lights and casters
	// spread out.
	ShadowDraws int
	// Culled2D counts sprites and glyphs outside the view, or outside the
	// 2D camera's view under a camera, that were dropped before reaching
	// the vertex stream.
	Culled2D int
	// Lights2DDropped counts the lights passed to SetLights2D past the
	// eighth, which lit sprites are not lit by; a nonzero count means the
	// game should pass its nearest lights first.
	Lights2DDropped int
	// LightsDropped counts point and spot lights added past MaxLights,
	// which a frame keeps none of; a nonzero count means the scene should
	// add its nearest lights first.
	LightsDropped int
	// Waits counts the times the frame stopped and waited for the GPU to
	// go idle. Uploads and destroys inside a frame go through the staging
	// arena and the retire ring, and every per-frame buffer grows through
	// the retire ring too, so a running game reports zero; a nonzero
	// count means something stalled the whole pipeline, such as a
	// Texture.Read or a resource destroyed outside a frame.
	Waits int
	// Lights counts the point and spot lights the frame kept, out of
	// MaxLights, whatever part of the view each one reaches. The
	// directional light is not counted: every frame has one.
	Lights int
	// Particles counts the instances drawn by DrawParticles and
	// DrawParticles3D. Each batch is one draw call however many
	// instances it holds, counted in Draws2D or Draws3D.
	Particles int
	// ProbesDropped counts reflection probes added past MaxProbes, which
	// a frame keeps none of.
	ProbesDropped int
	// GPU is how long the GPU spent in each pass, in the order the passes
	// were recorded: the shadow atlas, the opaque and blended scene, the
	// reflections, the decals, bloom, ambient occlusion, the composite,
	// the anti-alias resolve and the 2D stream. A pass that runs for a
	// render texture as well as the screen is summed into one entry. It is
	// empty on a device without timestamp queries or before results arrive.
	// Available queries can still report zero durations when the device's
	// timestamp resolution cannot distinguish the pass endpoints. MoltenVK
	// without Metal counter sampling can report zero for every pass. The
	// figures come from queries read back without waiting, so they describe
	// a frame two frames back, and the slice is reused every frame; copy it
	// to keep it.
	GPU []GPUSpan
	// GPUFrameMS is the GPU time from the frame's first pass to the end
	// of its last, so it covers the gaps between passes as well. It is zero
	// when no results are available or the timestamps cannot resolve a
	// duration, including on some devices that emulate timestamp queries.
	GPUFrameMS float64
}

FrameStats counts what a frame cost the GPU, for the debug overlay and a draw-call budget.

type Frustum

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

Frustum is the volume a camera sees, as six planes facing inward. The engine culls every mesh draw against the camera's frustum on its own; a game uses one to skip whole chunks, regions or units before it asks to draw them, which saves the work of building their draws at all.

func FrustumOf

func FrustumOf(viewProj lin.Mat4) Frustum

FrustumOf extracts the frustum of a view-projection matrix.

func (Frustum) ContainsBox

func (f Frustum) ContainsBox(min, max lin.Vec3) bool

ContainsBox reports whether any of an axis-aligned box lies inside the frustum. It errs on the side of visible: a box near a corner may pass while being just outside, which only costs a draw.

func (Frustum) ContainsPoint

func (f Frustum) ContainsPoint(p lin.Vec3) bool

ContainsPoint reports whether a point lies inside the frustum.

func (Frustum) ContainsSphere

func (f Frustum) ContainsSphere(centre lin.Vec3, radius float32) bool

ContainsSphere reports whether any of a sphere lies inside the frustum.

type GPUSpan

type GPUSpan struct {
	Name string
	MS   float64
}

GPUSpan is one pass of a frame and the milliseconds the GPU spent in it, as FrameStats.GPU reports it.

type Geometry2D

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

Geometry2D is reusable triangle geometry in GPU memory. DrawGeometry places it in the ordinary 2D queue with the current transform, camera, layer, sort key, clip, blend and shader. Graphics owns its lifetime; Destroy releases it early. Its zero value cannot be drawn or updated.

func (*Geometry2D) Bounds

func (m *Geometry2D) Bounds() lin.Rect

Bounds returns the local axis-aligned bounds of all uploaded vertices, including unused vertices. It excludes the graphics transform and camera.

func (*Geometry2D) Destroy

func (m *Geometry2D) Destroy()

Destroy releases this geometry after queued and in-flight draws finish. Repeated calls do nothing. Later DrawGeometry calls with it draw nothing.

func (*Geometry2D) Update

func (m *Geometry2D) Update(vertices []Vertex2D, indices []uint32) error

Update replaces the geometry. Draws already queued keep the previous version until their GPU work finishes. Failure leaves the old data intact.

type Glyph

type Glyph struct {
	Pos      lin.Vec2 // top-left of the glyph image
	Size     lin.Vec2
	UV0, UV1 lin.Vec2 // region of the font's Texture
	Index    int      // index of the first byte of its text in the string
	// Advance is how far the pen moves after the glyph, in view units at
	// the font's own size, for caret positions and hit-testing. It is the
	// line height for vertical text.
	Advance float32
	Empty   bool // no image (a space)
	Color   bool // a colour glyph such as an emoji, drawn untinted
}

Glyph is one positioned glyph from Shape: where to draw a piece of the atlas relative to the text's origin (the pen at the start of the baseline), in view units at the font's size.

type Gradient

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

Gradient colours a fill or stroke by position: linear from one point to another, or radial out from a centre. Graphics releases its small texture at shutdown, or Destroy releases it earlier.

func (*Gradient) Destroy

func (gr *Gradient) Destroy()

Destroy frees the gradient's texture.

func (*Gradient) Linear

func (gr *Gradient) Linear(from, to lin.Vec2) *Gradient

Linear runs the gradient from one point to another, in the units of the drawing it is used in; beyond the ends the end colours hold.

func (*Gradient) Radial

func (gr *Gradient) Radial(center lin.Vec2, radius float32) *Gradient

Radial runs the gradient out from a centre to a radius.

type GradientStop

type GradientStop struct {
	T     float32
	Color Color
}

GradientStop is a colour at a position along a gradient, 0 to 1.

type Graphics

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

Graphics is the drawing context for one window. The engine opens a frame, the Draw* calls queue work, and the engine submits it. Obtain Graphics from engine.Context; its zero value is not usable. Use it and its GPU resources only on the game goroutine. Graphics owns every GPU resource it creates and releases it when the engine closes, including when game setup or drawing fails. Call a resource's Destroy method to release it earlier, for example when unloading a level.

GPU resources belong to the Graphics that created them. Passing resources from another output to drawing or state methods panics before recording their handles. Constructors and transfer methods with error results return errors instead; text drawing reports invalid font ownership at submission.

func (*Graphics) AddOccluder2D

func (g *Graphics) AddOccluder2D(points ...lin.Vec2)

AddOccluder2D adds a shadow caster for this frame: a closed polygon in the same units as sprite positions, which is world units under a 2D camera. Lights given Shadows in SetLights2D are blocked by it, and every DrawLit sprite in the frame sees the same set. Two points make a single wall segment; fewer than two are ignored. Occluders are cleared at the start of each frame, like the lights, so a game adds them every frame. The cost is the occluder's edges times the shadowed lights, computed on the CPU, so a few hundred edges are free and tens of thousands are not.

func (*Graphics) AddOccluder3D

func (g *Graphics) AddOccluder3D(m *Mesh, model lin.Mat4)

AddOccluder3D marks a mesh as blocking the camera's view for this frame: a wall, a hill, a building's shell. The engine rasterises the frame's occluders into a small depth buffer on the CPU and skips the draws that lie entirely behind them, which the frustum test cannot do; FrameStats.Occluded counts them and they still cast shadows. Adding an occluder does not draw it, so draw the mesh as well, or add a coarse stand-in for geometry that is drawn in detail. Occluders are cleared at the end of the frame, like lights. Keep them few and low-poly: every triangle is rasterised on the CPU, and a mesh with more than MaxOccluderTriangles triangles is ignored.

func (*Graphics) AddOccluder3DAt

func (g *Graphics) AddOccluder3DAt(m *Mesh, t Transform)

AddOccluder3DAt is AddOccluder3D with a Transform.

func (*Graphics) AddPoint

func (g *Graphics) AddPoint(p PointLight)

AddPoint adds a point light for this frame.

func (*Graphics) AddPointLight

func (g *Graphics) AddPointLight(pos lin.Vec3, c Color, rng float32)

AddPointLight adds a light shining from a point in every direction for this frame, fading to nothing rng units away: torches, muzzle flashes, glowing ore. A frame keeps its first 1024 point and spot lights (MaxLights); add the nearest ones first when a scene has more.

func (*Graphics) AddProbe

func (g *Graphics) AddProbe(p *ReflectionProbe)

AddProbe adds a reflection probe for this frame. Draws inside its volume reflect it; a frame keeps its first MaxProbes probes and counts the rest in FrameStats.ProbesDropped. A probe that has not been baked is ignored.

func (*Graphics) AddSpot

func (g *Graphics) AddSpot(s SpotLight)

AddSpot adds a spot light for this frame.

func (*Graphics) AddSpotLight

func (g *Graphics) AddSpotLight(pos, dir lin.Vec3, c Color, rng, innerAngle, outerAngle float32)

AddSpotLight adds a light shining from a point along dir in a cone, fading to nothing rng units away: flashlights, headlights, stage lights. The cone is full inside innerAngle and fades to nothing at outerAngle (both full angles in radians; a zero inner angle means a hard-edged cone, a zero outer angle means 45 degrees). Spot lights count against the same limit as point lights.

func (*Graphics) BakeImpostor

func (g *Graphics) BakeImpostor(m *Model, opts ImpostorOptions) (*Impostor, error)

BakeImpostor renders a model from a ring of directions around it into one atlas texture, which DrawImpostor then draws as a billboard. Call it from Init or Update, never from Draw: it runs a frame of its own to render the views and reads them back, so it costs one stall and must not be nested inside the game's frame.

The colour of each view comes from the model with its own materials, and its shape from a second pass that draws the model unlit and white, so the atlas is a hard cutout with no background bleeding into it. A model or material resource from another Graphics returns an error.

func (*Graphics) BakeLightProbes

func (g *Graphics) BakeLightProbes(grid *LightProbeGrid, scene func()) error

BakeLightProbes renders the scene from every cell of the grid and projects what it sees onto spherical harmonics. Call it from Init or Update, not from Draw: it submits its own command buffers and waits for them, once for every four cells. The scene function queues the draws and lights the bake sees, exactly as Draw would; it is called once for each face rendered together, up to 24 times, so it must queue the same scene every time. Baking again replaces the harmonics.

func (*Graphics) BakeProbe

func (g *Graphics) BakeProbe(p *ReflectionProbe, scene func()) error

BakeProbe renders the scene from the probe's position into a cube map and prefilters it for every roughness. Call it from Init or Update, not from Draw: it submits its own command buffer and waits for it, once for all six faces. The scene function queues the draws and lights the bake sees, exactly as Draw would, and the engine sets the camera for each of the six faces. It is called once for each face, so it must queue the same scene every time. A second call rebakes the probe and frees what the first one made.

func (*Graphics) Blend

func (g *Graphics) Blend() Blend

Blend returns the current built-in 2D blend mode. CustomBlended temporarily overrides its equations without changing this value.

func (*Graphics) Blended

func (g *Graphics) Blended(b Blend, draw func())

Blended runs draw with the blend mode set, then restores the original queue's mode, including when draw panics.

func (*Graphics) Camera2D

func (g *Graphics) Camera2D() (Camera2D, bool)

Camera2D returns the active 2D camera and whether one is set.

func (*Graphics) ClearStencil

func (g *Graphics) ClearStencil(value uint8)

ClearStencil queues a stencil-only clear in the current view and clips. Drawing before and after it cannot reorder across the clear, even when their layers or sort keys differ. Colour and depth remain unchanged. It panics if the target has no stencil attachment.

func (*Graphics) Clip

func (g *Graphics) Clip(r lin.Rect, draw func())

Clip runs draw clipped to r intersected with the enclosing clip, then restores the original queue's clip stack, including when draw panics.

func (*Graphics) ColorMatrixed

func (g *Graphics) ColorMatrixed(m ColorMatrix, draw func())

ColorMatrixed runs draw with the matrix set, then restores the original queue's matrix, including when draw panics.

func (*Graphics) CompileMeshShader

func (g *Graphics) CompileMeshShader(ctx context.Context, source string) (*Shader, error)

CompileMeshShader compiles Bunyip mesh WGSL source and creates an owned GPU shader. The source defines fn surface(s: Surface) -> Surface and may define finish and vertex hooks. All required lit, transparency and vertex variants are compiled together. Compiler requirements and threading are the same as CompileShader. See the shader guide for hook signatures and engine bindings.

func (*Graphics) CompilePath

func (g *Graphics) CompilePath(path *Path, opts PathOptions) (*CompiledPath, error)

CompilePath tessellates a path once using opts, independently of current graphics state. DrawPath applies the current transform, camera, clipping, layer, blend and shader. Empty paths compile successfully and draw nothing. Paint textures and gradients must belong to this Graphics; foreign paints return an error before any geometry is uploaded.

func (*Graphics) CompileShader

func (g *Graphics) CompileShader(ctx context.Context, source string) (*Shader, error)

CompileShader compiles Bunyip sprite WGSL source and creates an owned GPU shader. The source defines fn fragment(uv: vec2f, color: vec4f) -> vec4f; the engine supplies bindings and the entry point. Compilation uses Go only. This synchronous method belongs on the game goroutine, like NewShader. Cancellation is checked between compilation phases, not during a phase or GPU creation. To compile on a worker, use shaders.Compiler.Compile, then call NewShader on the game goroutine.

func (*Graphics) ConfigurePost

func (g *Graphics) ConfigurePost(edit func(*PostSettings))

ConfigurePost edits a copy of the current global post-processing settings and commits it when edit returns normally. A panic leaves the settings unchanged unless edit changed them directly. Numeric zero is kept as supplied; fields not edited retain their current values. Like SetPost, the result applies to the screen and all render textures when the frame submits. Do not retain the pointer passed to edit.

func (*Graphics) CustomBlended

func (g *Graphics) CustomBlended(options BlendOptions, draw func())

CustomBlended runs 2D drawing with explicit blend equations, restoring the original queue's blend state even on panic. It includes geometry and flat particles. Invalid factors or equations panic before drawing.

func (*Graphics) DebugFont

func (g *Graphics) DebugFont() *Font

DebugFont is the engine's built-in font, 14 view units tall, for overlays and tools; nil when it could not be made.

func (*Graphics) DebugText

func (g *Graphics) DebugText(x, y float32, text string)

DebugText draws a line of text in the engine's own font with a dark shadow, so a value can go on screen without loading a font first.

func (*Graphics) DebugText3D

func (g *Graphics) DebugText3D(p lin.Vec3, text string)

DebugText3D draws debug text at a world position, projected to the view: an entity's id over its head, a value beside a probe. Points behind the camera draw nothing.

func (*Graphics) Debugf

func (g *Graphics) Debugf(x, y float32, format string, args ...any)

Debugf is DebugText with a format string.

func (*Graphics) Draw

func (g *Graphics) Draw(tex *Texture, s Sprite)

Draw queues a sprite. A nil texture draws with a 1x1 white texture, so a coloured rectangle is a tinted sprite. A sprite wholly outside the view, or outside the 2D camera's view under a camera, is dropped and counted in FrameStats.Culled2D.

Example
package main

import (
	"image"

	"github.com/matjam/bunyip/gfx"
	"github.com/matjam/bunyip/lin"
)

// The Graphics value comes from engine.Context.Gfx inside a game's Init
// and Draw; these examples show the calls a game makes with it.
var (
	g   *gfx.Graphics
	img image.Image
)

func main() {
	tex, err := g.NewTexture(img, gfx.TextureOptions{Linear: true})
	if err != nil {
		return
	}
	defer tex.Destroy()
	// A sprite is a rectangle with a texture window and a tint.
	g.Draw(tex, gfx.Sprite{Pos: lin.V2(100, 80), Size: lin.V2(64, 64), UV1: lin.V2(1, 1), Color: gfx.White})
	g.DrawTexture(tex, 200, 80) // at the texture's own size
	g.FillRect(0, 0, 320, 4, gfx.RGB(255, 200, 40))
}

func (*Graphics) DrawAxes

func (g *Graphics) DrawAxes(m lin.Mat4, size float32)

DrawAxes draws a transform's x, y and z axes in red, green and blue, each size units long.

func (*Graphics) DrawBatch

func (g *Graphics) DrawBatch(b *StaticBatch)

DrawBatch queues the items of a static batch the camera can see. The hierarchy is walked when the frame's draws are prepared, so occluders added after this call still cull it, and the items that survive are ordinary draws: instanced together, sorted, shadowed and lit like any others. Items the camera cannot see but a shadow map can are queued for the shadow pass alone, so they cast shadows as culled DrawMesh draws do.

func (*Graphics) DrawBillboard

func (g *Graphics) DrawBillboard(b Billboard)

DrawBillboard draws a camera-facing quad in the scene.

func (*Graphics) DrawDecal

func (g *Graphics) DrawDecal(tex *Texture, box lin.Mat4, tint Color)

DrawDecal projects a texture onto whatever geometry lies inside a box: bullet holes, blood, footprints, road markings. box maps the unit cube to the world; the texture is projected along the box's y axis, its x and z spanning the image, and fades on surfaces facing away from it.

func (*Graphics) DrawFrame

func (g *Graphics) DrawFrame(sheet *Sheet, frame int, s Sprite)

DrawFrame draws one frame of a sheet with the sprite's placement; the sprite's UV fields are filled in and a zero Size means the frame size.

func (*Graphics) DrawGeometry

func (g *Graphics) DrawGeometry(tex *Texture, geometry *Geometry2D)

DrawGeometry queues a GPU-resident geometry version without copying its vertices. A nil texture means white. Nil, empty or destroyed geometry draws nothing. Geometry and textures must belong to this Graphics context.

func (*Graphics) DrawGlyphs

func (g *Graphics) DrawGlyphs(f *Font, glyphs []Glyph, x, y, scale float32, c Color)

DrawGlyphs draws glyphs from Shape with the text's origin at (x, y), scaled by scale (1, or zero, for the font's own size).

func (*Graphics) DrawImpostor

func (g *Graphics) DrawImpostor(im *Impostor, pos lin.Vec3, yaw float32, tint Color)

DrawImpostor draws the baked view nearest the camera as a quad at pos, with the model turned by yaw radians about the world's up axis. A zero tint means white. The quad is a cutout, so it writes depth and casts shadows like the model it stands for.

func (*Graphics) DrawIndexed

func (g *Graphics) DrawIndexed(tex *Texture, verts []Vertex2D, indices []uint32)

DrawIndexed queues textured triangles from vertices and indices, three indices per triangle, for meshes whose vertices are shared.

func (*Graphics) DrawLOD

func (g *Graphics) DrawLOD(l *LOD, mat Material, model lin.Mat4)

DrawLOD draws the level of detail for the model's distance from the frame's camera, with a material and model matrix like DrawMesh.

func (*Graphics) DrawLODAt

func (g *Graphics) DrawLODAt(l *LOD, mat Material, t Transform)

DrawLODAt is DrawLOD with a Transform.

func (*Graphics) DrawLine3D

func (g *Graphics) DrawLine3D(a, b lin.Vec3, c Color)

DrawLine3D draws a one-pixel line between two world points, on top of everything: for seeing colliders, paths, rays and bones while a game is being written. Lines ignore depth so nothing hides them.

func (*Graphics) DrawLit

func (g *Graphics) DrawLit(tex, normal *Texture, s Sprite)

DrawLit draws a sprite lit by the SetLights2D lights through a tangent-space normal map (a texture made with TextureOptions.Data), so a flat sprite catches light from the side a torch is on. Lights that cast shadows are blocked by the occluders AddOccluder2D added this frame.

func (*Graphics) DrawMesh

func (g *Graphics) DrawMesh(m *Mesh, mat Material, model lin.Mat4)

DrawMesh queues a mesh with a material and a model matrix. Draws that share a mesh and material become one instanced draw call; blended materials draw after everything opaque, farthest first.

Example
package main

import (
	"image"

	"github.com/matjam/bunyip/gfx"
	"github.com/matjam/bunyip/lin"
)

// The Graphics value comes from engine.Context.Gfx inside a game's Init
// and Draw; these examples show the calls a game makes with it.
var g *gfx.Graphics

func main() {
	verts, indices := gfx.CubeMesh()
	cube, err := g.NewMesh(verts, indices)
	if err != nil {
		return
	}
	defer cube.Destroy()
	g.SetCamera(gfx.OrbitCamera(lin.V3(0, 0, 0), 0.6, 0.4, 6))
	g.SetLight(gfx.Light{Direction: lin.V3(-0.4, -1, -0.5), Color: gfx.Color{R: 2, G: 2, B: 1.8, A: 1}, Shadows: true})
	g.DrawMeshAt(cube, gfx.Material{BaseColor: gfx.RGB(200, 80, 60), Roughness: 0.5}, gfx.At(0, 0, 0).Rotated(lin.V3(0, 1, 0), 0.7))
}

func (*Graphics) DrawMeshAt

func (g *Graphics) DrawMeshAt(m *Mesh, mat Material, t Transform)

DrawMeshAt draws a mesh at a transform.

func (*Graphics) DrawMeshMoved

func (g *Graphics) DrawMeshMoved(m *Mesh, mat Material, model, prev lin.Mat4)

DrawMeshMoved is DrawMesh for a mesh that moved: prev is the model matrix it was drawn with last frame. The velocity buffer carries the difference, so temporal anti-aliasing reprojects the mesh instead of smearing it and motion blur smears it along its own path. Drawing through DrawMesh says the mesh did not move, which is what a static scene wants; the camera's own motion is reconstructed from depth either way.

func (*Graphics) DrawModel

func (g *Graphics) DrawModel(m *Model, world lin.Mat4)

DrawModel queues every part of the model under a world transform, each with the material its file gave it and its current morph pose.

func (*Graphics) DrawModelAnimated

func (g *Graphics) DrawModelAnimated(m *Model, t Transform, p *AnimPlayer)

DrawModelAnimated draws a model under a transform with the player's pose: node-animated parts move rigidly, skinned parts deform and morph targets blend to the player's weights. Each draw captures its morph pose, so players sharing a model can draw different expressions.

func (*Graphics) DrawModelAnimatedMoved

func (g *Graphics) DrawModelAnimatedMoved(m *Model, t, prev Transform, p *AnimPlayer, override MaterialOverride)

DrawModelAnimatedMoved is DrawModelAnimatedWith for a model that moved: prev is the transform it was drawn with last frame, which the velocity buffer carries for temporal anti-aliasing and motion blur. The pose's own motion is not carried; see DrawSkinnedMoved.

func (*Graphics) DrawModelAnimatedWith

func (g *Graphics) DrawModelAnimatedWith(m *Model, t Transform, p *AnimPlayer, override MaterialOverride)

DrawModelAnimatedWith is DrawModelAnimated with a material override, so a posed character can be drawn in a team colour or with one part swapped. A nil override draws the file's materials.

func (*Graphics) DrawModelAt

func (g *Graphics) DrawModelAt(m *Model, t Transform)

DrawModelAt draws a model at a transform.

func (*Graphics) DrawModelImpostor

func (g *Graphics) DrawModelImpostor(m *Model, im *Impostor, t Transform)

DrawModelImpostor draws the model while the camera is inside the impostor's Distance and the impostor beyond it, which is a level of detail whose far level costs one quad. A nil impostor draws the model at any distance, and a nil model draws the impostor at any distance, so a game can bake lazily and still call this every frame.

func (*Graphics) DrawModelMoved

func (g *Graphics) DrawModelMoved(m *Model, world, prev lin.Mat4, override MaterialOverride)

DrawModelMoved is DrawModelWith for a model that moved: prev is the world transform it was drawn with last frame, which the velocity buffer carries for temporal anti-aliasing and motion blur.

func (*Graphics) DrawModelWith

func (g *Graphics) DrawModelWith(m *Model, world lin.Mat4, override MaterialOverride)

DrawModelWith queues every part of the model under a world transform, passing each part through override to decide the material it is drawn with: one material for the whole model, a different one for a named part, or the file's own material with a field changed. A nil override is DrawModel.

gr.DrawModelWith(ship, world, func(i int, p gfx.ModelPart) gfx.Material {
	if p.Name == "hull" {
		m := p.Material
		m.BaseColor = team
		return m
	}
	return p.Material
})

func (*Graphics) DrawNineSlice

func (g *Graphics) DrawNineSlice(ns NineSlice, r lin.Rect, tint Color)

DrawNineSlice draws a nine-slice stretched over r while keeping its corners at their pixel size; a zero tint means white.

func (*Graphics) DrawParticles

func (g *Graphics) DrawParticles(tex *Texture, quads []ParticleQuad)

DrawParticles queues a batch of 2D particles as one instanced draw, for the very large counts a sprite-by-sprite path cannot afford. A nil texture draws plain quads. The batch takes the queue's current layer and blend mode, and draws in the same place a sprite drawn at that point would: by layer first, then by the order the calls were made. A sort key set with SetSortKey orders sprites within a layer but not particle batches, which keep their call order.

The slice is copied into this frame's instance buffer, so it may be reused as soon as the call returns. Particles are drawn in the order given, without depth sorting, which is what additive effects want; for alpha-blended particles that overlap, order the slice yourself.

func (*Graphics) DrawParticles3D

func (g *Graphics) DrawParticles3D(tex *Texture, quads []ParticleQuad, opts Particles3D)

DrawParticles3D queues a batch of camera-facing particles in the 3D scene as one instanced draw: smoke, embers, snow, magic. A nil texture draws plain quads. Positions and sizes are in world units.

The particles are drawn over the finished scene, after decals, and are hidden by geometry in front of them; opts.Soft fades them out as they approach it. They are neither depth sorted against each other nor lit, so additive and unlit effects suit them best. The slice is copied, so it may be reused as soon as the call returns.

func (*Graphics) DrawPath

func (g *Graphics) DrawPath(path *CompiledPath)

DrawPath queues a compiled path's fill followed by its stroke. Nil or destroyed compiled paths draw nothing. It performs no tessellation or vertex upload, and uses the same drawing state as DrawGeometry.

func (*Graphics) DrawRegion

func (g *Graphics) DrawRegion(r Region, s Sprite)

DrawRegion draws a region with the sprite's placement; the sprite's UVs are taken from the region, and a zero Size means the region's own.

func (*Graphics) DrawRichText

func (g *Graphics) DrawRichText(fonts RichFonts, text RichText, x, y float32, opts TextOptions, tint Color) []RichLink

DrawRichText draws a styled block through the common text layout and returns its link rectangles translated to the drawing origin. A zero tint is white; explicit run colours multiply tint. Layout and upload failures are reported by frame submission, as with DrawTextBlock.

func (*Graphics) DrawSkinned

func (g *Graphics) DrawSkinned(m *Mesh, mat Material, model lin.Mat4, joints []lin.Mat4)

DrawSkinned draws a skinned mesh with explicit joint matrices (one per joint, already multiplied by the inverse bind matrices).

func (*Graphics) DrawSkinnedMoved

func (g *Graphics) DrawSkinnedMoved(m *Mesh, mat Material, model, prev lin.Mat4, joints []lin.Mat4)

DrawSkinnedMoved is DrawSkinned for a mesh that moved: prev is the model matrix it was drawn with last frame. The motion vectors it produces carry the model matrix's motion only, not the pose's, so a character walking across the screen reprojects correctly while an arm swinging in place does not.

func (*Graphics) DrawTerrain

func (g *Graphics) DrawTerrain(t *Terrain)

DrawTerrain queues every chunk of a terrain at the resolution its distance from the frame's camera deserves. Chunks are ordinary mesh draws, so the frustum and the frame's occluders cull them and ChunkLevel reports what each was drawn at.

func (*Graphics) DrawText

func (g *Graphics) DrawText(f *Font, text string, x, y float32, c Color)

DrawText draws one line with its top-left corner at (x, y).

func (*Graphics) DrawText3D

func (g *Graphics) DrawText3D(f *Font, text string, pos lin.Vec3, scale float32, c Color, onTop bool, opts TextOptions)

DrawText3D draws a line of text in the scene facing the camera, its origin at pos, scale world units per view unit of the font (a 32 unit font at 0.02 stands about 0.64 units tall). The text is centred on pos and drawn on top of the scene when onTop is set; opts gives alignment and size as for DrawText. Each glyph is a billboard, so a label is one instanced draw.

func (*Graphics) DrawTextBlock

func (g *Graphics) DrawTextBlock(f *Font, text string, x, y float32, opts TextOptions, c Color)

DrawTextBlock draws wrapped, aligned text with its top-left at (x, y), or its first baseline there with Baseline set. With a Width, alignment is within that width; without, lines align to x. Size scales the text and Angle rotates it about (x, y). Vertical text runs down from (x, y) in columns stepping left, so x is the right edge.

func (*Graphics) DrawTextLayout

func (g *Graphics) DrawTextLayout(l *TextLayout, x, y float32, tint Color)

DrawTextLayout draws a reusable layout at its origin. Zero tint is white. Tint multiplies explicit rich colours; runs without a colour use tint. Colour glyphs retain RGB and use the effective alpha. A nil layout is a no-op. Invalid fonts or upload failures are reported by frame submission.

func (*Graphics) DrawTextOnPath

func (g *Graphics) DrawTextOnPath(f *Font, text string, p *Path, offset float32, opts TextOptions, c Color)

DrawTextOnPath lays one line of text along a path, each glyph turned to follow it, starting offset units from the path's start: labels on arcs, text around a badge, a river's name along its course. Glyphs past the end of the path are not drawn; only the path's first sub-path is used.

func (*Graphics) DrawTexture

func (g *Graphics) DrawTexture(tex *Texture, x, y float32)

DrawTexture queues a texture at its own size.

func (*Graphics) DrawTilemap

func (g *Graphics) DrawTilemap(t *Tilemap, x, y float32, tint Color)

DrawTilemap draws the map with its top-left at (x, y), skipping tiles outside the view, or outside the active 2D camera's view under a camera. The view is taken back through the transform stack into the map's own units, so a scrolled, scaled or rotated map only visits the tiles that can be seen.

func (*Graphics) DrawTo

func (g *Graphics) DrawTo(rt *RenderTexture, clear Color, draw func())

DrawTo runs draw with the render texture as the output; every Draw*, SetCamera and SetLight call inside it lands on the texture. The texture is rendered before the main frame, so it can be drawn in the same frame. A second DrawTo on the same texture in one frame adds to what the first queued, with the first call's clear colour. Camera and lighting state belong to the target; post-processing is global and uses the final SetPost settings when the frame submits. The previous output is restored even when draw panics; drawing already queued is not rolled back. This call does not submit GPU work itself. A render texture from another Graphics panics before switching output or invoking draw.

Example
package main

import (
	"image"

	"github.com/matjam/bunyip/gfx"
)

// The Graphics value comes from engine.Context.Gfx inside a game's Init
// and Draw; these examples show the calls a game makes with it.
var g *gfx.Graphics

func main() {
	rt, err := g.NewRenderTexture(256, 256)
	if err != nil {
		return
	}
	defer rt.Destroy()
	rt.SetView(256, 256)
	g.DrawTo(rt, gfx.Black, func() {
		g.FillRect(64, 64, 128, 128, gfx.RGB(90, 200, 255))
	})
	g.DrawTexture(rt.Texture(), 16, 16) // the render texture is an ordinary texture now
}

func (*Graphics) DrawTriangles

func (g *Graphics) DrawTriangles(tex *Texture, verts []Vertex2D)

DrawTriangles queues textured triangles: three vertices each, with positions in view units, texture coordinates in 0..1 and a tint. It is the primitive under sprites and paths, for games that build their own geometry.

func (*Graphics) DrawWireBox

func (g *Graphics) DrawWireBox(min, max lin.Vec3, c Color)

DrawWireBox outlines the axis-aligned box between two corners.

func (*Graphics) DrawWireCube

func (g *Graphics) DrawWireCube(m lin.Mat4, c Color)

DrawWireCube outlines the unit cube (corners at ±0.5) under a matrix: an oriented box, the shape of a Box3 collider.

func (*Graphics) DrawWireFrustum

func (g *Graphics) DrawWireFrustum(cam Camera, aspect float32, c Color)

DrawWireFrustum outlines what a camera sees, for the given aspect ratio: another camera's view, a light's shadow box, a culling volume being debugged.

func (*Graphics) DrawWireSphere

func (g *Graphics) DrawWireSphere(center lin.Vec3, radius float32, c Color)

DrawWireSphere outlines a sphere as three great circles.

func (*Graphics) FillCircle

func (g *Graphics) FillCircle(cx, cy, r float32, c Color)

FillCircle fills a circle.

func (*Graphics) FillGradient

func (g *Graphics) FillGradient(r lin.Rect, gr *Gradient)

FillGradient fills a rectangle with a gradient.

func (*Graphics) FillPath

func (g *Graphics) FillPath(p *Path, c Color, opts FillOptions)

FillPath fills the path's interior with a colour.

func (*Graphics) FillPolygon

func (g *Graphics) FillPolygon(points []lin.Vec2, c Color)

FillPolygon fills a polygon through the points.

func (*Graphics) FillRect

func (g *Graphics) FillRect(x, y, w, h float32, c Color)

FillRect queues a solid rectangle.

func (*Graphics) Frustum

func (g *Graphics) Frustum() Frustum

Frustum returns the frustum of the camera set for this frame, for the current view's aspect ratio.

func (*Graphics) Layer

func (g *Graphics) Layer() int

Layer returns the current sprite layer.

func (*Graphics) Layered

func (g *Graphics) Layered(layer int, draw func())

Layered runs draw on layer, then restores the original queue's layer, including when draw panics. Drawing already queued is not undone.

func (*Graphics) LoadModel

func (g *Graphics) LoadModel(doc *gltf.Document) (*Model, error)

LoadModel uploads a parsed glTF document.

func (*Graphics) Masked

func (g *Graphics) Masked(mask, draw func())

Masked draws only where mask rasterizes fragments, composing up to eight nested masks. Mask drawing writes no colour. Transparent fragments still mark coverage unless their shader discards them; use an opaque shape or a shader that discards outside the desired mask.

Setup, mask, body and cleanup are separate ordering groups. Layers and sort keys order within each group, so callbacks may change either safely. Masked restores the original stencil, layer and sort key even on panic; queued draws remain queued. It temporarily uses one low stencil bit per nesting level, clears that bit afterward, and preserves all other bits. Advanced Stenciled state is suspended during the mask and then restored. A helper using Masked may also be called from mask: its clipped drawing contributes to the enclosing mask's coverage without writing colour. A depthless target or more than eight nested masks panic before mutation.

func (*Graphics) MaxSamples

func (g *Graphics) MaxSamples() int

MaxSamples is the highest sample count PostSettings.Samples and RenderTextureOptions.Samples accept on this GPU: 1 when it cannot multisample at all, and usually 8.

func (*Graphics) NewBlankTexture

func (g *Graphics) NewBlankTexture(width, height int, opts TextureOptions) (*Texture, error)

NewBlankTexture makes a transparent texture of a size, to be filled by Write: a canvas to paint on, a video frame, a procedural map.

func (*Graphics) NewCompressedTexture

func (g *Graphics) NewCompressedTexture(data []byte, opts TextureOptions) (*Texture, error)

NewCompressedTexture uploads a KTX2 file written by bunyip-tex. Its blocks and its mip levels go to the GPU as they stand, so a game pays nothing at load time for compression or for mip generation, and the texture takes a quarter to an eighth of the memory an uncompressed one would.

The file's format decides whether sampling decodes from sRGB, so TextureOptions.Data is ignored; Linear and Repeat choose the sampler as usual, and NoMipmaps uploads level 0 alone. Where the device cannot sample the format, which some MoltenVK configurations cannot for the BC formats, level zero is decoded on the processor into a plain RGBA texture and any requested mipmaps are generated at load. This fallback supports the formats and BC7 modes the ktx2 CPU decoder implements; unsupported formats such as ASTC return an error on such a device.

func (*Graphics) NewEnvironment

func (g *Graphics) NewEnvironment(panorama image.Image, opts EnvironmentOptions) (*Environment, error)

NewEnvironment builds an environment from an equirectangular panorama: longitude across, latitude down, sRGB colour, any size. It prefilters the image for every roughness on every core, which takes a fraction of a second for a large panorama.

func (*Graphics) NewEnvironmentHDR

func (g *Graphics) NewEnvironmentHDR(panorama *HDRImage, opts EnvironmentOptions) (*Environment, error)

NewEnvironmentHDR builds an environment from a floating-point panorama, keeping its full range so a bright sun in it lights the scene as strongly as it should.

func (*Graphics) NewFont

func (g *Graphics) NewFont(ttf []byte, size float32, opts FontOptions) (*Font, error)

NewFont parses TTF/OTF bytes and prepares an atlas for size view units.

func (*Graphics) NewGeometry2D

func (g *Graphics) NewGeometry2D(vertices []Vertex2D, indices []uint32) (*Geometry2D, error)

NewGeometry2D uploads vertices and triangle indices once. Nil or empty indices use consecutive groups of three vertices. Incomplete triangles, out-of-range indices and non-finite positions return errors. Empty geometry is valid and draws nothing. The input slices may be reused after return.

func (*Graphics) NewGradient

func (g *Graphics) NewGradient(stops ...GradientStop) (*Gradient, error)

NewGradient bakes stops into a gradient; stops need not be sorted and a single stop is a flat colour. Give it a direction with Linear or Radial before drawing with it.

func (*Graphics) NewLUT

func (g *Graphics) NewLUT(img image.Image) (*Texture, error)

NewLUT uploads a colour lookup table for PostSettings.LUT: linear filtering, no colour-space conversion.

func (*Graphics) NewMesh

func (g *Graphics) NewMesh(verts []Vertex, indices []uint32) (*Mesh, error)

NewMesh uploads vertices and triangle indices.

func (*Graphics) NewMeshShader

func (g *Graphics) NewMeshShader(spirv []byte) (*Shader, error)

NewMeshShader creates a mesh (surface) shader from SPIR-V produced by bunyip-shader -kind mesh from a source that defines fn surface(s: Surface) -> Surface.

func (*Graphics) NewRenderTexture

func (g *Graphics) NewRenderTexture(width, height int) (*RenderTexture, error)

NewRenderTexture creates an offscreen surface in pixels. It has the full 3D pipeline (shadows, bloom, post) but no FXAA pass, matches the window's colour format and samples with linear filtering; NewRenderTextureOptions chooses all of that, multisampling included.

func (*Graphics) NewRenderTextureOptions

func (g *Graphics) NewRenderTextureOptions(width, height int, opts RenderTextureOptions) (*RenderTexture, error)

NewRenderTextureOptions is NewRenderTexture with a choice of sampling, colour format, depth and multisampling.

func (*Graphics) NewSDFFont

func (g *Graphics) NewSDFFont(ttf []byte, size float32, opts FontOptions) (*Font, error)

NewSDFFont prepares a scalable font. Size is a nominal em size in view units used by DrawText; TextOptions.Size draws at any other size and stays sharp, where a bitmap font would blur. The printable ASCII glyphs every font preloads are rasterised on all cores.

func (*Graphics) NewShader

func (g *Graphics) NewShader(spirv []byte) (*Shader, error)

NewShader creates a sprite (2D) shader from SPIR-V produced by bunyip-shader from a source that defines fn fragment(uv: vec2f, color: vec4f) -> vec4f.

func (*Graphics) NewSkinnedMesh

func (g *Graphics) NewSkinnedMesh(verts []SkinVertex, indices []uint32) (*Mesh, error)

NewSkinnedMesh uploads skinned geometry; draw it with DrawSkinned or through an animated model.

func (*Graphics) NewStaticBatch

func (g *Graphics) NewStaticBatch(items []BatchItem) *StaticBatch

NewStaticBatch builds the hierarchy over a set of draws that never move. Items with no mesh are skipped, and an empty set gives a batch that draws nothing. Building costs one pass over the items per level of the tree, so do it at load rather than every frame.

func (*Graphics) NewTerrain

func (g *Graphics) NewTerrain(opts TerrainOptions) (*Terrain, error)

NewTerrain builds the chunk meshes, the splat texture and the terrain shader from a heightfield. It uploads every chunk at every level at once, so a large terrain costs its whole geometry in device memory: with the default chunk size and four levels that is about a third more than the finest level alone. Layer textures must belong to this Graphics; foreign layers return an error.

func (*Graphics) NewTexture

func (g *Graphics) NewTexture(src image.Image, opts TextureOptions) (*Texture, error)

NewTexture uploads an image without modifying it. Colour pixels are premultiplied in linear light and stored as sRGB, so shaders sample premultiplied linear colour. Data textures skip this colour conversion. Nil sources, empty bounds and unsupported dimensions return an error. During Draw, the upload is recorded before rendering; outside a frame it waits for the GPU.

func (*Graphics) PopClip

func (g *Graphics) PopClip()

PopClip restores the clip rectangle in force before the matching PushClip.

func (*Graphics) PopTransform

func (g *Graphics) PopTransform()

PopTransform restores the transform in force before the matching PushTransform.

func (*Graphics) Post

func (g *Graphics) Post() PostSettings

Post returns the current settings.

func (*Graphics) Project

func (g *Graphics) Project(p lin.Vec3) (x, y float32, ok bool)

Project maps a world point to the current 2D view through the queue's camera; see Camera.Project. It only answers while drawing.

func (*Graphics) PushClip

func (g *Graphics) PushClip(r lin.Rect)

PushClip limits later sprite drawing to a view-space rectangle, intersected with any enclosing clip. Pair with PopClip.

func (*Graphics) PushTransform

func (g *Graphics) PushTransform(m lin.Affine)

PushTransform composes a transform onto the 2D transform stack: later sprites, text and paths are mapped through it (after their own placement, before the camera). Pair with PopTransform.

func (*Graphics) Resources

func (g *Graphics) Resources() []Resource

Resources lists the GPU resources this context has created and not destroyed, oldest first: what a debug view shows to find a leak or a texture nobody meant to load. A font's atlas, a render texture's image and a model's meshes are counted once each, under their own kind. The byte figures are estimates of the images and buffers alone, with no allowance for alignment or driver overhead.

func (*Graphics) ScreenRay

func (g *Graphics) ScreenRay(x, y float32) Ray

ScreenRay returns the world-space ray under a point in the current 2D view through the queue's camera; see Camera.ScreenRay. It only answers while drawing.

Example
package main

import (
	"image"

	"github.com/matjam/bunyip/gfx"
	"github.com/matjam/bunyip/lin"
)

// The Graphics value comes from engine.Context.Gfx inside a game's Init
// and Draw; these examples show the calls a game makes with it.
var g *gfx.Graphics

func main() {
	verts, indices := gfx.SphereMesh(16, 32)
	sphere, err := g.NewMesh(verts, indices)
	if err != nil {
		return
	}
	defer sphere.Destroy()
	world := lin.Translate(lin.V3(0, 1, -5))
	ray := g.ScreenRay(400, 300) // the pixel under the mouse
	if hit, ok := sphere.Intersect(world, ray); ok {
		_ = hit.Point // where the ray met the surface
	}
}

func (*Graphics) ScreenSpace

func (g *Graphics) ScreenSpace()

ScreenSpace returns sprite drawing to view coordinates.

func (*Graphics) SetBlend

func (g *Graphics) SetBlend(b Blend)

SetBlend sets the blend mode for later 2D drawing in the current queue. It is reset to BlendAlpha at the start of each frame.

func (*Graphics) SetCamera

func (g *Graphics) SetCamera(c Camera)

SetCamera sets the camera for this frame's meshes.

func (*Graphics) SetCamera2D

func (g *Graphics) SetCamera2D(cam Camera2D)

SetCamera2D makes later sprite draws world-space under cam. Call ScreenSpace to return to view coordinates for interface drawing. Sprites wholly outside the camera's view are dropped before they reach the vertex stream.

Example
package main

import (
	"image"

	"github.com/matjam/bunyip/gfx"
	"github.com/matjam/bunyip/lin"
)

// The Graphics value comes from engine.Context.Gfx inside a game's Init
// and Draw; these examples show the calls a game makes with it.
var (
	g *gfx.Graphics

	font *gfx.Font
)

func main() {
	// World-space sprites follow the camera; screen-space ones (HUD) do not.
	cam := gfx.Camera2D{Position: lin.V2(1000, 500), Zoom: 2}
	g.SetCamera2D(cam)
	g.FillRect(990, 490, 20, 20, gfx.White) // drawn at the view centre
	g.ScreenSpace()
	g.DrawText(font, "score 10", 8, 8, gfx.White)
}

func (*Graphics) SetColorMatrix

func (g *Graphics) SetColorMatrix(m *ColorMatrix)

SetColorMatrix recolours later sprite, text and shape drawing in the current queue through the matrix; nil restores plain colours. It is reset at the start of each frame, and a game's own SetShader takes precedence over it.

func (*Graphics) SetLayer

func (g *Graphics) SetLayer(layer int)

SetLayer sets the sort layer for later sprite draws. Sprites draw in ascending layer order and, within a layer, by sort key (SetSortKey) and then in submission order. Text and interface drawing typically use a high layer.

func (*Graphics) SetLight

func (g *Graphics) SetLight(l Light)

SetLight sets the directional light, ambient term and shadow settings.

func (*Graphics) SetLightProbes

func (g *Graphics) SetLightProbes(grid *LightProbeGrid)

SetLightProbes uses a baked grid for this frame's ambient light, or nil for none. An unbaked grid is ignored.

func (*Graphics) SetLights2D

func (g *Graphics) SetLights2D(ambient Color, lights ...Light2D)

SetLights2D sets the ambient light and up to eight point lights that DrawLit sprites in the current queue are lit by, for this frame. Lights with Shadows are blocked by the frame's AddOccluder2D occluders. Eight is the limit the lit shader holds: lights past the eighth are dropped and counted in FrameStats.Lights2DDropped, so pass the lights nearest what is drawn first.

func (*Graphics) SetOcclusionSize

func (g *Graphics) SetOcclusionSize(width, height int)

SetOcclusionSize sizes the software occlusion buffer in pixels. A larger buffer culls more, because a gap narrower than a pixel counts as covered, and costs more to rasterise into and to test against. Zero restores the default of 256 by 144, and sizes are clamped to 2048.

func (*Graphics) SetPost

func (g *Graphics) SetPost(p PostSettings)

SetPost replaces the global post-processing settings for the screen and every render texture. Queued DrawTo calls use the final settings when the frame submits, so they cannot choose different post effects. A change to Samples takes effect on the next frame, which rebuilds the scene targets.

func (*Graphics) SetShader

func (g *Graphics) SetShader(s *Shader)

SetShader makes later 2D drawing in the current queue use a sprite shader; nil restores the default. It is reset at the start of each frame. A shader from another Graphics panics without changing the current shader.

func (*Graphics) SetSortKey

func (g *Graphics) SetSortKey(key float32)

SetSortKey orders later sprite draws within their layer: draws with a lower key are drawn first, and equal keys keep submission order. A game that sorts by depth sets the key to each sprite's feet, so a character standing lower on the screen draws over one behind it, without ordering its own draw calls. Zero, the default, keeps submission order alone.

func (*Graphics) SetView

func (g *Graphics) SetView(width, height float32)

SetView sets the 2D coordinate space: (0,0) top-left to (width,height) bottom-right, whatever the framebuffer's pixel size. It panics inside WithView.

func (*Graphics) SetViewport

func (g *Graphics) SetViewport(r lin.Rect) error

SetViewport limits the main output to a pixel rectangle: the 2D view maps onto it, the 3D scene renders at its size, and the window outside it stays black. The engine sets it from Config's view size and scaling policy; a zero rect means the whole window. It panics inside WithView.

func (*Graphics) Shaded

func (g *Graphics) Shaded(s *Shader, draw func())

Shaded runs draw with the shader set, then restores the original queue's shader, including when draw panics.

func (*Graphics) SortKey

func (g *Graphics) SortKey() float32

SortKey returns the current sort key.

func (*Graphics) Stats

func (g *Graphics) Stats() FrameStats

Stats returns the last finished frame's counts.

func (*Graphics) Stenciled

func (g *Graphics) Stenciled(options StencilOptions, draw func())

Stenciled applies advanced stencil controls to 2D drawing, including geometry and flat particles, and restores the previous options on panic. Options are captured per draw, but ordinary layer and sort-key ordering still applies. Use Masked for automatic mask setup and ordering boundaries. Stencil contents persist for the rest of this target's frame. Invalid options or a target without stencil panic before draw is called.

func (*Graphics) StrokeCircle

func (g *Graphics) StrokeCircle(cx, cy, r, width float32, c Color)

StrokeCircle outlines a circle with a line width.

func (*Graphics) StrokeLine

func (g *Graphics) StrokeLine(x0, y0, x1, y1, width float32, c Color)

StrokeLine draws a line segment with a width and butt caps.

func (*Graphics) StrokePath

func (g *Graphics) StrokePath(p *Path, c Color, opts StrokeOptions)

StrokePath outlines the path with a colour.

func (*Graphics) StrokeRect

func (g *Graphics) StrokeRect(x, y, w, h, width float32, c Color)

StrokeRect outlines a rectangle with a line width.

func (*Graphics) Transform

func (g *Graphics) Transform() lin.Affine

Transform returns the current composed 2D transform.

func (*Graphics) Transformed

func (g *Graphics) Transformed(m lin.Affine, draw func())

Transformed runs draw with the transform pushed, then restores the original queue's transform stack, including when draw panics.

func (*Graphics) View

func (g *Graphics) View() (float32, float32)

View returns the current 2D coordinate space size.

func (*Graphics) Viewport

func (g *Graphics) Viewport() lin.Rect

Viewport returns the main output's pixel rectangle.

func (*Graphics) WithCamera2D

func (g *Graphics) WithCamera2D(cam Camera2D, draw func())

WithCamera2D runs draw under cam, then restores the original queue's camera or screen-space state, including when draw panics.

func (*Graphics) WithView

func (g *Graphics) WithView(view View2D, draw func())

WithView draws in a local 2D view, clipped to its viewport and enclosing clips. It inherits the current camera, recalculated for the virtual size; WithCamera2D can select another camera inside. The viewport itself is in enclosing view coordinates and is not moved by a camera or transform.

View geometry is validated before any state changes. The previous view, camera and clips are restored even on panic; queued draws remain queued. This affects sprites, paths, text, geometry and 2D particles, not 3D passes. Use render textures for separately rendered 3D cameras. SetView and SetViewport panic inside the closure; configure the main output outside view scopes. DrawTo may select another target normally.

type HDRImage

type HDRImage struct {
	Width, Height int
	Pix           []float32 // row-major RGB
}

HDRImage is a floating-point RGB image: linear radiance, no gamma, values above 1 for bright light sources. DecodeHDR reads one from a Radiance .hdr file and NewEnvironmentHDR lights a scene with it.

func DecodeEXR

func DecodeEXR(data []byte) (*HDRImage, error)

DecodeEXR reads an OpenEXR image, as HDR panoramas are often distributed. Half and float channels are read from single-part scanline files that are uncompressed or compressed with RLE, ZIPS or ZIP. The R, G and B channels become the result's radiance; a file with a single Y channel becomes grey. Tiled, deep and multi-part files, and the PIZ, PXR24, B44, B44A, DWAA and DWAB schemes, are refused with an error saying so. Pass the result to NewEnvironmentHDR. The chunks are decoded on up to GOMAXPROCS goroutines.

func DecodeHDR

func DecodeHDR(data []byte) (*HDRImage, error)

DecodeHDR reads a Radiance RGBE (.hdr) file, flat or run-length encoded, as most panoramas are distributed.

func DecodePanorama

func DecodePanorama(data []byte) (*HDRImage, error)

DecodePanorama reads an equirectangular panorama from encoded bytes, whichever format it is in: an OpenEXR file, a Radiance .hdr file, or any image the program has registered a decoder for, whose sRGB colours are converted to linear radiance. Pass the result to NewEnvironmentHDR. A program that loads PNG or JPEG panoramas must import image/png or image/jpeg for their decoders, as it would for image.Decode.

func (*HDRImage) At

func (h *HDRImage) At(x, y int) (r, g, b float32)

At returns the radiance at a pixel.

type Hit

type Hit struct {
	Distance float32
	Point    lin.Vec3
	Normal   lin.Vec3
	Part     int // index of the model part, for models
}

Hit describes where a ray met geometry.

type Hyphenator

type Hyphenator struct {

	// MinLeft and MinRight are the fewest letters left before and after a
	// break; TeX's defaults for English are 2 and 3.
	MinLeft, MinRight int
	// contains filtered or unexported fields
}

Hyphenator finds the points where a word may break at a line end, by Liang's pattern method as TeX does. Set one on TextOptions.Hyphenate and wrapped text breaks long words with a hyphen instead of leaving ragged gaps.

func EnglishHyphenator

func EnglishHyphenator() *Hyphenator

EnglishHyphenator returns the shared American English hyphenator, built from the standard TeX patterns on first use.

func HyphenatorFor

func HyphenatorFor(lang string) (*Hyphenator, error)

HyphenatorFor returns the shared hyphenator for a BCP 47 language tag, built from the TeX patterns the engine ships on first use. A tag with no patterns of its own falls back to its primary language, so "de-AT" gives the German hyphenator and "en-AU" the American English one; "en-GB" has patterns of its own. Languages the engine ships no patterns for return an error, and the shipped set is listed in gfx/hyph/README.md. The hyphenator is shared, so treat MinLeft and MinRight as read-only.

func NewHyphenator

func NewHyphenator(patterns, exceptions []string) *Hyphenator

NewHyphenator builds a hyphenator from Liang patterns ("hy3ph", ".ab1o") and exception words with their breaks marked ("ta-ble").

func ParseTeXPatterns

func ParseTeXPatterns(src string) *Hyphenator

ParseTeXPatterns reads a TeX hyphenation file: every \patterns{...} block and every \hyphenation{...} block of exceptions. A hyphenmins comment in the file's header, which the hyph-utf8 pattern files carry, sets MinLeft and MinRight from its typesetting values; without one they are TeX's 2 and 3.

func (*Hyphenator) Hyphenate

func (h *Hyphenator) Hyphenate(word string) []int

Hyphenate returns the rune offsets in word where it may break, in order, respecting MinLeft and MinRight.

func (*Hyphenator) SoftHyphens

func (h *Hyphenator) SoftHyphens(text string) string

SoftHyphens returns text with a soft hyphen (U+00AD) at every break point of every word of letters, which is how wrapping is told where a word may split; the marks are invisible unless a line ends on one.

type Image

type Image struct{ *image.NRGBA }

Image owns editable CPU pixels in straight-alpha NRGBA form. NewImage copies its source, so later edits do not affect that source. The embedded NRGBA and its Pix slice are exposed for standard image/draw operations; subimages share those pixels. The zero value is empty. Methods are not synchronized.

func NewImage

func NewImage(src image.Image) (*Image, error)

NewImage copies src to owned, zero-based bounds. Nil or empty sources and dimensions whose RGBA storage would overflow return an error.

func (*Image) At

func (i *Image) At(x, y int) color.Color

At returns a straight-alpha pixel, or transparent black outside the image.

func (*Image) Bounds

func (i *Image) Bounds() image.Rectangle

Bounds returns the pixel bounds, or an empty rectangle for the zero value.

func (*Image) ColorModel

func (i *Image) ColorModel() color.Model

ColorModel returns color.NRGBAModel, including for the zero value.

func (*Image) CopyFrom

func (i *Image) CopyFrom(src image.Image, dst image.Point) error

CopyFrom copies the full source at dst using draw.Src, clipped to this image. Source bounds may start anywhere. Overlapping self-copies read original pixels before writing, including when src is a subimage sharing this image's storage.

func (*Image) FlipHorizontal

func (i *Image) FlipHorizontal()

FlipHorizontal reverses each row in place. An empty image is unchanged.

func (*Image) FlipVertical

func (i *Image) FlipVertical()

FlipVertical reverses the row order in place. An empty image is unchanged.

func (*Image) Mask

func (i *Image) Mask(c color.Color)

Mask sets alpha to zero for pixels whose straight RGB exactly matches c. The supplied alpha is ignored; existing RGB values are preserved. Nil colours and empty images have no effect. There is no tolerance or colour-space conversion.

func (*Image) SavePNG

func (i *Image) SavePNG(path string) error

SavePNG creates or truncates path, writes PNG pixels, and closes the file.

func (*Image) Set

func (i *Image) Set(x, y int, c color.Color)

Set replaces a pixel. Coordinates outside the image are ignored.

func (*Image) WritePNG

func (i *Image) WritePNG(w io.Writer) error

WritePNG encodes the image to w and leaves the borrowed writer open.

type Impostor

type Impostor struct {
	// Size is the quad's width and height in world units. BakeImpostor
	// sets it to the model's bounds, and a game may change it.
	Size lin.Vec2
	// Offset moves the quad in its own plane in units of its size, as
	// Billboard.Offset does. BakeImpostor sets it to stand the quad where
	// the model stood on the ground.
	Offset lin.Vec2
	// Distance is the camera distance past which DrawModelImpostor draws
	// the impostor rather than the model. Zero means always the impostor.
	Distance float32
	// Upright turns the quad about the world's up axis only, so it stays
	// vertical when the camera looks down on it. BakeImpostor sets it.
	Upright bool
	// contains filtered or unexported fields
}

Impostor is a model baked into an atlas of views around it, drawn as one camera-facing quad. A tree, a rock or a building far enough away covers a few pixels, and an impostor spends one quad and no vertex work on it where the model would spend thousands of triangles. Bake one with BakeImpostor, draw it with DrawImpostor, or hand both the model and the impostor to DrawModelImpostor and let the distance choose. Every impostor of one model shares its atlas, so a forest of them is one instanced draw.

The bake fixes the lighting into the atlas, and it is lit the same way relative to each view, so an impostor does not turn its shading as the sun moves. Keep them far enough away that this does not read, which is where they belong anyway.

func (*Impostor) Destroy

func (im *Impostor) Destroy()

Destroy frees the atlas.

func (*Impostor) Texture

func (im *Impostor) Texture() *Texture

Texture returns the baked atlas, for a game that wants to draw the views itself or to inspect the bake.

func (*Impostor) Views

func (im *Impostor) Views() int

Views is how many directions the atlas holds.

type ImpostorOptions

type ImpostorOptions struct {
	// Views is how many directions around the model are baked, evenly
	// spaced; zero means 8. More views turn more smoothly and cost atlas
	// space. The most is MaxImpostorViews.
	Views int
	// Resolution is the pixels across one view; zero means 128. The atlas
	// is the smallest grid of views that holds them all.
	Resolution int
	// Pitch is how far above the model each view looks down, in radians;
	// zero means 15 degrees. Match it to the camera's usual elevation.
	Pitch float32
	// Light lights the bake. Pass the light the scene draws under, so the
	// impostor matches the model it replaces; its Background, Environment,
	// Shadows and Fog are ignored, since the sky must stay out of the
	// atlas's transparent parts and the fog is applied again when the
	// impostor is drawn. The zero value is a sun over the viewer's left
	// shoulder against a pale sky.
	Light Light
	// Upright is what the drawn quad's Upright becomes; it is on by
	// default, which is what a ring of views around a model wants. Set
	// FaceCamera to turn it off.
	FaceCamera bool
}

ImpostorOptions says how BakeImpostor renders a model.

type LOD

type LOD struct {
	Levels []LODLevel
}

LOD is a mesh at several levels of detail: a full model up close, a simpler one at a distance, a few triangles far away and nothing at all beyond. Levels are listed nearest first, each with the distance at which the next takes over; DrawLOD picks by the camera's distance to the model's origin.

func NewLOD

func NewLOD(meshes []*Mesh, distances []float32) *LOD

NewLOD builds a LOD from meshes and the distances at which each hands over to the next; the last mesh serves beyond the last distance, so there is one fewer distance than meshes. Pass a nil mesh last to draw nothing far away.

func (*LOD) Pick

func (l *LOD) Pick(distance float32) *Mesh

Pick returns the mesh for a camera distance, nil when the LOD draws nothing there.

type LODLevel

type LODLevel struct {
	Mesh     *Mesh   // nil draws nothing at this level, for things that vanish far away
	Distance float32 // used while the camera is closer than this; zero means always
}

LODLevel is one mesh of a LOD and the camera distance up to which it is drawn.

type Light

type Light struct {
	Direction lin.Vec3 // direction the light travels
	Color     Color
	Ambient   Color // light from every direction when the Sky leaves a colour unset
	// Sky is the procedural environment: sky and ground colours around an
	// up axis, thinning to space, with a drawn sun and stars.
	Sky Sky

	Shadows        bool    // render cascaded shadow maps for the directional light
	ShadowDistance float32 // how far from the camera shadows reach; default 60
	ShadowStrength float32 // 0..1 how dark shadows are; zero means 1

	// Environment lights the scene from every direction with an image:
	// reflections in metals, tinted ambient on everything. It replaces
	// Ambient and Sky when set.
	Environment *Environment
	// Background draws the environment, or the Sky, behind the scene.
	Background bool
	// Fog fades distant geometry into a colour; the zero value is none.
	Fog Fog
}

Light is the directional light plus ambient, with optional shadows.

type Light2D

type Light2D struct {
	Pos    lin.Vec2
	Height float32 // zero means 40
	Radius float32 // zero means 300
	Color  Color   // zero means white
	// Shadows makes the occluders added with AddOccluder2D block this
	// light, so a wall between it and a sprite darkens the sprite. It
	// costs one polar shadow map a frame, built on the CPU.
	Shadows bool
	// Softness is the width of the shadow's soft edge in view units at
	// the shadowed point; zero means 8. It has no effect without
	// Shadows.
	Softness float32
}

Light2D is a point light for lit sprites: a position in the same units as sprites, a height above their plane and a radius where it fades out.

type LightProbeGrid

type LightProbeGrid struct {
	// Origin is the world position of cell (0, 0, 0).
	Origin lin.Vec3
	// Spacing is the distance between neighbouring cells on each axis;
	// a zero component means 1.
	Spacing lin.Vec3
	// Counts is how many cells the grid has along x, y and z. Each is at
	// least 1, and their product is at most 4096.
	Counts [3]int
	// Resolution is the cube face size each cell is rendered at before it
	// is projected onto harmonics; zero means 16. The harmonics keep only
	// the low frequencies, so small is enough.
	Resolution int
	// Intensity multiplies the grid's light; zero means 1.
	Intensity float32
	// contains filtered or unexported fields
}

LightProbeGrid is the diffuse light of a scene sampled on a lattice of points: the red bounce along a red wall, the dark under a bridge, the warm glow near a fire. Each cell holds the irradiance around it as nine spherical harmonics, baked from the scene by BakeLightProbes and uploaded once a frame by SetLightProbes. Where the grid covers a fragment it replaces the single environment ambient, blended between the eight cells around the point; outside the grid the environment or sky ambient stands.

A grid lights the diffuse term. Reflections come from the light's Environment, the Sky or a ReflectionProbe.

func (*LightProbeGrid) Baked

func (grid *LightProbeGrid) Baked() bool

Baked reports whether the grid holds harmonics yet.

func (*LightProbeGrid) Position

func (grid *LightProbeGrid) Position(x, y, z int) lin.Vec3

Position is where one cell sits in the world.

func (*LightProbeGrid) Probe

func (grid *LightProbeGrid) Probe(x, y, z int) [9]lin.Vec4

Probe returns one cell's nine irradiance harmonics, the same form an Environment keeps, or zeros before the grid is baked or outside it.

type LineCap

type LineCap uint8

LineCap is how a stroke ends.

const (
	CapButt   LineCap = iota // stops at the end point
	CapRound                 // a half circle past it
	CapSquare                // half the width past it
)

type LineJoin

type LineJoin uint8

LineJoin is how a stroke turns a corner.

const (
	JoinMiter LineJoin = iota // a sharp corner, up to MiterLimit
	JoinRound                 // a rounded corner
	JoinBevel                 // a cut corner
)

type Material

type Material struct {
	Texture   *Texture // albedo, sRGB
	BaseColor Color    // multiplies the albedo; zero means white
	Metallic  float32  // 0 dielectric .. 1 metal; with a texture, a factor (0 means 1)
	Roughness float32  // 0.04 .. 1; zero means 0.6

	MetalRoughTexture *Texture // glTF layout: G roughness, B metallic; data, not colour
	NormalTexture     *Texture // tangent-space normal map; data, not colour
	EmissiveTexture   *Texture // sRGB, scaled by Emissive
	Emissive          float32  // glow strength; without a texture the mesh glows in its base colour
	// OcclusionTexture darkens ambient light by its red channel, for baked
	// crevice shadows; OcclusionStrength scales it (zero means 1).
	OcclusionTexture  *Texture
	OcclusionStrength float32

	// AlphaCutoff discards fragments whose alpha is below it, in both the
	// lit and shadow passes: leaves, fences, decals with hard edges. Zero
	// means no cutout.
	AlphaCutoff float32
	// Blend draws after opaque geometry, back to front or through the
	// order-independent transparency pass. BaseColor alpha, multiplied by
	// texture and vertex alpha, fades the entire shaded surface, including
	// lighting, emissive and fog. Pass straight colors; the engine
	// premultiplies the result before blending. Without Blend or
	// Transmission, alpha only controls AlphaCutoff.
	Blend       bool
	DoubleSided bool // no back-face culling; back faces are lit with a flipped normal
	Unlit       bool // the base colour and emissive as they are, ignoring lights

	NoDepthTest  bool // draw over everything already drawn: overlays, highlights through walls
	NoDepthWrite bool // leave the depth buffer alone: ghosts, additive effects

	// UVTransform maps texture coordinates before sampling the material's
	// textures: scrolling, tiling, rotation. Zero means identity.
	UVTransform lin.Affine
	// OcclusionUV2 samples the occlusion map with the vertices' second
	// texture coordinates, the lightmap convention.
	OcclusionUV2 bool

	// Clearcoat adds a glossy varnish layer of that strength (0..1) with
	// its own roughness: car paint, lacquer, wet surfaces.
	Clearcoat          float32
	ClearcoatRoughness float32
	// Sheen adds soft back-scattered light at grazing angles in that colour,
	// the look of velvet and cloth; zero means none.
	Sheen          Color
	SheenRoughness float32 // zero means 0.5
	// Subsurface (0..1) lets light through thin parts, tinted by the base
	// colour: leaves, wax, skin. ThicknessTexture (red channel, 1 = thick)
	// shapes it; nil is uniformly thin.
	Subsurface       float32
	ThicknessTexture *Texture

	// Transmission (0..1) is how much light passes through the surface:
	// glass, water, ice. The scene behind shows through, refracted by IOR
	// (zero means 1.5) across Thickness world units of material, blurred
	// by the roughness and tinted by the base colour. AttenuationColor is
	// what white light becomes after AttenuationDistance units inside the
	// volume; a zero distance means no absorption. ThicknessTexture scales
	// Thickness; with a Thickness and no map the mesh is uniformly thick.
	// Transmissive meshes draw after the opaque ones, like Blend.
	Transmission        float32
	IOR                 float32
	Thickness           float32
	AttenuationColor    Color
	AttenuationDistance float32
	// TransmissionTexture scales Transmission by its red channel, so a
	// window frame can be opaque and its panes glass in one material;
	// nil is the factor everywhere. Data, not colour.
	TransmissionTexture *Texture

	// Specular scales a dielectric's reflection and SpecularColor tints
	// it, the KHR_materials_specular extension: zero means 1 and white,
	// the plain material. A small Specular such as 0.01 all but removes
	// the reflection, for chalk and unglazed clay. SpecularTexture
	// carries the tint in its RGB and the strength in its alpha. Metals
	// keep their own reflection, which is their base colour.
	Specular        float32
	SpecularColor   Color
	SpecularTexture *Texture

	// Iridescence (0..1) puts a thin film over the surface, whose
	// interference shifts the reflection's hue with the viewing angle:
	// soap bubbles, oil on water, beetle shells, tempered steel.
	// IridescenceIOR is the film's index of refraction (zero means 1.3)
	// and IridescenceThickness how thick it is in nanometres (zero means
	// 400, and 100 to 800 is the range that shows colour).
	// IridescenceTexture scales the strength by its red channel and mixes
	// the thickness from IridescenceThicknessMin to IridescenceThickness
	// by its green channel, the two maps glTF packs into one image.
	Iridescence             float32
	IridescenceIOR          float32
	IridescenceThickness    float32
	IridescenceThicknessMin float32
	IridescenceTexture      *Texture

	// Anisotropy (-1..1) stretches the specular highlight along the
	// surface rather than leaving it round: brushed metal, hair, satin,
	// vinyl records. AnisotropyRotation turns the direction it stretches
	// in, in radians, and AnisotropyTexture holds a direction of its own
	// in red and green (around a half, as glTF stores it) and a strength
	// in blue. The direction comes from the mesh's texture coordinates,
	// so an anisotropic mesh needs UVs but no tangents of its own.
	Anisotropy         float32
	AnisotropyRotation float32
	AnisotropyTexture  *Texture

	// Shells draws the mesh that many more times, each a little further
	// out along its normals, for fur, grass, moss and hair; zero means
	// none and eight to twenty-four look like fur. ShellLength is how far
	// the outermost shell stands off in world units (zero means 0.05).
	// FurTexture is the strand mask: a shell keeps a fragment where the
	// map's red channel is above that shell's height, so a tiled noise
	// image gives strands, and the material's UVTransform tiles it.
	// Without a map the shells are solid and only fade outwards. Shells
	// draw after the opaque scene, leave the depth buffer alone and cast
	// no shadow, and each one costs an instance of the mesh.
	Shells      int
	ShellLength float32
	FurTexture  *Texture

	// Stencil masks the material against the stencil buffer: it draws only
	// where the value already there compares to StencilRef the way the
	// test says. StencilAlways, the zero value, draws everywhere.
	// StencilWrite is what a drawn fragment stores, StencilKeep leaving
	// the buffer alone. One material marks a shape with StencilReplace
	// and another draws only inside it with StencilEqual: portals,
	// cutaways, magic windows. The buffer starts each frame at zero, and
	// materials that write it draw before those that do not, whatever
	// order they were queued in. A material with an Outline uses the
	// stencil buffer for the outline itself and ignores these three.
	Stencil      StencilTest
	StencilRef   uint8
	StencilWrite StencilOp

	// Outline draws a line of that many pixels around the mesh's
	// silhouette in OutlineColor (zero means black): selection rings,
	// cartoon edges. It needs a depth format with stencil, which every
	// desktop GPU has.
	Outline      float32
	OutlineColor Color
	// XRay tints the parts of the mesh hidden behind other geometry, so a
	// unit shows through walls; zero means none.
	XRay Color

	// Shader is a mesh shader from NewMeshShader that adjusts the surface
	// before lighting; nil is the standard material.
	Shader *Shader
}

Material is how a mesh is shaded, in the metallic-roughness model. Every texture is optional: nil albedo is white, nil metal-rough is the factors alone, nil normal map is the geometric normal, nil emissive is black.

type MaterialOverride

type MaterialOverride func(i int, part ModelPart) Material

MaterialOverride returns the material to draw one part of a model with. i is the part's index in Model.Parts and part is the part itself, so a game can decide by index or by part.Name, the name glTF gave the material. Returning part.Material draws what the file asked for.

type Mesh

type Mesh struct {
	IndexCount uint32
	Min, Max   lin.Vec3 // axis-aligned bounds in mesh space
	// contains filtered or unexported fields
}

Mesh is indexed triangle geometry in device memory. Build one from vertices with NewMesh, from the shapes in this package (CubeMesh, SphereMesh, PlaneMesh, HeightfieldMesh and the rest), or by loading a glTF Model. Meshes that change, such as voxel chunks and procedural terrain, take new geometry through Update.

func (*Mesh) Bounds

func (m *Mesh) Bounds() (min, max lin.Vec3)

Bounds returns the mesh's axis-aligned bounds in mesh space, the box culling and picking test. They come from the vertices unless SetBounds replaced them.

func (*Mesh) Destroy

func (m *Mesh) Destroy()

Destroy frees the mesh. Called inside a frame it costs no wait: the buffers go on the frame slot's retire list and are freed once that frame has finished, so draws already queued this frame still draw.

func (*Mesh) Indices

func (m *Mesh) Indices() []uint32

Indices returns the mesh's triangle indices, three per triangle; the slice is the mesh's own and must not be modified. Copy it to retain a snapshot across Update.

func (*Mesh) Intersect

func (m *Mesh) Intersect(model lin.Mat4, r Ray) (Hit, bool)

Intersect tests the ray against a mesh under a model matrix, first by bounding box and then triangle by triangle, returning the nearest hit.

func (*Mesh) SetBounds

func (m *Mesh) SetBounds(min, max lin.Vec3)

SetBounds replaces the bounds culling tests the mesh against, for a mesh whose drawn shape leaves its vertices: a material shader that displaces vertices, or an animation that swings a limb outside the geometry as uploaded. Give the box the drawn shape stays inside, in mesh space. The bounds hold until the next SetBounds; Update and UpdateSkinned leave them alone. A mesh that has never been given bounds uses the box its vertices fill, and a skinned one the boxes of its joints under the pose.

func (*Mesh) Update

func (m *Mesh) Update(verts []Vertex, indices []uint32) error

Update replaces the mesh's geometry: a voxel chunk after a block is broken, terrain after an edit, a procedural mesh that grows. Draws already queued this frame keep the old geometry, which is freed once the frame is done, so Update is safe at any point of a frame. Skinned meshes cannot be updated.

func (*Mesh) UpdateSkinned

func (m *Mesh) UpdateSkinned(verts []SkinVertex, indices []uint32) error

UpdateSkinned replaces a skinned mesh's geometry, as Update does for a plain mesh: draws already queued this frame keep the old geometry. It is what morph targets on a skinned model go through.

func (*Mesh) Vertices

func (m *Mesh) Vertices() []Vertex

Vertices returns the mesh's vertices as uploaded, for picking and physics; the slice is the mesh's own, so do not change it.

type Model

type Model struct {
	Parts    []ModelPart
	Min, Max lin.Vec3
	// contains filtered or unexported fields
}

Model is a glTF document uploaded to the GPU: one Mesh per primitive, one Texture per image, and the placements to draw.

func (*Model) ClipDuration

func (m *Model) ClipDuration(name string) float32

ClipDuration returns a clip's length in seconds; unknown names give 0.

func (*Model) Clips

func (m *Model) Clips() []string

Clips lists the model's animation names.

func (*Model) Destroy

func (m *Model) Destroy()

Destroy frees the model's meshes, textures and morph targets after queued and submitted draws have finished using them.

func (*Model) Intersect

func (m *Model) Intersect(world lin.Mat4, r Ray) (Hit, bool)

Intersect tests every part of a model under a world matrix.

func (*Model) MaskNodes

func (m *Model) MaskNodes(names ...string) AnimMask

MaskNodes makes a mask of exactly the named nodes; unknown names are ignored.

func (*Model) MaskSubtree

func (m *Model) MaskSubtree(names ...string) AnimMask

MaskSubtree makes a mask of the named nodes and everything under them: "Spine1" for the upper body, "Head" for the head and its children.

func (*Model) MorphTargets

func (m *Model) MorphTargets(node int) []string

MorphTargets names the morph targets of the node's mesh, blank where the file names none; nil when the node has no morph targets.

func (*Model) MorphWeights

func (m *Model) MorphWeights(node int) []float32

MorphWeights returns the morph target weights the node's mesh is drawn with, whether they blend in the vertex shader or on the processor; nil when the node has no morph targets. The slice is the model's own.

func (*Model) NewAnimPlayer

func (m *Model) NewAnimPlayer() *AnimPlayer

NewAnimPlayer makes a player for the model in its rest pose.

func (*Model) NodeCount

func (m *Model) NodeCount() int

NodeCount is the number of nodes in the model's hierarchy.

func (*Model) NodeIndex

func (m *Model) NodeIndex(name string) int

NodeIndex returns the index of the first node with the name, or -1.

func (*Model) NodeMatrix

func (m *Model) NodeMatrix(node int) lin.Mat4

NodeMatrix returns a node's rest-pose world matrix in model space, for a socket on a model that is not animated: a lamp's bulb, a turret's muzzle. An animated model's current pose comes from AnimPlayer.NodeMatrix. An unknown index gives the identity.

func (*Model) NodeName

func (m *Model) NodeName(node int) string

NodeName returns a node's name; an unknown index gives "".

func (*Model) NodeParent

func (m *Model) NodeParent(node int) int

NodeParent returns a node's parent index, or -1 for a root.

func (*Model) NodePosition

func (m *Model) NodePosition(node int) lin.Vec3

NodePosition returns a node's rest-pose position in model space.

func (*Model) SetMorphWeights

func (m *Model) SetMorphWeights(node int, weights []float32) error

SetMorphWeights blends the node's morph targets by the weights (one per target, 0 for none and 1 for the full shape) and uploads the result: a facial expression, a wind-bent plant. A player's weights channels do the same through DrawModelAnimated. Up to MaxGPUMorphTargets open at once blend in the vertex shader and cost nothing to change; past that the blend runs here, one pass over the mesh's vertices per open target plus an upload, each time the weights change. DrawModel captures the current weights and geometry, so later changes do not affect instances already queued.

type ModelPart

type ModelPart struct {
	Mesh *Mesh
	// Name is the name glTF gave the primitive's material, empty when the
	// file names none. Match on it to override one part's material.
	Name     string
	Material Material
	World    lin.Mat4
	// contains filtered or unexported fields
}

ModelPart is one primitive placed by one node.

type NineSlice

type NineSlice struct {
	Tex                      *Texture
	Left, Top, Right, Bottom float32
	// Tile repeats the edge and centre pieces at their own size instead
	// of stretching them, for patterned borders and textured fills.
	Tile bool
}

NineSlice is a texture drawn stretched to any size while its corners keep their size and its edges stretch along one axis: panels, buttons and speech bubbles from one small image. The borders are in texture pixels.

type ParticleQuad

type ParticleQuad struct {
	// Pos is the quad's centre: view units for DrawParticles, world
	// units for DrawParticles3D, whose Z is ignored in 2D.
	Pos lin.Vec3
	// Rotation turns the quad about its centre, in radians. In 3D it
	// turns about the axis facing the camera.
	Rotation float32
	// Size is the width and height. Zero draws nothing.
	Size lin.Vec2
	// UV0 and UV1 are the texture's top-left and bottom-right corners,
	// so one atlas serves a whole effect. Both zero shows the top-left
	// texel alone; use Region.UV0 and Region.UV1, or (0,0) and (1,1).
	UV0, UV1 lin.Vec2
	// Color tints the texture. Zero is transparent, not white, because
	// this is a raw GPU record rather than an options struct.
	Color Color
}

ParticleQuad is one particle handed to the instanced draw path: where it is, how big it is, which part of the texture it shows and what colour it is tinted. DrawParticles and DrawParticles3D take a whole slice of them and draw it as one instanced call, so hundreds of thousands cost one draw rather than one draw each.

The struct is the GPU's instance layout, so a slice of them uploads without being converted or copied field by field. Keep it that way: the particle package fills a slice of these directly. Color is straight alpha, not premultiplied, and the shader premultiplies it.

type Particles3D

type Particles3D struct {
	// Blend combines the particles with the scene. Zero is alpha
	// blending; BlendAdd suits fire, sparks and magic.
	Blend Blend
	// Soft fades a particle out over this many world units as it
	// approaches the geometry behind it, which hides the hard line a
	// quad otherwise cuts where it meets the ground. Zero is a hard
	// edge. One or two units suits smoke.
	Soft float32
}

Particles3D is how a batch of 3D particles is drawn.

type Path

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

Path is a sequence of lines and curves in view units, built by chaining calls: MoveTo starts a sub-path, the others extend it, Close joins it back to its start. A path can be filled, stroked, or both, as many times as you like; it holds no GPU state.

func (*Path) Arc

func (p *Path) Arc(cx, cy, r, start, sweep float32) *Path

Arc adds an arc of a circle centred at (cx, cy) with radius r, from angle start sweeping by sweep radians (positive turns the way angles increase: clockwise on a y-down screen). It joins the current point to the arc's start with a line when the sub-path is open.

func (*Path) ArcTo

func (p *Path) ArcTo(x1, y1, x2, y2, r float32) *Path

ArcTo adds an arc of radius r tangent to the lines from the current point to (x1, y1) and from there to (x2, y2), as a rounded corner.

func (*Path) Bounds

func (p *Path) Bounds() lin.Rect

Bounds returns the tight axis-aligned bounds of the path's lines and Bézier curves, including isolated MoveTo points. It excludes stroke width, antialiasing and graphics transforms. An empty path returns a zero Rect. Arcs and ellipses are bounded as the cubic curves stored by Path.

func (*Path) Circle

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

Circle adds a closed circle as its own sub-path.

func (*Path) Close

func (p *Path) Close() *Path

Close joins the sub-path back to its start with a straight segment.

func (*Path) CubicTo

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

CubicTo adds a cubic Bézier curve to (x, y) with two control points.

func (*Path) Ellipse

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

Ellipse adds a closed axis-aligned ellipse as its own sub-path.

func (*Path) Empty

func (p *Path) Empty() bool

Empty reports whether the path has no segments.

func (*Path) LineTo

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

LineTo adds a straight segment to (x, y).

func (*Path) MoveTo

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

MoveTo starts a new sub-path at (x, y).

func (*Path) Polygon

func (p *Path) Polygon(points ...lin.Vec2) *Path

Polygon adds a closed polygon through the points.

func (*Path) QuadTo

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

QuadTo adds a quadratic Bézier curve to (x, y) with control point (cx, cy).

func (*Path) Rect

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

Rect adds a closed rectangle as its own sub-path.

func (*Path) Reset

func (p *Path) Reset()

Reset empties the path for reuse without freeing its memory.

func (*Path) RoundRect

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

RoundRect adds a closed rectangle with rounded corners of radius r.

type PathOptions

type PathOptions struct {
	Fill                   *FillOptions
	Stroke                 *StrokeOptions
	FillColor, StrokeColor Color
	// PixelsPerUnit chooses curve precision and antialias fringe width.
	// Zero means 1. Choose the expected framebuffer pixels per local path
	// unit, including camera zoom and scale. Recompile when a substantially
	// different density is needed; drawing never tessellates the path again.
	PixelsPerUnit float32
}

PathOptions selects the paints baked into a CompiledPath. The zero value fills white. When either Fill or Stroke is non-nil, only the non-nil paints are used; Fill precedes Stroke. Zero colours mean white. To make a paint transparent, use a nonzero colour with A=0, or omit that paint.

type PointLight

type PointLight struct {
	Position lin.Vec3
	Color    Color
	Range    float32 // fades to nothing this far away
	Shadows  bool    // render a cube shadow map for this light
}

PointLight is a light shining from a point in every direction for AddPoint, with the option of a shadow map: a lamp in a room, a fire under a bridge. The first four shadowed point lights a frame get cube maps (MaxPointShadows), the rest shine without; add the nearest first.

type PostSettings

type PostSettings struct {
	Exposure       float32 // scene multiplier before tone mapping; default 1
	Bloom          float32 // bloom strength; default 0.25, 0 disables the passes
	BloomThreshold float32 // luminance where bloom starts; default 1
	Vignette       float32 // 0..1 edge darkening; default 0
	Saturation     float32 // default 1
	Contrast       float32 // default 1
	NoAntiAlias    bool    // skip the FXAA pass on the main frame
	// Samples multisamples the 3D scene pass: 1 (the default), 2, 4 or 8,
	// clamped to what the GPU supports. Every triangle edge is then
	// resolved from that many coverage samples, which is the one form of
	// anti-aliasing that does not blur the picture, at the cost of that
	// many times the scene's colour and depth memory and bandwidth. Set
	// NoAntiAlias with it: FXAA over an already resolved image only
	// softens it. TemporalAA already resolves the edges and turns FXAA off
	// by itself, so leave this at 1 when that is on. Changing it rebuilds
	// the scene targets and the pipelines that draw into them, on the next
	// frame.
	Samples int
	// AmbientOcclusion is the strength of screen-space ambient occlusion,
	// 0 (off) to 1; default 0.6. It darkens creases and contact points.
	AmbientOcclusion float32
	// OcclusionRadius is the occlusion kernel size in world units; default 1.
	OcclusionRadius float32
	// ShowOcclusion displays the occlusion buffer instead of the scene, for tuning.
	ShowOcclusion bool
	// OrderIndependent composites blended materials without sorting them.
	// Each pixel's translucent fragments accumulate with a weight that
	// favours the nearest, and one pass resolves them, so meshes that
	// intersect or overlap themselves no longer pick a single order for
	// the whole draw (weighted blended order-independent transparency,
	// McGuire and Bavoil). It costs two more images the size of the frame
	// and one pass. Zero keeps the sorted path, and transmissive
	// materials stay on it either way, because they read the scene behind
	// them and so must draw in order.
	OrderIndependent bool
	// Reflections is the strength of screen-space reflections, 0 (off, the
	// default) to 1. A smooth surface mirrors what the screen already
	// shows: a polished floor under a bright object, a wet road under a
	// sign. Where a ray leaves the screen or hits nothing the surface
	// keeps its environment or probe reflection.
	Reflections float32
	// ReflectionRoughness is the roughness a surface stops reflecting the
	// screen at, fading out over the half of the range below it; zero
	// means 0.35.
	ReflectionRoughness float32
	// ReflectionDistance is how far a reflection ray travels in world
	// units; zero means 30.
	ReflectionDistance float32
	// ReflectionSteps is the most samples a reflection ray takes along the
	// way; zero means 32. A ray that crosses fewer half-resolution pixels
	// on screen takes one a pixel. More is sharper and slower.
	ReflectionSteps int
	// LUT grades the final colours through a lookup table: a strip of n
	// slices of n by n, n by n squared pixels wide, as NeutralLUT lays it
	// out and image editors export it after grading a screenshot. Load it
	// with NewLUT; nil grades nothing. LUTStrength blends towards the
	// graded colour; zero means 1.
	LUT         *Texture
	LUTStrength float32

	// TemporalAA averages each frame with the ones before it, jittering
	// the projection by a fraction of a pixel so the average fills in the
	// steps along an edge. It replaces FXAA on the main frame while it is
	// on; default off. Moving meshes need DrawMeshMoved and its
	// companions, or they smear until the neighbourhood clamp catches up.
	// Motion vectors are written by the opaque meshes the camera sees, so
	// a moving blended or transmissive mesh reprojects as if it were
	// still whatever it was drawn with.
	TemporalAA bool
	// TemporalBlend is how much of the new frame goes into the average,
	// 0.02 to 1; zero means 0.1. Lower is steadier and softer.
	TemporalBlend float32

	// FocusDistance is how far in front of the camera the image is sharp,
	// in world units; zero turns depth of field off. FocusRange is how
	// far either side of it stays sharp before the blur grows, and how
	// far past that the blur reaches its full width; zero means a quarter
	// of FocusDistance. BokehRadius is that full width in pixels (zero
	// means 12) and BokehSamples how many taps the disc takes (zero means
	// 16).
	FocusDistance float32
	FocusRange    float32
	BokehRadius   float32
	BokehSamples  int

	// MotionBlur smears each pixel back along the way it moved since the
	// last frame, 0 (off) to 1; default 0. MotionSamples is how many taps
	// it takes along that path; zero means 8. The camera's motion is read
	// from depth, an object's from the velocity buffer, so a moving mesh
	// needs DrawMeshMoved to blur along its own path.
	MotionBlur    float32
	MotionSamples int

	// Aberration splits the red and blue channels apart towards the edge
	// of the frame, as a cheap lens does; zero means off, 1 is about three
	// pixels at the edge of a 1080-wide frame and 0.5 is a subtle fringe.
	Aberration float32
	// Distortion bends the image about the centre: positive is barrel,
	// negative pincushion; zero means off.
	Distortion float32
	// Ghosts draws the bright pass mirrored through the centre a few
	// times over, the reflections a lens makes of a bright light; zero
	// means off. It reads the bloom image, so it needs Bloom above zero.
	Ghosts float32
	// Grain adds per-pixel noise that moves each frame, as film does;
	// zero means off, 0.05 is subtle.
	Grain float32

	// GodRays is the strength of the shafts of light the directional
	// light throws past an occluder; zero means off. GodRayDecay is how
	// fast a shaft fades along its length (zero means 0.96),
	// GodRayDensity how far towards the sun each pixel walks (zero means
	// 0.6) and GodRaySamples how many steps it takes (zero means 32).
	// The pass is skipped when the sun is behind the camera.
	GodRays       float32
	GodRayDecay   float32
	GodRayDensity float32
	GodRaySamples int

	// Post2D runs the composite on a frame that has no 3D draws at all,
	// so bloom, the grade, the LUT, the lens effects and FXAA reach a 2D
	// game. Zero keeps the direct path, which draws the 2D stream
	// straight to the screen and costs nothing. Exposure and tone mapping
	// are skipped in this mode, so a 2D game with no other setting on
	// gets back the colours it drew; the effects that need depth
	// (ambient occlusion, depth of field, motion blur, temporal
	// anti-aliasing, god rays) stay off. It applies to the screen and not
	// to a render texture, whose alpha the composite would flatten.
	Post2D bool
}

PostSettings controls the post-processing applied to 3D scenes.

func DefaultPost

func DefaultPost() PostSettings

DefaultPost is the starting PostSettings.

type Ray

type Ray struct {
	Origin, Dir lin.Vec3
}

Ray is a half-line in world space.

type ReflectionProbe

type ReflectionProbe struct {
	// Position is where the cube map is captured, in world units. It is
	// also the centre a box projection reflects around, so put it where a
	// viewer looks from rather than in a wall.
	Position lin.Vec3
	// Extent is the half-size of the box the probe covers. A zero Extent
	// with a positive Radius makes a sphere probe instead. A probe with
	// neither covers nothing and is ignored.
	Extent lin.Vec3
	// Radius is the sphere probe's radius in world units; zero means the
	// probe is a box.
	Radius float32
	// Margin is how far inside the volume's edge the probe fades towards
	// the frame's own environment, in world units; zero means it does not
	// fade and the reflection changes at the boundary.
	Margin float32
	// Resolution is the cube face size in texels the bake renders and
	// prefilters; zero means 64. Larger is sharper in a mirror and slower
	// to bake.
	Resolution int
	// Intensity multiplies the probe's light; zero means 1.
	Intensity float32
	// BoxProjection reflects the box's walls at the place the ray meets
	// them rather than at infinity, so a floor mirrors the wall it faces.
	// It applies to box probes and is ignored by a sphere probe, which
	// always projects onto its sphere.
	BoxProjection bool
	// contains filtered or unexported fields
}

ReflectionProbe is the environment of one part of a scene, captured from a point and reflected by the surfaces inside its volume: a red room that reddens the chrome in it, a cave that stays dark under a bright sky. Fill in the position and the volume, bake it once with BakeProbe, and add it to each frame with AddProbe. Draws whose centre falls inside the volume reflect the probe instead of the light's Environment or Sky; everything outside every probe keeps those.

A probe changes reflections, not the diffuse ambient light, which comes from the light's environment or a LightProbeGrid.

func (*ReflectionProbe) Destroy

func (p *ReflectionProbe) Destroy()

Destroy frees the probe's cube map. Baking again destroys the previous one on its own, so this is for a probe a game is finished with.

func (*ReflectionProbe) Environment

func (p *ReflectionProbe) Environment() *Environment

Environment returns the probe's baked environment, or nil before the first BakeProbe. It is the same form NewEnvironment builds, so it can be set as Light.Environment to light a whole scene from a probe.

type Region

type Region struct {
	Tex      *Texture
	UV0, UV1 lin.Vec2
}

Region is a rectangle of a texture, the piece an atlas or a sheet frame refers to. DrawRegion draws it; Sheet.Region and NewRegion make them.

func NewRegion

func NewRegion(tex *Texture, r lin.Rect) Region

NewRegion takes a rectangle of a texture in pixels.

func (Region) Size

func (r Region) Size() lin.Vec2

Size is the region's size in texture pixels.

type RegionAnimation

type RegionAnimation struct {
	Frames    []Region
	Durations []float32 // seconds per frame; a zero duration means 0.1
	Loop      bool
}

RegionAnimation is a tag's frames with the timing the atlas gave each one, for playing an Aseprite animation as authored. Build one with Atlas.Animation and read the frame to draw with At.

func (RegionAnimation) At

func (r RegionAnimation) At(t float64) (Region, bool)

At returns the frame showing at a time from the start, and whether the animation has ended (never, for one that loops). An animation with no frames returns an empty region and done.

func (RegionAnimation) Length

func (r RegionAnimation) Length() float64

Length is the animation's total time in seconds.

type RenderTexture

type RenderTexture struct {
	Width, Height int
	// contains filtered or unexported fields
}

RenderTexture is an offscreen surface that draws like the screen and is then used like a texture: minimaps, portraits, mirrors, picture-in-picture.

func (*RenderTexture) Destroy

func (rt *RenderTexture) Destroy()

Destroy frees the surface. Called inside a frame it costs no wait: everything it owns goes on the frame slot's retire list and is freed once that frame has finished.

func (*RenderTexture) Read

func (rt *RenderTexture) Read() (*image.RGBA, error)

Read copies the last rendered image back from the GPU, after waiting for it to finish: thumbnails, saved portraits, tests. Whatever the surface's colour format, the result is an ordinary image: a ColorHDR surface is encoded the way the screen is, so values above 1 clip, and a ColorMask surface reads as grey, its one channel copied into red, green and blue alike. Colours follow Go's sRGB-premultiplied alpha convention. Calls during an active frame return an error; its queued draws have not been submitted yet.

func (*RenderTexture) ReadDepth

func (rt *RenderTexture) ReadDepth() ([]float32, error)

ReadDepth copies the depth the last 3D scene drawn into this texture left behind, one float per pixel, row-major from the top-left corner: 0 at the near plane and 1 at the far plane, in the non-linear distribution a perspective projection produces. It is the depth the engine's own ambient occlusion and decals read, resolved to one sample per pixel when the scene is multisampled.

It waits for the GPU and copies the whole image back to the host, so it is for tools, tests and one-off queries rather than for every frame. Read only after a completed 3D render; no previous depth content is guaranteed before that. Active frames and missing or destroyed scene targets return an error.

func (*RenderTexture) SetView

func (rt *RenderTexture) SetView(width, height float32)

SetView sets the render texture's 2D coordinate space; default is pixels.

func (*RenderTexture) Texture

func (rt *RenderTexture) Texture() *Texture

Texture returns the surface for drawing as a sprite or material. RenderTexture owns it; destroy the RenderTexture rather than this view.

type RenderTextureOptions

type RenderTextureOptions struct {
	// Nearest keeps a low-resolution scene's pixels sharp when it is
	// scaled up (a pixel-art game rendering at 320 by 180).
	Nearest bool
	// Repeat tiles the texture instead of clamping at its edges.
	Repeat bool
	// Format is the colour format; the default matches the window.
	Format ColorFormat
	// NoDepth leaves out the depth buffer of the surface's own pass, which
	// nothing tests against: the 3D scene has its own depth buffer and
	// composites through it, and 2D drawing never uses one. Set it to save
	// the memory on a target that is only ever drawn to.
	NoDepth bool
	// Samples multisamples the surface itself: 1 (the default), 2, 4 or 8,
	// clamped to what the GPU supports and reported by Graphics.MaxSamples.
	// Every edge drawn into it, including 2D paths and triangles, is
	// resolved from that many coverage samples. It is separate from
	// PostSettings.Samples, which multisamples the 3D scene behind the
	// composite, here as on screen.
	Samples int
}

RenderTextureOptions says how a render texture is made and how it samples when it is drawn.

type Resource

type Resource struct {
	Kind ResourceKind
	// Width and Height are texels, for textures, render textures, font
	// atlases and an environment's cube face.
	Width, Height int
	// Vertices and Indices are a mesh's counts.
	Vertices, Indices int
	// Parts is a model's primitive count.
	Parts int
	// Bytes is an estimate of the GPU memory the resource holds. It
	// counts the images and buffers the resource owns, so a model reads
	// as zero: its meshes and textures are listed on their own.
	Bytes int
}

Resource describes one live GPU resource: what it is, how big it is and roughly how much GPU memory it holds. Only the fields that suit the kind are filled in.

type ResourceKind

type ResourceKind uint8

ResourceKind names one kind of GPU resource in a Resources snapshot.

const (
	ResourceTexture ResourceKind = iota
	ResourceMesh
	ResourceModel
	ResourceFont
	ResourceRenderTexture
	ResourceEnvironment
	ResourceGeometry2D
)

func (ResourceKind) String

func (k ResourceKind) String() string

String names the kind in lower case, for a debug listing.

type RichFonts

type RichFonts struct {
	Regular, Bold, Italic, BoldItalic *Font
}

RichFonts are the faces rich text draws with; a nil variant falls back to Regular, so plain text needs only that.

func (RichFonts) Layout

func (rf RichFonts) Layout(text RichText, opts TextOptions) (*TextLayout, error)

Layout constructs the same reusable result as Font.Layout, preserving styles and links. Text indices address RichText.Plain, never markup tags. Regular is required; missing style faces fall back to it. Fonts must be live and belong to the same Graphics. The result borrows their atlases. A layout of the same runs and options made recently is returned from the regular font's cache; finding it hashes the runs, so keep the returned layout and draw it with DrawTextLayout to skip even that.

func (RichFonts) MeasureRich

func (rf RichFonts) MeasureRich(rt RichText, opts TextOptions) (w, h float32)

MeasureRich returns logical text dimensions using the same Unicode shaping and wrapping as Layout, without rasterizing or uploading glyphs. It returns zero for missing fonts or invalid options; Layout reports those errors.

type RichLink struct {
	Name string
	Rect lin.Rect
}

RichLink is where a link was drawn, for hit-testing clicks; a link that wraps reports one rectangle per line.

type RichRun

type RichRun struct {
	Text          string
	Color         Color // zero means the block's colour
	Bold          bool
	Italic        bool
	Underline     bool
	Strikethrough bool
	OutlineWidth  float32 // zero inherits TextOptions.OutlineWidth
	OutlineColor  Color   // zero inherits the block's outline colour
	Link          string  // a name reported back with its rectangle
}

RichRun is a stretch of text in one style: a colour, a bold or italic face, decorations, an outline, or a link a click can hit. A shaping cluster crossing a style boundary takes all styles from its first source byte; combining sequences and ligatures are never split by a colour or link change.

type RichText

type RichText struct {
	Runs []RichRun
}

RichText is styled text made of runs, from ParseRich or by hand.

func ParseRich

func ParseRich(markup string) RichText

ParseRich reads a small markup: [b]bold[/b], [i]italic[/i], [u]underlined[/u], [s]struck through[/s], [#ff8800]coloured[/#] (or [color=#ff8800]...[/color]), and [link=name]text[/link]. Tags nest, "[[" is a literal bracket, and an unknown tag is kept as text.

func (RichText) Plain

func (rt RichText) Plain() string

Plain returns the text without styling.

type Shader

type Shader struct {
	// VertexBounds is how far a mesh shader's vertex program moves a
	// vertex, as a multiple of the mesh's bounding radius: 0.25 for a flag
	// that ripples a quarter of its own size. Culling grows a draw's
	// radius by 1 + VertexBounds. Zero means the program may put a vertex
	// anywhere, so draws made with the shader are never culled; set it as
	// soon as the displacement has a limit. This applies only to shaders
	// with a vertex hook. It is read when the frame prepares its queued
	// draws, so the final value applies to every draw using this shader.
	VertexBounds float32
	// contains filtered or unexported fields
}

Shader is a fragment program the game wrote, compiled to SPIR-V with bunyip-shader or Compiler. A sprite shader colours 2D drawing; a mesh shader adjusts a surface before the engine lights it. Uniforms and up to four extra images ride along with every draw made while it is set.

func (*Shader) Destroy

func (s *Shader) Destroy()

Destroy frees the shader's pipelines. Called inside a frame it costs no wait: they go on the frame slot's retire list and are freed once that frame has finished.

func (*Shader) Reload

func (s *Shader) Reload(spirv []byte) error

Reload replaces the shader's program with newly compiled SPIR-V from bunyip-shader, rebuilding its pipelines, so a game watching its shader files (asset.Watcher) can swap them while it runs. Images and uniforms are kept. The old pipelines are freed once the frame that may still be drawing with them has finished.

func (*Shader) ReloadSource

func (s *Shader) ReloadSource(ctx context.Context, source string) error

ReloadSource compiles WGSL for this shader's existing kind, then replaces its GPU programs. Compilation or pipeline creation errors preserve the old shader. Uniforms and images are retained. Call on the game goroutine; this method compiles in Go and blocks until compilation finishes. For background compilation, compile through shaders.Compiler and call Reload with the resulting bytes on the game goroutine. Cancellation is checked between compilation phases, not during a phase or GPU pipeline creation.

func (*Shader) SetImage

func (s *Shader) SetImage(slot int, t *Texture)

SetImage binds a texture as image0..image3 for draws from now on; nil unbinds it (the shader then samples white). A texture from another Graphics panics without changing the binding.

func (*Shader) SetUniforms

func (s *Shader) SetUniforms(v any) error

SetUniforms packs a struct or non-nil pointer to one into a std140 block for subsequent draws. Fields follow declaration order and must be exported. Supported values are float32, int32, uint32, bool (including named scalar types), lin.Vec2/Vec3/Vec4, Color, lin.Mat3/Mat4, fixed arrays and nested structs. Matrices are column-major. A plain [N]float32 is a scalar array, with 16-byte strides; use lin vector/matrix types for WGSL vectors/matrices. Booleans map to WGSL u32 fields (0 or 1). WGSL scalar arrays need padded element wrappers to match the 16-byte std140 stride. Padding is automatic and zeroed. No Go memory is retained. Unsupported fields or blocks exceeding 1024 packed bytes return errors and preserve the previous block. The caller must match the shader's declarations; this does not inspect SPIR-V or perform numeric precision conversions.

type Sheet

type Sheet struct {
	Texture       *Texture
	FrameW        int
	FrameH        int
	Columns, Rows int
	Margin        int // pixels around the whole grid
	Spacing       int // pixels between frames
}

Sheet cuts a texture into a grid of equal frames, numbered row-major from the top-left, for tilesets and sprite sheets.

func NewSheet

func NewSheet(tex *Texture, frameW, frameH int) *Sheet

NewSheet describes a grid of frameW x frameH cells over the texture.

func (*Sheet) Count

func (s *Sheet) Count() int

Count is the number of frames.

func (*Sheet) Region

func (s *Sheet) Region(frame int) Region

Region returns a frame as a Region, for DrawRegion and atlases.

func (*Sheet) UV

func (s *Sheet) UV(frame int) (uv0, uv1 lin.Vec2)

UV returns the texture rectangle of a frame in 0..1.

type SkinVertex

type SkinVertex struct {
	Pos     lin.Vec3
	Normal  lin.Vec3
	UV      lin.Vec2
	UV2     lin.Vec2
	Color   Color // zero means white
	Joints  [4]uint8
	Weights [4]float32
}

SkinVertex is a Vertex with up to four joint influences.

type Sky

type Sky struct {
	// Space is a distant image environment behind the procedural sky. Its
	// radiance is attenuated by the atmosphere and adds to diffuse lighting
	// and reflections. Light.Environment, when set, takes precedence.
	Space   *Environment
	Up      lin.Vec3 // away from the ground, or from the planet below a ship; zero means +Y
	Zenith  Color    // the sky straight up, in full atmosphere; zero means Horizon
	Horizon Color    // the sky at the horizon; zero means Zenith, or the light's Ambient
	Ground  Color    // light from below: terrain, sea, the face of a planet; zero means Ambient
	// Vacuum thins the air: 0 is a full sky, 1 is space, where the sky is
	// black and the stars come out while the ground half stays.
	Vacuum  float32
	Sun     Color   // radiance of the drawn sun disc; zero means thirty times the light's colour
	SunSize float32 // the disc's angular radius in radians; zero means 0.0047, the Sun seen from Earth
	Stars   float32 // brightness of a starfield showing through thin air; zero means none
	// Atmosphere replaces Zenith and Horizon with scattered sunlight when
	// its Height is set: blue overhead, red along the horizon at sunrise
	// and sunset, dark when the sun is down, and thinning as the camera
	// climbs. Ground still colours the half below the horizon.
	Atmosphere Atmosphere
	// contains filtered or unexported fields
}

Sky is a procedural environment described by what a game already knows: which way is up, how much atmosphere there is, and where the sun is. It needs no image and costs nothing to change, so it can follow a ship from orbit down to the ground, or point its ground half at the planet a ship is passing. Set it as Light.Sky. Rough surfaces take its tint from every direction, metals reflect its gradient, and with Light.Background the sun's disc and the stars are drawn behind the scene. An image Environment on the light replaces it.

type SpotLight

type SpotLight struct {
	Position  lin.Vec3
	Direction lin.Vec3
	Color     Color
	Range     float32 // fades to nothing this far away
	// InnerAngle and OuterAngle are the cone's full angles in radians: full
	// inside the inner, fading to nothing at the outer; zero outer means
	// 45 degrees.
	InnerAngle, OuterAngle float32
	Shadows                bool // render a shadow map for this light
}

SpotLight is a cone of light for AddSpot, with the option of a shadow map: a flashlight that throws the bars' shadows, a lamp over a table. The first four shadowed spot lights a frame get maps (MaxSpotShadows), the rest shine without; add the nearest first.

type Sprite

type Sprite struct {
	Pos      lin.Vec2 // pivot position in view units before the transform stack
	Size     lin.Vec2 // dimensions in view units; DrawRegion/DrawFrame fill a zero size
	UV0, UV1 lin.Vec2 // normalized texture bounds; zero UV1 selects the full texture
	Color    Color    // straight linear tint; zero means white
	Rotation float32  // radians clockwise on a Y-down screen
	Origin   lin.Vec2 // pivot fraction: zero is top-left, (0.5, 0.5) is center
	// FlipX and FlipY mirror the image, for a character facing the other
	// way.
	FlipX, FlipY bool
	// Filter overrides the texture's own filtering for this draw.
	Filter Filter
}

Sprite is one textured quad. Size is in view units; UV0 and UV1 select the texture region in 0..1; Origin is the rotation pivot as a fraction of Size.

func (Sprite) Bounds

func (s Sprite) Bounds() lin.Rect

Bounds returns the axis-aligned rectangle enclosing Corners. It includes placement, origin and rotation, but not the graphics transform or camera.

func (Sprite) Corners

func (s Sprite) Corners() [4]lin.Vec2

Corners returns the four corners in texture order: top-left, top-right, bottom-right, bottom-left, after placement, origin and rotation. Negative sizes reverse the corresponding axis. The graphics transform and camera are not included, and texture flips do not move the corners.

type StaticBatch

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

StaticBatch is a set of mesh draws that never move, held behind a bounding volume hierarchy built once. Drawing the batch tests the hierarchy against the camera's frustum and the frame's occluders and queues only the items that survive, so a level's ten thousand rocks, crates and lamp posts cost a few dozen box tests instead of ten thousand. Items keep their own meshes and materials, so draws that share both are still merged into one instanced call. Items the camera cannot see still cast shadows: a subtree the camera rejects is walked again against the frame's shadow maps.

A batch does not own its meshes or textures; destroy those as usual. Its meshes, materials and shader belong to the Graphics that built it; constructing or drawing with resources from another Graphics panics. Build one with NewStaticBatch and draw it with DrawBatch. Anything that moves belongs in DrawMesh instead: the hierarchy is built from the models given and is not rebuilt. Mesh geometry and bounds must also remain fixed; rebuild the batch after changing either. Include any shader displacement in mesh bounds before building the hierarchy.

func (*StaticBatch) Bounds

func (b *StaticBatch) Bounds() (min, max lin.Vec3)

Bounds is the world box every item of the batch fits inside. An empty batch reports a zero box.

func (*StaticBatch) Len

func (b *StaticBatch) Len() int

Len is how many draws the batch holds.

type StencilOp

type StencilOp uint8

StencilOp is what a fragment that passes both the stencil and the depth test does to the stencil buffer. The zero value leaves it alone.

const (
	StencilKeep          StencilOp = iota // leave the value alone: the default
	StencilReplace                        // store StencilRef
	StencilIncrement                      // add one, stopping at 255
	StencilDecrement                      // subtract one, stopping at 0
	StencilZero                           // store zero
	StencilInvert                         // invert all bits
	StencilIncrementWrap                  // add one, wrapping 255 to zero
	StencilDecrementWrap                  // subtract one, wrapping zero to 255

)

func (StencilOp) String

func (o StencilOp) String() string

String names the stencil operation.

type StencilOptions

type StencilOptions struct {
	Test                  StencilTest
	Reference             uint8
	Pass, Fail, DepthFail StencilOp
	ReadMask, WriteMask   uint8
	DisableWrite          bool
	NoColor               bool
}

StencilOptions controls stencil testing and updates for 2D fragments. Zero options draw normally and leave stencil unchanged. Zero ReadMask and WriteMask mean all eight bits; DisableWrite prevents all stencil updates. NoColor suppresses colour writes while retaining fragment stencil updates. The test compares the masked stored value to the masked Reference.

type StencilTest

type StencilTest uint8

StencilTest is when a material's fragments pass the stencil test: how the value already in the stencil buffer must compare to the material's StencilRef. The zero value draws everywhere.

const (
	StencilAlways       StencilTest = iota // no test at all: the default
	StencilEqual                           // only where the buffer holds StencilRef
	StencilNotEqual                        // only where it holds anything else
	StencilLess                            // only where it holds less than StencilRef
	StencilGreater                         // only where it holds more than StencilRef
	StencilNever                           // reject every fragment; only its Fail operation can update stencil
	StencilLessEqual                       // only where it holds at most StencilRef
	StencilGreaterEqual                    // only where it holds at least StencilRef

)

func (StencilTest) String

func (s StencilTest) String() string

String names the stencil test.

type StrokeOptions

type StrokeOptions struct {
	Width      float32 // zero means 1
	Cap        LineCap
	Join       LineJoin
	MiterLimit float32 // miter length over width beyond which corners bevel; zero means 4
	// Dash is a pattern of on and off lengths in view units, repeated
	// along the path, starting DashOffset in; empty strokes solid.
	Dash       []float32
	DashOffset float32
	// Gradient colours the stroke by position; the colour then tints it.
	Gradient    *Gradient
	NoAntiAlias bool
}

StrokeOptions controls StrokePath.

type Terrain

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

Terrain is a heightfield split into square chunks, each with a mesh at several resolutions, drawn at the resolution its distance from the camera deserves. Chunks are ordinary draws, so the frustum and the frame's occluders cull them, and each carries a skirt around its edge deep enough to hide the crack where it meets a coarser neighbour.

The ground is shaded by the built-in terrain shader: a splat map whose four channels weight four tiling layer textures. Height and Normal answer where the ground is, for placing trees, dropping items and walking on it, and Heights with Update let a game dig into it.

Build one with NewTerrain, draw it with DrawTerrain and free it with Destroy. One Terrain owns one shader and its pipelines, so a game with several of them pays for each; a game usually has one.

func (*Terrain) Bounds

func (t *Terrain) Bounds() (min, max lin.Vec3)

Bounds is the world box the terrain fills.

func (*Terrain) ChunkCentre

func (t *Terrain) ChunkCentre(i int) lin.Vec3

ChunkCentre is the middle of a chunk's world box, which is what the level is chosen by.

func (*Terrain) ChunkLevel

func (t *Terrain) ChunkLevel(i int) int

ChunkLevel is the resolution the last DrawTerrain chose for a chunk: 0 is the finest, each level after it halves the samples along each side. It is what to print when the terrain is refining in the wrong places.

func (*Terrain) Chunks

func (t *Terrain) Chunks() int

Chunks is how many chunks the terrain is split into.

func (*Terrain) Destroy

func (t *Terrain) Destroy()

Destroy frees the chunk meshes, the shader and the splat texture the terrain made. Layer textures belong to the game and are left alone.

func (*Terrain) Height

func (t *Terrain) Height(x, z float32) float32

Height is the ground's world y at a world x and z, interpolated across the cell the point falls in. Outside the terrain it is the height of the nearest edge sample.

func (*Terrain) Heights

func (t *Terrain) Heights() []float32

Heights is the terrain's own height samples, row by row, so Heights()[z*cols+x] is the height at column x of row z. Write into it to dig or raise the ground, then call Update over the samples that changed so the meshes and their normals follow.

func (*Terrain) Levels

func (t *Terrain) Levels() int

Levels is how many resolutions each chunk keeps.

func (*Terrain) Normal

func (t *Terrain) Normal(x, z float32) lin.Vec3

Normal is the ground's unit normal at a world x and z, from the heights either side of the nearest sample. Use it to lie a rock flat on a slope or to refuse to build on one.

func (*Terrain) Raycast

func (t *Terrain) Raycast(r Ray, reach float32) (lin.Vec3, bool)

Raycast walks a ray over the heightfield and returns the first point where it passes under the ground, for a click that digs, a shot that throws up dust or a unit ordered to a spot. It steps a cell at a time and then narrows the step it crossed on, so it finds the nearest hit on ground that is no steeper than a cell is wide; reach is how far along the ray to look, and zero means the terrain's whole diagonal. A ray that starts under the ground reports its own origin.

func (*Terrain) SetSplat

func (t *Terrain) SetSplat(img image.Image) error

SetSplat replaces the layer weights, for a splat map painted after the terrain was built or repainted as the ground changes: the game asks the terrain's own Height and Normal where sand, grass, rock and snow belong, then hands the answer back. The image is stretched over the whole heightfield, its channels weighting layers one to four, and the terrain owns and frees the texture it makes from it. A nil image restores the default of the first layer everywhere.

func (*Terrain) Shader

func (t *Terrain) Shader() *Shader

Shader is the terrain's own mesh shader, for a game that wants to rebind a layer with SetImage or change the layer scales with SetUniforms after it is built.

func (*Terrain) Size

func (t *Terrain) Size() (cols, rows int, cell float32)

Size is the terrain's samples across and deep and the world units between them.

func (*Terrain) Update

func (t *Terrain) Update(minX, minZ, maxX, maxZ int) error

Update rebuilds the chunks covering a rectangle of samples after the game has written into Heights: the cost is one mesh upload per level of each chunk it touches. The rectangle is grown by one sample first, because a chunk's edge normals read its neighbour's heights.

type TerrainOptions

type TerrainOptions struct {
	// Heights is one world height per sample, row by row, so
	// Heights[z*Cols+x] is the height at column x of row z. NewTerrain
	// copies it.
	Heights []float32
	// Cols and Rows are the samples across (x) and deep (z). Both minus
	// one must be whole multiples of ChunkSize.
	Cols, Rows int
	// Cell is the world units between samples; zero means 1.
	Cell float32
	// Centre is where the middle of the heightfield sits in the world,
	// and its y is added to every height. Zero puts it at the origin.
	Centre lin.Vec3
	// ChunkSize is the samples across one chunk, a power of two; zero
	// means 32. Small chunks cull and refine finely and cost more draws.
	ChunkSize int
	// Levels is how many resolutions each chunk keeps, each halving the
	// samples of the one before; zero means 4, and it is clamped to what
	// ChunkSize can be halved to.
	Levels int
	// LODDistance is how far the finest level reaches; each level after
	// it covers twice the distance of the one before. Zero means eight
	// chunks' width.
	LODDistance float32
	// Splat weights the four layers by its channels, stretched over the
	// whole heightfield. Nil weights the first layer everywhere.
	Splat image.Image
	// Layers are the tiling albedo textures the splat's red, green, blue
	// and alpha channels choose between. Give them TextureOptions.Repeat,
	// since they tile. A nil layer samples white.
	Layers [4]*Texture
	// LayerScale is the world units per repeat of each layer; a zero
	// entry means 8.
	LayerScale [4]float32
	// LayerRoughness is each layer's roughness; a zero entry means 0.9,
	// which is the ground.
	LayerRoughness [4]float32
}

TerrainOptions describes a heightfield to NewTerrain.

type TextCaret

type TextCaret struct {
	Index    int
	Affinity CaretAffinity
}

TextCaret identifies an insertion boundary in the original UTF-8 source. Ligatures and combining clusters are atomic. Invalid or interior indices snap to the nearest valid cluster boundary, preferring the lower on a tie.

type TextLayout

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

TextLayout is an immutable, reusable shaped text block. It owns ordinary Go data and borrows its fonts and their atlases; it needs no Destroy. Queries remain valid after font destruction, but drawing requires live fonts. Construct one with Font.Layout or RichFonts.Layout, then DrawTextLayout.

func (*TextLayout) Bounds

func (l *TextLayout) Bounds() lin.Rect

Bounds returns logical advance and line-box bounds, including alignment, spacing and rotation. Wrapped trailing whitespace has zero advance but retains source caret boundaries; unwrapped whitespace keeps its advance. Glyphs can extend beyond this rectangle.

func (*TextLayout) Caret

func (l *TextLayout) Caret(position TextCaret) lin.Rect

Caret returns the caret's axis-aligned rectangle in layout coordinates. The rectangle is one view unit thick before rotation. Out-of-range indices clamp to the source ends; points inside a cluster snap to its closest edge.

func (*TextLayout) HitTest

func (l *TextLayout) HitTest(point lin.Vec2) TextCaret

HitTest returns the closest cluster boundary to a point in layout coordinates. It inverse-rotates the point and clamps outside the text to its closest line and caret, preserving wrap and bidi affinity.

func (*TextLayout) InkBounds

func (l *TextLayout) InkBounds() lin.Rect

InkBounds returns glyph ink and decoration bounds, including outlines and rotation. Atlas padding and the sampling filter's antialias fringe are excluded.

func (*TextLayout) Lines

func (l *TextLayout) Lines() []TextLine

Lines returns an independent copy of the line descriptions.

func (l *TextLayout) Links() []RichLink

Links returns an independent copy of link rectangles in layout coordinates.

func (*TextLayout) Text

func (l *TextLayout) Text() string

Text returns the original text (RichText.Plain for a styled layout).

type TextLine

type TextLine struct {
	Start, End int
	Bounds     lin.Rect
	Baseline   lin.Vec2
	Direction  Direction
}

TextLine describes one visual line or vertical column. Start and End are byte offsets into TextLayout.Text, excluding an explicit terminating newline. Bounds includes advances and the line height, not glyph overhangs. Baseline is its baseline origin; all coordinates include TextOptions.Angle.

type TextOptions

type TextOptions struct {
	Underline     bool
	Strikethrough bool
	OutlineWidth  float32 // view units; zero disables the outline
	OutlineColor  Color   // zero follows the effective text colour
	Width         float32 // wrap width in view units (column height for vertical text); zero means no wrapping
	Align         Align
	LineSpacing   float32 // multiplier; zero means 1
	// Size is the em size to draw at; zero means the font's own. SDF fonts
	// stay crisp at any size; bitmap fonts resample their atlas.
	Size float32
	// Angle rotates the text about its origin, in radians, clockwise on
	// screen.
	Angle float32
	// Baseline puts the first line's baseline at the origin's y instead of
	// the block's top, so text of different sizes lines up.
	Baseline bool
	// LetterSpacing adds view units between glyphs, for tracked-out
	// headings; negative tightens.
	LetterSpacing float32
	// Hyphenate breaks long words at the hyphenator's points when a line
	// wraps, drawing a hyphen at the break.
	Hyphenate *Hyphenator
	// AutoHyphenate breaks long words with the hyphenator for Language, or
	// American English when Language is empty. A language the engine ships
	// no patterns for is not hyphenated. Hyphenate wins when both are set.
	AutoHyphenate bool
	Direction     Direction
	// Language is a BCP 47 tag ("tr", "zh-Hant") that picks language-specific
	// glyph forms; empty means the font's default.
	Language string
}

TextOptions lays out text.

type Texture

type Texture struct {
	Width, Height int
	// contains filtered or unexported fields
}

Texture is an image on the GPU, sampled by sprites, materials and shaders. Create it through Graphics; its zero value is not drawable. Width and Height are pixel dimensions maintained by the engine and must not be assigned by callers. Destroy releases owned GPU storage.

func (*Texture) CopyFrom

func (t *Texture) CopyFrom(src *Texture, srcRect image.Rectangle, dst image.Point) error

CopyFrom copies srcRect from src to dst on this texture's GPU image, preserving the stored bytes and regenerating this texture's mip chain. A zero rectangle selects the whole source. Both regions must fit; there is no clipping, scaling, blending or colour conversion. Source and destination need identical formats and Graphics ownership. Compressed textures, destroyed textures, overlapping self-copies and render-texture destinations are rejected.

Within a frame this records before all queued drawing, like Write. A source render texture already queued through DrawTo is rejected because its new pixels will not exist until the frame renders. Otherwise it copies the last completed source image, plus any preceding texture uploads in the frame. Outside a frame it waits for the GPU. Non-overlapping self-copies are supported.

func (*Texture) Destroy

func (t *Texture) Destroy()

Destroy frees the texture. Called inside a frame it costs no wait: the image and its descriptor sets go on the frame slot's retire list and are freed once that frame has finished, so sprites and meshes already queued this frame still draw with it.

func (*Texture) Read

func (t *Texture) Read() (*image.RGBA, error)

Read copies pixels back from the GPU as an ordinary Go image, with colours premultiplied in sRGB space. Data texture channels retain their stored values. It waits for the GPU and is only valid outside an active frame; queued uploads and rendering have not been submitted during Update or Draw. A compressed texture holds blocks rather than texels, so reading one is an error; decode its KTX2 file with gfx/ktx2 instead.

func (*Texture) Replace

func (t *Texture) Replace(src image.Image) error

Replace swaps the texture's pixels for another image, keeping the *Texture the game holds valid: every sprite, material and shader slot that names it draws the new image without being told. Use it to reload a texture whose file changed on disk; asset.Reloader calls it for you. The image may be a different size, and the filtering, edge handling, colour handling and mip choice the texture was made with are kept. Inside a frame it costs no wait, and the old image is freed once the frames that may still draw from it have finished. A render texture's image belongs to the render texture, so replacing one is an error.

func (*Texture) ReplaceCompressed

func (t *Texture) ReplaceCompressed(data []byte) error

ReplaceCompressed swaps a compressed texture's blocks for those of another KTX2 file, keeping the *Texture the game holds, the way Replace does for an image. asset.Reloader calls it when a .ktx2 file changes on disk.

func (*Texture) SavePNG

func (t *Texture) SavePNG(path string) error

SavePNG reads the completed texture, then creates or truncates path and closes the output file. It has the same format and frame-timing restrictions as Read.

func (*Texture) Write

func (t *Texture) Write(x, y int, src image.Image) error

Write replaces the pixels under src placed at (x, y), clipped to the texture, and rebuilds the mip chain. Inside a frame (between the engine's Begin and End, which is where Update and Draw run) the copy is recorded into the frame and costs no wait, so video and painting can write every frame; outside one it joins the batch of uploads the next frame submits first, and also costs no wait. Nil sources and coordinate overflow return errors. Render-texture views reject Write; use Graphics.DrawTo to change their pixels.

func (*Texture) WritePNG

func (t *Texture) WritePNG(w io.Writer) error

WritePNG reads the completed texture and writes PNG to a borrowed writer. It has the same format and frame-timing restrictions as Read.

type TextureOptions

type TextureOptions struct {
	Linear bool // bilinear filtering; the default is nearest, for pixel art
	// Data marks pixels that are not sRGB colour (masks, glyph coverage,
	// lookup tables); they are sampled without gamma decoding.
	Data bool
	// NoMipmaps keeps a single level; linear textures get a full mip chain
	// by default so distant surfaces do not shimmer.
	NoMipmaps bool
	// Repeat tiles the texture instead of clamping at the edges.
	Repeat bool
}

TextureOptions selects sampling and colour handling.

type TileAnimation

type TileAnimation struct {
	Frames    []int
	Durations []float32
}

TileAnimation cycles a frame through others: water, torches, grass in the wind. Durations are seconds per frame; one value applies to all.

type Tilemap

type Tilemap struct {
	Sheet         *Sheet
	Width, Height int     // in tiles
	Tiles         []int   // row-major, len Width*Height; frames with optional flip bits
	TileW, TileH  float32 // drawn size of one tile; zero means the frame size
	// contains filtered or unexported fields
}

Tilemap is a grid of frame indices into a sheet; -1 is empty.

func NewTilemap

func NewTilemap(sheet *Sheet, width, height int) *Tilemap

NewTilemap makes an empty map of the given size.

func (*Tilemap) Advance

func (t *Tilemap) Advance(dt float64)

Advance moves the map's animations forward by dt seconds.

func (*Tilemap) Animate

func (t *Tilemap) Animate(frame int, a TileAnimation)

Animate makes every cell showing frame play the animation instead.

func (*Tilemap) Get

func (t *Tilemap) Get(x, y int) int

Get returns the frame at a cell, or -1.

func (*Tilemap) Set

func (t *Tilemap) Set(x, y, frame int)

Set places a frame at a cell; out-of-range cells are ignored.

type Transform

type Transform struct {
	Position lin.Vec3
	Rotation lin.Quat // zero means no rotation
	Scale    lin.Vec3 // zero means 1
}

Transform is a position, rotation and scale in 3D; its zero value is identity. Use it instead of building matrices by hand.

func At

func At(x, y, z float32) Transform

At makes a transform at a position.

func (Transform) Forward

func (t Transform) Forward() lin.Vec3

Forward is the local -Z axis in world space.

func (Transform) Matrix

func (t Transform) Matrix() lin.Mat4

Matrix returns the model matrix.

func (Transform) Moved

func (t Transform) Moved(d lin.Vec3) Transform

Moved returns the transform shifted by d.

func (Transform) Rotated

func (t Transform) Rotated(axis lin.Vec3, angle float32) Transform

Rotated adds a rotation of angle radians about axis.

func (Transform) Scaled

func (t Transform) Scaled(s float32) Transform

Scaled sets a uniform scale.

type Transform2

type Transform2 struct {
	Position lin.Vec2
	Rotation float32
	Scale    lin.Vec2
}

Transform2 places a 2D entity: its centre in view or world units, a rotation in radians and a scale (zero means 1). Physics and animation systems write it; Apply turns a sprite template into the sprite to draw there.

func At2

func At2(x, y float32) Transform2

At2 makes a 2D transform at a position.

func (Transform2) Apply

func (t Transform2) Apply(s Sprite) Sprite

Apply centres the sprite on the transform's position, rotating about its centre and scaling its size.

type Vertex

type Vertex struct {
	Pos    lin.Vec3
	Normal lin.Vec3
	UV     lin.Vec2
	UV2    lin.Vec2
	Color  Color
}

Vertex is a mesh vertex: position, normal, a texture coordinate, an optional second set (UV2, for lightmaps and occlusion) and an optional colour that multiplies the material's base colour (zero means white).

func AppendMesh

func AppendMesh(verts []Vertex, indices []uint32, moreVerts []Vertex, moreIndices []uint32) ([]Vertex, []uint32)

AppendMesh adds a second mesh's geometry to the first, offsetting its indices, so a chunk, a building or a compound shape becomes one mesh and one draw.

func CapsuleMesh

func CapsuleMesh(rings, segments int, halfHeight float32) ([]Vertex, []uint32)

CapsuleMesh returns a capsule of radius 1 whose straight middle runs from y = -halfHeight to y = halfHeight, with rings across each cap and segments around: the shape of a Capsule collider and of most characters' bodies.

func ConeMesh

func ConeMesh(segments int) ([]Vertex, []uint32)

ConeMesh returns a cone of radius 1 at y = -1 rising to a point at y = 1, in segments around: spikes, trees, arrow heads, spot light gizmos.

func CubeMesh

func CubeMesh() ([]Vertex, []uint32)

CubeMesh returns a unit cube centred on the origin with flat normals and a full UV square on each face.

func CylinderMesh

func CylinderMesh(segments int) ([]Vertex, []uint32)

CylinderMesh returns a cylinder of radius 1 from y = -1 to y = 1 with flat caps, in segments around: pillars, barrels, wheels, the shape of a capsule collider's middle.

func FlatShaded

func FlatShaded(verts []Vertex, indices []uint32) ([]Vertex, []uint32)

FlatShaded returns a copy of a mesh with no shared vertices, each triangle's vertices carrying its face normal: the faceted look of low-poly art and voxel worlds.

func HeightfieldMesh

func HeightfieldMesh(heights []float32, cols, rows int, cell float32) ([]Vertex, []uint32)

HeightfieldMesh returns terrain from a grid of heights, cols across (x) by rows deep (z), cell world units apart and centred on the origin, with smooth normals and UVs running 0..1 across the grid. Heights are read row by row, so heights[z*cols+x] is the height at column x of row z. Pair it with a MeshShape collider of the same vertices.

func PlaneMesh

func PlaneMesh(segments int) ([]Vertex, []uint32)

PlaneMesh returns a unit square in the xz plane centred on the origin, facing +y, divided into segments by segments quads so a vertex shader can ripple it: ground, water, a tabletop. UVs run 0..1 across it.

func QuadMesh

func QuadMesh() ([]Vertex, []uint32)

QuadMesh returns a unit square in the xy plane centred on the origin, facing +z, its UVs running from the top-left: the shape of a billboard or a flat sprite in a 3D scene.

func SphereMesh

func SphereMesh(rings, segments int) ([]Vertex, []uint32)

SphereMesh returns a UV sphere of radius 1 with the given resolution.

func TorusMesh

func TorusMesh(tube float32, rings, segments int) ([]Vertex, []uint32)

TorusMesh returns a ring of radius 1 with a tube of radius tube, in rings around the ring and segments around the tube: rings, tyres, selection circles.

func TransformVertices

func TransformVertices(verts []Vertex, m lin.Mat4) []Vertex

TransformVertices returns a copy of the vertices moved by a matrix, normals turned with it, for placing parts before merging them.

type Vertex2D

type Vertex2D struct {
	Pos   lin.Vec2
	UV    lin.Vec2
	Color Color // zero means white
}

Vertex2D is one corner of a triangle for DrawTriangles.

type View2D

type View2D struct {
	Viewport lin.Rect
	Size     lin.Vec2
}

View2D maps a local 2D coordinate space into a rectangle of its enclosing view. Viewport is in enclosing view units, independent of camera and transform state. Size is the local virtual size; a zero component uses the matching viewport dimension. Coordinates outside the viewport clip.

Viewport dimensions must be positive, Size components nonnegative, and all values finite. Mapping methods and WithView panic on invalid values.

func (View2D) LocalToParent

func (v View2D) LocalToParent(p lin.Vec2) lin.Vec2

LocalToParent maps a local view point into the enclosing view. It does not apply a camera or clamp points to the viewport.

func (View2D) ParentToLocal

func (v View2D) ParentToLocal(p lin.Vec2) lin.Vec2

ParentToLocal maps an enclosing view point, such as pointer input, into local view coordinates. Points outside the viewport are not clamped.

func (View2D) ParentToWorld

func (v View2D) ParentToWorld(p lin.Vec2, camera Camera2D) lin.Vec2

ParentToWorld maps an enclosing view point through the inverse camera into world coordinates. Test Viewport.Contains first when input outside the view should be ignored. Nested views map through each parent in turn.

func (View2D) WorldToParent

func (v View2D) WorldToParent(p lin.Vec2, camera Camera2D) lin.Vec2

WorldToParent maps a world point through camera and into the enclosing view, using this view's resolved virtual size.

Directories

Path Synopsis
Package ktx2 reads and writes KTX2 texture files and encodes and decodes the block-compressed formats they carry.
Package ktx2 reads and writes KTX2 texture files and encodes and decodes the block-compressed formats they carry.
Package shaders holds the gfx package's WGSL sources and committed SPIR-V, and the preludes that game shaders are compiled against.
Package shaders holds the gfx package's WGSL sources and committed SPIR-V, and the preludes that game shaders are compiled against.

Jump to

Keyboard shortcuts

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