diff --git a/backend/gogl/shaders.go b/backend/gogl/shaders.go index 0e9d6e2..83ebadb 100755 --- a/backend/gogl/shaders.go +++ b/backend/gogl/shaders.go @@ -244,7 +244,7 @@ void main() { return; } float o = max(o1, o2); - float r = radFrom + o * (radTo - radFrom); + //float r = radFrom + o * (radTo - radFrom); vec4 col = texture2D(gradient, vec2(o, 0.0)); col.a *= texture2D(alphaTex, v_atc).a * globalAlpha; gl_FragColor = col; diff --git a/backend/software/fill.go b/backend/software/fill.go index ab4acdc..fde56d7 100644 --- a/backend/software/fill.go +++ b/backend/software/fill.go @@ -3,6 +3,7 @@ package softwarebackend import ( "image" "image/color" + "math" "github.com/tfriedel6/canvas/backend/backendbase" ) @@ -19,23 +20,50 @@ func (b *SoftwareBackend) Clear(pts [4][2]float64) { } func (b *SoftwareBackend) Fill(style *backendbase.FillStyle, pts [][2]float64) { - p2 := b.mask.Pix - for i := range p2 { - p2[i] = 0 - } + b.clearMask() - iterateTriangles(pts[:], func(tri [][2]float64) { - b.fillTriangle(tri, func(x, y int) { - if b.clip.AlphaAt(x, y).A == 0 { + if lg := style.LinearGradient; lg != nil { + lg := lg.(*LinearGradient) + from := [2]float64{style.Gradient.X0, style.Gradient.Y0} + dir := [2]float64{style.Gradient.X1 - style.Gradient.X0, style.Gradient.Y1 - style.Gradient.Y0} + 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]} + 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))) + }) + } else if rg := style.RadialGradient; rg != nil { + rg := rg.(*RadialGradient) + from := [2]float64{style.Gradient.X0, style.Gradient.Y0} + 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)} + 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)* + (from[0]*from[0]-2.0*from[0]*to[0]+to[0]*to[0]+from[1]*from[1]-2.0*from[1]*to[1]+to[1]*to[1]-radFrom*radFrom+2.0*radFrom*radTo-radTo*radTo)) + ob := (from[0]*from[0] - from[0]*to[0] - from[0]*pos[0] + to[0]*pos[0] + from[1]*from[1] - from[1]*to[1] - from[1]*pos[1] + to[1]*pos[1] - radFrom*radFrom + radFrom*radTo) + oc := (from[0]*from[0] - 2.0*from[0]*to[0] + to[0]*to[0] + from[1]*from[1] - 2.0*from[1]*to[1] + to[1]*to[1] - radFrom*radFrom + 2.0*radFrom*radTo - radTo*radTo) + o1 := (-oa + ob) / oc + o2 := (oa + ob) / oc + if math.IsNaN(o1) && math.IsNaN(o2) { return } - if b.mask.AlphaAt(x, y).A > 0 { - return - } - b.mask.SetAlpha(x, y, color.Alpha{A: 255}) + o := math.Max(o1, o2) + col := rg.data.ColorAt(o) + b.Image.SetRGBA(x, y, mix(col, b.Image.RGBAAt(x, y))) + b.Image.SetRGBA(x, y, color.RGBA{R: 255, A: 255}) + }) + } else { + b.fillTriangles(pts, func(x, y int) { b.Image.SetRGBA(x, y, mix(style.Color, b.Image.RGBAAt(x, y))) }) - }) + } } func (b *SoftwareBackend) FillImageMask(style *backendbase.FillStyle, mask *image.Alpha, pts [4][2]float64) { @@ -52,6 +80,13 @@ func (b *SoftwareBackend) FillImageMask(style *backendbase.FillStyle, mask *imag }) } +func (b *SoftwareBackend) clearMask() { + p := b.mask.Pix + for i := range p { + p[i] = 0 + } +} + func (b *SoftwareBackend) ClearClip() { p := b.clip.Pix for i := range p { diff --git a/backend/software/triangles.go b/backend/software/triangles.go index a0b2786..ede37dc 100644 --- a/backend/software/triangles.go +++ b/backend/software/triangles.go @@ -1,6 +1,7 @@ package softwarebackend import ( + "image/color" "math" ) @@ -173,3 +174,18 @@ func iterateTriangles(pts [][2]float64, fn func(tri [][2]float64)) { fn(pts[i-3 : i]) } } + +func (b *SoftwareBackend) fillTriangles(pts [][2]float64, fn func(x, y int)) { + iterateTriangles(pts[:], func(tri [][2]float64) { + b.fillTriangle(tri, 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}) + fn(x, y) + }) + }) +}