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 return
} }
// FillRectangle draws a filled rectangle with the specified pattern.
func FillRectangle ( func FillRectangle (
destination tomo.Canvas, destination tomo.Canvas,
source Pattern, source Pattern,

View File

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

View File

@ -3,15 +3,6 @@ package artist
import "image" import "image"
import "image/color" 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 is a struct that allows an image to be converted into a tiling
// texture pattern. // texture pattern.
type Texture struct { type Texture struct {

View File

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

View File

@ -1 +1,27 @@
package artist 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
}