diff --git a/artist/color.go b/artist/color.go new file mode 100644 index 0000000..1729447 --- /dev/null +++ b/artist/color.go @@ -0,0 +1,12 @@ +package artist + +import "image/color" + +// Hex creates a color.RGBA value from an RGBA integer value. +func Hex (color uint32) (c color.RGBA) { + c.A = uint8(color) + c.B = uint8(color >> 8) + c.G = uint8(color >> 16) + c.R = uint8(color >> 24) + return +} diff --git a/artist/patterns/uniform.go b/artist/patterns/uniform.go index c31aad4..8efb8be 100644 --- a/artist/patterns/uniform.go +++ b/artist/patterns/uniform.go @@ -3,6 +3,7 @@ package patterns import "image" import "image/color" import "git.tebibyte.media/sashakoshka/tomo/canvas" +import "git.tebibyte.media/sashakoshka/tomo/artist" import "git.tebibyte.media/sashakoshka/tomo/artist/shapes" // Uniform is a pattern that draws a solid color. @@ -15,13 +16,5 @@ func (pattern Uniform) Draw (destination canvas.Canvas, clip image.Rectangle) { // Uhex creates a new Uniform pattern from an RGBA integer value. func Uhex (color uint32) (uniform Uniform) { - return Uniform(hex(color)) -} - -func hex (color uint32) (c color.RGBA) { - c.A = uint8(color) - c.B = uint8(color >> 8) - c.G = uint8(color >> 16) - c.R = uint8(color >> 24) - return + return Uniform(artist.Hex(color)) } diff --git a/artist/shapes/ellipse.go b/artist/shapes/ellipse.go index 3acc2e2..0e5f0c5 100644 --- a/artist/shapes/ellipse.go +++ b/artist/shapes/ellipse.go @@ -5,23 +5,23 @@ import "image" import "image/color" import "git.tebibyte.media/sashakoshka/tomo/canvas" -// FillEllipse draws the content of one canvas onto another, clipped by an -// ellipse stretched to the bounds of the source canvas. The offset point -// defines where the origin point of the source canvas is positioned in relation -// to the origin point of the destination canvas. To prevent the entire source -// canvas's bounds from being used, it must be cut with canvas.Cut(). +// TODO: redo fill ellipse, stroke ellipse, etc. so that it only takes in +// destination and source, using the bounds of destination as the bounds of the +// ellipse and the bounds of source as the "clipping rectangle". Line up the Min +// of both canvases. + func FillEllipse ( destination canvas.Canvas, source canvas.Canvas, - offset image.Point, ) ( updatedRegion image.Rectangle, ) { dstData, dstStride := destination.Buffer() srcData, srcStride := source.Buffer() - bounds := source.Bounds().Intersect(destination.Bounds()).Canon() - realBounds := source.Bounds() + offset := source.Bounds().Min.Sub(destination.Bounds().Min) + bounds := source.Bounds().Sub(offset).Intersect(destination.Bounds()) + realBounds := destination.Bounds() if bounds.Empty() { return } updatedRegion = bounds @@ -30,22 +30,17 @@ func FillEllipse ( for point.X = bounds.Min.X; point.X < bounds.Max.X; point.X ++ { if inEllipse(point, realBounds) { offsetPoint := point.Add(offset) - dstIndex := offsetPoint.X + (offsetPoint.Y) * dstStride - srcIndex := point.X + point.Y * srcStride + dstIndex := point.X + point.Y * dstStride + srcIndex := offsetPoint.X + offsetPoint.Y * srcStride dstData[dstIndex] = srcData[srcIndex] } }} return } -// StrokeEllipse is similar to FillEllipse, but it draws an elliptical inset -// outline of the source canvas onto the destination canvas. To prevent the -// entire source canvas's bounds from being used, it must be cut with -// canvas.Cut(). func StrokeEllipse ( destination canvas.Canvas, source canvas.Canvas, - offset image.Point, weight int, ) { if weight < 1 { return } @@ -53,7 +48,10 @@ func StrokeEllipse ( dstData, dstStride := destination.Buffer() srcData, srcStride := source.Buffer() - bounds := source.Bounds().Inset(weight - 1) + bounds := destination.Bounds().Inset(weight - 1) + offset := source.Bounds().Min.Sub(destination.Bounds().Min) + realBounds := destination.Bounds() + if bounds.Empty() { return } context := ellipsePlottingContext { plottingContext: plottingContext { @@ -63,9 +61,9 @@ func StrokeEllipse ( srcStride: srcStride, weight: weight, offset: offset, - bounds: bounds.Intersect(destination.Bounds()), + bounds: realBounds, }, - radii: image.Pt(bounds.Dx() / 2 - 1, bounds.Dy() / 2 - 1), + radii: image.Pt(bounds.Dx() / 2, bounds.Dy() / 2), } context.center = bounds.Min.Add(context.radii) context.plotEllipse() @@ -205,7 +203,7 @@ func StrokeColorEllipse ( if weight < 1 { return } dstData, dstStride := destination.Buffer() - bounds = bounds.Inset(weight - 1) + insetBounds := bounds.Inset(weight - 1) context := ellipsePlottingContext { plottingContext: plottingContext { @@ -215,9 +213,9 @@ func StrokeColorEllipse ( weight: weight, bounds: bounds.Intersect(destination.Bounds()), }, - radii: image.Pt(bounds.Dx() / 2 - 1, bounds.Dy() / 2 - 1), + radii: image.Pt(insetBounds.Dx() / 2, insetBounds.Dy() / 2), } - context.center = bounds.Min.Add(context.radii) + context.center = insetBounds.Min.Add(context.radii) context.plotEllipse() return } diff --git a/artist/shapes/plot.go b/artist/shapes/plot.go index b629bd9..6749768 100644 --- a/artist/shapes/plot.go +++ b/artist/shapes/plot.go @@ -16,32 +16,31 @@ type plottingContext struct { bounds image.Rectangle } -func (context plottingContext) square (center image.Point) image.Rectangle { +func (context plottingContext) square (center image.Point) (square image.Rectangle) { return image.Rect(0, 0, context.weight, context.weight). Sub(image.Pt(context.weight / 2, context.weight / 2)). Add(center). - Add(context.offset). Intersect(context.bounds) } func (context plottingContext) plotColor (center image.Point) { square := context.square(center) - for y := square.Min.Y; y < square.Min.Y; y ++ { - for x := square.Min.X; x < square.Min.X; x ++ { + for y := square.Min.Y; y < square.Max.Y; y ++ { + for x := square.Min.X; x < square.Max.X; x ++ { context.dstData[x + y * context.dstStride] = context.color }} } func (context plottingContext) plotSource (center image.Point) { square := context.square(center) - for y := square.Min.Y; y < square.Min.Y; y ++ { - for x := square.Min.X; x < square.Min.X; x ++ { + for y := square.Min.Y; y < square.Max.Y; y ++ { + for x := square.Min.X; x < square.Max.X; x ++ { // we offset srcIndex here because we have already applied the // offset to the square, and we need to reverse that to get the // proper source coordinates. srcIndex := - x - context.offset.X + - (y - context.offset.Y) * context.dstStride + x + context.offset.X + + (y + context.offset.Y) * context.dstStride dstIndex := x + y * context.dstStride context.dstData[dstIndex] = context.srcData [srcIndex] }} diff --git a/artist/shapes/rectangle.go b/artist/shapes/rectangle.go index 9e6f86f..8912ade 100644 --- a/artist/shapes/rectangle.go +++ b/artist/shapes/rectangle.go @@ -7,51 +7,44 @@ import "git.tebibyte.media/sashakoshka/tomo/shatter" // TODO: return updatedRegion for all routines in this package -// FillRectangle draws the content of one canvas onto another. The offset point -// defines where the origin point of the source canvas is positioned in relation -// to the origin point of the destination canvas. To prevent the entire source -// canvas from being drawn, it must be cut with canvas.Cut(). func FillRectangle ( destination canvas.Canvas, source canvas.Canvas, - offset image.Point, ) ( updatedRegion image.Rectangle, ) { dstData, dstStride := destination.Buffer() srcData, srcStride := source.Buffer() - sourceBounds := - source.Bounds().Canon(). - Intersect(destination.Bounds().Sub(offset)) - if sourceBounds.Empty() { return } + offset := source.Bounds().Min.Sub(destination.Bounds().Min) + bounds := source.Bounds().Sub(offset).Intersect(destination.Bounds()) + if bounds.Empty() { return } + updatedRegion = bounds - updatedRegion = sourceBounds.Add(offset) - for y := sourceBounds.Min.Y; y < sourceBounds.Max.Y; y ++ { - for x := sourceBounds.Min.X; x < sourceBounds.Max.X; x ++ { - dstData[x + offset.X + (y + offset.Y) * dstStride] = - srcData[x + y * srcStride] + point := image.Point { } + for point.Y = bounds.Min.Y; point.Y < bounds.Max.Y; point.Y ++ { + for point.X = bounds.Min.X; point.X < bounds.Max.X; point.X ++ { + offsetPoint := point.Add(offset) + dstIndex := point.X + point.Y * dstStride + srcIndex := offsetPoint.X + offsetPoint.Y * srcStride + dstData[dstIndex] = srcData[srcIndex] }} return } -// StrokeRectangle is similar to FillRectangle, but it draws an inset outline of -// the source canvas onto the destination canvas. To prevent the entire source -// canvas's bounds from being used, it must be cut with canvas.Cut(). func StrokeRectangle ( destination canvas.Canvas, source canvas.Canvas, - offset image.Point, weight int, ) { - bounds := source.Bounds() + bounds := destination.Bounds() insetBounds := bounds.Inset(weight) if insetBounds.Empty() { - FillRectangle(destination, source, offset) + FillRectangle(destination, source) return } - FillRectangleShatter(destination, source, offset, insetBounds) + FillRectangleShatter(destination, source, insetBounds) } // FillRectangleShatter is like FillRectangle, but it does not draw in areas @@ -59,12 +52,14 @@ func StrokeRectangle ( func FillRectangleShatter ( destination canvas.Canvas, source canvas.Canvas, - offset image.Point, rocks ...image.Rectangle, ) { - tiles := shatter.Shatter(source.Bounds().Sub(offset), rocks...) + tiles := shatter.Shatter(destination.Bounds(), rocks...) + offset := source.Bounds().Min.Sub(destination.Bounds().Min) for _, tile := range tiles { - FillRectangle(destination, canvas.Cut(source, tile), offset) + FillRectangle ( + canvas.Cut(destination, tile), + canvas.Cut(source, tile.Add(offset))) } } diff --git a/elements/testing/artist.go b/elements/testing/artist.go index 7db6f3e..d3b5475 100644 --- a/elements/testing/artist.go +++ b/elements/testing/artist.go @@ -4,11 +4,14 @@ import "fmt" import "time" import "image" import "image/color" +import "git.tebibyte.media/sashakoshka/tomo/canvas" import "git.tebibyte.media/sashakoshka/tomo/artist" import "git.tebibyte.media/sashakoshka/tomo/shatter" import "git.tebibyte.media/sashakoshka/tomo/textdraw" import "git.tebibyte.media/sashakoshka/tomo/defaultfont" import "git.tebibyte.media/sashakoshka/tomo/elements/core" +import "git.tebibyte.media/sashakoshka/tomo/artist/shapes" +import "git.tebibyte.media/sashakoshka/tomo/artist/patterns" // Artist is an element that displays shapes and patterns drawn by the artist // package in order to test it. @@ -21,103 +24,52 @@ type Artist struct { func NewArtist () (element *Artist) { element = &Artist { } element.Core, element.core = core.NewCore(element.draw) - element.core.SetMinimumSize(240, 360) + element.core.SetMinimumSize(240, 240) return } func (element *Artist) draw () { bounds := element.Bounds() - artist.FillRectangle(element.core, artist.NewUniform(hex(0)), bounds) + patterns.Uhex(0x000000FF).Draw(element.core, bounds) drawStart := time.Now() - // 0, 0 - artist.FillRectangle ( - element.core, - artist.Beveled { - artist.NewUniform(hex(0xFF0000FF)), - artist.NewUniform(hex(0x0000FFFF)), - }, - element.cellAt(0, 0)) - - // 1, 0 - artist.StrokeRectangle ( - element.core, - artist.NewUniform(hex(0x00FF00FF)), 3, - element.cellAt(1, 0)) - - // 2, 0 - artist.FillRectangle ( - element.core, - artist.NewMultiBordered ( - artist.Stroke { Pattern: uhex(0xFF0000FF), Weight: 1 }, - artist.Stroke { Pattern: uhex(0x888800FF), Weight: 2 }, - artist.Stroke { Pattern: uhex(0x00FF00FF), Weight: 3 }, - artist.Stroke { Pattern: uhex(0x008888FF), Weight: 4 }, - artist.Stroke { Pattern: uhex(0x0000FFFF), Weight: 5 }, - ), - element.cellAt(2, 0)) - - // 3, 0 - artist.FillRectangle ( - element.core, - artist.Bordered { - Stroke: artist.Stroke { Pattern: uhex(0x0000FFFF), Weight: 5 }, - Fill: uhex(0xFF0000FF), - }, - element.cellAt(3, 0)) + // 0, 0 - 3, 0 + for x := 0; x < 4; x ++ { + element.colorLines(x + 1, element.cellAt(x, 0).Bounds()) + } // 4, 0 - artist.FillRectangle ( - element.core, - artist.Padded { - Stroke: uhex(0xFFFFFFFF), - Fill: uhex(0x666666FF), - Sides: []int { 4, 13, 2, 0 }, - }, - element.cellAt(4, 0)) + c40 := element.cellAt(4, 0) + shapes.StrokeColorRectangle(c40, artist.Hex(0x888888FF), c40.Bounds(), 1) + shapes.ColorLine ( + c40, artist.Hex(0xFF0000FF), 1, + c40.Bounds().Min, c40.Bounds().Max) - // 0, 1 - 3, 1 - for x := 0; x < 4; x ++ { - artist.FillRectangle ( - element.core, - artist.Striped { - First: artist.Stroke { Pattern: uhex(0xFF8800FF), Weight: 7 }, - Second: artist.Stroke { Pattern: uhex(0x0088FFFF), Weight: 2 }, - Orientation: artist.Orientation(x), - - }, - element.cellAt(x, 1)) - } + // 0, 1 + c01 := element.cellAt(0, 1) + shapes.StrokeColorRectangle(c01, artist.Hex(0x888888FF), c01.Bounds(), 1) + shapes.FillColorEllipse(element.core, artist.Hex(0x00FF00FF), c01.Bounds()) - // 0, 2 - 3, 2 - for x := 0; x < 4; x ++ { - element.lines(x + 1, element.cellAt(x, 2)) - } - - // 0, 3 - artist.StrokeRectangle ( - element.core, uhex(0x888888FF), 1, - element.cellAt(0, 3)) - artist.FillEllipse(element.core, uhex(0x00FF00FF), element.cellAt(0, 3)) - - // 1, 3 - 3, 3 + // 1, 1 - 3, 1 for x := 1; x < 4; x ++ { - artist.StrokeRectangle ( - element.core,uhex(0x888888FF), 1, - element.cellAt(x, 3)) - artist.StrokeEllipse ( + c := element.cellAt(x, 1) + shapes.StrokeColorRectangle ( + element.core, artist.Hex(0x888888FF), + c.Bounds(), 1) + shapes.StrokeColorEllipse ( element.core, - []artist.Pattern { - uhex(0xFF0000FF), - uhex(0x00FF00FF), - uhex(0xFF00FFFF), + []color.RGBA { + artist.Hex(0xFF0000FF), + artist.Hex(0x00FF00FF), + artist.Hex(0xFF00FFFF), } [x - 1], - x, element.cellAt(x, 3)) + c.Bounds(), x) } - // 4, 3 - shatterPos := element.cellAt(4, 3).Min + // 4, 1 + c41 := element.cellAt(4, 1) + shatterPos := c41.Bounds().Min rocks := []image.Rectangle { image.Rect(3, 12, 13, 23).Add(shatterPos), // image.Rect(30, 10, 40, 23).Add(shatterPos), @@ -125,159 +77,36 @@ func (element *Artist) draw () { image.Rect(30, -10, 40, 43).Add(shatterPos), image.Rect(80, 30, 90, 45).Add(shatterPos), } - tiles := shatter.Shatter(element.cellAt(4, 3), rocks...) - for _, tile := range tiles { - artist.FillRectangle ( - element.core, - artist.Bordered { - Fill: uhex(0x888888FF), - Stroke: artist.Stroke { - Pattern: artist.Beveled { - uhex(0xCCCCCCFF), - uhex(0x444444FF), - }, - Weight: 1, - }, - }, - tile) + tiles := shatter.Shatter(c41.Bounds(), rocks...) + for index, tile := range tiles { + artist.DrawBounds ( + element.core, tile, + []artist.Pattern { + patterns.Uhex(0xFF0000FF), + patterns.Uhex(0x00FF00FF), + patterns.Uhex(0xFF00FFFF), + patterns.Uhex(0xFFFF00FF), + patterns.Uhex(0x00FFFFFF), + } [index % 5], tile) } - // 0, 4 - 3, 4 - for x := 0; x < 4; x ++ { - artist.FillEllipse ( - element.core, - artist.Split { - First: uhex(0xFF0000FF), - Second: uhex(0x0000FFFF), - Orientation: artist.Orientation(x), - }, - element.cellAt(x, 4)) - } + // 0, 2 + c02 := element.cellAt(0, 2) + shapes.StrokeColorRectangle(c02, artist.Hex(0x888888FF), c02.Bounds(), 1) + shapes.FillEllipse(c02, c41) + + // 1, 2 + c12 := element.cellAt(1, 2) + shapes.StrokeColorRectangle(c12, artist.Hex(0x888888FF), c12.Bounds(), 1) + shapes.StrokeEllipse(c12, c41, 5) - // 0, 5 - artist.FillRectangle ( - element.core, - artist.QuadBeveled { - uhex(0x880000FF), - uhex(0x00FF00FF), - uhex(0x0000FFFF), - uhex(0xFF00FFFF), - }, - element.cellAt(0, 5)) - - // 1, 5 - artist.FillRectangle ( - element.core, - artist.Checkered { - First: artist.QuadBeveled { - uhex(0x880000FF), - uhex(0x00FF00FF), - uhex(0x0000FFFF), - uhex(0xFF00FFFF), - }, - Second: artist.Striped { - First: artist.Stroke { Pattern: uhex(0xFF8800FF), Weight: 1 }, - Second: artist.Stroke { Pattern: uhex(0x0088FFFF), Weight: 1 }, - Orientation: artist.OrientationVertical, - }, - CellWidth: 32, - CellHeight: 16, - }, - element.cellAt(1, 5)) - - // 2, 5 - artist.FillRectangle ( - element.core, - artist.Dotted { - Foreground: uhex(0x00FF00FF), - Background: artist.Checkered { - First: uhex(0x444444FF), - Second: uhex(0x888888FF), - CellWidth: 16, - CellHeight: 16, - }, - Size: 8, - Spacing: 16, - }, - element.cellAt(2, 5)) - - // 3, 5 - artist.FillRectangle ( - element.core, - artist.Tiled { - Pattern: artist.QuadBeveled { - uhex(0x880000FF), - uhex(0x00FF00FF), - uhex(0x0000FFFF), - uhex(0xFF00FFFF), - }, - CellWidth: 17, - CellHeight: 23, - }, - element.cellAt(3, 5)) - - // 0, 6 - 3, 6 - for x := 0; x < 4; x ++ { - artist.FillRectangle ( - element.core, - artist.Gradient { - First: uhex(0xFF0000FF), - Second: uhex(0x0000FFFF), - Orientation: artist.Orientation(x), - }, - element.cellAt(x, 6)) - } + // 2, 2 + c22 := element.cellAt(2, 2) + shapes.FillRectangle(c22, c41) - // 0, 7 - artist.FillEllipse ( - element.core, - artist.EllipticallyBordered { - Fill: artist.Gradient { - First: uhex(0x00FF00FF), - Second: uhex(0x0000FFFF), - Orientation: artist.OrientationVertical, - }, - Stroke: artist.Stroke { Pattern: uhex(0x00FF00), Weight: 5 }, - }, - element.cellAt(0, 7)) - - // 1, 7 - artist.FillRectangle ( - element.core, - artist.Noisy { - Low: uhex(0x000000FF), - High: uhex(0xFFFFFFFF), - Seed: 0, - }, - element.cellAt(1, 7), - ) - - // 2, 7 - artist.FillRectangle ( - element.core, - artist.Noisy { - Low: uhex(0x000000FF), - High: artist.Gradient { - First: uhex(0x000000FF), - Second: uhex(0xFFFFFFFF), - Orientation: artist.OrientationVertical, - }, - Seed: 0, - }, - element.cellAt(2, 7), - ) - - // 3, 7 - artist.FillRectangle ( - element.core, - artist.Noisy { - Low: uhex(0x000000FF), - High: uhex(0xFFFFFFFF), - Seed: 0, - Harsh: true, - }, - element.cellAt(3, 7), - ) + // 3, 2 + c32 := element.cellAt(3, 2) + shapes.StrokeRectangle(c32, c41, 5) // how long did that take to render? drawTime := time.Since(drawStart) @@ -288,68 +117,51 @@ func (element *Artist) draw () { drawTime.Milliseconds(), drawTime.Microseconds()))) textDrawer.Draw ( - element.core, uhex(0xFFFFFFFF), + element.core, artist.Hex(0xFFFFFFFF), image.Pt(bounds.Min.X + 8, bounds.Max.Y - 24)) } -func (element *Artist) lines (weight int, bounds image.Rectangle) { +func (element *Artist) colorLines (weight int, bounds image.Rectangle) { bounds = bounds.Inset(4) - c := uhex(0xFFFFFFFF) - artist.Line(element.core, c, weight, bounds.Min, bounds.Max) - artist.Line ( + c := artist.Hex(0xFFFFFFFF) + shapes.ColorLine(element.core, c, weight, bounds.Min, bounds.Max) + shapes.ColorLine ( element.core, c, weight, image.Pt(bounds.Max.X, bounds.Min.Y), image.Pt(bounds.Min.X, bounds.Max.Y)) - artist.Line ( + shapes.ColorLine ( element.core, c, weight, image.Pt(bounds.Max.X, bounds.Min.Y + 16), image.Pt(bounds.Min.X, bounds.Max.Y - 16)) - artist.Line ( + shapes.ColorLine ( element.core, c, weight, image.Pt(bounds.Min.X, bounds.Min.Y + 16), image.Pt(bounds.Max.X, bounds.Max.Y - 16)) - artist.Line ( + shapes.ColorLine ( element.core, c, weight, image.Pt(bounds.Min.X + 20, bounds.Min.Y), image.Pt(bounds.Max.X - 20, bounds.Max.Y)) - artist.Line ( + shapes.ColorLine ( element.core, c, weight, image.Pt(bounds.Max.X - 20, bounds.Min.Y), image.Pt(bounds.Min.X + 20, bounds.Max.Y)) - artist.Line ( + shapes.ColorLine ( element.core, c, weight, image.Pt(bounds.Min.X, bounds.Min.Y + bounds.Dy() / 2), image.Pt(bounds.Max.X, bounds.Min.Y + bounds.Dy() / 2)) - artist.Line ( + shapes.ColorLine ( element.core, c, weight, image.Pt(bounds.Min.X + bounds.Dx() / 2, bounds.Min.Y), image.Pt(bounds.Min.X + bounds.Dx() / 2, bounds.Max.Y)) } -func (element *Artist) cellAt (x, y int) (image.Rectangle) { +func (element *Artist) cellAt (x, y int) (canvas.Canvas) { bounds := element.Bounds() cellBounds := image.Rectangle { } cellBounds.Min = bounds.Min cellBounds.Max.X = bounds.Min.X + bounds.Dx() / 5 - cellBounds.Max.Y = bounds.Min.Y + (bounds.Dy() - 48) / 8 - return cellBounds.Add (image.Pt ( + cellBounds.Max.Y = bounds.Min.Y + (bounds.Dy() - 48) / 4 + return canvas.Cut (element.core, cellBounds.Add (image.Pt ( x * cellBounds.Dx(), - y * cellBounds.Dy())) -} - -func hex (n uint32) (c color.RGBA) { - c.A = uint8(n) - c.B = uint8(n >> 8) - c.G = uint8(n >> 16) - c.R = uint8(n >> 24) - return -} - -func uhex (n uint32) (artist.Pattern) { - return artist.NewUniform (color.RGBA { - A: uint8(n), - B: uint8(n >> 8), - G: uint8(n >> 16), - R: uint8(n >> 24), - }) + y * cellBounds.Dy()))) } diff --git a/elements/testing/mouse.go b/elements/testing/mouse.go index 63695c0..57eeb67 100644 --- a/elements/testing/mouse.go +++ b/elements/testing/mouse.go @@ -1,11 +1,11 @@ package testing import "image" -import "image/color" import "git.tebibyte.media/sashakoshka/tomo/input" -import "git.tebibyte.media/sashakoshka/tomo/config" import "git.tebibyte.media/sashakoshka/tomo/theme" +import "git.tebibyte.media/sashakoshka/tomo/config" import "git.tebibyte.media/sashakoshka/tomo/artist" +import "git.tebibyte.media/sashakoshka/tomo/artist/shapes" import "git.tebibyte.media/sashakoshka/tomo/elements/core" // Mouse is an element capable of testing mouse input. When the mouse is clicked @@ -14,7 +14,6 @@ type Mouse struct { *core.Core core core.CoreControl drawing bool - color artist.Pattern lastMousePos image.Point config config.Config @@ -27,7 +26,6 @@ func NewMouse () (element *Mouse) { element = &Mouse { c: theme.C("testing", "mouse") } element.Core, element.core = core.NewCore(element.draw) element.core.SetMinimumSize(32, 32) - element.color = artist.NewUniform(color.Black) return } @@ -55,17 +53,17 @@ func (element *Mouse) draw () { theme.PatternAccent, theme.PatternState { }, element.c) - artist.FillRectangle(element.core, pattern, bounds) - artist.StrokeRectangle ( + pattern.Draw(element.core, bounds) + shapes.StrokeColorRectangle ( element.core, - artist.NewUniform(color.Black), 1, - bounds) - artist.Line ( - element.core, artist.NewUniform(color.White), 1, + artist.Hex(0x000000FF), + bounds, 1) + shapes.ColorLine ( + element.core, artist.Hex(0xFFFFFFFF), 1, bounds.Min.Add(image.Pt(1, 1)), bounds.Min.Add(image.Pt(bounds.Dx() - 2, bounds.Dy() - 2))) - artist.Line ( - element.core, artist.NewUniform(color.White), 1, + shapes.ColorLine ( + element.core, artist.Hex(0xFFFFFFFF), 1, bounds.Min.Add(image.Pt(1, bounds.Dy() - 2)), bounds.Min.Add(image.Pt(bounds.Dx() - 2, 1))) } @@ -78,8 +76,8 @@ func (element *Mouse) HandleMouseDown (x, y int, button input.Button) { func (element *Mouse) HandleMouseUp (x, y int, button input.Button) { element.drawing = false mousePos := image.Pt(x, y) - element.core.DamageRegion (artist.Line ( - element.core, element.color, 1, + element.core.DamageRegion (shapes.ColorLine ( + element.core, artist.Hex(0x000000FF), 1, element.lastMousePos, mousePos)) element.lastMousePos = mousePos } @@ -87,8 +85,8 @@ func (element *Mouse) HandleMouseUp (x, y int, button input.Button) { func (element *Mouse) HandleMouseMove (x, y int) { if !element.drawing { return } mousePos := image.Pt(x, y) - element.core.DamageRegion (artist.Line ( - element.core, element.color, 1, + element.core.DamageRegion (shapes.ColorLine ( + element.core, artist.Hex(0x000000FF), 1, element.lastMousePos, mousePos)) element.lastMousePos = mousePos } diff --git a/examples/artist/main.go b/examples/artist/main.go index b09932b..3b4517f 100644 --- a/examples/artist/main.go +++ b/examples/artist/main.go @@ -11,12 +11,12 @@ func main () { } func run () { - window, _ := tomo.NewWindow(128, 128) + window, _ := tomo.NewWindow(480, 360) window.SetTitle("Draw Test") window.Adopt(testing.NewArtist()) window.OnClose(tomo.Stop) window.Show() go func () { - http.ListenAndServe("localhost:6060", nil) + http.ListenAndServe("localhost:9090", nil) } () } diff --git a/textdraw/drawer.go b/textdraw/drawer.go index 09fe749..3ef4011 100644 --- a/textdraw/drawer.go +++ b/textdraw/drawer.go @@ -3,9 +3,9 @@ package textdraw import "image" import "unicode" import "image/draw" +import "image/color" import "golang.org/x/image/math/fixed" import "git.tebibyte.media/sashakoshka/tomo/canvas" -import "git.tebibyte.media/sashakoshka/tomo/artist" // Drawer is an extended TypeSetter that is able to draw text. Much like // TypeSetter, It has no constructor and its zero value can be used safely. @@ -14,17 +14,11 @@ type Drawer struct { TypeSetter } // Draw draws the drawer's text onto the specified canvas at the given offset. func (drawer Drawer) Draw ( destination canvas.Canvas, - source artist.Pattern, + color color.RGBA, offset image.Point, ) ( updatedRegion image.Rectangle, ) { - wrappedSource := artist.WrappedPattern { - Pattern: source, - Width: 0, - Height: 0, // TODO: choose a better width and height - } - drawer.For (func ( index int, char rune, @@ -46,7 +40,7 @@ func (drawer Drawer) Draw ( draw.DrawMask ( destination, destinationRectangle, - wrappedSource, image.Point { }, + image.NewUniform(color), image.Point { }, mask, maskPoint, draw.Over)