added code for MSAA, doesn't work properly yet though
This commit is contained in:
parent
d56f68b2e7
commit
554fa84a0a
4 changed files with 200 additions and 26 deletions
|
@ -5,6 +5,16 @@ import (
|
|||
"math"
|
||||
)
|
||||
|
||||
func toRGBA(src color.Color) color.RGBA {
|
||||
ir, ig, ib, ia := src.RGBA()
|
||||
return color.RGBA{
|
||||
R: uint8(ir >> 8),
|
||||
G: uint8(ig >> 8),
|
||||
B: uint8(ib >> 8),
|
||||
A: uint8(ia >> 8),
|
||||
}
|
||||
}
|
||||
|
||||
func mix(src, dest color.Color) color.RGBA {
|
||||
ir1, ig1, ib1, ia1 := src.RGBA()
|
||||
r1 := float64(ir1) / 65535.0
|
||||
|
|
|
@ -10,7 +10,7 @@ import (
|
|||
|
||||
func (b *SoftwareBackend) Clear(pts [4][2]float64) {
|
||||
iterateTriangles(pts[:], func(tri [][2]float64) {
|
||||
b.fillTriangle(tri, func(x, y int) {
|
||||
b.fillTriangleNoAA(tri, func(x, y int) {
|
||||
if b.clip.AlphaAt(x, y).A == 0 {
|
||||
return
|
||||
}
|
||||
|
@ -29,11 +29,10 @@ func (b *SoftwareBackend) Fill(style *backendbase.FillStyle, pts [][2]float64) {
|
|||
dirlen := math.Sqrt(dir[0]*dir[0] + dir[1]*dir[1])
|
||||
dir[0] /= dirlen
|
||||
dir[1] /= dirlen
|
||||
b.fillTriangles(pts, func(x, y int) {
|
||||
pos := [2]float64{float64(x) - from[0], float64(y) - from[1]}
|
||||
b.fillTriangles(pts, func(x, y float64) color.RGBA {
|
||||
pos := [2]float64{x - from[0], y - from[1]}
|
||||
r := (pos[0]*dir[0] + pos[1]*dir[1]) / dirlen
|
||||
color := lg.data.ColorAt(r)
|
||||
b.Image.SetRGBA(x, y, mix(color, b.Image.RGBAAt(x, y)))
|
||||
return lg.data.ColorAt(r)
|
||||
})
|
||||
} else if rg := style.RadialGradient; rg != nil {
|
||||
rg := rg.(*RadialGradient)
|
||||
|
@ -41,8 +40,8 @@ func (b *SoftwareBackend) Fill(style *backendbase.FillStyle, pts [][2]float64) {
|
|||
to := [2]float64{style.Gradient.X1, style.Gradient.Y1}
|
||||
radFrom := style.Gradient.RadFrom
|
||||
radTo := style.Gradient.RadTo
|
||||
b.fillTriangles(pts, func(x, y int) {
|
||||
pos := [2]float64{float64(x), float64(y)}
|
||||
b.fillTriangles(pts, func(x, y float64) color.RGBA {
|
||||
pos := [2]float64{x, y}
|
||||
oa := 0.5 * math.Sqrt(
|
||||
math.Pow(-2.0*from[0]*from[0]+2.0*from[0]*to[0]+2.0*from[0]*pos[0]-2.0*to[0]*pos[0]-2.0*from[1]*from[1]+2.0*from[1]*to[1]+2.0*from[1]*pos[1]-2.0*to[1]*pos[1]+2.0*radFrom*radFrom-2.0*radFrom*radTo, 2.0)-
|
||||
4.0*(from[0]*from[0]-2.0*from[0]*pos[0]+pos[0]*pos[0]+from[1]*from[1]-2.0*from[1]*pos[1]+pos[1]*pos[1]-radFrom*radFrom)*
|
||||
|
@ -52,11 +51,10 @@ func (b *SoftwareBackend) Fill(style *backendbase.FillStyle, pts [][2]float64) {
|
|||
o1 := (-oa + ob) / oc
|
||||
o2 := (oa + ob) / oc
|
||||
if math.IsNaN(o1) && math.IsNaN(o2) {
|
||||
return
|
||||
return color.RGBA{}
|
||||
}
|
||||
o := math.Max(o1, o2)
|
||||
col := rg.data.ColorAt(o)
|
||||
b.Image.SetRGBA(x, y, mix(col, b.Image.RGBAAt(x, y)))
|
||||
return rg.data.ColorAt(o)
|
||||
})
|
||||
} else if ip := style.ImagePattern; ip != nil {
|
||||
ip := ip.(*ImagePattern)
|
||||
|
@ -66,16 +64,16 @@ func (b *SoftwareBackend) Fill(style *backendbase.FillStyle, pts [][2]float64) {
|
|||
fw, fh := float64(w), float64(h)
|
||||
rx := ip.data.Repeat == backendbase.Repeat || ip.data.Repeat == backendbase.RepeatX
|
||||
ry := ip.data.Repeat == backendbase.Repeat || ip.data.Repeat == backendbase.RepeatY
|
||||
b.fillTriangles(pts, func(x, y int) {
|
||||
pos := [2]float64{float64(x), float64(y)}
|
||||
b.fillTriangles(pts, func(x, y float64) color.RGBA {
|
||||
pos := [2]float64{x, y}
|
||||
tfptx := pos[0]*ip.data.Transform[0] + pos[1]*ip.data.Transform[1] + ip.data.Transform[2]
|
||||
tfpty := pos[0]*ip.data.Transform[3] + pos[1]*ip.data.Transform[4] + ip.data.Transform[5]
|
||||
|
||||
if !rx && (tfptx < 0 || tfptx >= fw) {
|
||||
return
|
||||
return color.RGBA{}
|
||||
}
|
||||
if !ry && (tfpty < 0 || tfpty >= fh) {
|
||||
return
|
||||
return color.RGBA{}
|
||||
}
|
||||
|
||||
mx := int(math.Floor(tfptx)) % w
|
||||
|
@ -87,12 +85,11 @@ func (b *SoftwareBackend) Fill(style *backendbase.FillStyle, pts [][2]float64) {
|
|||
my += h
|
||||
}
|
||||
|
||||
col := mip.At(mx, my)
|
||||
b.Image.SetRGBA(x, y, mix(col, b.Image.RGBAAt(x, y)))
|
||||
return toRGBA(mip.At(mx, my))
|
||||
})
|
||||
} else {
|
||||
b.fillTriangles(pts, func(x, y int) {
|
||||
b.Image.SetRGBA(x, y, mix(style.Color, b.Image.RGBAAt(x, y)))
|
||||
b.fillTriangles(pts, func(x, y float64) color.RGBA {
|
||||
return style.Color
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -132,7 +129,7 @@ func (b *SoftwareBackend) Clip(pts [][2]float64) {
|
|||
}
|
||||
|
||||
iterateTriangles(pts[:], func(tri [][2]float64) {
|
||||
b.fillTriangle(tri, func(x, y int) {
|
||||
b.fillTriangleNoAA(tri, func(x, y int) {
|
||||
b.mask.SetAlpha(x, y, color.Alpha{A: 255})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -9,6 +9,9 @@ import (
|
|||
|
||||
type SoftwareBackend struct {
|
||||
Image *image.RGBA
|
||||
|
||||
// MSAA int
|
||||
|
||||
clip *image.Alpha
|
||||
mask *image.Alpha
|
||||
w, h int
|
||||
|
|
|
@ -46,7 +46,7 @@ func triangleLR(tri [][2]float64, y float64) (l, r float64, outside bool) {
|
|||
return
|
||||
}
|
||||
|
||||
func (b *SoftwareBackend) fillTriangle(tri [][2]float64, fn func(x, y int)) {
|
||||
func (b *SoftwareBackend) fillTriangleNoAA(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 {
|
||||
|
@ -88,6 +88,102 @@ func (b *SoftwareBackend) fillTriangle(tri [][2]float64, fn func(x, y int)) {
|
|||
}
|
||||
}
|
||||
|
||||
type msaaPixel struct {
|
||||
ix, iy int
|
||||
fx, fy float64
|
||||
}
|
||||
|
||||
func (b *SoftwareBackend) fillTriangleMSAA(tri [][2]float64, msaaLevel int, msaaPixels []msaaPixel, fn func(x, y int)) []msaaPixel {
|
||||
msaaStep := 1.0 / float64(msaaLevel+1)
|
||||
|
||||
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 msaaPixels
|
||||
}
|
||||
if maxY < 0 {
|
||||
return msaaPixels
|
||||
} else if maxY >= b.h {
|
||||
maxY = b.h - 1
|
||||
}
|
||||
|
||||
for y := minY; y <= maxY; y++ {
|
||||
var l, r [5]float64
|
||||
allOut := true
|
||||
minL, maxR := math.MaxFloat64, 0.0
|
||||
|
||||
sy := float64(y) + msaaStep*0.5
|
||||
for step := 0; step <= msaaLevel; step++ {
|
||||
var out bool
|
||||
l[step], r[step], out = triangleLR(tri, sy)
|
||||
if l[step] < 0 {
|
||||
l[step] = 0
|
||||
} else if l[step] > float64(b.w) {
|
||||
l[step] = float64(b.w)
|
||||
out = true
|
||||
}
|
||||
if r[step] < 0 {
|
||||
r[step] = 0
|
||||
out = true
|
||||
} else if r[step] > float64(b.w) {
|
||||
r[step] = float64(b.w)
|
||||
}
|
||||
if r[step] <= l[step] {
|
||||
out = true
|
||||
}
|
||||
if !out {
|
||||
allOut = false
|
||||
minL = math.Min(minL, l[step])
|
||||
maxR = math.Max(maxR, r[step])
|
||||
}
|
||||
sy += msaaStep
|
||||
}
|
||||
|
||||
if allOut {
|
||||
continue
|
||||
}
|
||||
|
||||
fl, cr := int(math.Floor(minL)), int(math.Ceil(maxR))
|
||||
for x := fl; x <= cr; x++ {
|
||||
sy = float64(y) + msaaStep*0.5
|
||||
allIn := true
|
||||
check:
|
||||
for stepy := 0; stepy <= msaaLevel; stepy++ {
|
||||
sx := float64(x) + msaaStep*0.5
|
||||
for stepx := 0; stepx <= msaaLevel; stepx++ {
|
||||
if sx < l[stepy] || sx >= r[stepy] {
|
||||
allIn = false
|
||||
break check
|
||||
}
|
||||
sx += msaaStep
|
||||
}
|
||||
sy += msaaStep
|
||||
}
|
||||
|
||||
if allIn {
|
||||
fn(x, y)
|
||||
continue
|
||||
}
|
||||
|
||||
sy = float64(y) + msaaStep*0.5
|
||||
for stepy := 0; stepy <= msaaLevel; stepy++ {
|
||||
sx := float64(x) + msaaStep*0.5
|
||||
for stepx := 0; stepx <= msaaLevel; stepx++ {
|
||||
if sx >= l[stepy] && sx < r[stepy] {
|
||||
msaaPixels = append(msaaPixels, msaaPixel{ix: x, iy: y, fx: sx, fy: sy})
|
||||
}
|
||||
sx += msaaStep
|
||||
}
|
||||
sy += msaaStep
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return msaaPixels
|
||||
}
|
||||
|
||||
func quadArea(quad [4][2]float64) float64 {
|
||||
leftv := [2]float64{quad[1][0] - quad[0][0], quad[1][1] - quad[0][1]}
|
||||
topv := [2]float64{quad[3][0] - quad[0][0], quad[3][1] - quad[0][1]}
|
||||
|
@ -181,9 +277,9 @@ func iterateTriangles(pts [][2]float64, fn func(tri [][2]float64)) {
|
|||
}
|
||||
}
|
||||
|
||||
func (b *SoftwareBackend) fillTriangles(pts [][2]float64, fn func(x, y int)) {
|
||||
func (b *SoftwareBackend) fillTrianglesNoAA(pts [][2]float64, fn func(x, y float64) color.RGBA) {
|
||||
iterateTriangles(pts[:], func(tri [][2]float64) {
|
||||
b.fillTriangle(tri, func(x, y int) {
|
||||
b.fillTriangleNoAA(tri, func(x, y int) {
|
||||
if b.clip.AlphaAt(x, y).A == 0 {
|
||||
return
|
||||
}
|
||||
|
@ -191,7 +287,75 @@ func (b *SoftwareBackend) fillTriangles(pts [][2]float64, fn func(x, y int)) {
|
|||
return
|
||||
}
|
||||
b.mask.SetAlpha(x, y, color.Alpha{A: 255})
|
||||
fn(x, y)
|
||||
col := fn(float64(x), float64(y))
|
||||
if col.A > 0 {
|
||||
b.Image.SetRGBA(x, y, mix(col, b.Image.RGBAAt(x, y)))
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func (b *SoftwareBackend) fillTrianglesMSAA(pts [][2]float64, msaaLevel int, fn func(x, y float64) color.RGBA) {
|
||||
var msaaPixelBuf [500]msaaPixel
|
||||
msaaPixels := msaaPixelBuf[:0]
|
||||
|
||||
iterateTriangles(pts[:], func(tri [][2]float64) {
|
||||
msaaPixels = b.fillTriangleMSAA(tri, msaaLevel, msaaPixels, func(x, y int) {
|
||||
if b.clip.AlphaAt(x, y).A == 0 {
|
||||
return
|
||||
}
|
||||
if b.mask.AlphaAt(x, y).A > 0 {
|
||||
return
|
||||
}
|
||||
b.mask.SetAlpha(x, y, color.Alpha{A: 255})
|
||||
col := fn(float64(x), float64(y))
|
||||
if col.A > 0 {
|
||||
b.Image.SetRGBA(x, y, mix(col, b.Image.RGBAAt(x, y)))
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
samples := (msaaLevel + 1) * (msaaLevel + 1)
|
||||
|
||||
for i, px := range msaaPixels {
|
||||
if px.ix < 0 || b.clip.AlphaAt(px.ix, px.iy).A == 0 || b.mask.AlphaAt(px.ix, px.iy).A > 0 {
|
||||
continue
|
||||
}
|
||||
b.mask.SetAlpha(px.ix, px.iy, color.Alpha{A: 255})
|
||||
|
||||
var mr, mg, mb, ma int
|
||||
for j, px2 := range msaaPixels[i:] {
|
||||
if px2.ix != px.ix || px2.iy != px.iy {
|
||||
continue
|
||||
}
|
||||
|
||||
col := fn(px.fx, px.fy)
|
||||
if col.A == 0 {
|
||||
return
|
||||
}
|
||||
mr += int(col.R)
|
||||
mg += int(col.G)
|
||||
mb += int(col.B)
|
||||
ma += int(col.A)
|
||||
|
||||
msaaPixels[i+j].ix = -1
|
||||
}
|
||||
|
||||
combined := color.RGBA{
|
||||
R: uint8(mr / samples),
|
||||
G: uint8(mg / samples),
|
||||
B: uint8(mb / samples),
|
||||
A: uint8(ma / samples),
|
||||
}
|
||||
b.Image.SetRGBA(px.ix, px.iy, mix(combined, b.Image.RGBAAt(px.ix, px.iy)))
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func (b *SoftwareBackend) fillTriangles(pts [][2]float64, fn func(x, y float64) color.RGBA) {
|
||||
// if b.MSAA > 0 {
|
||||
// b.fillTrianglesMSAA(pts, b.MSAA, fn)
|
||||
// } else {
|
||||
b.fillTrianglesNoAA(pts, fn)
|
||||
// }
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue