This repository has been archived on 2023-08-08. You can view files and clone it, but cannot push or open issues or pull requests.
tomo-old/artist/patterns/border.go
2023-02-25 23:04:51 -05:00

93 lines
2.9 KiB
Go

package patterns
import "image"
import "git.tebibyte.media/sashakoshka/tomo/canvas"
import "git.tebibyte.media/sashakoshka/tomo/artist"
// Border is a pattern that behaves similarly to border-image in CSS. It divides
// a source canvas into nine sections...
//
// Inset[1]
// ┌──┴──┐
// ┌─┌─────┬─────┬─────┐
// Inset[0]─┤ │ 0 │ 1 │ 2 │
// └─├─────┼─────┼─────┤
// │ 3 │ 4 │ 5 │
// ├─────┼─────┼─────┤─┐
// │ 6 │ 7 │ 8 │ ├─Inset[2]
// └─────┴─────┴─────┘─┘
// └──┬──┘
// Inset[3]
//
// ... Where the bounds of section 4 are defined as the application of the
// pattern's inset to the canvas's bounds. The bounds of the other eight
// sections are automatically sized around it.
//
// When drawn to a destination canvas, the bounds of sections 1, 3, 4, 5, and 7
// are expanded or contracted to fit the destination's bounds. All sections
// are rendered as if they are Texture patterns, meaning these flexible sections
// will repeat to fill in any empty space.
//
// This pattern can be used to make a static image texture into something that
// responds well to being resized.
type Border struct {
canvas.Canvas
artist.Inset
}
// Draw draws the border pattern onto the destination canvas within the clipping
// bounds.
func (pattern Border) Draw (destination canvas.Canvas, clip image.Rectangle) {
bounds := clip.Canon().Intersect(destination.Bounds())
if bounds.Empty() { return }
srcSections := nonasect(pattern.Bounds(), pattern.Inset)
srcTextures := [9]Texture { }
for index, section := range srcSections {
srcTextures[index] = Texture {
Canvas: canvas.Cut(pattern, section),
}
}
dstSections := nonasect(destination.Bounds(), pattern.Inset)
for index, section := range dstSections {
srcTextures[index].Draw(canvas.Cut(destination, section), clip)
}
}
func nonasect (bounds image.Rectangle, inset artist.Inset) [9]image.Rectangle {
center := inset.Apply(bounds)
return [9]image.Rectangle {
// top
image.Rectangle {
bounds.Min,
center.Min },
image.Rect (
center.Min.X, bounds.Min.Y,
center.Max.X, center.Min.Y),
image.Rect (
center.Max.X, bounds.Min.Y,
bounds.Max.X, center.Min.Y),
// center
image.Rect (
bounds.Min.X, center.Min.Y,
center.Min.X, center.Max.Y),
center,
image.Rect (
center.Max.X, center.Min.Y,
bounds.Max.X, center.Max.Y),
// bottom
image.Rect (
bounds.Min.X, center.Max.Y,
center.Min.X, bounds.Max.Y),
image.Rect (
center.Min.X, center.Max.Y,
center.Max.X, bounds.Max.Y),
image.Rect (
center.Max.X, center.Max.Y,
bounds.Max.X, bounds.Max.Y),
}
}