started a software backend
This commit is contained in:
parent
a4826a3e12
commit
9f99dff89b
4 changed files with 240 additions and 0 deletions
23
backend/software/fill.go
Normal file
23
backend/software/fill.go
Normal file
|
@ -0,0 +1,23 @@
|
|||
package softwarebackend
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
|
||||
"github.com/tfriedel6/canvas/backend/backendbase"
|
||||
)
|
||||
|
||||
func (b *SoftwareBackend) Clear(pts [4][2]float64) {
|
||||
iterateTriangles(pts[:], func(tri [][2]float64) {
|
||||
b.fillTriangle(tri, func(x, y int) {
|
||||
b.Image.SetRGBA(x, y, color.RGBA{})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func (b *SoftwareBackend) Fill(style *backendbase.FillStyle, pts [][2]float64) {
|
||||
iterateTriangles(pts[:], func(tri [][2]float64) {
|
||||
b.fillTriangle(tri, func(x, y int) {
|
||||
b.Image.SetRGBA(x, y, style.Color)
|
||||
})
|
||||
})
|
||||
}
|
42
backend/software/images.go
Normal file
42
backend/software/images.go
Normal file
|
@ -0,0 +1,42 @@
|
|||
package softwarebackend
|
||||
|
||||
import (
|
||||
"image"
|
||||
|
||||
"github.com/tfriedel6/canvas/backend/backendbase"
|
||||
)
|
||||
|
||||
type Image struct {
|
||||
img image.Image
|
||||
}
|
||||
|
||||
func (b *SoftwareBackend) LoadImage(img image.Image) (backendbase.Image, error) {
|
||||
return &Image{img: img}, nil
|
||||
}
|
||||
|
||||
func (b *SoftwareBackend) DrawImage(dimg backendbase.Image, sx, sy, sw, sh float64, pts [4][2]float64, alpha float64) {
|
||||
}
|
||||
|
||||
func (b *SoftwareBackend) FillImageMask(style *backendbase.FillStyle, mask *image.Alpha, pts [][2]float64) {
|
||||
}
|
||||
|
||||
func (img *Image) Width() int {
|
||||
return img.img.Bounds().Dx()
|
||||
}
|
||||
|
||||
func (img *Image) Height() int {
|
||||
return img.img.Bounds().Dy()
|
||||
}
|
||||
|
||||
func (img *Image) Size() (w, h int) {
|
||||
b := img.img.Bounds()
|
||||
return b.Dx(), b.Dy()
|
||||
}
|
||||
|
||||
func (img *Image) Delete() {
|
||||
}
|
||||
|
||||
func (img *Image) Replace(src image.Image) error {
|
||||
img.img = src
|
||||
return nil
|
||||
}
|
81
backend/software/software.go
Normal file
81
backend/software/software.go
Normal file
|
@ -0,0 +1,81 @@
|
|||
package softwarebackend
|
||||
|
||||
import (
|
||||
"image"
|
||||
"image/draw"
|
||||
|
||||
"github.com/tfriedel6/canvas/backend/backendbase"
|
||||
)
|
||||
|
||||
type SoftwareBackend struct {
|
||||
Image *image.RGBA
|
||||
w, h int
|
||||
}
|
||||
|
||||
func New(w, h int) *SoftwareBackend {
|
||||
return &SoftwareBackend{
|
||||
Image: image.NewRGBA(image.Rect(0, 0, w, h)),
|
||||
w: w,
|
||||
h: h,
|
||||
}
|
||||
}
|
||||
|
||||
func (b *SoftwareBackend) SetSize(w, h int) {
|
||||
b.w, b.h = w, h
|
||||
b.Image = image.NewRGBA(image.Rect(0, 0, w, h))
|
||||
}
|
||||
|
||||
func (b *SoftwareBackend) Size() (int, int) {
|
||||
return b.w, b.h
|
||||
}
|
||||
|
||||
func (b *SoftwareBackend) ClearClip() {
|
||||
}
|
||||
|
||||
func (b *SoftwareBackend) Clip(pts [][2]float64) {
|
||||
}
|
||||
|
||||
func (b *SoftwareBackend) GetImageData(x, y, w, h int) *image.RGBA {
|
||||
return b.Image.SubImage(image.Rect(x, y, w, h)).(*image.RGBA)
|
||||
}
|
||||
|
||||
func (b *SoftwareBackend) PutImageData(img *image.RGBA, x, y int) {
|
||||
draw.Draw(b.Image, image.Rect(x, y, img.Rect.Dx(), img.Rect.Dy()), img, image.ZP, draw.Src)
|
||||
}
|
||||
|
||||
func (b *SoftwareBackend) CanUseAsImage(b2 backendbase.Backend) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (b *SoftwareBackend) AsImage() backendbase.Image {
|
||||
return nil
|
||||
}
|
||||
|
||||
type LinearGradient struct {
|
||||
data backendbase.Gradient
|
||||
}
|
||||
type RadialGradient struct {
|
||||
data backendbase.Gradient
|
||||
}
|
||||
|
||||
func (b *SoftwareBackend) LoadLinearGradient(data backendbase.Gradient) backendbase.LinearGradient {
|
||||
return &LinearGradient{data: data}
|
||||
}
|
||||
|
||||
func (b *SoftwareBackend) LoadRadialGradient(data backendbase.Gradient) backendbase.RadialGradient {
|
||||
return &RadialGradient{data: data}
|
||||
}
|
||||
|
||||
func (g *LinearGradient) Delete() {
|
||||
}
|
||||
|
||||
func (g *LinearGradient) Replace(data backendbase.Gradient) {
|
||||
g.data = data
|
||||
}
|
||||
|
||||
func (g *RadialGradient) Delete() {
|
||||
}
|
||||
|
||||
func (g *RadialGradient) Replace(data backendbase.Gradient) {
|
||||
g.data = data
|
||||
}
|
94
backend/software/triangles.go
Normal file
94
backend/software/triangles.go
Normal file
|
@ -0,0 +1,94 @@
|
|||
package softwarebackend
|
||||
|
||||
import "math"
|
||||
|
||||
func triangleLR(tri [][2]float64, y float64) (l, r float64) {
|
||||
a, b, c := tri[0], tri[1], tri[2]
|
||||
|
||||
// check general bounds
|
||||
if y < a[1] && y < b[1] && y < c[1] {
|
||||
return 0, 0
|
||||
}
|
||||
if y > a[1] && y > b[1] && y > c[1] {
|
||||
return 0, 0
|
||||
}
|
||||
|
||||
// sort by y
|
||||
if a[1] > b[1] {
|
||||
a, b = b, a
|
||||
}
|
||||
if b[1] > c[1] {
|
||||
b, c = c, b
|
||||
if a[1] > b[1] {
|
||||
a, b = b, a
|
||||
}
|
||||
}
|
||||
|
||||
// find left and right x at y
|
||||
if y >= a[1] && y <= b[1] {
|
||||
r0 := (y - a[1]) / (b[1] - a[1])
|
||||
l = (b[0]-a[0])*r0 + a[0]
|
||||
r1 := (y - a[1]) / (c[1] - a[1])
|
||||
r = (c[0]-a[0])*r1 + a[0]
|
||||
} else {
|
||||
r0 := (y - b[1]) / (c[1] - b[1])
|
||||
l = (c[0]-b[0])*r0 + b[0]
|
||||
r1 := (y - a[1]) / (c[1] - a[1])
|
||||
r = (c[0]-a[0])*r1 + a[0]
|
||||
}
|
||||
if l > r {
|
||||
l, r = r, l
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (b *SoftwareBackend) fillTriangle(tri [][2]float64, fn func(x, y int)) {
|
||||
minY := int(math.Floor(math.Min(math.Min(tri[0][1], tri[1][1]), tri[2][1])))
|
||||
maxY := int(math.Ceil(math.Max(math.Max(tri[0][1], tri[1][1]), tri[2][1])))
|
||||
if minY < 0 {
|
||||
minY = 0
|
||||
} else if minY >= b.h {
|
||||
return
|
||||
}
|
||||
if maxY < 0 {
|
||||
return
|
||||
} else if maxY >= b.h {
|
||||
maxY = b.h - 1
|
||||
}
|
||||
for y := minY; y <= maxY; y++ {
|
||||
lf, rf := triangleLR(tri, float64(y)+0.5)
|
||||
l := int(math.Floor(lf))
|
||||
r := int(math.Ceil(rf))
|
||||
if l < 0 {
|
||||
l = 0
|
||||
} else if l >= b.w {
|
||||
continue
|
||||
}
|
||||
if r < 0 {
|
||||
continue
|
||||
} else if r >= b.w {
|
||||
r = b.w - 1
|
||||
}
|
||||
for x := l; x <= r; x++ {
|
||||
fn(x, y)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func iterateTriangles(pts [][2]float64, fn func(tri [][2]float64)) {
|
||||
if len(pts) == 4 {
|
||||
var buf [3][2]float64
|
||||
buf[0] = pts[0]
|
||||
buf[1] = pts[1]
|
||||
buf[2] = pts[2]
|
||||
fn(buf[:])
|
||||
buf[1] = pts[2]
|
||||
buf[2] = pts[3]
|
||||
fn(buf[:])
|
||||
return
|
||||
}
|
||||
for i := 3; i <= len(pts); i += 3 {
|
||||
fn(pts[i-3 : i])
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue