shapes

package module
v0.0.0-...-8d4b776 Latest Latest
Warning

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

Go to latest
Published: Dec 11, 2025 License: MIT Imports: 8 Imported by: 1

README

shapes

Go Reference

shapes is a package for Ebitengine (the 2D game library written by Hajime Hoshi) that allows rendering some common shapes and effects in complementary ways to the official vector package. Some examples:

  • Smooth circles, triangles, hexagons, ellipses, rings, rects... (all with the option of rounding).
  • High quality image outlines, expansions and blurs.
  • Simple patterns like dots, rhombuses and triangles.
  • Some color functions and gradients.
  • Other misc effects like noise, dithering, warps, quad mapping...

Unlike vector, shapes relies more on simple Kage shaders instead of raw triangles rasterization. This means rendering tends to be smoother, but extra care has to be taken as changing shaders or some of its parameters will break batching.

[TODO: simple UI surface example image]

Credit

Many of the SDFs are based on https://iquilezles.org/articles/distfunctions2d.

Pending improvements

  • Revise target origins being properly applied everywhere, and document target/source origins behavior clearly.
  • Missing proper rounding conventions. All shapes that accept rounding should support a positive rounding value for SDF expansion, and optionally, if inner rounding is allowed, handle it through negative values. Currently, most shapes do inner rounding with positive values, so newer functions can't even be properly adapted. This respects size boundaries but it's a missed opportunity.

Documentation

Overview

shapes is a package for Ebitengine (the 2D game library written by Hajime Hoshi) that allows rendering some common shapes and effects in complementary ways to the official github.com/hajimehoshi/ebiten/v2/vector package. Unlike vector, shapes relies more on Kage shaders instead of raw triangles rasterization. This means rendering tends to be smoother, but extra care has to be taken as changing shaders or some of its parameters will break batching.

Index

Constants

View Source
const (
	RadsRight  = 0.0
	RadsLeft   = math.Pi
	RadsBottom = math.Pi / 2
	RadsTop    = 3 * math.Pi / 2

	RadsBottomRight = math.Pi / 4
	RadsTopRight    = 7 * math.Pi / 4
	RadsBottomLeft  = 3 * math.Pi / 4
	RadsTopLeft     = 5 * math.Pi / 4
)

Angle constants in radians, for use with drawing functions.

The general conventions for working with angles in this package are the following:

  • 0 is right, pi/2 is bottom, and so on (positive x axis goes left, positive y axis goes down).
  • All angles are expected in [0, 2*pi) range, and will be normalized to this range if they are negative, using a mod/wrap operation.
  • When working with ranges (start, end), the range is interpreted to go in clockwise direction.
  • A range of start == end will be considered empty.
  • A range of end >= start + 2*pi will be considered full.
View Source
const (
	DirRadsLTR = 0.0             // left to right
	DirRadsRTL = math.Pi         // right to left
	DirRadsTTB = math.Pi / 2     // top to bottom
	DirRadsBTT = 3 * math.Pi / 2 // bottom to top

	DirRadsTLBR = math.Pi / 4     // top-left to bottom-right
	DirRadsBLTR = 7 * math.Pi / 4 // bottom-left to top-right
	DirRadsTRBL = 3 * math.Pi / 4 // top-right to bottom-left
	DirRadsBRTL = 5 * math.Pi / 4 // bottom-right to top-left
)

Direction constants for use with gradient generation functions. See RadsRight constants for angle conventions and docs.

View Source
const AAMargin = 1.333

AAMargin is the standard antialias margin or soft edge value recommended for operations that accept it explicitly.

View Source
const MaxFloat16 = 65504

Variables

View Source
var (
	BlendSubtract = ebiten.Blend{
		BlendFactorSourceRGB:        ebiten.BlendFactorOne,
		BlendFactorSourceAlpha:      ebiten.BlendFactorOne,
		BlendFactorDestinationRGB:   ebiten.BlendFactorOne,
		BlendFactorDestinationAlpha: ebiten.BlendFactorOne,
		BlendOperationRGB:           ebiten.BlendOperationReverseSubtract,
		BlendOperationAlpha:         ebiten.BlendOperationReverseSubtract,
	}
	BlendMultiply = ebiten.Blend{
		BlendFactorSourceRGB:        ebiten.BlendFactorDestinationColor,
		BlendFactorSourceAlpha:      ebiten.BlendFactorDestinationColor,
		BlendFactorDestinationRGB:   ebiten.BlendFactorOneMinusSourceAlpha,
		BlendFactorDestinationAlpha: ebiten.BlendFactorOneMinusSourceAlpha,
		BlendOperationRGB:           ebiten.BlendOperationAdd,
		BlendOperationAlpha:         ebiten.BlendOperationAdd,
	}
)

Common blend modes not directly exposed on Ebitengine.

View Source
var DitherAlpha8 []float32 = []float32{
	0.0, 0.0, 0.0, 0.0,
	1.0 / 7.0, 1.0 / 7.0, 1.0 / 7.0, 1.0 / 7.0,
	2.0 / 7.0, 2.0 / 7.0, 2.0 / 7.0, 2.0 / 7.0,
	3.0 / 7.0, 3.0 / 7.0, 3.0 / 7.0, 3.0 / 7.0,
	4.0 / 7.0, 4.0 / 7.0, 4.0 / 7.0, 4.0 / 7.0,
	5.0 / 7.0, 5.0 / 7.0, 5.0 / 7.0, 5.0 / 7.0,
	6.0 / 7.0, 6.0 / 7.0, 6.0 / 7.0, 6.0 / 7.0,
	1.0, 1.0, 1.0, 1.0,
}
View Source
var DitherBRG []float32 = []float32{
	0.0, 0.0, 1.0, 1.0,
	1.0, 0.0, 0.0, 1.0,
	0.0, 1.0, 0.0, 1.0,
}
View Source
var DitherBW []float32 = []float32{
	0.0, 0.0, 0.0, 1.0,
	1.0, 1.0, 1.0, 1.0,
}
View Source
var DitherBW4 []float32 = []float32{
	0.0, 0.0, 0.0, 1.0,
	0.333, 0.333, 0.333, 1.0,
	0.666, 0.666, 0.666, 1.0,
	1.0, 1.0, 1.0, 1.0,
}
View Source
var DitherBayes [16]float32 = [16]float32{
	0.0 / 16.0, 12.0 / 16.0, 3.0 / 16.0, 15.0 / 16.0,
	8.0 / 16.0, 4.0 / 16.0, 11.0 / 16.0, 7.0 / 16.0,
	2.0 / 16.0, 14.0 / 16.0, 1.0 / 16.0, 13.0 / 16.0,
	10.0 / 16.0, 6.0 / 16.0, 9.0 / 16.0, 5.0 / 16.0,
}
View Source
var DitherCrumbs [16]float32 = [16]float32{
	0.0 / 16.0, 4.0 / 16.0, 8.0 / 16.0, 1.0 / 16.0,
	11.0 / 16.0, 14.0 / 16.0, 12.0 / 16.0, 5.0 / 16.0,
	7.0 / 16.0, 13.0 / 16.0, 15.0 / 16.0, 9.0 / 16.0,
	3.0 / 16.0, 10.0 / 16.0, 6.0 / 16.0, 2.0 / 16.0,
}
View Source
var DitherDots [16]float32 = [16]float32{
	12.0 / 16.0, 4.0 / 16.0, 11.0 / 16.0, 15.0 / 16.0,
	5.0 / 16.0, 0.0 / 16.0, 3.0 / 16.0, 10.0 / 16.0,
	6.0 / 16.0, 1.0 / 16.0, 2.0 / 16.0, 9.0 / 16.0,
	13.0 / 16.0, 7.0 / 16.0, 8.0 / 16.0, 14.0 / 16.0,
}
View Source
var DitherGlitch [16]float32 = [16]float32{
	0.0 / 16.0, 1.0 / 16.0, 2.0 / 16.0, 3.0 / 16.0,
	4.0 / 16.0, 5.0 / 16.0, 6.0 / 16.0, 7.0 / 16.0,
	8.0 / 16.0, 9.0 / 16.0, 10.0 / 16.0, 11.0 / 16.0,
	12.0 / 16.0, 13.0 / 16.0, 14.0 / 16.0, 15.0 / 16.0,
}
View Source
var DitherSerp [16]float32 = [16]float32{
	0.0 / 16.0, 12.0 / 16.0, 13.0 / 16.0, 1.0 / 16.0,
	3.0 / 16.0, 7.0 / 16.0, 6.0 / 16.0, 2.0 / 16.0,
	4.0 / 16.0, 8.0 / 16.0, 9.0 / 16.0, 5.0 / 16.0,
	11.0 / 16.0, 15.0 / 16.0, 14.0 / 16.0, 10.0 / 16.0,
}

Functions

func ColorToF32

func ColorToF32(clr color.Color) [4]float32

func Float32Inf

func Float32Inf() float32

func RGBF32

func RGBF32(clr color.Color) [3]float32

Types

type AlphaMaskPattern

type AlphaMaskPattern int

Related to DrawAlphaMaskCirc

const (
	MaskPatternDefault AlphaMaskPattern = iota // particles

	MaskPatternFlare       // lines, elliptical, flare
	MaskPatternEllipseCuts // modern elliptical cuts
	MaskPatternCircMesh    // circular mesh
	MaskPatternPhiGrid     // artistic phi-based grid geometry
)

type Clamping

type Clamping uint8
const (
	ClampNone   Clamping = 0b0000
	ClampTop    Clamping = 0b1000
	ClampBottom Clamping = 0b0100
	ClampLeft   Clamping = 0b0010
	ClampRight  Clamping = 0b0001

	ClampTopLeft     Clamping = ClampTop | ClampLeft
	ClampTopRight    Clamping = ClampTop | ClampRight
	ClampBottomLeft  Clamping = ClampBottom | ClampLeft
	ClampBottomRight Clamping = ClampBottom | ClampRight
)

type GaussKern

type GaussKern uint8
const (
	GaussKern3 GaussKern = iota
	GaussKern5
	GaussKern7
	GaussKern9
	GaussKern11
	GaussKern13
	GaussKern15
	GaussKern17
)

func (GaussKern) Radius

func (k GaussKern) Radius() int

func (GaussKern) Size

func (k GaussKern) Size() int

type GoldenRatioGen

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

func (*GoldenRatioGen) Float64

func (gen *GoldenRatioGen) Float64() float64

func (*GoldenRatioGen) Reset

func (gen *GoldenRatioGen) Reset()

type PointF32

type PointF32 struct {
	X, Y float32
}

func (PointF32) Add

func (p PointF32) Add(o PointF32) PointF32

func (PointF32) Dot

func (p PointF32) Dot(o PointF32) float32

func (PointF32) Length

func (p PointF32) Length() float32

func (PointF32) Normalize

func (p PointF32) Normalize() PointF32

func (PointF32) Scale

func (p PointF32) Scale(s float32) PointF32

func (PointF32) Sub

func (p PointF32) Sub(o PointF32) PointF32

type Renderer

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

Renderer is a helper type for basic shape rendering which reuses vertices and options for slightly reduced memory usage.

func NewRenderer

func NewRenderer() *Renderer

func (*Renderer) ApplyBlur

func (r *Renderer) ApplyBlur(target *ebiten.Image, mask *ebiten.Image, ox, oy, radius, colorMix float32)

ApplyBlur applies a gaussian blur to the given mask and draws it onto the given target. colorMix = 0 will use the renderer's vertex colors; colorMix = 1 will use the original mask colors.

WARNING: this is a quadratic algorithm on GPU. For radiuses above 4, you want to look at Renderer.ApplyBlur2() or Renderer.ApplyBlurD4().

func (*Renderer) ApplyBlur2

func (r *Renderer) ApplyBlur2(target *ebiten.Image, mask *ebiten.Image, ox, oy, radius, colorMix float32)

ApplyBlur2 is similar to ApplyBlur, but uses two 1D passes instead of a single 2D pass. This greatly reduces the amount of sampled pixels for the shader, and despite breaking batching tends to be much more efficient than Renderer.ApplyBlur().

This function uses one internal offscreen (#0).

func (*Renderer) ApplyBlurD4

func (r *Renderer) ApplyBlurD4(target *ebiten.Image, mask *ebiten.Image, ox, oy float32, horzKernel, vertKernel GaussKern, colorMix float32)

ApplyBlurD4 is a less flexible form of blur, similar to Renderer.ApplyBlur2(), that downscales the source x4 before applying a gaussian kernel. This blur implementation tends to be more efficient than ApplyBlur2 when it comes to less powerful hardware and large blur areas (it uses less memory and compute at the cost of more steps). When enough resources are available (e.g. most medium-sized or small blurs), ApplyBlur2 tends to be slightly more efficient than ApplyBlurD4.

This function uses two internal offscreens (#0, #1), and target and mask can be on the same internal atlas.

func (*Renderer) ApplyColorGlowD4

func (r *Renderer) ApplyColorGlowD4(target *ebiten.Image, mask *ebiten.Image, ox, oy float32, horzKernel, vertKernel GaussKern, rgb [3]float32, threshStart, threshEnd, colorMix float32)

ApplyColorGlowD4 is a color-specific version of Renderer.ApplyGlowD4(), where glow intensity is determined by color similarity instead of lightness.

This function uses two internal offscreens (#0, #1), and target and mask can be on the same internal atlas.

func (*Renderer) ApplyDarkHorzGlow

func (r *Renderer) ApplyDarkHorzGlow(target *ebiten.Image, mask *ebiten.Image, ox, oy, horzRadius, threshStart, threshEnd, colorMix float32)

ApplyDarkHorzGlow is the "negative" version of Renderer.ApplyHorzGlow(). Instead of using an additive blending effect around high luminosity areas, it uses multiplicative blending around dark areas.

Notice that unlike regular glow effects, dark glows expects threshStart >= threshEnd.

func (*Renderer) ApplyErosion

func (r *Renderer) ApplyErosion(target *ebiten.Image, mask *ebiten.Image, ox, oy, thickness float32)

Precondition: thickness can't exceed 32.

WARNING: this is a quadratic algorithm on GPU. For large erosions, consider [Renderer.JFMErosion]() instead.

func (*Renderer) ApplyExpansion

func (r *Renderer) ApplyExpansion(target *ebiten.Image, mask *ebiten.Image, ox, oy, thickness float32)

Precondition: thickness can't exceed 32.

WARNING: this is a quadratic algorithm on GPU. For large expansions, consider Renderer.ApplyExpansionRect() or [Renderer.JFMExpansion]() instead, but both of those are only useful in specific situations.

func (*Renderer) ApplyExpansionRect

func (r *Renderer) ApplyExpansionRect(target *ebiten.Image, mask *ebiten.Image, ox, oy, thickness float32)

ApplyExpansionRect performs double pass expansion with a square kernel. This is less general but more efficient than Renderer.ApplyExpansion().

Precondition: thickness can't exceed 32.

This function uses one internal offscreen (#0), and target and mask can be on the same internal atlas.

func (*Renderer) ApplyGlow

func (r *Renderer) ApplyGlow(target *ebiten.Image, mask *ebiten.Image, ox, oy, horzRadius, vertRadius, threshStart, threshEnd, colorMix float32)

ApplyGlow draws a horizontal glow effect for the given mask into the target, at the given coordinates. The effect mix intensity is determined by the renderer's color alphas.

Regarding the advanced control parameters:

  • threshStart and threshEnd indicate the start luminosity threshold at which the glow effect kicks in and the point at which it's fully active. threshStart must be <= threshEnd, and the values must be in [0, 1] range.
  • colorMix controls the glow's color. If 0, the glow color will be determined fully by the renderer's vertex colors. If 1, the glow color will be determined by the original mask colors. Any values in between will lead to linear interpolation.

Notice that this effect uses an internal offscreen (#0) and two passes, and target and mask can be on the same internal atlas.

func (*Renderer) ApplyGlowD4

func (r *Renderer) ApplyGlowD4(target *ebiten.Image, mask *ebiten.Image, ox, oy float32, horzKernel, vertKernel GaussKern, threshStart, threshEnd, colorMix float32)

ApplyGlowD4 is the multipass downscaling version of Renderer.ApplyGlow(). See Renderer.ApplyBlurD4() for further docs and context.

This function uses two internal offscreens (#0, #1), and target and mask can be on the same internal atlas.

func (*Renderer) ApplyHardShadow

func (r *Renderer) ApplyHardShadow(target *ebiten.Image, mask *ebiten.Image, ox, oy, xOffset, yOffset float32, clamping Clamping)

func (*Renderer) ApplyHorzBlur

func (r *Renderer) ApplyHorzBlur(target *ebiten.Image, mask *ebiten.Image, ox, oy, radius, colorMix float32)

func (*Renderer) ApplyHorzGlow

func (r *Renderer) ApplyHorzGlow(target *ebiten.Image, mask *ebiten.Image, ox, oy, horzRadius, threshStart, threshEnd, colorMix float32)

ApplyHorzGlow draws a horizontal glow effect for the given mask into the target, at the given coordinates. See Renderer.ApplyGlow() for additional documentation. Comparedto Renderer.ApplyGlow, this effect only applies the glow horizontally and it's much cheaper, requiring no offscreen and a single pass.

func (*Renderer) ApplyOutline

func (r *Renderer) ApplyOutline(target *ebiten.Image, mask *ebiten.Image, ox, oy, thickness float32)

Precondition: thickness can't exceed 32.

WARNING: this is a quadratic algorithm on GPU. For large outlines, consider Renderer.JFMOutline() instead.

func (*Renderer) ApplyScanlinesSharp

func (r *Renderer) ApplyScanlinesSharp(target *ebiten.Image, darkThick, clearThick int, intensity, offset float32)

func (*Renderer) ApplyShadow

func (r *Renderer) ApplyShadow(target *ebiten.Image, mask *ebiten.Image, ox, oy, xOffset, yOffset, radius float32, clamping Clamping)

func (*Renderer) ApplySimpleGlow

func (r *Renderer) ApplySimpleGlow(target *ebiten.Image, mask *ebiten.Image, ox, oy, radius float32)

ApplySimpleGlow draws the given mask into the target, at the given coordinates, with an glow effect added. The effect mix intensity is determined by the renderer's color alphas. For finer control, see also Renderer.ApplyGlow().

func (*Renderer) ApplyVertBlur

func (r *Renderer) ApplyVertBlur(target *ebiten.Image, mask *ebiten.Image, ox, oy, radius, colorMix float32)

func (*Renderer) ApplyWaveLines

func (r *Renderer) ApplyWaveLines(target *ebiten.Image, lineThick, minFillRate, maxFillRate, linesPerOsc, offset float32, dirRadians float64)

func (*Renderer) ApplyZoomShadow

func (r *Renderer) ApplyZoomShadow(target *ebiten.Image, mask *ebiten.Image, ox, oy, xOffset, yOffset, zoom float32, clamping Clamping)

func (*Renderer) ColorMix

func (r *Renderer) ColorMix(target, base, over *ebiten.Image, x, y int, alpha, mixLevel float32)

ColorMix draws 'base' and 'over' to 'target' using the mix() function for color mixing instead of BlendSourceOver or other standard composition operations. This is useful to interpolate color transitions or other image changes when the images have translucent areas.

The bounds of 'base' and 'over' must match.

func (*Renderer) ColorizeByLightness

func (r *Renderer) ColorizeByLightness(target, source *ebiten.Image, x, y float32, from, to color.RGBA, fromLightness, toLightness float32, steps int, curveFactor float32)

ColorizeByLightness draws source into target at the given (x, y), taking the lightness of each source pixel and remapping it to a color between 'from' and 'to'.

Key parameters:

  • fromLightness: pixels below this threshold take 'from' color. Expected range: [0.0, 1.0]
  • toLightness: pixels above this threshold take 'to' color. Expected range: [0.0, 1.0].
  • steps: number of color steps in the gradient. Use steps <= 0 for a continuous gradient.
  • curveFactor: adjusts the gradient's interpolation curve; use 1.0 for linear, <= 1.0 to bias towards 'from', > 1.0 to bias towards 'to'. Recommended range: [0.2, 5.0].

func (*Renderer) DitherMat4

func (r *Renderer) DitherMat4(target, mask *ebiten.Image, ox, oy float32, xOffset, yOffset int, rgbaColors []float32, ditherMatrix [16]float32, rendererClrMix, maskColorMix float32)

DitherMat4 draws the given mask to the target applying a static 4x4 dithering pattern to select colors from rgbaColors. The rgbaColors argument can contain up to 8 colors, flattened as RGBA quadruplets in [0...1] range. You can test with DitherBW4. The ditherMatrix argument is a 4x4 dithering matrix in column major order (like GLSL), where the values indicate the thresholds of the pattern in 0...1 range. You can test with DitherBayes.

func (*Renderer) DrawAlphaMaskCirc

func (r *Renderer) DrawAlphaMaskCirc(target *ebiten.Image, ox, oy, dist, distRand float32, pattern AlphaMaskPattern)

DrawAlphaMaskCirc draws a circular mask going from RGBA(0, 0, 0, 0) at cx, cy to the renderer's color at >= dist. This is primarily a utility method to create masks for Renderer.Mask() or Renderer.MaskThreshold() operations.

func (*Renderer) DrawArea

func (r *Renderer) DrawArea(target *ebiten.Image, ox, oy, w, h, rounding float32)

func (*Renderer) DrawCircle

func (r *Renderer) DrawCircle(target *ebiten.Image, cx, cy, radius float32)

func (*Renderer) DrawEllipse

func (r *Renderer) DrawEllipse(target *ebiten.Image, cx, cy, horzRadius, vertRadius float32, rads float64)

Notice: ellipses don't have a perfect SDF, so approximations can be very slightly bigger or smaller than the requested radiuses.

func (*Renderer) DrawHexagon

func (r *Renderer) DrawHexagon(target *ebiten.Image, ox, oy, radius, roundness, rads float32)

DrawHexagon renders an hexagon that can be fully contained within the given radius. Roundness can be used to round the corners. Rads can be used to rotate the hexagon, in radians.

func (*Renderer) DrawIntArea

func (r *Renderer) DrawIntArea(target *ebiten.Image, ox, oy, w, h int)

func (*Renderer) DrawIntRect

func (r *Renderer) DrawIntRect(target *ebiten.Image, rect image.Rectangle)

DrawIntRect is the image.Rectangle compatible equivalent of Renderer.DrawIntArea().

func (*Renderer) DrawLine

func (r *Renderer) DrawLine(target *ebiten.Image, ox, oy, fx, fy float64, thickness float64)

DrawLine draws a smooth line between the given two points, with rounded ends.

func (*Renderer) DrawPie

func (r *Renderer) DrawPie(target *ebiten.Image, cx, cy, radius float32, startRads, endRads float64, rounding float32)

DrawPie draws circular sector defined by (startRads, endRads). See RadsRight constants for angle conventions and docs.

Some examples:

  • startRads = RadsRight, endRads = RadsBottom will draw the bottom-right quarter circle pie.
  • startRads = RadsBottom, endRads = RadsRight will draw a pie missing the bottom-right quarter.

Notice that the rounding parameter doesn't expand the shape beyond the radius, but it does expand the side flat faces of the pie.

func (*Renderer) DrawPieRate

func (r *Renderer) DrawPieRate(target *ebiten.Image, cx, cy, radius float32, centerDir, rate float64, rounding float32)

DrawPieRate is similar to DrawPie, but using a single direction for the center of the pie slice and a rate value between (0, 1), with 0 being empty pie and 1 being completely filled. See RadsRight constants for angle conventions and docs.

func (*Renderer) DrawQuad

func (r *Renderer) DrawQuad(target *ebiten.Image, quad [4]PointF32, thickening float32)

DrawQuad renders a convex quad with the current renderer colors. The thickening acts as a rounding parameter, but it extends the shape outwards instead of "cutting" the corners. Notice that non-zero thickening involves additional CPU-side precomputations.

quad must be given in clockwise order starting from top-left.

func (*Renderer) DrawQuadSoft

func (r *Renderer) DrawQuadSoft(target *ebiten.Image, quad [4]PointF32, thickening, softEdge float32)

func (*Renderer) DrawRect

func (r *Renderer) DrawRect(target *ebiten.Image, rect image.Rectangle, rounding float32)

DrawRect is the image.Rectangle compatible equivalent of Renderer.DrawArea(). When no rounding is required, prefer Renderer.DrawIntArea() instead.

func (*Renderer) DrawRectShader

func (r *Renderer) DrawRectShader(target *ebiten.Image, ox, oy, w, h, horzMargin, vertMargin float32, shader *ebiten.Shader)

func (*Renderer) DrawRing

func (r *Renderer) DrawRing(target *ebiten.Image, cx, cy, inRadius, outRadius float32)

DrawRing draws a smooth ring at the given position. For ring segments with start and end angles, see Renderer.DrawRingSector() instead.

func (*Renderer) DrawRingSector

func (r *Renderer) DrawRingSector(target *ebiten.Image, cx, cy, inRadius, outRadius float32, startRads, endRads float64, rounding float32)

DrawRingSector draws a smooth ring segment. See RadsRight constants for angle conventions and docs.

Only outer rounding is supported at the moment.

func (*Renderer) DrawShader

func (r *Renderer) DrawShader(target *ebiten.Image, horzMargin, vertMargin float32, shader *ebiten.Shader)

func (*Renderer) DrawShaderAt

func (r *Renderer) DrawShaderAt(target, source *ebiten.Image, ox, oy, horzMargin, vertMargin float32, shader *ebiten.Shader)

func (*Renderer) DrawTriangle

func (r *Renderer) DrawTriangle(target *ebiten.Image, ox1, oy1, ox2, oy2, ox3, oy3, rounding float64)

DrawTriangle draws a smooth triangle using the given vertices and an optional rounding factor. Notice that, if provided, handling the rounding is relatively non-trivial (two dozen f64 products and 3 square roots for CPU-side precomputations).

func (*Renderer) FlatPaint

func (r *Renderer) FlatPaint(target, mask *ebiten.Image, ox, oy float32)

FlatPaint draws the mask onto the given target using the renderer vertex colors.

func (*Renderer) GetColorF32

func (r *Renderer) GetColorF32() [4]float32

func (*Renderer) Gradient

func (r *Renderer) Gradient(target, mask *ebiten.Image, ox, oy float32, from, to color.RGBA, numSteps int, dirRadians, curveFactor float32)

Gradient paints a high quality gradient over the given target. If mask is nil, the target will have the gradient applied starting from (ox, oy) throughout the entire image. See DirRadsLTR and similar constants for common gradient directions.

CurveFactor allows making the gradient linear (1.0), or ease it towards an early start (e.g. 0.5) or late start (e.g. 2.0). Reasonable CurveFactor values typically fall in the ~[0.2...4.0] range.

See also Renderer.SimpleGradient().

func (*Renderer) GradientRadial

func (r *Renderer) GradientRadial(target *ebiten.Image, cx, cy float32, from, to color.RGBA, fromRadius, transRadius, toRadius float32, numSteps int, curveFactor float32)

GradientRadial paints a high quality radial gradient over the given target.

CurveFactor allows making the gradient linear (1.0), or ease it towards an early start (e.g. 0.5) or late start (e.g. 2.0). Reasonable CurveFactor values typically fall in the ~[0.2...4.0] range.

Three radiuses are necessary:

  • fromRadius: distances below this threshold take 'from' color. Use 0.0 if you don't need a solid central area.
  • transRadius: distances below this threshold but above fromRadius interpolate colors between 'from' and 'to'.
  • toRadius: distances below this threshold but above transRadius take 'to' color. Distances above this threshold are not painted. Use toRadius = transRadius for a gradient that ends at the given radius, or Float32Inf() if you want 'to' color to extend beyond the gradient radius.

To mask the gradient over an existing image, consider Renderer.SetBlend(ebiten.BlendSourceIn) and similar tricks.

func (*Renderer) HalftoneTri

func (r *Renderer) HalftoneTri(target, source *ebiten.Image, ox, oy, outTriBaseSize, minInTriBaseSize, maxInTriBaseSize, xOffset, yOffset float32)

func (*Renderer) JFMErode

func (r *Renderer) JFMErode(target, source, jfmap *ebiten.Image, ox, oy, radius, aaMargin float32)

JFMErode performs morphological erosion. Radius must be in [0, 32k].

  • jfmap can be nil, in which case it will be automatically generated for only this operation using [JFMPixel] mode with [0.0, 0.0] alpha interval (transparent pixels are seeds).
  • source and jfmap should be in the same atlas to avoid automatic atlasing issues.
  • aaMargin is the antialias margin. AAMargin can be used for a reasonable default.

func (*Renderer) JFMExpand

func (r *Renderer) JFMExpand(target, source, jfmap *ebiten.Image, ox, oy, thickness, aaMargin float32)

JFMExpand performs morphological expansion. Thickness must be in [0, 32k]. Notice that since jumping flood algorithms are based on distances to seeds, the only work well for shapes with hard edges. For soft edges, pure Renderer.ApplyExpansion() is the only real high quality option.

  • jfmap can be nil, in which case it will be automatically generated for only this operation using [JFMPixel] mode with [0.001, 1.0] alpha interval (all not fully transparent pixels are seeds).
  • source and jfmap should be in the same atlas to avoid automatic atlasing issues.
  • aaMargin is the antialias margin. AAMargin can be used for a reasonable default.

func (*Renderer) JFMHeat

func (r *Renderer) JFMHeat(target, jfmap *ebiten.Image, ox, oy float32, maxDistance float32)

JFMHeat is a debug and utility method to draw a heatmap for jfmap into the given target, using 0 and maxDistance as reference distances for "hot" and "cold". The seeds of a jfmap can be visualized by setting maxDistance to a positive value below 1 (e.g. 0.1).

func (*Renderer) JFMInsetContour

func (r *Renderer) JFMInsetContour(target, source, jfmap *ebiten.Image, ox, oy, inThickness, inOpacity, colorMix float32)

TODO: unimplemented

JFMInsetContour is a specific effect designed mainly for text animations. It creates an internal outline, which includes the image borders where the target clips the source, while also allowing to control the inner fill opacity.

  • colorMix controls the outline color (0 = use vertex colors, 1 = use source colors)
  • jfmap can be nil, in which case it will be automatically generated for only this operation using [JFMBoundary] mode.
  • source and jfmap should be in the same atlas to avoid automatic atlasing issues.

func (*Renderer) JFMOutline

func (r *Renderer) JFMOutline(target, source, jfmap *ebiten.Image, ox, oy, inThickness, outThickness, inOpacity, colorMix float32)

TODO: unimplemented

JFMOutline performs morphological outlining.

  • colorMix controls the outline color (0 = use vertex colors, 1 = use source colors)
  • jfmap can be nil, in which case it will be automatically generated for only this operation using [JFMBoundary] mode.
  • source and jfmap should be in the same atlas to avoid automatic atlasing issues.

func (*Renderer) JFMapBoundary

func (r *Renderer) JFMapBoundary(jfmap, source *ebiten.Image, maxDistance int, minAlpha, maxAlpha float32, outer bool, extendEdges bool)

JFMapBoundary computes a jumping flood map of the given source image and stores it in jfmap.

Preconditions (panics if violated):

  • source and jfmap must have the same size
  • 0 <= maxDistance <= 32k
  • 0.0 <= minAlpha <= maxAlpha <= 1.0

Parameters:

  • minAlpha, maxAlpha: inclusive range defining the area inside the boundary. For exclusive bounds, shift by +/-0.001.
  • outer: if false, the boundary is marked at the last pixel inside the (minAlpha, maxAlpha) region; if true, at the first pixel outside it.
  • extendEdges: if false, out-of-bounds pixels are treated as zero (vec4(0)); if true, the nearest edge pixel is repeated.

This function uses one internal offscreen (#0); neither source nor jfmap can use it, but they can share internal atlas otherwise. jfmap doesn't need to be cleared before operation.

For additional context on jumping flood maps, see Renderer.JFMapCompute().

func (*Renderer) JFMapCompute

func (r *Renderer) JFMapCompute(jfmap, seeds *ebiten.Image, maxDistance int)

JFMapCompute computes a jumping flood map from the given seeds and stores it in jfmap.

A jumping flood map encodes offsets to nearest seeds, which allows computing precise distances and can make large radius morphological operations like outlining, expansion and erosion viable.

Jumping flood map internal encoding details are documented in shaders/jfm_pass.kage.

Seed pixels in 'seeds' must be marked as trasparent vec4(0); all other pixels must be pure white. maxDistance acts as the cutoff distance for the algorithm, leaving pixels beyond it as pure white. maxDistance must be in [0, 32000] (inclusive). Higher maxDistance values require more iterations of the algorithm, up to a maximum of 16.

This function uses one internal offscreen (#0). seeds can be on #0 if the image being overwritten is not a concern. jfmap is always overwritten and doesn't need to be cleared before operation.

This is a low-level operation; most users should use Renderer.JFMapFill() or Renderer.JFMapBoundary() instead.

func (*Renderer) JFMapFill

func (r *Renderer) JFMapFill(jfmap, source *ebiten.Image, maxDistance int, minAlpha, maxAlpha float32)

JFMapFill computes a jumping flood map of the given source image and stores it in jfmap.

Preconditions (panics if violated):

  • source and jfmap must have the same size
  • 0 <= maxDistance <= 32k
  • 0.0 <= minAlpha <= maxAlpha <= 1.0

Parameters:

  • minAlpha, maxAlpha: inclusive range defining the area inside the boundary. For exclusive bounds, shift by +/-0.001.

This function uses one internal offscreen (#0); neither source nor jfmap can use it, but they can share internal atlas otherwise. jfmap doesn't need to be cleared before operation.

For additional context on jumping flood maps, see Renderer.JFMapCompute().

func (*Renderer) MapProjective

func (r *Renderer) MapProjective(target, source *ebiten.Image, quad [4]PointF32)

MapProjective draws the given source texture into the given quad. This function computes the homography between the quad and the texture space, which involves solving an 8x8 equation system. This can be somewhat CPU heavy, so avoid drawing more than ~100 elements with it if you are not targeting powerful devices.

quad must be given in clockwise order starting from top-left.

The renderer's color is applied multiplicatively as a color scale; set it to white for neutral operation.

func (*Renderer) MapQuad4

func (r *Renderer) MapQuad4(target, source *ebiten.Image, quad [4]PointF32)

MapQuad4 draws the given source texture into the given quad using 4 triangles. This will produce noticeable texture projection distortions, but it's not as bad as using just two triangles and can work well enough in some cases. Otherwise, consider Renderer.MapProjective().

quad must be given in clockwise order starting from top-left.

The renderer's color is applied multiplicatively as a color scale; set it to white for neutral operation.

func (*Renderer) Mask

func (r *Renderer) Mask(target, source, mask *ebiten.Image, ox, oy float32)

Mask draws 'source' over 'target' using 'mask' as an alpha mask. If the source and mask sizes are different, the mask will be adjusted to fit the source (sampling is always nearest, not bilinear). For manual mask placement, see Renderer.MaskAt() instead.

func (*Renderer) MaskAt

func (r *Renderer) MaskAt(target, source, mask *ebiten.Image, ox, oy, oxMask, oyMask float32)

MaskAt draws 'source' over 'target' using 'mask' as an alpha mask at the given position. If you want the mask to be fit to the source instead, see Renderer.Mask().

func (*Renderer) MaskCircle

func (r *Renderer) MaskCircle(target, source *ebiten.Image, cx, cy, srcOffsetX, srcOffsetY, hardRadius, softEdge float32)

MaskCircle draws 'source' into 'target', centered at (cx + srcOffsetX, cy + srcOffset), but filtering out pixels beyond a distance of hardRadius + softEdge from (cx, cy).

func (*Renderer) MaskHorz

func (r *Renderer) MaskHorz(target, source *ebiten.Image, x, y, inX, outX float32)

MaskHorz draws 'source' over 'target' but with an horizontal alpha fade between the given points.

func (*Renderer) MaskThreshold

func (r *Renderer) MaskThreshold(target, source, mask *ebiten.Image, reveal, ox, oy float32)

MaskThreshold draws source into target, at the given position, using 'mask' to hide the pixels where 'reveal' < mask.alpha.

For example, if a mask goes from transparent to opaque, left to right, the source will start appearing from left to right as the 'reveal' threshold increases from 0 to 1.

If source and mask sizes differ, the mask is adjusted like in Renderer.Mask().

func (*Renderer) NewCircle

func (r *Renderer) NewCircle(radius float64) *ebiten.Image

func (*Renderer) NewRect

func (r *Renderer) NewRect(width, height int) *ebiten.Image

func (*Renderer) NewRing

func (r *Renderer) NewRing(inRadius, outRadius float64) *ebiten.Image

func (*Renderer) NewSimpleGradient

func (r *Renderer) NewSimpleGradient(w, h int, from, to color.RGBA, dirRadians float32) *ebiten.Image

func (*Renderer) Noise

func (r *Renderer) Noise(target *ebiten.Image, intensity float32, seed, cycle float32)

Noise draws pseudo-random, hash-based white noise with the current renderer color over the given target.

The cycle parameter controls the noise animation. Progressively increasing the cycle value from 0 to 1 and looping back to zero will create a continuous, looping animation with an organic feel. If you don't need animation, leave cycle to zero to reduce shader calculations.

Seed must be in [0, 1].

func (*Renderer) NoiseGolden

func (r *Renderer) NoiseGolden(target *ebiten.Image, scale, intensity, t float32)

NoiseGolden draws a grid geometric noise with the current renderer color over the given target. This noise is based on the golden ratio and it's highly sensitive to the scale, producing very different results at different levels. Some interesting scales are 0.06, 1.0, 64.0, 93.0 and upwards (patterns start to darken and vanish afterwards).

The param t controls the animation pace. Increase t at a rate of 1.0 per second for a natural animation rate.

func (*Renderer) OklabShift

func (r *Renderer) OklabShift(target, source *ebiten.Image, x, y, lightnessShift, chromaShift, hueShift float32)

OklabShift draws the source image to the target, at the given coordinates, with the given LCh shifts applied on oklab color space. The expected value ranges are the following:

  • lightness: [0, 1]
  • chroma: [0, 0.5]
  • hue: in radians, wrapping is done automatically

func (*Renderer) Options

func (*Renderer) Scale

func (r *Renderer) Scale(target, source *ebiten.Image, ox, oy, scale float32, scaledSampling bool)

Scale draws the source into the given target with two differences from Ebitengine's scaling:

  • scaledSampling can be set to true to mimic Ebitengine's v2.9.0 FilterPixelated.
  • Subimages can be scaled without bleeding edges, as the shader uses clamping.

func (*Renderer) ScaleAlphaBy

func (r *Renderer) ScaleAlphaBy(alphaFactor float32)

func (*Renderer) SetBlend

func (r *Renderer) SetBlend(blend ebiten.Blend)

func (*Renderer) SetColor

func (r *Renderer) SetColor(clr color.Color, vertexIndices ...int)

SetColor sets the color of all vertices, unless vertexIndices are specifically provided, in which case only the given indices will be set. In general, most shaders use vertex 0 as top-left, vertex 1 as top-right, vertex 2 as bottom-right, vertex 3 as bottom-left, but this is shader dependent (or even variable in some cases).

func (*Renderer) SetColorF32

func (r *Renderer) SetColorF32(red, green, blue, alpha float32, vertexIndices ...int)

func (*Renderer) SetCustomVAs

func (r *Renderer) SetCustomVAs(vas ...float32)

SetCustomVAs configures up to 4 custom vertex attributes.

func (*Renderer) SimpleGradient

func (r *Renderer) SimpleGradient(target *ebiten.Image, from, to color.RGBA, dirRadians float32)

SimpleGradient paints a high quality gradient over the given target. See DirRadsLTR and similar constants for common gradient directions.

func (*Renderer) StrokeArea

func (r *Renderer) StrokeArea(target *ebiten.Image, ox, oy, w, h, outThickness, inThickness, rounding float32)

func (*Renderer) StrokeCircle

func (r *Renderer) StrokeCircle(target *ebiten.Image, cx, cy, radius, thickness float32)

func (*Renderer) StrokeIntArea

func (r *Renderer) StrokeIntArea(target *ebiten.Image, ox, oy, w, h, outThickness, inThickness int)

func (*Renderer) StrokeIntRect

func (r *Renderer) StrokeIntRect(target *ebiten.Image, area image.Rectangle, outThickness, inThickness int)

StrokeIntRect is the image.Rectangle compatible equivalent of Renderer.StrokeIntArea().

func (*Renderer) StrokePie

func (r *Renderer) StrokePie(target *ebiten.Image, cx, cy, radius, thickness float32, startRads, endRads float64, rounding float32)

StrokePie is the stroke version of Renderer.DrawPie(). The shape is drawn with an ouline of the given thickness.

func (*Renderer) StrokePieRate

func (r *Renderer) StrokePieRate(target *ebiten.Image, cx, cy, radius, thickness float32, centerDir, rate float64, rounding float32)

StrokePie is the stroke version of Renderer.DrawPieRate(). The shape is drawn with an ouline of the given thickness.

func (*Renderer) StrokeRect

func (r *Renderer) StrokeRect(target *ebiten.Image, rect image.Rectangle, outThickness, inThickness, rounding float32)

StrokeRect is the image.Rectangle compatible equivalent of Renderer.DrawArea(). When no rounding is required, prefer Renderer.DrawIntArea() instead.

func (*Renderer) StrokeRingSector

func (r *Renderer) StrokeRingSector(target *ebiten.Image, cx, cy, inRadius, outRadius, thickness float32, startRads, endRads float64, rounding float32)

StrokeRingSector draws the outline of a smooth ring segment. See RadsRight constants for angle conventions and docs.

Only outer rounding is supported at the moment.

func (*Renderer) StrokeTriangle

func (r *Renderer) StrokeTriangle(target *ebiten.Image, ox1, oy1, ox2, oy2, ox3, oy3, thickness, rounding float64)

StrokeTriangle draws an unfilled triangle. The outline will expand [-thickness/2, +thickness/2] around the given points, unless the passed thickness is negative, in which case the outline will be interior only, going from [-thickness, 0].

For more details on rounding, see Renderer.DrawTriangle().

func (*Renderer) TileDotsGrid

func (r *Renderer) TileDotsGrid(target *ebiten.Image, radius, spacing, xOffset, yOffset float32)

func (*Renderer) TileDotsHex

func (r *Renderer) TileDotsHex(target *ebiten.Image, radius, horzSpacing, xOffset, yOffset float32)

TileDotsHex draws dots of the given radius distributed in a hexagonal lattice. HorzSpacing should always be at least twice the radius.

func (*Renderer) TileRectsGrid

func (r *Renderer) TileRectsGrid(target *ebiten.Image, outWidth, outHeight, inWidth, inHeight, xOffset, yOffset float32)

func (*Renderer) TileTriHex

func (r *Renderer) TileTriHex(target *ebiten.Image, outTriBase, inTriBase, xOffset, yOffset float32)

func (*Renderer) TileTriUpGrid

func (r *Renderer) TileTriUpGrid(target *ebiten.Image, outTriBase, inTriBase, xOffset, yOffset float32)

func (*Renderer) UnsafeTemp

func (r *Renderer) UnsafeTemp(offscreenIndex int, w, h int, clear bool) *ebiten.Image

UnsafeTemp allows requesting offscreens to the renderer. These offscreens might have already been created while the renderer was doing complex operations, so reusing them can prevent the creation of additional offscreens.

The offscreens returned by this function should only be used for local operations, and the offscreen must not be stored. Any renderer function documented to use an internal offscreen can panic or fail in any other way if an offscreen returned by this function is passed as an input parameter.

func (*Renderer) UnsafeTempCopy

func (r *Renderer) UnsafeTempCopy(offscreenIndex int, source *ebiten.Image, clear bool) *ebiten.Image

UnsafeTempCopy calls Renderer.UnsafeTemp() and copies the contents of source into the returned offscreen. See safety warnings and docs for UnsafeTemp. The 'clear' argument allows specifying whether a 1 pixel clear margin is required or not.

func (*Renderer) UnsafeTempDual

func (r *Renderer) UnsafeTempDual(offscreenIndex int, source *ebiten.Image, clear bool) (sourceTemp, variantTemp *ebiten.Image)

UnsafeTempDual calls Renderer.UnsafeTemp(), copies the contents of source into the specified offscreen, and returns both this copy and an extra image of the same size on the same offscreen. This function is highly specific and meant to prepare images for shaders that use two source images: an original source and variant or mask for it.

See safety warnings and docs for UnsafeTemp.

func (*Renderer) WarpArc

func (r *Renderer) WarpArc(target, source *ebiten.Image, cx, cy, outRadius float32, rads float64)

WarpArc projects the given source image onto a curved arc on target. The arc is characterized by (cx, cy) and outRadius. The content is horizontally centered at 'rads'. If the source's width > circumference, the content is automatically clamped.

See RadsRight constants for angle conventions and docs.

func (*Renderer) WarpBarrel

func (r *Renderer) WarpBarrel(target, source *ebiten.Image, ox, oy float32, horzWarp, vertWarp float32)

WarpBarrel draws the given image with a simple, CRT-like barrel warp. Intensity should be in ~[0.2, 1.5], with 0.5 being a good starting value to play with.

The size of the output image will always be equal or smaller than the input source, as the corner vertices are warped towards the interior.

If both warp values are <= 0, a quadratic curve-based pincushion effect will be used instead. Notice that very large warp factors in both axes will make the image start to "shrink".

For visually pleasing effects, you usually want to normalize the warps by the image aspect ratio.

Notice that the effects are designed to be adjustable per axis and fast. More mathematically accurate atan/sin based warps are possible, but for soft warps the quadratic versions are pleasant enough.

Warps of different signs will panic.

Jump to

Keyboard shortcuts

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