Path2D now caches the triangulation for filling
This commit is contained in:
parent
804a9c2774
commit
34087abece
17 changed files with 116 additions and 28 deletions
|
@ -18,7 +18,7 @@ type Backend interface {
|
||||||
LoadRadialGradient(data Gradient) RadialGradient
|
LoadRadialGradient(data Gradient) RadialGradient
|
||||||
|
|
||||||
Clear(pts [4]Vec)
|
Clear(pts [4]Vec)
|
||||||
Fill(style *FillStyle, pts []Vec, canOverlap bool)
|
Fill(style *FillStyle, pts []Vec, tf Mat, canOverlap bool)
|
||||||
DrawImage(dimg Image, sx, sy, sw, sh float64, pts [4]Vec, alpha float64)
|
DrawImage(dimg Image, sx, sy, sw, sh float64, pts [4]Vec, alpha float64)
|
||||||
FillImageMask(style *FillStyle, mask *image.Alpha, pts [4]Vec) // pts must have four points
|
FillImageMask(style *FillStyle, mask *image.Alpha, pts [4]Vec) // pts must have four points
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,7 @@ func (b *GoGLBackend) Clip(pts []backendbase.Vec) {
|
||||||
gl.UseProgram(b.shd.ID)
|
gl.UseProgram(b.shd.ID)
|
||||||
gl.Uniform4f(b.shd.Color, 1, 1, 1, 1)
|
gl.Uniform4f(b.shd.Color, 1, 1, 1, 1)
|
||||||
gl.Uniform2f(b.shd.CanvasSize, float32(b.fw), float32(b.fh))
|
gl.Uniform2f(b.shd.CanvasSize, float32(b.fw), float32(b.fh))
|
||||||
|
gl.UniformMatrix3fv(b.shd.Matrix, 1, false, &mat3identity[0])
|
||||||
gl.Uniform1f(b.shd.GlobalAlpha, 1)
|
gl.Uniform1f(b.shd.GlobalAlpha, 1)
|
||||||
gl.Uniform1i(b.shd.UseAlphaTex, 0)
|
gl.Uniform1i(b.shd.UseAlphaTex, 0)
|
||||||
gl.Uniform1i(b.shd.Func, shdFuncSolid)
|
gl.Uniform1i(b.shd.Func, shdFuncSolid)
|
||||||
|
|
|
@ -35,6 +35,7 @@ func (b *GoGLBackend) Clear(pts [4]backendbase.Vec) {
|
||||||
|
|
||||||
gl.UseProgram(b.shd.ID)
|
gl.UseProgram(b.shd.ID)
|
||||||
gl.Uniform2f(b.shd.CanvasSize, float32(b.fw), float32(b.fh))
|
gl.Uniform2f(b.shd.CanvasSize, float32(b.fw), float32(b.fh))
|
||||||
|
gl.UniformMatrix3fv(b.shd.Matrix, 1, false, &mat3identity[0])
|
||||||
gl.Uniform4f(b.shd.Color, 0, 0, 0, 0)
|
gl.Uniform4f(b.shd.Color, 0, 0, 0, 0)
|
||||||
gl.Uniform1f(b.shd.GlobalAlpha, 1)
|
gl.Uniform1f(b.shd.GlobalAlpha, 1)
|
||||||
gl.Uniform1i(b.shd.UseAlphaTex, 0)
|
gl.Uniform1i(b.shd.UseAlphaTex, 0)
|
||||||
|
@ -85,7 +86,7 @@ func extent(pts []backendbase.Vec) (min, max backendbase.Vec) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *GoGLBackend) Fill(style *backendbase.FillStyle, pts []backendbase.Vec, canOverlap bool) {
|
func (b *GoGLBackend) Fill(style *backendbase.FillStyle, pts []backendbase.Vec, tf backendbase.Mat, canOverlap bool) {
|
||||||
b.activate()
|
b.activate()
|
||||||
|
|
||||||
if style.Blur > 0 {
|
if style.Blur > 0 {
|
||||||
|
@ -115,7 +116,7 @@ func (b *GoGLBackend) Fill(style *backendbase.FillStyle, pts []backendbase.Vec,
|
||||||
gl.BufferData(gl.ARRAY_BUFFER, len(b.ptsBuf)*4, unsafe.Pointer(&b.ptsBuf[0]), gl.STREAM_DRAW)
|
gl.BufferData(gl.ARRAY_BUFFER, len(b.ptsBuf)*4, unsafe.Pointer(&b.ptsBuf[0]), gl.STREAM_DRAW)
|
||||||
|
|
||||||
if !canOverlap || style.Color.A >= 255 {
|
if !canOverlap || style.Color.A >= 255 {
|
||||||
vertex, _ := b.useShader(style, false, 0)
|
vertex, _ := b.useShader(style, mat3(tf), false, 0)
|
||||||
|
|
||||||
gl.StencilFunc(gl.EQUAL, 0, 0xFF)
|
gl.StencilFunc(gl.EQUAL, 0, 0xFF)
|
||||||
gl.EnableVertexAttribArray(vertex)
|
gl.EnableVertexAttribArray(vertex)
|
||||||
|
@ -132,6 +133,8 @@ func (b *GoGLBackend) Fill(style *backendbase.FillStyle, pts []backendbase.Vec,
|
||||||
gl.UseProgram(b.shd.ID)
|
gl.UseProgram(b.shd.ID)
|
||||||
gl.Uniform4f(b.shd.Color, 0, 0, 0, 0)
|
gl.Uniform4f(b.shd.Color, 0, 0, 0, 0)
|
||||||
gl.Uniform2f(b.shd.CanvasSize, float32(b.fw), float32(b.fh))
|
gl.Uniform2f(b.shd.CanvasSize, float32(b.fw), float32(b.fh))
|
||||||
|
m3 := mat3(tf)
|
||||||
|
gl.UniformMatrix3fv(b.shd.Matrix, 1, false, &m3[0])
|
||||||
gl.Uniform1f(b.shd.GlobalAlpha, 1)
|
gl.Uniform1f(b.shd.GlobalAlpha, 1)
|
||||||
gl.Uniform1i(b.shd.UseAlphaTex, 0)
|
gl.Uniform1i(b.shd.UseAlphaTex, 0)
|
||||||
gl.Uniform1i(b.shd.Func, shdFuncSolid)
|
gl.Uniform1i(b.shd.Func, shdFuncSolid)
|
||||||
|
@ -145,7 +148,7 @@ func (b *GoGLBackend) Fill(style *backendbase.FillStyle, pts []backendbase.Vec,
|
||||||
|
|
||||||
gl.StencilFunc(gl.EQUAL, 1, 0xFF)
|
gl.StencilFunc(gl.EQUAL, 1, 0xFF)
|
||||||
|
|
||||||
vertex, _ := b.useShader(style, false, 0)
|
vertex, _ := b.useShader(style, mat3identity, false, 0)
|
||||||
gl.EnableVertexAttribArray(vertex)
|
gl.EnableVertexAttribArray(vertex)
|
||||||
gl.VertexAttribPointer(vertex, 2, gl.FLOAT, false, 0, nil)
|
gl.VertexAttribPointer(vertex, 2, gl.FLOAT, false, 0, nil)
|
||||||
|
|
||||||
|
@ -190,7 +193,7 @@ func (b *GoGLBackend) FillImageMask(style *backendbase.FillStyle, mask *image.Al
|
||||||
|
|
||||||
gl.BindBuffer(gl.ARRAY_BUFFER, b.buf)
|
gl.BindBuffer(gl.ARRAY_BUFFER, b.buf)
|
||||||
|
|
||||||
vertex, alphaTexCoord := b.useShader(style, true, 1)
|
vertex, alphaTexCoord := b.useShader(style, mat3identity, true, 1)
|
||||||
|
|
||||||
gl.EnableVertexAttribArray(vertex)
|
gl.EnableVertexAttribArray(vertex)
|
||||||
gl.EnableVertexAttribArray(alphaTexCoord)
|
gl.EnableVertexAttribArray(alphaTexCoord)
|
||||||
|
@ -267,6 +270,7 @@ func (b *GoGLBackend) drawBlurred(size float64, min, max backendbase.Vec) {
|
||||||
gl.UseProgram(b.shd.ID)
|
gl.UseProgram(b.shd.ID)
|
||||||
gl.Uniform1i(b.shd.Image, 0)
|
gl.Uniform1i(b.shd.Image, 0)
|
||||||
gl.Uniform2f(b.shd.CanvasSize, float32(b.fw), float32(b.fh))
|
gl.Uniform2f(b.shd.CanvasSize, float32(b.fw), float32(b.fh))
|
||||||
|
gl.UniformMatrix3fv(b.shd.Matrix, 1, false, &mat3identity[0])
|
||||||
gl.Uniform1i(b.shd.UseAlphaTex, 0)
|
gl.Uniform1i(b.shd.UseAlphaTex, 0)
|
||||||
gl.Uniform1i(b.shd.Func, shdFuncBoxBlur)
|
gl.Uniform1i(b.shd.Func, shdFuncBoxBlur)
|
||||||
|
|
||||||
|
|
|
@ -258,9 +258,10 @@ func (b *GoGLBackendOffscreen) AsImage() backendbase.Image {
|
||||||
return &b.offscrImg
|
return &b.offscrImg
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *GoGLBackend) useShader(style *backendbase.FillStyle, useAlpha bool, alphaTexSlot int32) (vertexLoc, alphaTexCoordLoc uint32) {
|
func (b *GoGLBackend) useShader(style *backendbase.FillStyle, tf [9]float32, useAlpha bool, alphaTexSlot int32) (vertexLoc, alphaTexCoordLoc uint32) {
|
||||||
gl.UseProgram(b.shd.ID)
|
gl.UseProgram(b.shd.ID)
|
||||||
gl.Uniform2f(b.shd.CanvasSize, float32(b.fw), float32(b.fh))
|
gl.Uniform2f(b.shd.CanvasSize, float32(b.fw), float32(b.fh))
|
||||||
|
gl.UniformMatrix3fv(b.shd.Matrix, 1, false, &tf[0])
|
||||||
if useAlpha {
|
if useAlpha {
|
||||||
gl.Uniform1i(b.shd.UseAlphaTex, 1)
|
gl.Uniform1i(b.shd.UseAlphaTex, 1)
|
||||||
gl.Uniform1i(b.shd.AlphaTex, alphaTexSlot)
|
gl.Uniform1i(b.shd.AlphaTex, alphaTexSlot)
|
||||||
|
@ -382,3 +383,18 @@ func (b *GoGLBackend) enableTextureRenderTarget(offscr *offscreenBuffer) {
|
||||||
|
|
||||||
gl.Clear(gl.COLOR_BUFFER_BIT | gl.STENCIL_BUFFER_BIT)
|
gl.Clear(gl.COLOR_BUFFER_BIT | gl.STENCIL_BUFFER_BIT)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func mat3(m backendbase.Mat) (m3 [9]float32) {
|
||||||
|
m3[0] = float32(m[0])
|
||||||
|
m3[1] = float32(m[1])
|
||||||
|
m3[2] = 0
|
||||||
|
m3[3] = float32(m[2])
|
||||||
|
m3[4] = float32(m[3])
|
||||||
|
m3[5] = 0
|
||||||
|
m3[6] = float32(m[4])
|
||||||
|
m3[7] = float32(m[5])
|
||||||
|
m3[8] = 1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var mat3identity = [9]float32{1, 0, 0, 0, 1, 0, 0, 0, 1}
|
||||||
|
|
|
@ -88,6 +88,7 @@ func (b *GoGLBackend) PutImageData(img *image.RGBA, x, y int) {
|
||||||
gl.UseProgram(b.shd.ID)
|
gl.UseProgram(b.shd.ID)
|
||||||
gl.Uniform1i(b.shd.Image, 0)
|
gl.Uniform1i(b.shd.Image, 0)
|
||||||
gl.Uniform2f(b.shd.CanvasSize, float32(b.fw), float32(b.fh))
|
gl.Uniform2f(b.shd.CanvasSize, float32(b.fw), float32(b.fh))
|
||||||
|
gl.UniformMatrix3fv(b.shd.Matrix, 1, false, &mat3identity[0])
|
||||||
gl.Uniform1f(b.shd.GlobalAlpha, 1)
|
gl.Uniform1f(b.shd.GlobalAlpha, 1)
|
||||||
gl.Uniform1i(b.shd.UseAlphaTex, 0)
|
gl.Uniform1i(b.shd.UseAlphaTex, 0)
|
||||||
gl.Uniform1i(b.shd.Func, shdFuncImage)
|
gl.Uniform1i(b.shd.Func, shdFuncImage)
|
||||||
|
|
|
@ -190,6 +190,7 @@ func (b *GoGLBackend) DrawImage(dimg backendbase.Image, sx, sy, sw, sh float64,
|
||||||
gl.UseProgram(b.shd.ID)
|
gl.UseProgram(b.shd.ID)
|
||||||
gl.Uniform1i(b.shd.Image, 0)
|
gl.Uniform1i(b.shd.Image, 0)
|
||||||
gl.Uniform2f(b.shd.CanvasSize, float32(b.fw), float32(b.fh))
|
gl.Uniform2f(b.shd.CanvasSize, float32(b.fw), float32(b.fh))
|
||||||
|
gl.UniformMatrix3fv(b.shd.Matrix, 1, false, &mat3identity[0])
|
||||||
gl.Uniform1f(b.shd.GlobalAlpha, float32(alpha))
|
gl.Uniform1f(b.shd.GlobalAlpha, float32(alpha))
|
||||||
gl.Uniform1i(b.shd.UseAlphaTex, 0)
|
gl.Uniform1i(b.shd.UseAlphaTex, 0)
|
||||||
gl.Uniform1i(b.shd.Func, shdFuncImage)
|
gl.Uniform1i(b.shd.Func, shdFuncImage)
|
||||||
|
|
|
@ -4,13 +4,16 @@ var unifiedVS = `
|
||||||
attribute vec2 vertex, texCoord;
|
attribute vec2 vertex, texCoord;
|
||||||
|
|
||||||
uniform vec2 canvasSize;
|
uniform vec2 canvasSize;
|
||||||
|
uniform mat3 matrix;
|
||||||
|
|
||||||
varying vec2 v_cp, v_tc;
|
varying vec2 v_cp, v_tc;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
v_tc = texCoord;
|
v_tc = texCoord;
|
||||||
v_cp = vertex;
|
vec3 v = matrix * vec3(vertex.xy, 1.0);
|
||||||
vec2 glp = vertex * 2.0 / canvasSize - 1.0;
|
vec2 tf = v.xy / v.z;
|
||||||
|
v_cp = tf;
|
||||||
|
vec2 glp = tf * 2.0 / canvasSize - 1.0;
|
||||||
gl_Position = vec4(glp.x, -glp.y, 0.0, 1.0);
|
gl_Position = vec4(glp.x, -glp.y, 0.0, 1.0);
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
@ -129,6 +132,7 @@ type unifiedShader struct {
|
||||||
TexCoord uint32
|
TexCoord uint32
|
||||||
|
|
||||||
CanvasSize int32
|
CanvasSize int32
|
||||||
|
Matrix int32
|
||||||
Color int32
|
Color int32
|
||||||
GlobalAlpha int32
|
GlobalAlpha int32
|
||||||
|
|
||||||
|
|
|
@ -19,9 +19,22 @@ func (b *SoftwareBackend) Clear(pts [4]backendbase.Vec) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *SoftwareBackend) Fill(style *backendbase.FillStyle, pts []backendbase.Vec, canOverlap bool) {
|
func (b *SoftwareBackend) Fill(style *backendbase.FillStyle, pts []backendbase.Vec, tf backendbase.Mat, canOverlap bool) {
|
||||||
ffn := fillFunc(style)
|
ffn := fillFunc(style)
|
||||||
|
|
||||||
|
var triBuf [500]backendbase.Vec
|
||||||
|
if tf != backendbase.MatIdentity {
|
||||||
|
ptsOld := pts
|
||||||
|
if len(pts) < len(triBuf) {
|
||||||
|
pts = triBuf[:len(pts)]
|
||||||
|
} else {
|
||||||
|
pts = make([]backendbase.Vec, len(pts))
|
||||||
|
}
|
||||||
|
for i, pt := range ptsOld {
|
||||||
|
pts[i] = pt.MulMat(tf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if style.Blur > 0 {
|
if style.Blur > 0 {
|
||||||
b.activateBlurTarget()
|
b.activateBlurTarget()
|
||||||
b.fillTriangles(pts, ffn)
|
b.fillTriangles(pts, ffn)
|
||||||
|
|
|
@ -39,6 +39,7 @@ func (b *XMobileBackend) Clip(pts []backendbase.Vec) {
|
||||||
b.glctx.UseProgram(b.shd.ID)
|
b.glctx.UseProgram(b.shd.ID)
|
||||||
b.glctx.Uniform4f(b.shd.Color, 1, 1, 1, 1)
|
b.glctx.Uniform4f(b.shd.Color, 1, 1, 1, 1)
|
||||||
b.glctx.Uniform2f(b.shd.CanvasSize, float32(b.fw), float32(b.fh))
|
b.glctx.Uniform2f(b.shd.CanvasSize, float32(b.fw), float32(b.fh))
|
||||||
|
b.glctx.UniformMatrix3fv(b.shd.Matrix, mat3identity[:])
|
||||||
b.glctx.Uniform1f(b.shd.GlobalAlpha, 1)
|
b.glctx.Uniform1f(b.shd.GlobalAlpha, 1)
|
||||||
b.glctx.Uniform1i(b.shd.UseAlphaTex, 0)
|
b.glctx.Uniform1i(b.shd.UseAlphaTex, 0)
|
||||||
b.glctx.Uniform1i(b.shd.Func, shdFuncSolid)
|
b.glctx.Uniform1i(b.shd.Func, shdFuncSolid)
|
||||||
|
|
|
@ -35,6 +35,7 @@ func (b *XMobileBackend) Clear(pts [4]backendbase.Vec) {
|
||||||
|
|
||||||
b.glctx.UseProgram(b.shd.ID)
|
b.glctx.UseProgram(b.shd.ID)
|
||||||
b.glctx.Uniform2f(b.shd.CanvasSize, float32(b.fw), float32(b.fh))
|
b.glctx.Uniform2f(b.shd.CanvasSize, float32(b.fw), float32(b.fh))
|
||||||
|
b.glctx.UniformMatrix3fv(b.shd.Matrix, mat3identity[:])
|
||||||
b.glctx.Uniform4f(b.shd.Color, 0, 0, 0, 0)
|
b.glctx.Uniform4f(b.shd.Color, 0, 0, 0, 0)
|
||||||
b.glctx.Uniform1f(b.shd.GlobalAlpha, 1)
|
b.glctx.Uniform1f(b.shd.GlobalAlpha, 1)
|
||||||
b.glctx.Uniform1i(b.shd.UseAlphaTex, 0)
|
b.glctx.Uniform1i(b.shd.UseAlphaTex, 0)
|
||||||
|
@ -85,7 +86,7 @@ func extent(pts []backendbase.Vec) (min, max backendbase.Vec) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *XMobileBackend) Fill(style *backendbase.FillStyle, pts []backendbase.Vec, canOverlap bool) {
|
func (b *XMobileBackend) Fill(style *backendbase.FillStyle, pts []backendbase.Vec, tf backendbase.Mat, canOverlap bool) {
|
||||||
b.activate()
|
b.activate()
|
||||||
|
|
||||||
if style.Blur > 0 {
|
if style.Blur > 0 {
|
||||||
|
@ -115,7 +116,7 @@ func (b *XMobileBackend) Fill(style *backendbase.FillStyle, pts []backendbase.Ve
|
||||||
b.glctx.BufferData(gl.ARRAY_BUFFER, byteSlice(unsafe.Pointer(&b.ptsBuf[0]), len(b.ptsBuf)*4), gl.STREAM_DRAW)
|
b.glctx.BufferData(gl.ARRAY_BUFFER, byteSlice(unsafe.Pointer(&b.ptsBuf[0]), len(b.ptsBuf)*4), gl.STREAM_DRAW)
|
||||||
|
|
||||||
if !canOverlap || style.Color.A >= 255 {
|
if !canOverlap || style.Color.A >= 255 {
|
||||||
vertex, _ := b.useShader(style, false, 0)
|
vertex, _ := b.useShader(style, mat3(tf), false, 0)
|
||||||
|
|
||||||
b.glctx.StencilFunc(gl.EQUAL, 0, 0xFF)
|
b.glctx.StencilFunc(gl.EQUAL, 0, 0xFF)
|
||||||
b.glctx.EnableVertexAttribArray(vertex)
|
b.glctx.EnableVertexAttribArray(vertex)
|
||||||
|
@ -132,6 +133,8 @@ func (b *XMobileBackend) Fill(style *backendbase.FillStyle, pts []backendbase.Ve
|
||||||
b.glctx.UseProgram(b.shd.ID)
|
b.glctx.UseProgram(b.shd.ID)
|
||||||
b.glctx.Uniform4f(b.shd.Color, 0, 0, 0, 0)
|
b.glctx.Uniform4f(b.shd.Color, 0, 0, 0, 0)
|
||||||
b.glctx.Uniform2f(b.shd.CanvasSize, float32(b.fw), float32(b.fh))
|
b.glctx.Uniform2f(b.shd.CanvasSize, float32(b.fw), float32(b.fh))
|
||||||
|
m3 := mat3(tf)
|
||||||
|
b.glctx.UniformMatrix3fv(b.shd.Matrix, m3[:])
|
||||||
b.glctx.Uniform1f(b.shd.GlobalAlpha, 1)
|
b.glctx.Uniform1f(b.shd.GlobalAlpha, 1)
|
||||||
b.glctx.Uniform1i(b.shd.UseAlphaTex, 0)
|
b.glctx.Uniform1i(b.shd.UseAlphaTex, 0)
|
||||||
b.glctx.Uniform1i(b.shd.Func, shdFuncSolid)
|
b.glctx.Uniform1i(b.shd.Func, shdFuncSolid)
|
||||||
|
@ -145,7 +148,7 @@ func (b *XMobileBackend) Fill(style *backendbase.FillStyle, pts []backendbase.Ve
|
||||||
|
|
||||||
b.glctx.StencilFunc(gl.EQUAL, 1, 0xFF)
|
b.glctx.StencilFunc(gl.EQUAL, 1, 0xFF)
|
||||||
|
|
||||||
vertex, _ := b.useShader(style, false, 0)
|
vertex, _ := b.useShader(style, mat3identity, false, 0)
|
||||||
b.glctx.EnableVertexAttribArray(vertex)
|
b.glctx.EnableVertexAttribArray(vertex)
|
||||||
b.glctx.VertexAttribPointer(vertex, 2, gl.FLOAT, false, 0, 0)
|
b.glctx.VertexAttribPointer(vertex, 2, gl.FLOAT, false, 0, 0)
|
||||||
|
|
||||||
|
@ -190,7 +193,7 @@ func (b *XMobileBackend) FillImageMask(style *backendbase.FillStyle, mask *image
|
||||||
|
|
||||||
b.glctx.BindBuffer(gl.ARRAY_BUFFER, b.buf)
|
b.glctx.BindBuffer(gl.ARRAY_BUFFER, b.buf)
|
||||||
|
|
||||||
vertex, alphaTexCoord := b.useShader(style, true, 1)
|
vertex, alphaTexCoord := b.useShader(style, mat3identity, true, 1)
|
||||||
|
|
||||||
b.glctx.EnableVertexAttribArray(vertex)
|
b.glctx.EnableVertexAttribArray(vertex)
|
||||||
b.glctx.EnableVertexAttribArray(alphaTexCoord)
|
b.glctx.EnableVertexAttribArray(alphaTexCoord)
|
||||||
|
@ -267,6 +270,7 @@ func (b *XMobileBackend) drawBlurred(size float64, min, max backendbase.Vec) {
|
||||||
b.glctx.UseProgram(b.shd.ID)
|
b.glctx.UseProgram(b.shd.ID)
|
||||||
b.glctx.Uniform1i(b.shd.Image, 0)
|
b.glctx.Uniform1i(b.shd.Image, 0)
|
||||||
b.glctx.Uniform2f(b.shd.CanvasSize, float32(b.fw), float32(b.fh))
|
b.glctx.Uniform2f(b.shd.CanvasSize, float32(b.fw), float32(b.fh))
|
||||||
|
b.glctx.UniformMatrix3fv(b.shd.Matrix, mat3identity[:])
|
||||||
b.glctx.Uniform1i(b.shd.UseAlphaTex, 0)
|
b.glctx.Uniform1i(b.shd.UseAlphaTex, 0)
|
||||||
b.glctx.Uniform1i(b.shd.Func, shdFuncBoxBlur)
|
b.glctx.Uniform1i(b.shd.Func, shdFuncBoxBlur)
|
||||||
|
|
||||||
|
|
|
@ -88,6 +88,7 @@ func (b *XMobileBackend) PutImageData(img *image.RGBA, x, y int) {
|
||||||
b.glctx.UseProgram(b.shd.ID)
|
b.glctx.UseProgram(b.shd.ID)
|
||||||
b.glctx.Uniform1i(b.shd.Image, 0)
|
b.glctx.Uniform1i(b.shd.Image, 0)
|
||||||
b.glctx.Uniform2f(b.shd.CanvasSize, float32(b.fw), float32(b.fh))
|
b.glctx.Uniform2f(b.shd.CanvasSize, float32(b.fw), float32(b.fh))
|
||||||
|
b.glctx.UniformMatrix3fv(b.shd.Matrix, mat3identity[:])
|
||||||
b.glctx.Uniform1f(b.shd.GlobalAlpha, 1)
|
b.glctx.Uniform1f(b.shd.GlobalAlpha, 1)
|
||||||
b.glctx.Uniform1i(b.shd.UseAlphaTex, 0)
|
b.glctx.Uniform1i(b.shd.UseAlphaTex, 0)
|
||||||
b.glctx.Uniform1i(b.shd.Func, shdFuncImage)
|
b.glctx.Uniform1i(b.shd.Func, shdFuncImage)
|
||||||
|
|
|
@ -192,6 +192,7 @@ func (b *XMobileBackend) DrawImage(dimg backendbase.Image, sx, sy, sw, sh float6
|
||||||
b.glctx.UseProgram(b.shd.ID)
|
b.glctx.UseProgram(b.shd.ID)
|
||||||
b.glctx.Uniform1i(b.shd.Image, 0)
|
b.glctx.Uniform1i(b.shd.Image, 0)
|
||||||
b.glctx.Uniform2f(b.shd.CanvasSize, float32(b.fw), float32(b.fh))
|
b.glctx.Uniform2f(b.shd.CanvasSize, float32(b.fw), float32(b.fh))
|
||||||
|
b.glctx.UniformMatrix3fv(b.shd.Matrix, mat3identity[:])
|
||||||
b.glctx.Uniform1f(b.shd.GlobalAlpha, float32(alpha))
|
b.glctx.Uniform1f(b.shd.GlobalAlpha, float32(alpha))
|
||||||
b.glctx.Uniform1i(b.shd.UseAlphaTex, 0)
|
b.glctx.Uniform1i(b.shd.UseAlphaTex, 0)
|
||||||
b.glctx.Uniform1i(b.shd.Func, shdFuncImage)
|
b.glctx.Uniform1i(b.shd.Func, shdFuncImage)
|
||||||
|
|
|
@ -8,13 +8,16 @@ var unifiedVS = `
|
||||||
attribute vec2 vertex, texCoord;
|
attribute vec2 vertex, texCoord;
|
||||||
|
|
||||||
uniform vec2 canvasSize;
|
uniform vec2 canvasSize;
|
||||||
|
uniform mat3 matrix;
|
||||||
|
|
||||||
varying vec2 v_cp, v_tc;
|
varying vec2 v_cp, v_tc;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
v_tc = texCoord;
|
v_tc = texCoord;
|
||||||
v_cp = vertex;
|
vec3 v = matrix * vec3(vertex.xy, 1.0);
|
||||||
vec2 glp = vertex * 2.0 / canvasSize - 1.0;
|
vec2 tf = v.xy / v.z;
|
||||||
|
v_cp = tf;
|
||||||
|
vec2 glp = tf * 2.0 / canvasSize - 1.0;
|
||||||
gl_Position = vec4(glp.x, -glp.y, 0.0, 1.0);
|
gl_Position = vec4(glp.x, -glp.y, 0.0, 1.0);
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
@ -133,6 +136,7 @@ type unifiedShader struct {
|
||||||
TexCoord gl.Attrib
|
TexCoord gl.Attrib
|
||||||
|
|
||||||
CanvasSize gl.Uniform
|
CanvasSize gl.Uniform
|
||||||
|
Matrix gl.Uniform
|
||||||
Color gl.Uniform
|
Color gl.Uniform
|
||||||
GlobalAlpha gl.Uniform
|
GlobalAlpha gl.Uniform
|
||||||
|
|
||||||
|
|
|
@ -251,9 +251,10 @@ func (b *XMobileBackendOffscreen) AsImage() backendbase.Image {
|
||||||
return &b.offscrImg
|
return &b.offscrImg
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *XMobileBackend) useShader(style *backendbase.FillStyle, useAlpha bool, alphaTexSlot int) (vertexLoc, alphaTexCoordLoc gl.Attrib) {
|
func (b *XMobileBackend) useShader(style *backendbase.FillStyle, tf [9]float32, useAlpha bool, alphaTexSlot int) (vertexLoc, alphaTexCoordLoc gl.Attrib) {
|
||||||
b.glctx.UseProgram(b.shd.ID)
|
b.glctx.UseProgram(b.shd.ID)
|
||||||
b.glctx.Uniform2f(b.shd.CanvasSize, float32(b.fw), float32(b.fh))
|
b.glctx.Uniform2f(b.shd.CanvasSize, float32(b.fw), float32(b.fh))
|
||||||
|
b.glctx.UniformMatrix3fv(b.shd.Matrix, tf[:])
|
||||||
if useAlpha {
|
if useAlpha {
|
||||||
b.glctx.Uniform1i(b.shd.UseAlphaTex, 1)
|
b.glctx.Uniform1i(b.shd.UseAlphaTex, 1)
|
||||||
b.glctx.Uniform1i(b.shd.AlphaTex, alphaTexSlot)
|
b.glctx.Uniform1i(b.shd.AlphaTex, alphaTexSlot)
|
||||||
|
@ -376,6 +377,21 @@ func (b *XMobileBackend) enableTextureRenderTarget(offscr *offscreenBuffer) {
|
||||||
b.glctx.Clear(gl.COLOR_BUFFER_BIT | gl.STENCIL_BUFFER_BIT)
|
b.glctx.Clear(gl.COLOR_BUFFER_BIT | gl.STENCIL_BUFFER_BIT)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func mat3(m backendbase.Mat) (m3 [9]float32) {
|
||||||
|
m3[0] = float32(m[0])
|
||||||
|
m3[1] = float32(m[1])
|
||||||
|
m3[2] = 0
|
||||||
|
m3[3] = float32(m[2])
|
||||||
|
m3[4] = float32(m[3])
|
||||||
|
m3[5] = 0
|
||||||
|
m3[6] = float32(m[4])
|
||||||
|
m3[7] = float32(m[5])
|
||||||
|
m3[8] = 1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var mat3identity = [9]float32{1, 0, 0, 0, 1, 0, 0, 0, 1}
|
||||||
|
|
||||||
func byteSlice(ptr unsafe.Pointer, size int) []byte {
|
func byteSlice(ptr unsafe.Pointer, size int) []byte {
|
||||||
var buf []byte
|
var buf []byte
|
||||||
sh := (*reflect.SliceHeader)(unsafe.Pointer(&buf))
|
sh := (*reflect.SliceHeader)(unsafe.Pointer(&buf))
|
||||||
|
|
11
path2d.go
11
path2d.go
|
@ -13,6 +13,9 @@ type Path2D struct {
|
||||||
p []pathPoint
|
p []pathPoint
|
||||||
move backendbase.Vec
|
move backendbase.Vec
|
||||||
cwSum float64
|
cwSum float64
|
||||||
|
|
||||||
|
standalone bool
|
||||||
|
fillCache []backendbase.Vec
|
||||||
}
|
}
|
||||||
|
|
||||||
type pathPoint struct {
|
type pathPoint struct {
|
||||||
|
@ -34,7 +37,11 @@ const (
|
||||||
|
|
||||||
// NewPath2D creates a new Path2D and returns it
|
// NewPath2D creates a new Path2D and returns it
|
||||||
func (cv *Canvas) NewPath2D() *Path2D {
|
func (cv *Canvas) NewPath2D() *Path2D {
|
||||||
return &Path2D{cv: cv, p: make([]pathPoint, 0, 20)}
|
return &Path2D{cv: cv, p: make([]pathPoint, 0, 20), standalone: true}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Path2D) clearCache() {
|
||||||
|
p.fillCache = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// func (p *Path2D) AddPath(p2 *Path2D) {
|
// func (p *Path2D) AddPath(p2 *Path2D) {
|
||||||
|
@ -45,6 +52,7 @@ func (p *Path2D) MoveTo(x, y float64) {
|
||||||
if len(p.p) > 0 && isSamePoint(p.p[len(p.p)-1].pos, backendbase.Vec{x, y}, 0.1) {
|
if len(p.p) > 0 && isSamePoint(p.p[len(p.p)-1].pos, backendbase.Vec{x, y}, 0.1) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
p.clearCache()
|
||||||
p.p = append(p.p, pathPoint{pos: backendbase.Vec{x, y}, flags: pathMove | pathIsConvex})
|
p.p = append(p.p, pathPoint{pos: backendbase.Vec{x, y}, flags: pathMove | pathIsConvex})
|
||||||
p.cwSum = 0
|
p.cwSum = 0
|
||||||
p.move = backendbase.Vec{x, y}
|
p.move = backendbase.Vec{x, y}
|
||||||
|
@ -60,6 +68,7 @@ func (p *Path2D) lineTo(x, y float64, checkSelfIntersection bool) {
|
||||||
if count > 0 && isSamePoint(p.p[len(p.p)-1].pos, backendbase.Vec{x, y}, 0.1) {
|
if count > 0 && isSamePoint(p.p[len(p.p)-1].pos, backendbase.Vec{x, y}, 0.1) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
p.clearCache()
|
||||||
if count == 0 {
|
if count == 0 {
|
||||||
p.MoveTo(x, y)
|
p.MoveTo(x, y)
|
||||||
return
|
return
|
||||||
|
|
28
paths.go
28
paths.go
|
@ -110,7 +110,7 @@ func (cv *Canvas) strokePath(path *Path2D, inv backendbase.Mat, doInv bool) {
|
||||||
cv.drawShadow(tris, nil, true)
|
cv.drawShadow(tris, nil, true)
|
||||||
|
|
||||||
stl := cv.backendFillStyle(&cv.state.stroke, 1)
|
stl := cv.backendFillStyle(&cv.state.stroke, 1)
|
||||||
cv.b.Fill(&stl, tris, true)
|
cv.b.Fill(&stl, tris, backendbase.MatIdentity, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cv *Canvas) strokeTris(path *Path2D, inv backendbase.Mat, doInv bool, target []backendbase.Vec) []backendbase.Vec {
|
func (cv *Canvas) strokeTris(path *Path2D, inv backendbase.Mat, doInv bool, target []backendbase.Vec) []backendbase.Vec {
|
||||||
|
@ -381,13 +381,25 @@ func (cv *Canvas) fillPath(path *Path2D, tf backendbase.Mat) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var tris []backendbase.Vec
|
||||||
var triBuf [500]backendbase.Vec
|
var triBuf [500]backendbase.Vec
|
||||||
tris := triBuf[:0]
|
if path.standalone && path.fillCache != nil {
|
||||||
|
tris = path.fillCache
|
||||||
|
} else {
|
||||||
|
if path.standalone {
|
||||||
|
tris = make([]backendbase.Vec, 0, 500)
|
||||||
|
} else {
|
||||||
|
tris = triBuf[:0]
|
||||||
|
}
|
||||||
|
runSubPaths(path.p, true, func(sp []pathPoint) bool {
|
||||||
|
tris = appendSubPathTriangles(tris, backendbase.MatIdentity, sp)
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
if path.standalone {
|
||||||
|
path.fillCache = tris
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
runSubPaths(path.p, true, func(sp []pathPoint) bool {
|
|
||||||
tris = appendSubPathTriangles(tris, tf, sp)
|
|
||||||
return false
|
|
||||||
})
|
|
||||||
if len(tris) == 0 {
|
if len(tris) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -395,7 +407,7 @@ func (cv *Canvas) fillPath(path *Path2D, tf backendbase.Mat) {
|
||||||
cv.drawShadow(tris, nil, false)
|
cv.drawShadow(tris, nil, false)
|
||||||
|
|
||||||
stl := cv.backendFillStyle(&cv.state.fill, 1)
|
stl := cv.backendFillStyle(&cv.state.fill, 1)
|
||||||
cv.b.Fill(&stl, tris, false)
|
cv.b.Fill(&stl, tris, tf, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func appendSubPathTriangles(tris []backendbase.Vec, mat backendbase.Mat, path []pathPoint) []backendbase.Vec {
|
func appendSubPathTriangles(tris []backendbase.Vec, mat backendbase.Mat, path []pathPoint) []backendbase.Vec {
|
||||||
|
@ -504,7 +516,7 @@ func (cv *Canvas) FillRect(x, y, w, h float64) {
|
||||||
cv.drawShadow(data[:], nil, false)
|
cv.drawShadow(data[:], nil, false)
|
||||||
|
|
||||||
stl := cv.backendFillStyle(&cv.state.fill, 1)
|
stl := cv.backendFillStyle(&cv.state.fill, 1)
|
||||||
cv.b.Fill(&stl, data[:], false)
|
cv.b.Fill(&stl, data[:], backendbase.MatIdentity, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClearRect sets the color of the rectangle to transparent black
|
// ClearRect sets the color of the rectangle to transparent black
|
||||||
|
|
|
@ -38,6 +38,6 @@ func (cv *Canvas) drawShadow(pts []backendbase.Vec, mask *image.Alpha, canOverla
|
||||||
copy(quad[:], cv.shadowBuf)
|
copy(quad[:], cv.shadowBuf)
|
||||||
cv.b.FillImageMask(&style, mask, quad)
|
cv.b.FillImageMask(&style, mask, quad)
|
||||||
} else {
|
} else {
|
||||||
cv.b.Fill(&style, cv.shadowBuf, canOverlap)
|
cv.b.Fill(&style, cv.shadowBuf, backendbase.MatIdentity, canOverlap)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue