From 643bbf1116014f1c0788f611cc5f61722cfe011f Mon Sep 17 00:00:00 2001 From: Sasha Koshka Date: Sat, 8 Apr 2023 19:23:23 -0400 Subject: [PATCH] Grid draws the glyphs inside of cells --- elements/grid.go | 58 +++++++++++++++++++++++++++++++++++++++++--- elements/terminal.go | 4 +-- 2 files changed, 56 insertions(+), 6 deletions(-) diff --git a/elements/grid.go b/elements/grid.go index 8b9d302..fc37466 100644 --- a/elements/grid.go +++ b/elements/grid.go @@ -1,10 +1,12 @@ package elements import "image" +import "unicode" import "image/color" import "golang.org/x/image/font" import "git.tebibyte.media/sashakoshka/tomo" import "git.tebibyte.media/sashakoshka/tomo/input" +import "git.tebibyte.media/sashakoshka/tomo/fixedutil" import "git.tebibyte.media/sashakoshka/tomo/artist/shapes" import "git.tebibyte.media/sashakoshka/tomo/default/theme" import "git.tebibyte.media/sashakoshka/tomo/default/config" @@ -46,6 +48,7 @@ type Grid struct { ignorePush bool + ascent int face font.Face config config.Wrapped theme theme.Wrapped @@ -195,6 +198,7 @@ func (element *Grid) updateFontAndColors () { metrics := element.face.Metrics() element.cellWidth = emSpace.Round() element.cellHeight = metrics.Height.Round() + element.ascent = metrics.Ascent.Round() for index := range element.colors { element.colors[index] = element.theme.Color ( @@ -243,16 +247,18 @@ func (element *Grid) bound (index int) image.Rectangle { } } -func (element *Grid) draw (force bool) image.Rectangle { +func (element *Grid) draw (force bool) (updatedRegion image.Rectangle) { bounds := element.Bounds() for index, cell := range element.cells { if force || !cell.clean { - // TODO + cellBounds := element.bound(index) + updatedRegion = updatedRegion.Union(cellBounds) shapes.FillColorRectangle ( element.core, element.colors[cell.Background], - element.bound(index)) + cellBounds) + element.drawCellGlyph(cellBounds, cell.Cell) }} if force { @@ -262,5 +268,49 @@ func (element *Grid) draw (force bool) image.Rectangle { bounds, element.gridBounds) } - return bounds // FIXME + return } + +func (element *Grid) drawCellGlyph (cellBounds image.Rectangle, cell Cell) { + if cell.Rune < 32 || unicode.IsSpace(cell.Rune) { return } + + glyphColor := element.colors[cell.Foreground] + destinationRectangle, mask, maskPoint, _, ok := element.face.Glyph ( + fixedutil.Pt(cellBounds.Min), + cell.Rune) + + if !ok { + // tofu + shapes.StrokeColorRectangle ( + element.core, glyphColor, cellBounds.Inset(1), 1) + return + } + + maxX := destinationRectangle.Dx() + maxY := destinationRectangle.Dy() + + data, stride := element.core.Buffer() + + for y := 0; y < maxY; y ++ { + for x := 0; x < maxX; x ++ { + _, _, _, + alpha := mask.At(x + maskPoint.X, y + maskPoint.Y).RGBA() + dstX := x + destinationRectangle.Min.X + dstY := y + destinationRectangle.Min.Y + element.ascent + dstIndex := dstX + dstY * stride + data[dstIndex] = blend ( + data[dstIndex], + glyphColor, + float64(alpha) / 0xFFFF) + }} +} + +func blend (bottom, top color.RGBA, fac float64) color.RGBA { + return color.RGBA { + R: uint8(float64(bottom.R) * (1 - fac) + float64(top.R) * fac), + G: uint8(float64(bottom.G) * (1 - fac) + float64(top.G) * fac), + B: uint8(float64(bottom.B) * (1 - fac) + float64(top.B) * fac), + A: 0xFF, + } +} + diff --git a/elements/terminal.go b/elements/terminal.go index b8b4b61..2f4f617 100644 --- a/elements/terminal.go +++ b/elements/terminal.go @@ -25,11 +25,11 @@ func (element *Terminal) handleResize () { element.Set(image.Pt(0, 0), Cell { Rune: 'X', Background: tomo.ColorRed, - Foreground: tomo.ColorBlack, + Foreground: tomo.ColorBrightWhite, }) element.Set(image.Pt(15, 10), Cell { Rune: 'Y', - Background: tomo.ColorBrightBlue, + Background: tomo.ColorBrightYellow, Foreground: tomo.ColorBlack, }) }