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/texture.go

78 lines
2.2 KiB
Go
Raw Normal View History

2023-02-25 16:41:16 -07:00
package patterns
2023-01-08 23:03:19 -07:00
import "image"
2023-02-25 16:41:16 -07:00
import "git.tebibyte.media/sashakoshka/tomo/canvas"
2023-02-25 16:41:16 -07:00
// Texture is a pattern that tiles the content of a canvas both horizontally and
// vertically.
type Texture struct {
2023-02-25 16:41:16 -07:00
canvas.Canvas
}
// Draw tiles the pattern's canvas within the given bounds. The minimum
2023-04-02 20:37:38 -06:00
// point of the pattern's canvas will be lined up with the minimum point of the
// bounding rectangle.
func (pattern Texture) Draw (destination canvas.Canvas, bounds image.Rectangle) {
2023-04-02 20:37:38 -06:00
dstBounds := bounds.Canon().Intersect(destination.Bounds())
if dstBounds.Empty() { return }
2023-02-25 16:41:16 -07:00
dstData, dstStride := destination.Buffer()
srcData, srcStride := pattern.Buffer()
srcBounds := pattern.Bounds()
2023-02-27 14:38:33 -07:00
2023-04-02 20:37:38 -06:00
// offset is a vector that is added to points in destination space to
// convert them to points in source space
offset := srcBounds.Min.Sub(bounds.Min)
// calculate the starting position in source space
srcPoint := dstBounds.Min.Add(offset)
2023-03-06 19:34:14 -07:00
srcPoint.X = wrap(srcPoint.X, srcBounds.Min.X, srcBounds.Max.X)
srcPoint.Y = wrap(srcPoint.Y, srcBounds.Min.Y, srcBounds.Max.Y)
2023-04-02 20:37:38 -06:00
srcStartPoint := srcPoint
// for each row
dstPoint := image.Point { }
for dstPoint.Y = dstBounds.Min.Y; dstPoint.Y < dstBounds.Max.Y; dstPoint.Y ++ {
srcPoint.X = srcStartPoint.X
dstPoint.X = dstBounds.Min.X
dstYComponent := dstPoint.Y * dstStride
srcYComponent := srcPoint.Y * srcStride
2023-04-02 20:37:38 -06:00
// for each pixel in the row
for {
2023-04-02 20:37:38 -06:00
// draw pixel
dstIndex := dstYComponent + dstPoint.X
srcIndex := srcYComponent + srcPoint.X
2023-03-06 19:34:14 -07:00
dstData[dstIndex] = srcData[srcIndex]
2023-04-02 20:37:38 -06:00
// increment X in source space. wrap to start if out of
// bounds.
2023-03-06 19:34:14 -07:00
srcPoint.X ++
if srcPoint.X >= srcBounds.Max.X {
srcPoint.X = srcBounds.Min.X
}
2023-04-02 20:37:38 -06:00
// increment X in destination space. stop drawing this
// row if out of bounds.
dstPoint.X ++
2023-04-02 20:37:38 -06:00
if dstPoint.X >= dstBounds.Max.X {
break
}
2023-03-06 19:34:14 -07:00
}
2023-04-02 20:37:38 -06:00
// increment row in source space. wrap to start if out of
// bounds.
2023-03-06 19:34:14 -07:00
srcPoint.Y ++
if srcPoint.Y >= srcBounds.Max.Y {
srcPoint.Y = srcBounds.Min.Y
}
}
}
2023-02-25 16:41:16 -07:00
func wrap (value, min, max int) int {
difference := max - min
value = (value - min) % difference
if value < 0 { value += difference }
return value + min
}