package xcanvas import "image" import "image/color" import "github.com/jezek/xgbutil" import "git.tebibyte.media/tomo/ggfx" import "github.com/jezek/xgbutil/xgraphics" import "git.tebibyte.media/tomo/tomo/canvas" // Canvas satisfies the canvas.Canvas interface. It draws to an xgraphics.Image. type Canvas struct { *xgraphics.Image } // New creates a new canvas from a bounding rectangle. func New (x *xgbutil.XUtil, bounds image.Rectangle) Canvas { return Canvas { xgraphics.New(x, bounds) } } // NewFrom creates a new canvas from an existing xgraphics.Image. func NewFrom (image *xgraphics.Image) Canvas { return Canvas { image } } // Pen returns a new drawing context. func (this Canvas) Pen () canvas.Pen { return pen { image: this.Image, gfx: ggfx.Image[uint8] { Pix: this.Image.Pix, Stride: this.Image.Stride, Bounds: this.Image.Rect, Width: 4, }, } } // Clip returns a sub-canvas of this canvas. func (this Canvas) Clip (bounds image.Rectangle) Canvas { return Canvas { this.Image.SubImage(bounds).(*xgraphics.Image) } } // TODO: we need to implement: // - cap // - joint // - align type pen struct { image *xgraphics.Image gfx ggfx.Image[uint8] closed bool endCap canvas.Cap joint canvas.Joint weight int align canvas.StrokeAlign stroke [4]uint8 fill [4]uint8 } func (this pen) Rectangle (bounds image.Rectangle) { if this.weight == 0 { this.gfx.FillRectangle(this.fill[:], bounds) } else { this.gfx.StrokeRectangle(this.stroke[:], this.weight, bounds) } } func (this pen) Path (points ...image.Point) { if this.weight == 0 { this.gfx.FillPolygon(this.fill[:], points...) } else if this.closed { this.gfx.StrokePolygon(this.stroke[:], this.weight, points...) } else { this.gfx.PolyLine(this.stroke[:], this.weight, points...) } } func (this pen) Closed (closed bool) { this.closed = closed } func (this pen) Cap (endCap canvas.Cap) { this.endCap = endCap } func (this pen) Joint (joint canvas.Joint) { this.joint = joint } func (this pen) StrokeWeight (weight int) { this.weight = weight } func (this pen) StrokeAlign (align canvas.StrokeAlign) { this.align = align } func (this pen) Stroke (stroke color.Color) { this.stroke = convertColor(stroke) } func (this pen) Fill (fill color.Color) { this.fill = convertColor(fill) } func convertColor (c color.Color) [4]uint8 { r, g, b, a := c.RGBA() return [4]uint8 { uint8(b >> 8), uint8(g >> 8), uint8(a >> 8), uint8(r >> 8), } }