implemented mipmapping

This commit is contained in:
Thomas Friedel 2019-05-01 22:21:07 +02:00
parent bbcb712b73
commit 4e5c38b295
3 changed files with 89 additions and 16 deletions

View file

@ -2,18 +2,45 @@ package softwarebackend
import (
"image"
"image/color"
"math"
"github.com/tfriedel6/canvas/backend/backendbase"
)
type Image struct {
img image.Image
mips []image.Image
deleted bool
}
func (b *SoftwareBackend) LoadImage(img image.Image) (backendbase.Image, error) {
return &Image{img: img}, nil
bimg := &Image{mips: make([]image.Image, 1, 10)}
bimg.Replace(img)
return bimg, nil
}
func halveImage(img image.Image) (*image.RGBA, int, int) {
bounds := img.Bounds()
w, h := bounds.Dx(), bounds.Dy()
w = w / 2
h = h / 2
rimg := image.NewRGBA(image.Rect(0, 0, w, h))
for y := 0; y < h; y++ {
sy := y * 2
for x := 0; x < w; x++ {
sx := x * 2
r1, g1, b1, a1 := img.At(sx, sy).RGBA()
r2, g2, b2, a2 := img.At(sx+1, sy).RGBA()
r3, g3, b3, a3 := img.At(sx, sy+1).RGBA()
r4, g4, b4, a4 := img.At(sx+1, sy+1).RGBA()
mixr := uint8((int(r1) + int(r2) + int(r3) + int(r4)) / 1024)
mixg := uint8((int(g1) + int(g2) + int(g3) + int(g4)) / 1024)
mixb := uint8((int(b1) + int(b2) + int(b3) + int(b4)) / 1024)
mixa := uint8((int(a1) + int(a2) + int(a3) + int(a4)) / 1024)
rimg.Set(x, y, color.RGBA{R: mixr, G: mixg, B: mixb, A: mixa})
}
}
return rimg, w, h
}
func (b *SoftwareBackend) DrawImage(dimg backendbase.Image, sx, sy, sw, sh float64, pts [4][2]float64, alpha float64) {
@ -21,33 +48,64 @@ func (b *SoftwareBackend) DrawImage(dimg backendbase.Image, sx, sy, sw, sh float
if simg.deleted {
return
}
bounds := simg.mips[0].Bounds()
w, h := bounds.Dx(), bounds.Dy()
factor := float64(w*h) / (sw * sh)
area := quadArea(pts) * factor
mip := simg.mips[0]
closest := math.MaxFloat64
mipW, mipH := w, h
for _, img := range simg.mips {
bounds := img.Bounds()
w, h := bounds.Dx(), bounds.Dy()
dist := math.Abs(float64(w*h) - area)
if dist < closest {
closest = dist
mip = img
mipW = w
mipH = h
}
}
mipScaleX := float64(mipW) / float64(w)
mipScaleY := float64(mipH) / float64(h)
sx *= mipScaleX
sy *= mipScaleY
sw *= mipScaleX
sh *= mipScaleY
b.fillQuad(pts, func(x, y int, sx2, sy2 float64) {
imgx := sx + sw*sx2
imgy := sy + sh*sy2
imgxf := math.Floor(imgx)
imgyf := math.Floor(imgy)
rx := imgx - imgxf
ry := imgy - imgyf
ca := simg.img.At(int(imgxf), int(imgyf))
cb := simg.img.At(int(imgxf+1), int(imgyf))
cc := simg.img.At(int(imgxf), int(imgyf+1))
cd := simg.img.At(int(imgxf+1), int(imgyf+1))
ctop := lerp(ca, cb, rx)
cbtm := lerp(cc, cd, rx)
b.Image.Set(x, y, lerp(ctop, cbtm, ry))
c := mip.At(int(imgxf), int(imgyf))
b.Image.Set(x, y, c)
// rx := imgx - imgxf
// ry := imgy - imgyf
// ca := mip.At(int(imgxf), int(imgyf))
// cb := mip.At(int(imgxf+1), int(imgyf))
// cc := mip.At(int(imgxf), int(imgyf+1))
// cd := mip.At(int(imgxf+1), int(imgyf+1))
// ctop := lerp(ca, cb, rx)
// cbtm := lerp(cc, cd, rx)
// b.Image.Set(x, y, lerp(ctop, cbtm, ry))
})
}
func (img *Image) Width() int {
return img.img.Bounds().Dx()
return img.mips[0].Bounds().Dx()
}
func (img *Image) Height() int {
return img.img.Bounds().Dy()
return img.mips[0].Bounds().Dy()
}
func (img *Image) Size() (w, h int) {
b := img.img.Bounds()
b := img.mips[0].Bounds()
return b.Dx(), b.Dy()
}
@ -56,7 +114,16 @@ func (img *Image) Delete() {
}
func (img *Image) Replace(src image.Image) error {
img.img = src
img.mips = img.mips[:1]
img.mips[0] = src
bounds := src.Bounds()
w, h := bounds.Dx(), bounds.Dy()
for w > 1 && h > 1 {
src, w, h = halveImage(src)
img.mips = append(img.mips, src)
}
return nil
}

View file

@ -88,6 +88,12 @@ func (b *SoftwareBackend) fillTriangle(tri [][2]float64, fn func(x, y int)) {
}
}
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]}
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)) {
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]))))

View file

@ -13,7 +13,7 @@ import (
"github.com/go-gl/gl/v3.2-core/gl"
"github.com/tfriedel6/canvas"
"github.com/tfriedel6/canvas/backend/software"
"github.com/tfriedel6/canvas/backend/softwarebackend"
"github.com/tfriedel6/canvas/sdlcanvas"
)