2024-09-10 13:52:46 -06:00
|
|
|
package typeset
|
|
|
|
|
|
|
|
import "image"
|
|
|
|
import "unicode"
|
|
|
|
import "image/draw"
|
|
|
|
import "image/color"
|
|
|
|
import "golang.org/x/image/font"
|
|
|
|
import "golang.org/x/image/math/fixed"
|
2024-09-19 22:07:32 -06:00
|
|
|
import "git.tebibyte.media/tomo/typeset/internal"
|
2024-09-10 13:52:46 -06:00
|
|
|
|
|
|
|
// Draw draws the contents of a TypeSetter to an image at the given offset. It
|
|
|
|
// returns a rectangle containing all pixels in the image that were updated.
|
|
|
|
func Draw (destination draw.Image, setter *TypeSetter, offset fixed.Point26_6, col color.Color) image.Rectangle {
|
|
|
|
source := image.NewUniform(col)
|
|
|
|
face := setter.Face()
|
|
|
|
var updatedRegion image.Rectangle
|
|
|
|
bounds := destination.Bounds()
|
|
|
|
|
|
|
|
setter.Runes()(func (position fixed.Point26_6, run rune) bool {
|
|
|
|
// leave empty space for space characters
|
|
|
|
if unicode.IsSpace(run) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
dot := offset.Add(position)
|
|
|
|
destinationRectangle, mask, maskPoint, _, ok := face.Glyph(dot, run)
|
|
|
|
|
|
|
|
if ok {
|
|
|
|
// don't bother drawing runes that are out of bounds
|
|
|
|
if destinationRectangle.Min.Y > bounds.Max.Y { return false }
|
|
|
|
if destinationRectangle.Intersect(bounds).Empty() { return true }
|
|
|
|
|
|
|
|
// draw rune
|
|
|
|
draw.DrawMask (
|
|
|
|
destination,
|
|
|
|
destinationRectangle,
|
|
|
|
source, image.Point { },
|
|
|
|
mask, maskPoint,
|
|
|
|
draw.Over)
|
|
|
|
} else {
|
|
|
|
// draw tofu
|
|
|
|
drawTofu(run, destination, dot, face, col)
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
updatedRegion = updatedRegion.Union(destinationRectangle)
|
|
|
|
return true
|
|
|
|
})
|
|
|
|
|
|
|
|
return updatedRegion
|
|
|
|
}
|
|
|
|
|
|
|
|
func drawTofu (
|
|
|
|
char rune,
|
|
|
|
destination draw.Image,
|
|
|
|
position fixed.Point26_6,
|
|
|
|
face font.Face,
|
|
|
|
col color.Color,
|
|
|
|
) {
|
|
|
|
bounds, _ := tofuBounds(face)
|
2024-09-19 22:07:32 -06:00
|
|
|
rectBounds := internal.RoundRect(bounds).Add(image.Pt (
|
2024-09-10 13:52:46 -06:00
|
|
|
position.X.Round(),
|
|
|
|
position.Y.Round()))
|
2024-09-19 22:07:32 -06:00
|
|
|
internal.DrawRectangleOutline(destination, rectBounds, col)
|
2024-09-10 13:52:46 -06:00
|
|
|
}
|