Text rendering is a thing again

This commit is contained in:
Sasha Koshka 2023-01-14 12:41:51 -05:00
parent 34bf3038ac
commit ec24eb7b4f
6 changed files with 88 additions and 61 deletions

12
artist/pattern.go Normal file
View File

@ -0,0 +1,12 @@
package artist
import "image/color"
// Pattern is capable of generating a pattern pixel by pixel.
type Pattern interface {
// AtWhen returns the color of the pixel located at (x, y) relative to
// the origin point of the pattern (0, 0), when the pattern has the
// specified width and height. Patterns may ignore the width and height
// parameters, but it may be useful for some patterns such as gradients.
AtWhen (x, y, width, height int) (color.RGBA)
}

View File

@ -29,6 +29,7 @@ func Paste (
return
}
// FillRectangle draws a filled rectangle with the specified pattern.
func FillRectangle (
destination tomo.Canvas,
source Pattern,

View File

@ -3,7 +3,7 @@ package artist
// import "fmt"
import "image"
import "unicode"
// import "image/draw"
import "image/draw"
import "golang.org/x/image/font"
import "golang.org/x/image/math/fixed"
import "git.tebibyte.media/sashakoshka/tomo"
@ -100,30 +100,36 @@ func (drawer *TextDrawer) Draw (
) (
updatedRegion image.Rectangle,
) {
wrappedSource := WrappedPattern {
Pattern: source,
Width: 0,
Height: 0, // TODO: choose a better width and height
}
if !drawer.layoutClean { drawer.recalculate() }
// TODO: reimplement a version of draw mask that takes in a pattern
// for _, word := range drawer.layout {
// for _, character := range word.text {
// destinationRectangle,
// mask, maskPoint, _, ok := drawer.face.Glyph (
// fixed.P (
// offset.X + word.position.X + character.x,
// offset.Y + word.position.Y),
// character.character)
// if !ok { continue }
for _, word := range drawer.layout {
for _, character := range word.text {
destinationRectangle,
mask, maskPoint, _, ok := drawer.face.Glyph (
fixed.P (
offset.X + word.position.X + character.x,
offset.Y + word.position.Y),
character.character)
if !ok { continue }
// FIXME: clip destination rectangle if we are on the cusp of
// the maximum height.
// draw.DrawMask (
// destination,
// destinationRectangle,
// source, image.Point { },
// mask, maskPoint,
// draw.Over)
draw.DrawMask (
destination,
destinationRectangle,
wrappedSource, image.Point { },
mask, maskPoint,
draw.Over)
// updatedRegion = updatedRegion.Union(destinationRectangle)
// }}
updatedRegion = updatedRegion.Union(destinationRectangle)
}}
return
}

View File

@ -3,15 +3,6 @@ package artist
import "image"
import "image/color"
// Pattern is capable of generating a pattern pixel by pixel.
type Pattern interface {
// AtWhen returns the color of the pixel located at (x, y) relative to
// the origin point of the pattern (0, 0), when the pattern has the
// specified width and height. Patterns may ignore the width and height
// parameters, but it may be useful for some patterns such as gradients.
AtWhen (x, y, width, height int) (color.RGBA)
}
// Texture is a struct that allows an image to be converted into a tiling
// texture pattern.
type Texture struct {

View File

@ -4,61 +4,52 @@ import "image"
import "image/color"
// Uniform is an infinite-sized pattern of uniform color. It implements the
// color.Color, color.Model, and image.Image interfaces.
type Uniform struct {
C color.RGBA
}
// Pattern, color.Color, color.Model, and image.Image interfaces.
type Uniform color.RGBA
// NewUniform returns a new Uniform image of the given color.
func NewUniform (c color.Color) (uniform *Uniform) {
uniform = &Uniform { }
func NewUniform (c color.Color) (uniform Uniform) {
r, g, b, a := c.RGBA()
uniform.C.R = uint8(r >> 8)
uniform.C.G = uint8(g >> 8)
uniform.C.B = uint8(b >> 8)
uniform.C.A = uint8(a >> 8)
uniform.R = uint8(r >> 8)
uniform.G = uint8(g >> 8)
uniform.B = uint8(b >> 8)
uniform.A = uint8(a >> 8)
return
}
func (uniform *Uniform) RGBA () (r, g, b, a uint32) {
r = uint32(uniform.C.R) << 8 | uint32(uniform.C.R)
g = uint32(uniform.C.G) << 8 | uint32(uniform.C.G)
b = uint32(uniform.C.B) << 8 | uint32(uniform.C.B)
a = uint32(uniform.C.A) << 8 | uint32(uniform.C.A)
return
}
func (uniform *Uniform) ColorModel () (model color.Model) {
// ColorModel satisfies the image.Image interface.
func (uniform Uniform) ColorModel () (model color.Model) {
return uniform
}
func (uniform *Uniform) Convert (in color.Color) (c color.Color) {
return uniform.C
// Convert satisfies the color.Model interface.
func (uniform Uniform) Convert (in color.Color) (c color.Color) {
return color.RGBA(uniform)
}
func (uniform *Uniform) Bounds () (rectangle image.Rectangle) {
// Bounds satisfies the image.Image interface.
func (uniform Uniform) Bounds () (rectangle image.Rectangle) {
rectangle.Min = image.Point { -1e9, -1e9 }
rectangle.Max = image.Point { 1e9, 1e9 }
return
}
func (uniform *Uniform) At (x, y int) (c color.Color) {
return uniform.C
// At satisfies the image.Image interface.
func (uniform Uniform) At (x, y int) (c color.Color) {
return color.RGBA(uniform)
}
func (uniform *Uniform) AtWhen (x, y, width, height int) (c color.RGBA) {
return uniform.C
// AtWhen satisfies the Pattern interface.
func (uniform Uniform) AtWhen (x, y, width, height int) (c color.RGBA) {
return color.RGBA(uniform)
}
func (uniform *Uniform) RGBA64At (x, y int) (c color.RGBA64) {
r := uint16(uniform.C.R) << 8 | uint16(uniform.C.R)
g := uint16(uniform.C.G) << 8 | uint16(uniform.C.G)
b := uint16(uniform.C.B) << 8 | uint16(uniform.C.B)
a := uint16(uniform.C.A) << 8 | uint16(uniform.C.A)
return color.RGBA64 { R: r, G: g, B: b, A: a }
// RGBA satisfies the color.Color interface.
func (uniform Uniform) RGBA () (r, g, b, a uint32) {
return color.RGBA(uniform).RGBA()
}
// Opaque scans the entire image and reports whether it is fully opaque.
func (uniform *Uniform) Opaque () (opaque bool) {
return uniform.C.A == 0xFF
func (uniform Uniform) Opaque () (opaque bool) {
return uniform.A == 0xFF
}

View File

@ -1 +1,27 @@
package artist
import "image"
import "image/color"
// WrappedPattern is a pattern that is able to behave like an image.Image.
type WrappedPattern struct {
Pattern
Width, Height int
}
// At satisfies the image.Image interface.
func (pattern WrappedPattern) At (x, y int) (c color.Color) {
return pattern.Pattern.AtWhen(x, y, pattern.Width, pattern.Height)
}
// Bounds satisfies the image.Image interface.
func (pattern WrappedPattern) Bounds () (rectangle image.Rectangle) {
rectangle.Min = image.Point { -1e9, -1e9 }
rectangle.Max = image.Point { 1e9, 1e9 }
return
}
// ColorModel satisfies the image.Image interface.
func (pattern WrappedPattern) ColorModel () (model color.Model) {
return color.RGBAModel
}