added shadow blur to software implementation
This commit is contained in:
parent
e0b88c0ca6
commit
505386f199
4 changed files with 196 additions and 0 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -2,6 +2,7 @@ test*.html
|
||||||
plan.txt
|
plan.txt
|
||||||
glowgen
|
glowgen
|
||||||
testapp
|
testapp
|
||||||
|
testblur
|
||||||
videocap
|
videocap
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.vscode
|
.vscode
|
||||||
|
|
188
backend/softwarebackend/blur.go
Normal file
188
backend/softwarebackend/blur.go
Normal file
|
@ -0,0 +1,188 @@
|
||||||
|
package softwarebackend
|
||||||
|
|
||||||
|
import (
|
||||||
|
"image"
|
||||||
|
"image/color"
|
||||||
|
"image/draw"
|
||||||
|
"math"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (b *SoftwareBackend) activateBlurTarget() {
|
||||||
|
b.blurSwap = b.Image
|
||||||
|
b.Image = image.NewRGBA(b.Image.Rect)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *SoftwareBackend) drawBlurred(size float64) {
|
||||||
|
blurred := box3(b.Image, size)
|
||||||
|
b.Image = b.blurSwap
|
||||||
|
draw.Draw(b.Image, b.Image.Rect, blurred, image.ZP, draw.Over)
|
||||||
|
}
|
||||||
|
|
||||||
|
func box3(img *image.RGBA, size float64) *image.RGBA {
|
||||||
|
rsize := int(math.Round(size * 0.75)) // todo properly size
|
||||||
|
img = box3x(img, rsize)
|
||||||
|
img = box3x(img, rsize)
|
||||||
|
img = box3x(img, rsize)
|
||||||
|
img = box3y(img, rsize)
|
||||||
|
img = box3y(img, rsize)
|
||||||
|
img = box3y(img, rsize)
|
||||||
|
return img
|
||||||
|
}
|
||||||
|
|
||||||
|
func box3x(img *image.RGBA, size int) *image.RGBA {
|
||||||
|
bounds := img.Bounds()
|
||||||
|
result := image.NewRGBA(bounds)
|
||||||
|
w, h := bounds.Dx(), bounds.Dy()
|
||||||
|
|
||||||
|
for y := 0; y < h; y++ {
|
||||||
|
if size >= w {
|
||||||
|
var r, g, b, a float64
|
||||||
|
for x := 0; x < w; x++ {
|
||||||
|
col := img.RGBAAt(x, y)
|
||||||
|
r += float64(col.R)
|
||||||
|
g += float64(col.G)
|
||||||
|
b += float64(col.B)
|
||||||
|
a += float64(col.A)
|
||||||
|
}
|
||||||
|
|
||||||
|
factor := 1.0 / float64(w)
|
||||||
|
col := color.RGBA{
|
||||||
|
R: uint8(math.Round(r * factor)),
|
||||||
|
G: uint8(math.Round(g * factor)),
|
||||||
|
B: uint8(math.Round(b * factor)),
|
||||||
|
A: uint8(math.Round(a * factor)),
|
||||||
|
}
|
||||||
|
for x := 0; x < w; x++ {
|
||||||
|
result.SetRGBA(x, y, col)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var r, g, b, a float64
|
||||||
|
for x := 0; x <= size; x++ {
|
||||||
|
col := img.RGBAAt(x, y)
|
||||||
|
r += float64(col.R)
|
||||||
|
g += float64(col.G)
|
||||||
|
b += float64(col.B)
|
||||||
|
a += float64(col.A)
|
||||||
|
}
|
||||||
|
|
||||||
|
samples := size + 1
|
||||||
|
x := 0
|
||||||
|
for {
|
||||||
|
factor := 1.0 / float64(samples)
|
||||||
|
col := color.RGBA{
|
||||||
|
R: uint8(math.Round(r * factor)),
|
||||||
|
G: uint8(math.Round(g * factor)),
|
||||||
|
B: uint8(math.Round(b * factor)),
|
||||||
|
A: uint8(math.Round(a * factor)),
|
||||||
|
}
|
||||||
|
result.SetRGBA(x, y, col)
|
||||||
|
|
||||||
|
if x >= w-1 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if left := x - size; left >= 0 {
|
||||||
|
col = img.RGBAAt(left, y)
|
||||||
|
r -= float64(col.R)
|
||||||
|
g -= float64(col.G)
|
||||||
|
b -= float64(col.B)
|
||||||
|
a -= float64(col.A)
|
||||||
|
samples--
|
||||||
|
}
|
||||||
|
|
||||||
|
x++
|
||||||
|
|
||||||
|
if right := x + size; right < w {
|
||||||
|
col = img.RGBAAt(right, y)
|
||||||
|
r += float64(col.R)
|
||||||
|
g += float64(col.G)
|
||||||
|
b += float64(col.B)
|
||||||
|
a += float64(col.A)
|
||||||
|
samples++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func box3y(img *image.RGBA, size int) *image.RGBA {
|
||||||
|
bounds := img.Bounds()
|
||||||
|
result := image.NewRGBA(bounds)
|
||||||
|
w, h := bounds.Dx(), bounds.Dy()
|
||||||
|
|
||||||
|
for x := 0; x < w; x++ {
|
||||||
|
if size >= h {
|
||||||
|
var r, g, b, a float64
|
||||||
|
for y := 0; y < h; y++ {
|
||||||
|
col := img.RGBAAt(x, y)
|
||||||
|
r += float64(col.R)
|
||||||
|
g += float64(col.G)
|
||||||
|
b += float64(col.B)
|
||||||
|
a += float64(col.A)
|
||||||
|
}
|
||||||
|
|
||||||
|
factor := 1.0 / float64(h)
|
||||||
|
col := color.RGBA{
|
||||||
|
R: uint8(math.Round(r * factor)),
|
||||||
|
G: uint8(math.Round(g * factor)),
|
||||||
|
B: uint8(math.Round(b * factor)),
|
||||||
|
A: uint8(math.Round(a * factor)),
|
||||||
|
}
|
||||||
|
for y := 0; y < h; y++ {
|
||||||
|
result.SetRGBA(x, y, col)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var r, g, b, a float64
|
||||||
|
for y := 0; y <= size; y++ {
|
||||||
|
col := img.RGBAAt(x, y)
|
||||||
|
r += float64(col.R)
|
||||||
|
g += float64(col.G)
|
||||||
|
b += float64(col.B)
|
||||||
|
a += float64(col.A)
|
||||||
|
}
|
||||||
|
|
||||||
|
samples := size + 1
|
||||||
|
y := 0
|
||||||
|
for {
|
||||||
|
factor := 1.0 / float64(samples)
|
||||||
|
col := color.RGBA{
|
||||||
|
R: uint8(math.Round(r * factor)),
|
||||||
|
G: uint8(math.Round(g * factor)),
|
||||||
|
B: uint8(math.Round(b * factor)),
|
||||||
|
A: uint8(math.Round(a * factor)),
|
||||||
|
}
|
||||||
|
result.SetRGBA(x, y, col)
|
||||||
|
|
||||||
|
if y >= h-1 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if top := y - size; top >= 0 {
|
||||||
|
col = img.RGBAAt(x, top)
|
||||||
|
r -= float64(col.R)
|
||||||
|
g -= float64(col.G)
|
||||||
|
b -= float64(col.B)
|
||||||
|
a -= float64(col.A)
|
||||||
|
samples--
|
||||||
|
}
|
||||||
|
|
||||||
|
y++
|
||||||
|
|
||||||
|
if bottom := y + size; bottom < h {
|
||||||
|
col = img.RGBAAt(x, bottom)
|
||||||
|
r += float64(col.R)
|
||||||
|
g += float64(col.G)
|
||||||
|
b += float64(col.B)
|
||||||
|
a += float64(col.A)
|
||||||
|
samples++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
|
@ -20,6 +20,11 @@ func (b *SoftwareBackend) Clear(pts [4][2]float64) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *SoftwareBackend) Fill(style *backendbase.FillStyle, pts [][2]float64) {
|
func (b *SoftwareBackend) Fill(style *backendbase.FillStyle, pts [][2]float64) {
|
||||||
|
if style.Blur > 0 {
|
||||||
|
b.activateBlurTarget()
|
||||||
|
defer b.drawBlurred(style.Blur)
|
||||||
|
}
|
||||||
|
|
||||||
if lg := style.LinearGradient; lg != nil {
|
if lg := style.LinearGradient; lg != nil {
|
||||||
lg := lg.(*LinearGradient)
|
lg := lg.(*LinearGradient)
|
||||||
from := [2]float64{style.Gradient.X0, style.Gradient.Y0}
|
from := [2]float64{style.Gradient.X0, style.Gradient.Y0}
|
||||||
|
|
|
@ -12,6 +12,8 @@ type SoftwareBackend struct {
|
||||||
|
|
||||||
MSAA int
|
MSAA int
|
||||||
|
|
||||||
|
blurSwap *image.RGBA
|
||||||
|
|
||||||
clip *image.Alpha
|
clip *image.Alpha
|
||||||
mask *image.Alpha
|
mask *image.Alpha
|
||||||
w, h int
|
w, h int
|
||||||
|
|
Loading…
Reference in a new issue