implemented clipping and drawImage
This commit is contained in:
parent
9f99dff89b
commit
faf179caa0
4 changed files with 138 additions and 24 deletions
|
@ -9,6 +9,9 @@ import (
|
|||
func (b *SoftwareBackend) Clear(pts [4][2]float64) {
|
||||
iterateTriangles(pts[:], func(tri [][2]float64) {
|
||||
b.fillTriangle(tri, func(x, y int) {
|
||||
if b.clip.AlphaAt(x, y).A == 0 {
|
||||
return
|
||||
}
|
||||
b.Image.SetRGBA(x, y, color.RGBA{})
|
||||
})
|
||||
})
|
||||
|
@ -17,7 +20,37 @@ func (b *SoftwareBackend) Clear(pts [4][2]float64) {
|
|||
func (b *SoftwareBackend) Fill(style *backendbase.FillStyle, pts [][2]float64) {
|
||||
iterateTriangles(pts[:], func(tri [][2]float64) {
|
||||
b.fillTriangle(tri, func(x, y int) {
|
||||
if b.clip.AlphaAt(x, y).A == 0 {
|
||||
return
|
||||
}
|
||||
b.Image.SetRGBA(x, y, style.Color)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func (b *SoftwareBackend) ClearClip() {
|
||||
p := b.clip.Pix
|
||||
for i := range p {
|
||||
p[i] = 255
|
||||
}
|
||||
}
|
||||
|
||||
func (b *SoftwareBackend) Clip(pts [][2]float64) {
|
||||
p2 := b.clip2.Pix
|
||||
for i := range p2 {
|
||||
p2[i] = 0
|
||||
}
|
||||
|
||||
iterateTriangles(pts[:], func(tri [][2]float64) {
|
||||
b.fillTriangle(tri, func(x, y int) {
|
||||
b.clip2.SetAlpha(x, y, color.Alpha{A: 255})
|
||||
})
|
||||
})
|
||||
|
||||
p := b.clip.Pix
|
||||
for i := range p {
|
||||
if p2[i] == 0 {
|
||||
p[i] = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
|
||||
type Image struct {
|
||||
img image.Image
|
||||
deleted bool
|
||||
}
|
||||
|
||||
func (b *SoftwareBackend) LoadImage(img image.Image) (backendbase.Image, error) {
|
||||
|
@ -15,9 +16,15 @@ func (b *SoftwareBackend) LoadImage(img image.Image) (backendbase.Image, error)
|
|||
}
|
||||
|
||||
func (b *SoftwareBackend) DrawImage(dimg backendbase.Image, sx, sy, sw, sh float64, pts [4][2]float64, alpha float64) {
|
||||
simg := dimg.(*Image)
|
||||
if simg.deleted {
|
||||
return
|
||||
}
|
||||
|
||||
func (b *SoftwareBackend) FillImageMask(style *backendbase.FillStyle, mask *image.Alpha, pts [][2]float64) {
|
||||
b.fillQuad(pts, func(x, y int, sx2, sy2 float64) {
|
||||
sxi := int(sx + sw*sx2 + 0.5)
|
||||
syi := int(sy + sh*sy2 + 0.5)
|
||||
b.Image.Set(x, y, simg.img.At(sxi, syi))
|
||||
})
|
||||
}
|
||||
|
||||
func (img *Image) Width() int {
|
||||
|
@ -34,9 +41,23 @@ func (img *Image) Size() (w, h int) {
|
|||
}
|
||||
|
||||
func (img *Image) Delete() {
|
||||
img.deleted = true
|
||||
}
|
||||
|
||||
func (img *Image) Replace(src image.Image) error {
|
||||
img.img = src
|
||||
return nil
|
||||
}
|
||||
|
||||
type ImagePattern struct {
|
||||
data backendbase.ImagePatternData
|
||||
}
|
||||
|
||||
func (b *SoftwareBackend) LoadImagePattern(data backendbase.ImagePatternData) backendbase.ImagePattern {
|
||||
return &ImagePattern{
|
||||
data: data,
|
||||
}
|
||||
}
|
||||
|
||||
func (ip *ImagePattern) Delete() {}
|
||||
func (ip *ImagePattern) Replace(data backendbase.ImagePatternData) { ip.data = data }
|
||||
|
|
|
@ -9,32 +9,29 @@ import (
|
|||
|
||||
type SoftwareBackend struct {
|
||||
Image *image.RGBA
|
||||
clip *image.Alpha
|
||||
clip2 *image.Alpha
|
||||
w, h int
|
||||
}
|
||||
|
||||
func New(w, h int) *SoftwareBackend {
|
||||
return &SoftwareBackend{
|
||||
Image: image.NewRGBA(image.Rect(0, 0, w, h)),
|
||||
w: w,
|
||||
h: h,
|
||||
}
|
||||
b := &SoftwareBackend{}
|
||||
b.SetSize(w, h)
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *SoftwareBackend) SetSize(w, h int) {
|
||||
b.w, b.h = w, h
|
||||
b.Image = image.NewRGBA(image.Rect(0, 0, w, h))
|
||||
b.clip = image.NewAlpha(image.Rect(0, 0, w, h))
|
||||
b.clip2 = image.NewAlpha(image.Rect(0, 0, w, h))
|
||||
b.ClearClip()
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
|
|
@ -1,18 +1,12 @@
|
|||
package softwarebackend
|
||||
|
||||
import "math"
|
||||
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
|
||||
|
@ -24,6 +18,14 @@ func triangleLR(tri [][2]float64, y float64) (l, r float64) {
|
|||
}
|
||||
}
|
||||
|
||||
// check general bounds
|
||||
if y < a[1] {
|
||||
return a[0], a[0]
|
||||
}
|
||||
if y > c[1] {
|
||||
return c[0], c[0]
|
||||
}
|
||||
|
||||
// find left and right x at y
|
||||
if y >= a[1] && y <= b[1] {
|
||||
r0 := (y - a[1]) / (b[1] - a[1])
|
||||
|
@ -76,6 +78,67 @@ func (b *SoftwareBackend) fillTriangle(tri [][2]float64, fn func(x, y int)) {
|
|||
}
|
||||
}
|
||||
|
||||
func (b *SoftwareBackend) fillQuad(quad [4][2]float64, fn func(x, y int, sx, sy float64)) {
|
||||
minY := int(math.Floor(math.Min(math.Min(quad[0][1], quad[1][1]), math.Min(quad[2][1], quad[3][1]))))
|
||||
maxY := int(math.Ceil(math.Max(math.Max(quad[0][1], quad[1][1]), math.Max(quad[2][1], quad[3][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
|
||||
}
|
||||
|
||||
leftv := [2]float64{quad[1][0] - quad[0][0], quad[1][1] - quad[0][1]}
|
||||
leftLen := math.Sqrt(leftv[0]*leftv[0] + leftv[1]*leftv[1])
|
||||
leftv[0] /= leftLen
|
||||
leftv[1] /= leftLen
|
||||
topv := [2]float64{quad[3][0] - quad[0][0], quad[3][1] - quad[0][1]}
|
||||
topLen := math.Sqrt(topv[0]*topv[0] + topv[1]*topv[1])
|
||||
topv[0] /= topLen
|
||||
topv[1] /= topLen
|
||||
|
||||
tri1 := [3][2]float64{quad[0], quad[1], quad[2]}
|
||||
tri2 := [3][2]float64{quad[0], quad[2], quad[3]}
|
||||
for y := minY; y <= maxY; y++ {
|
||||
lf1, rf1 := triangleLR(tri1[:], float64(y)+0.5)
|
||||
lf2, rf2 := triangleLR(tri2[:], float64(y)+0.5)
|
||||
l := int(math.Floor(math.Min(lf1, lf2)))
|
||||
r := int(math.Ceil(math.Max(rf1, rf2)))
|
||||
if l < 0 {
|
||||
l = 0
|
||||
} else if l >= b.w {
|
||||
continue
|
||||
}
|
||||
if r < 0 {
|
||||
continue
|
||||
} else if r >= b.w {
|
||||
r = b.w - 1
|
||||
}
|
||||
|
||||
v0 := [2]float64{float64(l) - quad[0][0], float64(y) - quad[0][1]}
|
||||
sx0 := topv[0]*v0[0] + topv[1]*v0[1]
|
||||
sy0 := leftv[0]*v0[0] + leftv[1]*v0[1]
|
||||
|
||||
v1 := [2]float64{float64(r) - quad[0][0], float64(y) - quad[0][1]}
|
||||
sx1 := topv[0]*v1[0] + topv[1]*v1[1]
|
||||
sy1 := leftv[0]*v1[0] + leftv[1]*v1[1]
|
||||
|
||||
sx, sy := sx0/topLen, sy0/leftLen
|
||||
sxStep := (sx1 - sx0) / float64(r-l) / topLen
|
||||
syStep := (sy1 - sy0) / float64(r-l) / leftLen
|
||||
|
||||
for x := l; x <= r; x++ {
|
||||
fn(x, y, sx, sy)
|
||||
sx += sxStep
|
||||
sy += syStep
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func iterateTriangles(pts [][2]float64, fn func(tri [][2]float64)) {
|
||||
if len(pts) == 4 {
|
||||
var buf [3][2]float64
|
||||
|
|
Loading…
Reference in a new issue