canvas/backend/backendbase/base.go
2019-05-23 16:32:03 +02:00

128 lines
2.8 KiB
Go

package backendbase
import (
"image"
"image/color"
"math"
)
// Backend is used by the canvas to actually do the final
// drawing. This enables the backend to be implemented by
// various methods (OpenGL, but also other APIs or software)
type Backend interface {
Size() (int, int)
LoadImage(img image.Image) (Image, error)
LoadImagePattern(data ImagePatternData) ImagePattern
LoadLinearGradient(data Gradient) LinearGradient
LoadRadialGradient(data Gradient) RadialGradient
Clear(pts [4][2]float64)
Fill(style *FillStyle, pts [][2]float64, canOverlap bool)
DrawImage(dimg Image, sx, sy, sw, sh float64, pts [4][2]float64, alpha float64)
FillImageMask(style *FillStyle, mask *image.Alpha, pts [4][2]float64) // pts must have four points
ClearClip()
Clip(pts [][2]float64)
GetImageData(x, y, w, h int) *image.RGBA
PutImageData(img *image.RGBA, x, y int)
CanUseAsImage(b Backend) bool
AsImage() Image // can return nil if not supported
}
// FillStyle is the color and other details on how to fill
type FillStyle struct {
Color color.RGBA
Blur float64
LinearGradient LinearGradient
RadialGradient RadialGradient
Gradient struct {
X0, Y0 float64
X1, Y1 float64
RadFrom float64
RadTo float64
}
ImagePattern ImagePattern
}
type Gradient []GradientStop
func (g Gradient) ColorAt(pos float64) color.RGBA {
if len(g) == 0 {
return color.RGBA{}
} else if len(g) == 1 {
return g[0].Color
}
beforeIdx, afterIdx := -1, -1
for i, stop := range g {
if stop.Pos > pos {
afterIdx = i
break
}
beforeIdx = i
}
if beforeIdx == -1 {
return g[0].Color
} else if afterIdx == -1 {
return g[len(g)-1].Color
}
before, after := g[beforeIdx], g[afterIdx]
p := (pos - before.Pos) / (after.Pos - before.Pos)
var c [4]float64
c[0] = (float64(after.Color.R)-float64(before.Color.R))*p + float64(before.Color.R)
c[1] = (float64(after.Color.G)-float64(before.Color.G))*p + float64(before.Color.G)
c[2] = (float64(after.Color.B)-float64(before.Color.B))*p + float64(before.Color.B)
c[3] = (float64(after.Color.A)-float64(before.Color.A))*p + float64(before.Color.A)
return color.RGBA{
R: uint8(math.Round(c[0])),
G: uint8(math.Round(c[1])),
B: uint8(math.Round(c[2])),
A: uint8(math.Round(c[3])),
}
}
type GradientStop struct {
Pos float64
Color color.RGBA
}
type LinearGradient interface {
Delete()
Replace(data Gradient)
}
type RadialGradient interface {
Delete()
Replace(data Gradient)
}
type Image interface {
Width() int
Height() int
Size() (w, h int)
Delete()
Replace(src image.Image) error
}
type ImagePatternData struct {
Image Image
Transform [9]float64
Repeat ImagePatternRepeat
}
type ImagePatternRepeat uint8
// Image pattern repeat constants
const (
Repeat ImagePatternRepeat = iota
RepeatX
RepeatY
NoRepeat
)
type ImagePattern interface {
Delete()
Replace(data ImagePatternData)
}