implemented MSAA on quad drawing
This commit is contained in:
parent
17b212acba
commit
e0b88c0ca6
3 changed files with 219 additions and 19 deletions
|
@ -20,8 +20,6 @@ func (b *SoftwareBackend) Clear(pts [4][2]float64) {
|
|||
}
|
||||
|
||||
func (b *SoftwareBackend) Fill(style *backendbase.FillStyle, pts [][2]float64) {
|
||||
b.clearMask()
|
||||
|
||||
if lg := style.LinearGradient; lg != nil {
|
||||
lg := lg.(*LinearGradient)
|
||||
from := [2]float64{style.Gradient.X0, style.Gradient.Y0}
|
||||
|
@ -97,14 +95,14 @@ func (b *SoftwareBackend) Fill(style *backendbase.FillStyle, pts [][2]float64) {
|
|||
func (b *SoftwareBackend) FillImageMask(style *backendbase.FillStyle, mask *image.Alpha, pts [4][2]float64) {
|
||||
mw := float64(mask.Bounds().Dx())
|
||||
mh := float64(mask.Bounds().Dy())
|
||||
b.fillQuad(pts, func(x, y int, sx2, sy2 float64) {
|
||||
b.fillQuad(pts, func(x, y, sx2, sy2 float64) color.RGBA {
|
||||
sxi := int(mw * sx2)
|
||||
syi := int(mh * sy2)
|
||||
a := mask.AlphaAt(sxi, syi)
|
||||
if a.A == 0 {
|
||||
return
|
||||
return color.RGBA{}
|
||||
}
|
||||
b.Image.SetRGBA(x, y, alphaColor(style.Color, a))
|
||||
return alphaColor(style.Color, a)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -76,13 +76,12 @@ func (b *SoftwareBackend) DrawImage(dimg backendbase.Image, sx, sy, sw, sh float
|
|||
sw *= mipScaleX
|
||||
sh *= mipScaleY
|
||||
|
||||
b.fillQuad(pts, func(x, y int, sx2, sy2 float64) {
|
||||
imgx := sx + sw*sx2
|
||||
imgy := sy + sh*sy2
|
||||
b.fillQuad(pts, func(x, y, tx, ty float64) color.RGBA {
|
||||
imgx := sx + sw*tx
|
||||
imgy := sy + sh*ty
|
||||
imgxf := math.Floor(imgx)
|
||||
imgyf := math.Floor(imgy)
|
||||
c := mip.At(int(imgxf), int(imgyf))
|
||||
b.Image.Set(x, y, c)
|
||||
return toRGBA(mip.At(int(imgxf), int(imgyf)))
|
||||
|
||||
// rx := imgx - imgxf
|
||||
// ry := imgy - imgyf
|
||||
|
|
|
@ -91,6 +91,7 @@ func (b *SoftwareBackend) fillTriangleNoAA(tri [][2]float64, fn func(x, y int))
|
|||
type msaaPixel struct {
|
||||
ix, iy int
|
||||
fx, fy float64
|
||||
tx, ty float64
|
||||
}
|
||||
|
||||
func (b *SoftwareBackend) fillTriangleMSAA(tri [][2]float64, msaaLevel int, msaaPixels []msaaPixel, fn func(x, y int)) []msaaPixel {
|
||||
|
@ -199,7 +200,7 @@ func quadArea(quad [4][2]float64) float64 {
|
|||
return math.Abs(leftv[0]*topv[1] - leftv[1]*topv[0])
|
||||
}
|
||||
|
||||
func (b *SoftwareBackend) fillQuad(quad [4][2]float64, fn func(x, y int, sx, sy float64)) {
|
||||
func (b *SoftwareBackend) fillQuadNoAA(quad [4][2]float64, fn func(x, y int, tx, ty 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 {
|
||||
|
@ -246,29 +247,229 @@ func (b *SoftwareBackend) fillQuad(quad [4][2]float64, fn func(x, y int, sx, sy
|
|||
continue
|
||||
}
|
||||
|
||||
sfy := float64(y) + 0.5 - quad[0][1]
|
||||
tfy := float64(y) + 0.5 - quad[0][1]
|
||||
fl, cr := int(math.Floor(l)), int(math.Ceil(r))
|
||||
for x := fl; x <= cr; x++ {
|
||||
fx := float64(x) + 0.5
|
||||
if fx < l || fx >= r {
|
||||
continue
|
||||
}
|
||||
sfx := fx - quad[0][0]
|
||||
tfx := fx - quad[0][0]
|
||||
|
||||
var sx, sy float64
|
||||
var tx, ty float64
|
||||
if math.Abs(leftv[0]) > math.Abs(leftv[1]) {
|
||||
sx = (sfy - sfx*(leftv[1]/leftv[0])) / (topv[1] - topv[0]*(leftv[1]/leftv[0]))
|
||||
sy = (sfx - topv[0]*sx) / leftv[0]
|
||||
tx = (tfy - tfx*(leftv[1]/leftv[0])) / (topv[1] - topv[0]*(leftv[1]/leftv[0]))
|
||||
ty = (tfx - topv[0]*tx) / leftv[0]
|
||||
} else {
|
||||
sx = (sfx - sfy*(leftv[0]/leftv[1])) / (topv[0] - topv[1]*(leftv[0]/leftv[1]))
|
||||
sy = (sfy - topv[1]*sx) / leftv[1]
|
||||
tx = (tfx - tfy*(leftv[0]/leftv[1])) / (topv[0] - topv[1]*(leftv[0]/leftv[1]))
|
||||
ty = (tfy - topv[1]*tx) / leftv[1]
|
||||
}
|
||||
|
||||
fn(x, y, sx/topLen, sy/leftLen)
|
||||
fn(x, y, tx/topLen, ty/leftLen)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (b *SoftwareBackend) fillQuadMSAA(quad [4][2]float64, msaaLevel int, msaaPixels []msaaPixel, fn func(x, y int, tx, ty float64)) []msaaPixel {
|
||||
msaaStep := 1.0 / float64(msaaLevel+1)
|
||||
|
||||
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 msaaPixels
|
||||
}
|
||||
if maxY < 0 {
|
||||
return msaaPixels
|
||||
} 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++ {
|
||||
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++ {
|
||||
lf1, rf1, out1 := triangleLR(tri1[:], sy)
|
||||
lf2, rf2, out2 := triangleLR(tri2[:], sy)
|
||||
l[step] = math.Min(lf1, lf2)
|
||||
r[step] = math.Max(rf1, rf2)
|
||||
out := out1 || out2
|
||||
|
||||
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 {
|
||||
tfx := float64(x) + 0.5 - quad[0][0]
|
||||
tfy := float64(y) + 0.5 - quad[0][1]
|
||||
|
||||
var tx, ty float64
|
||||
if math.Abs(leftv[0]) > math.Abs(leftv[1]) {
|
||||
tx = (tfy - tfx*(leftv[1]/leftv[0])) / (topv[1] - topv[0]*(leftv[1]/leftv[0]))
|
||||
ty = (tfx - topv[0]*tx) / leftv[0]
|
||||
} else {
|
||||
tx = (tfx - tfy*(leftv[0]/leftv[1])) / (topv[0] - topv[1]*(leftv[0]/leftv[1]))
|
||||
ty = (tfy - topv[1]*tx) / leftv[1]
|
||||
}
|
||||
|
||||
fn(x, y, tx/topLen, ty/leftLen)
|
||||
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] {
|
||||
tfx := sx - quad[0][0]
|
||||
tfy := sy - quad[0][1]
|
||||
|
||||
var tx, ty float64
|
||||
if math.Abs(leftv[0]) > math.Abs(leftv[1]) {
|
||||
tx = (tfy - tfx*(leftv[1]/leftv[0])) / (topv[1] - topv[0]*(leftv[1]/leftv[0]))
|
||||
ty = (tfx - topv[0]*tx) / leftv[0]
|
||||
} else {
|
||||
tx = (tfx - tfy*(leftv[0]/leftv[1])) / (topv[0] - topv[1]*(leftv[0]/leftv[1]))
|
||||
ty = (tfy - topv[1]*tx) / leftv[1]
|
||||
}
|
||||
|
||||
msaaPixels = addMSAAPixel(msaaPixels, msaaPixel{ix: x, iy: y, fx: sx, fy: sy, tx: tx / topLen, ty: ty / leftLen})
|
||||
}
|
||||
sx += msaaStep
|
||||
}
|
||||
sy += msaaStep
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return msaaPixels
|
||||
}
|
||||
|
||||
func (b *SoftwareBackend) fillQuad(pts [4][2]float64, fn func(x, y, tx, ty float64) color.RGBA) {
|
||||
b.clearMask()
|
||||
|
||||
if b.MSAA > 0 {
|
||||
var msaaPixelBuf [500]msaaPixel
|
||||
msaaPixels := msaaPixelBuf[:0]
|
||||
|
||||
msaaPixels = b.fillQuadMSAA(pts, b.MSAA, msaaPixels, func(x, y int, tx, ty float64) {
|
||||
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)+0.5, float64(y)+0.5, tx, ty)
|
||||
if col.A > 0 {
|
||||
b.Image.SetRGBA(x, y, mix(col, b.Image.RGBAAt(x, y)))
|
||||
}
|
||||
})
|
||||
|
||||
samples := (b.MSAA + 1) * (b.MSAA + 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(px2.fx, px2.fy, px2.tx, px2.ty)
|
||||
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)))
|
||||
}
|
||||
|
||||
} else {
|
||||
b.fillQuadNoAA(pts, func(x, y int, tx, ty float64) {
|
||||
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)+0.5, float64(y)+0.5, tx, ty)
|
||||
if col.A > 0 {
|
||||
b.Image.SetRGBA(x, y, mix(col, b.Image.RGBAAt(x, y)))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func iterateTriangles(pts [][2]float64, fn func(tri [][2]float64)) {
|
||||
if len(pts) == 4 {
|
||||
var buf [3][2]float64
|
||||
|
@ -358,6 +559,8 @@ func (b *SoftwareBackend) fillTrianglesMSAA(pts [][2]float64, msaaLevel int, fn
|
|||
}
|
||||
|
||||
func (b *SoftwareBackend) fillTriangles(pts [][2]float64, fn func(x, y float64) color.RGBA) {
|
||||
b.clearMask()
|
||||
|
||||
if b.MSAA > 0 {
|
||||
b.fillTrianglesMSAA(pts, b.MSAA, fn)
|
||||
} else {
|
||||
|
|
Loading…
Reference in a new issue