2023-02-25 16:41:16 -07:00
|
|
|
package patterns
|
2023-01-08 23:03:19 -07:00
|
|
|
|
2023-01-13 23:54:57 -07:00
|
|
|
import "image"
|
2023-02-25 16:41:16 -07:00
|
|
|
import "git.tebibyte.media/sashakoshka/tomo/canvas"
|
2023-01-13 23:54:57 -07:00
|
|
|
|
2023-02-25 16:41:16 -07:00
|
|
|
// Texture is a pattern that tiles the content of a canvas both horizontally and
|
|
|
|
// vertically.
|
2023-01-13 23:54:57 -07:00
|
|
|
type Texture struct {
|
2023-02-25 16:41:16 -07:00
|
|
|
canvas.Canvas
|
2023-01-13 23:54:57 -07:00
|
|
|
}
|
|
|
|
|
2023-03-11 23:04:06 -07:00
|
|
|
// Draw tiles the pattern's canvas within the given bounds. The minimum
|
2023-02-25 16:41:16 -07:00
|
|
|
// points of the pattern's canvas and the destination canvas will be lined up.
|
2023-03-11 23:04:06 -07:00
|
|
|
func (pattern Texture) Draw (destination canvas.Canvas, bounds image.Rectangle) {
|
|
|
|
drawBounds := bounds.Canon().Intersect(destination.Bounds())
|
|
|
|
if drawBounds.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-03-06 19:34:14 -07:00
|
|
|
dstPoint := image.Point { }
|
2023-03-11 23:04:06 -07:00
|
|
|
srcPoint := drawBounds.Min.Sub(bounds.Min).Add(srcBounds.Min)
|
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-03-11 23:04:06 -07:00
|
|
|
for dstPoint.Y = drawBounds.Min.Y; dstPoint.Y < drawBounds.Max.Y; dstPoint.Y ++ {
|
2023-03-07 10:48:29 -07:00
|
|
|
srcPoint.X = srcBounds.Min.X
|
2023-03-11 23:04:06 -07:00
|
|
|
dstPoint.X = drawBounds.Min.X
|
2023-03-07 10:48:29 -07:00
|
|
|
dstYComponent := dstPoint.Y * dstStride
|
|
|
|
srcYComponent := srcPoint.Y * srcStride
|
2023-03-06 19:40:20 -07:00
|
|
|
|
2023-03-07 10:48:29 -07:00
|
|
|
for {
|
|
|
|
dstIndex := dstYComponent + dstPoint.X
|
|
|
|
srcIndex := srcYComponent + srcPoint.X
|
2023-03-06 19:34:14 -07:00
|
|
|
dstData[dstIndex] = srcData[srcIndex]
|
|
|
|
|
|
|
|
srcPoint.X ++
|
|
|
|
if srcPoint.X >= srcBounds.Max.X {
|
|
|
|
srcPoint.X = srcBounds.Min.X
|
|
|
|
}
|
2023-03-07 10:48:29 -07:00
|
|
|
|
|
|
|
dstPoint.X ++
|
2023-03-11 23:04:06 -07:00
|
|
|
if dstPoint.X >= drawBounds.Max.X {
|
2023-03-07 10:48:29 -07:00
|
|
|
break
|
|
|
|
}
|
2023-03-06 19:34:14 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
srcPoint.Y ++
|
|
|
|
if srcPoint.Y >= srcBounds.Max.Y {
|
|
|
|
srcPoint.Y = srcBounds.Min.Y
|
|
|
|
}
|
|
|
|
}
|
2023-01-13 23:54:57 -07:00
|
|
|
}
|
|
|
|
|
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
|
2023-01-13 23:54:57 -07:00
|
|
|
}
|