small performance improvements
This commit is contained in:
parent
b5212c916a
commit
5ce888f8b9
10 changed files with 75 additions and 32 deletions
|
@ -18,7 +18,7 @@ type Backend interface {
|
|||
LoadRadialGradient(data Gradient) RadialGradient
|
||||
|
||||
Clear(pts [4][2]float64)
|
||||
Fill(style *FillStyle, pts [][2]float64)
|
||||
Fill(style *FillStyle, pts [][2]float64, canOverlap bool)
|
||||
DrawImage(dimg Image, sx, sy, sw, sh float64, pts [4][2]float64, alpha float64)
|
||||
FillImageMask(style *FillStyle, mask *image.Alpha, pts [4][2]float64) // pts must have four points
|
||||
|
||||
|
|
|
@ -43,18 +43,21 @@ func (b *GoGLBackend) Clip(pts [][2]float64) {
|
|||
|
||||
gl.ColorMask(false, false, false, false)
|
||||
|
||||
// set bit 2 in the stencil buffer in the given shape
|
||||
gl.StencilMask(0x04)
|
||||
gl.StencilFunc(gl.ALWAYS, 4, 0x04)
|
||||
gl.StencilFunc(gl.ALWAYS, 4, 0)
|
||||
gl.StencilOp(gl.REPLACE, gl.REPLACE, gl.REPLACE)
|
||||
gl.DrawArrays(mode, 4, int32(len(pts)))
|
||||
|
||||
// on entire screen, where neither bit 1 or 2 are set, invert bit 1
|
||||
gl.StencilMask(0x02)
|
||||
gl.StencilFunc(gl.EQUAL, 0, 0x06)
|
||||
gl.StencilOp(gl.KEEP, gl.INVERT, gl.INVERT)
|
||||
gl.DrawArrays(gl.TRIANGLE_FAN, 0, 4)
|
||||
|
||||
// on entire screen, clear bit 2
|
||||
gl.StencilMask(0x04)
|
||||
gl.StencilFunc(gl.ALWAYS, 0, 0x04)
|
||||
gl.StencilFunc(gl.ALWAYS, 0, 0)
|
||||
gl.StencilOp(gl.ZERO, gl.ZERO, gl.ZERO)
|
||||
gl.DrawArrays(gl.TRIANGLE_FAN, 0, 4)
|
||||
|
||||
|
|
|
@ -69,7 +69,19 @@ func (b *GoGLBackend) clearRect(x, y, w, h int) {
|
|||
gl.Disable(gl.SCISSOR_TEST)
|
||||
}
|
||||
|
||||
func (b *GoGLBackend) Fill(style *backendbase.FillStyle, pts [][2]float64) {
|
||||
func extent(pts [][2]float64) (min, max vec) {
|
||||
min[0] = math.MaxFloat64
|
||||
min[1] = math.MaxFloat64
|
||||
for _, v := range pts {
|
||||
min[0] = math.Min(min[0], v[0])
|
||||
min[1] = math.Min(min[1], v[1])
|
||||
max[0] = math.Max(max[0], v[0])
|
||||
max[1] = math.Max(max[1], v[1])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (b *GoGLBackend) Fill(style *backendbase.FillStyle, pts [][2]float64, canOverlap bool) {
|
||||
b.activate()
|
||||
|
||||
if style.Blur > 0 {
|
||||
|
@ -80,11 +92,12 @@ func (b *GoGLBackend) Fill(style *backendbase.FillStyle, pts [][2]float64) {
|
|||
}
|
||||
|
||||
b.ptsBuf = b.ptsBuf[:0]
|
||||
min, max := extent(pts)
|
||||
b.ptsBuf = append(b.ptsBuf,
|
||||
0, 0,
|
||||
0, float32(b.fh),
|
||||
float32(b.fw), float32(b.fh),
|
||||
float32(b.fw), 0)
|
||||
float32(min[0]), float32(min[1]),
|
||||
float32(min[0]), float32(max[1]),
|
||||
float32(max[0]), float32(max[1]),
|
||||
float32(max[0]), float32(min[1]))
|
||||
for _, pt := range pts {
|
||||
b.ptsBuf = append(b.ptsBuf, float32(pt[0]), float32(pt[1]))
|
||||
}
|
||||
|
@ -97,7 +110,7 @@ func (b *GoGLBackend) Fill(style *backendbase.FillStyle, pts [][2]float64) {
|
|||
gl.BindBuffer(gl.ARRAY_BUFFER, b.buf)
|
||||
gl.BufferData(gl.ARRAY_BUFFER, len(b.ptsBuf)*4, unsafe.Pointer(&b.ptsBuf[0]), gl.STREAM_DRAW)
|
||||
|
||||
if style.Color.A >= 255 {
|
||||
if !canOverlap || style.Color.A >= 255 {
|
||||
vertex := b.useShader(style)
|
||||
|
||||
gl.StencilFunc(gl.EQUAL, 0, 0xFF)
|
||||
|
@ -130,7 +143,6 @@ func (b *GoGLBackend) Fill(style *backendbase.FillStyle, pts [][2]float64) {
|
|||
gl.EnableVertexAttribArray(vertex)
|
||||
gl.VertexAttribPointer(vertex, 2, gl.FLOAT, false, 0, nil)
|
||||
|
||||
b.ptsBuf = append(b.ptsBuf[:0], 0, 0, float32(b.fw), 0, float32(b.fw), float32(b.fh), 0, float32(b.fh))
|
||||
gl.DrawArrays(gl.TRIANGLE_FAN, 0, 4)
|
||||
gl.DisableVertexAttribArray(vertex)
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ 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, canOverlap bool) {
|
||||
ffn := fillFunc(style)
|
||||
|
||||
if style.Blur > 0 {
|
||||
|
|
|
@ -43,18 +43,21 @@ func (b *XMobileBackend) Clip(pts [][2]float64) {
|
|||
|
||||
b.glctx.ColorMask(false, false, false, false)
|
||||
|
||||
// set bit 2 in the stencil buffer in the given shape
|
||||
b.glctx.StencilMask(0x04)
|
||||
b.glctx.StencilFunc(gl.ALWAYS, 4, 0x04)
|
||||
b.glctx.StencilFunc(gl.ALWAYS, 4, 0)
|
||||
b.glctx.StencilOp(gl.REPLACE, gl.REPLACE, gl.REPLACE)
|
||||
b.glctx.DrawArrays(mode, 4, len(pts))
|
||||
|
||||
// on entire screen, where neither bit 1 or 2 are set, invert bit 1
|
||||
b.glctx.StencilMask(0x02)
|
||||
b.glctx.StencilFunc(gl.EQUAL, 0, 0x06)
|
||||
b.glctx.StencilOp(gl.KEEP, gl.INVERT, gl.INVERT)
|
||||
b.glctx.DrawArrays(gl.TRIANGLE_FAN, 0, 4)
|
||||
|
||||
// on entire screen, clear bit 2
|
||||
b.glctx.StencilMask(0x04)
|
||||
b.glctx.StencilFunc(gl.ALWAYS, 0, 0x04)
|
||||
b.glctx.StencilFunc(gl.ALWAYS, 0, 0)
|
||||
b.glctx.StencilOp(gl.ZERO, gl.ZERO, gl.ZERO)
|
||||
b.glctx.DrawArrays(gl.TRIANGLE_FAN, 0, 4)
|
||||
|
||||
|
|
|
@ -69,7 +69,19 @@ func (b *XMobileBackend) clearRect(x, y, w, h int) {
|
|||
b.glctx.Disable(gl.SCISSOR_TEST)
|
||||
}
|
||||
|
||||
func (b *XMobileBackend) Fill(style *backendbase.FillStyle, pts [][2]float64) {
|
||||
func extent(pts [][2]float64) (min, max vec) {
|
||||
min[0] = math.MaxFloat64
|
||||
min[1] = math.MaxFloat64
|
||||
for _, v := range pts {
|
||||
min[0] = math.Min(min[0], v[0])
|
||||
min[1] = math.Min(min[1], v[1])
|
||||
max[0] = math.Max(max[0], v[0])
|
||||
max[1] = math.Max(max[1], v[1])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (b *XMobileBackend) Fill(style *backendbase.FillStyle, pts [][2]float64, canOverlap bool) {
|
||||
b.activate()
|
||||
|
||||
if style.Blur > 0 {
|
||||
|
@ -80,11 +92,12 @@ func (b *XMobileBackend) Fill(style *backendbase.FillStyle, pts [][2]float64) {
|
|||
}
|
||||
|
||||
b.ptsBuf = b.ptsBuf[:0]
|
||||
min, max := extent(pts)
|
||||
b.ptsBuf = append(b.ptsBuf,
|
||||
0, 0,
|
||||
0, float32(b.fh),
|
||||
float32(b.fw), float32(b.fh),
|
||||
float32(b.fw), 0)
|
||||
float32(min[0]), float32(min[1]),
|
||||
float32(min[0]), float32(max[1]),
|
||||
float32(max[0]), float32(max[1]),
|
||||
float32(max[0]), float32(min[1]))
|
||||
for _, pt := range pts {
|
||||
b.ptsBuf = append(b.ptsBuf, float32(pt[0]), float32(pt[1]))
|
||||
}
|
||||
|
@ -97,7 +110,7 @@ func (b *XMobileBackend) Fill(style *backendbase.FillStyle, pts [][2]float64) {
|
|||
b.glctx.BindBuffer(gl.ARRAY_BUFFER, b.buf)
|
||||
b.glctx.BufferData(gl.ARRAY_BUFFER, byteSlice(unsafe.Pointer(&b.ptsBuf[0]), len(b.ptsBuf)*4), gl.STREAM_DRAW)
|
||||
|
||||
if style.Color.A >= 255 {
|
||||
if !canOverlap || style.Color.A >= 255 {
|
||||
vertex := b.useShader(style)
|
||||
|
||||
b.glctx.StencilFunc(gl.EQUAL, 0, 0xFF)
|
||||
|
@ -130,7 +143,6 @@ func (b *XMobileBackend) Fill(style *backendbase.FillStyle, pts [][2]float64) {
|
|||
b.glctx.EnableVertexAttribArray(vertex)
|
||||
b.glctx.VertexAttribPointer(vertex, 2, gl.FLOAT, false, 0, 0)
|
||||
|
||||
b.ptsBuf = append(b.ptsBuf[:0], 0, 0, float32(b.fw), 0, float32(b.fw), float32(b.fh), 0, float32(b.fh))
|
||||
b.glctx.DrawArrays(gl.TRIANGLE_FAN, 0, 4)
|
||||
b.glctx.DisableVertexAttribArray(vertex)
|
||||
|
||||
|
|
|
@ -169,7 +169,7 @@ func (cv *Canvas) DrawImage(image interface{}, coords ...float64) {
|
|||
data[2] = cv.tf(vec{dx + dw, dy + dh})
|
||||
data[3] = cv.tf(vec{dx + dw, dy})
|
||||
|
||||
cv.drawShadow(data[:], nil)
|
||||
cv.drawShadow(data[:], nil, false)
|
||||
|
||||
cv.b.DrawImage(img.img, sx, sy, sw, sh, data, cv.state.globalAlpha)
|
||||
}
|
||||
|
|
29
paths.go
29
paths.go
|
@ -95,10 +95,10 @@ func (cv *Canvas) strokePath(path *Path2D, inv mat, doInv bool) {
|
|||
var triBuf [500][2]float64
|
||||
tris := cv.strokeTris(path, inv, doInv, triBuf[:0])
|
||||
|
||||
cv.drawShadow(tris, nil)
|
||||
cv.drawShadow(tris, nil, true)
|
||||
|
||||
stl := cv.backendFillStyle(&cv.state.stroke, 1)
|
||||
cv.b.Fill(&stl, tris)
|
||||
cv.b.Fill(&stl, tris, true)
|
||||
}
|
||||
|
||||
func (cv *Canvas) strokeTris(path *Path2D, inv mat, doInv bool, target [][2]float64) [][2]float64 {
|
||||
|
@ -371,10 +371,10 @@ func (cv *Canvas) fillPath(path *Path2D, tf mat) {
|
|||
return
|
||||
}
|
||||
|
||||
cv.drawShadow(tris, nil)
|
||||
cv.drawShadow(tris, nil, false)
|
||||
|
||||
stl := cv.backendFillStyle(&cv.state.fill, 1)
|
||||
cv.b.Fill(&stl, tris)
|
||||
cv.b.Fill(&stl, tris, false)
|
||||
}
|
||||
|
||||
func appendSubPathTriangles(tris [][2]float64, mat mat, path []pathPoint) [][2]float64 {
|
||||
|
@ -412,8 +412,21 @@ func (cv *Canvas) clip(path *Path2D, tf mat) {
|
|||
return
|
||||
}
|
||||
|
||||
var triBuf [500][2]float64
|
||||
tris := triBuf[:0]
|
||||
var buf [500][2]float64
|
||||
|
||||
if path.p[len(path.p)-1].flags&pathIsRect != 0 {
|
||||
cv.state.clip.p = make([]pathPoint, len(path.p))
|
||||
copy(cv.state.clip.p, path.p)
|
||||
|
||||
quad := buf[:4]
|
||||
for i := range quad {
|
||||
quad[i] = path.p[i].pos
|
||||
}
|
||||
cv.b.Clip(quad)
|
||||
return
|
||||
}
|
||||
|
||||
tris := buf[:0]
|
||||
runSubPaths(path.p, true, func(sp []pathPoint) bool {
|
||||
tris = appendSubPathTriangles(tris, tf, sp)
|
||||
return false
|
||||
|
@ -467,10 +480,10 @@ func (cv *Canvas) FillRect(x, y, w, h float64) {
|
|||
|
||||
data := [4][2]float64{{p0[0], p0[1]}, {p1[0], p1[1]}, {p2[0], p2[1]}, {p3[0], p3[1]}}
|
||||
|
||||
cv.drawShadow(data[:], nil)
|
||||
cv.drawShadow(data[:], nil, false)
|
||||
|
||||
stl := cv.backendFillStyle(&cv.state.fill, 1)
|
||||
cv.b.Fill(&stl, data[:])
|
||||
cv.b.Fill(&stl, data[:], false)
|
||||
}
|
||||
|
||||
// ClearRect sets the color of the rectangle to transparent black
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
"github.com/tfriedel6/canvas/backend/backendbase"
|
||||
)
|
||||
|
||||
func (cv *Canvas) drawShadow(pts [][2]float64, mask *image.Alpha) {
|
||||
func (cv *Canvas) drawShadow(pts [][2]float64, mask *image.Alpha, canOverlap bool) {
|
||||
if cv.state.shadowColor.A == 0 {
|
||||
return
|
||||
}
|
||||
|
@ -38,6 +38,6 @@ func (cv *Canvas) drawShadow(pts [][2]float64, mask *image.Alpha) {
|
|||
copy(quad[:], cv.shadowBuf)
|
||||
cv.b.FillImageMask(&style, mask, quad)
|
||||
} else {
|
||||
cv.b.Fill(&style, cv.shadowBuf)
|
||||
cv.b.Fill(&style, cv.shadowBuf, canOverlap)
|
||||
}
|
||||
}
|
||||
|
|
2
text.go
2
text.go
|
@ -215,7 +215,7 @@ func (cv *Canvas) FillText(str string, x, y float64) {
|
|||
|
||||
mask := textImage.SubImage(image.Rect(0, 0, strWidth, strHeight)).(*image.Alpha)
|
||||
|
||||
cv.drawShadow(pts[:], mask)
|
||||
cv.drawShadow(pts[:], mask, false)
|
||||
|
||||
stl := cv.backendFillStyle(&cv.state.fill, 1)
|
||||
cv.b.FillImageMask(&stl, mask, pts)
|
||||
|
|
Loading…
Reference in a new issue