From 896af05ba4f1ebb097d5d46772ae4d706db88eb8 Mon Sep 17 00:00:00 2001 From: Thomas Friedel Date: Tue, 17 Mar 2020 15:22:56 +0100 Subject: [PATCH] updated xmobile backend --- backend/xmobilebackend/clip.go | 16 +- backend/xmobilebackend/fill.go | 208 +++++----- backend/xmobilebackend/gen/gen.go | 19 +- backend/xmobilebackend/gradients.go | 10 +- backend/xmobilebackend/imagedata.go | 22 +- backend/xmobilebackend/images.go | 22 +- backend/xmobilebackend/shaders.go | 562 ++++++---------------------- backend/xmobilebackend/xmobile.go | 280 +++----------- 8 files changed, 309 insertions(+), 830 deletions(-) diff --git a/backend/xmobilebackend/clip.go b/backend/xmobilebackend/clip.go index fbf1034..7644d8e 100755 --- a/backend/xmobilebackend/clip.go +++ b/backend/xmobilebackend/clip.go @@ -33,13 +33,15 @@ func (b *XMobileBackend) Clip(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) - b.glctx.VertexAttribPointer(b.sr.Vertex, 2, gl.FLOAT, false, 0, 0) + b.glctx.VertexAttribPointer(b.shd.Vertex, 2, gl.FLOAT, false, 0, 0) - b.glctx.UseProgram(b.sr.ID) - b.glctx.Uniform4f(b.sr.Color, 1, 1, 1, 1) - b.glctx.Uniform2f(b.sr.CanvasSize, float32(b.fw), float32(b.fh)) - b.glctx.Uniform1f(b.sr.GlobalAlpha, 1) - b.glctx.EnableVertexAttribArray(b.sr.Vertex) + b.glctx.UseProgram(b.shd.ID) + b.glctx.Uniform4f(b.shd.Color, 1, 1, 1, 1) + b.glctx.Uniform2f(b.shd.CanvasSize, float32(b.fw), float32(b.fh)) + b.glctx.Uniform1f(b.shd.GlobalAlpha, 1) + b.glctx.Uniform1i(b.shd.UseAlphaTex, 0) + b.glctx.Uniform1i(b.shd.Func, shdFuncSolid) + b.glctx.EnableVertexAttribArray(b.shd.Vertex) b.glctx.ColorMask(false, false, false, false) @@ -61,7 +63,7 @@ func (b *XMobileBackend) Clip(pts [][2]float64) { b.glctx.StencilOp(gl.ZERO, gl.ZERO, gl.ZERO) b.glctx.DrawArrays(gl.TRIANGLE_FAN, 0, 4) - b.glctx.DisableVertexAttribArray(b.sr.Vertex) + b.glctx.DisableVertexAttribArray(b.shd.Vertex) b.glctx.ColorMask(true, true, true, true) b.glctx.StencilOp(gl.KEEP, gl.KEEP, gl.KEEP) diff --git a/backend/xmobilebackend/fill.go b/backend/xmobilebackend/fill.go index 1bb02f1..57b27ac 100755 --- a/backend/xmobilebackend/fill.go +++ b/backend/xmobilebackend/fill.go @@ -33,10 +33,12 @@ func (b *XMobileBackend) Clear(pts [4][2]float64) { float32(pts[2][0]), float32(pts[2][1]), float32(pts[3][0]), float32(pts[3][1])} - b.glctx.UseProgram(b.sr.ID) - b.glctx.Uniform2f(b.sr.CanvasSize, float32(b.fw), float32(b.fh)) - b.glctx.Uniform4f(b.sr.Color, 0, 0, 0, 0) - b.glctx.Uniform1f(b.sr.GlobalAlpha, 1) + b.glctx.UseProgram(b.shd.ID) + b.glctx.Uniform2f(b.shd.CanvasSize, float32(b.fw), float32(b.fh)) + b.glctx.Uniform4f(b.shd.Color, 0, 0, 0, 0) + b.glctx.Uniform1f(b.shd.GlobalAlpha, 1) + b.glctx.Uniform1i(b.shd.UseAlphaTex, 0) + b.glctx.Uniform1i(b.shd.Func, shdFuncSolid) b.glctx.Disable(gl.BLEND) @@ -45,10 +47,10 @@ func (b *XMobileBackend) Clear(pts [4][2]float64) { b.glctx.StencilFunc(gl.EQUAL, 0, 0xFF) - b.glctx.VertexAttribPointer(b.sr.Vertex, 2, gl.FLOAT, false, 0, 0) - b.glctx.EnableVertexAttribArray(b.sr.Vertex) + b.glctx.VertexAttribPointer(b.shd.Vertex, 2, gl.FLOAT, false, 0, 0) + b.glctx.EnableVertexAttribArray(b.shd.Vertex) b.glctx.DrawArrays(gl.TRIANGLE_FAN, 0, 4) - b.glctx.DisableVertexAttribArray(b.sr.Vertex) + b.glctx.DisableVertexAttribArray(b.shd.Vertex) b.glctx.StencilFunc(gl.ALWAYS, 0, 0xFF) @@ -70,6 +72,8 @@ func (b *XMobileBackend) clearRect(x, y, w, h int) { } func extent(pts [][2]float64) (min, max vec) { + max[0] = -math.MaxFloat64 + max[1] = -math.MaxFloat64 min[0] = math.MaxFloat64 min[1] = math.MaxFloat64 for _, v := range pts { @@ -111,7 +115,7 @@ func (b *XMobileBackend) Fill(style *backendbase.FillStyle, pts [][2]float64, ca 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 { - vertex := b.useShader(style) + vertex, _ := b.useShader(style, false, 0) b.glctx.StencilFunc(gl.EQUAL, 0, 0xFF) b.glctx.EnableVertexAttribArray(vertex) @@ -125,21 +129,23 @@ func (b *XMobileBackend) Fill(style *backendbase.FillStyle, pts [][2]float64, ca b.glctx.StencilOp(gl.REPLACE, gl.REPLACE, gl.REPLACE) b.glctx.StencilMask(0x01) - b.glctx.UseProgram(b.sr.ID) - b.glctx.Uniform4f(b.sr.Color, 0, 0, 0, 0) - b.glctx.Uniform2f(b.sr.CanvasSize, float32(b.fw), float32(b.fh)) - b.glctx.Uniform1f(b.sr.GlobalAlpha, 1) + b.glctx.UseProgram(b.shd.ID) + b.glctx.Uniform4f(b.shd.Color, 0, 0, 0, 0) + b.glctx.Uniform2f(b.shd.CanvasSize, float32(b.fw), float32(b.fh)) + b.glctx.Uniform1f(b.shd.GlobalAlpha, 1) + b.glctx.Uniform1i(b.shd.UseAlphaTex, 0) + b.glctx.Uniform1i(b.shd.Func, shdFuncSolid) - b.glctx.EnableVertexAttribArray(b.sr.Vertex) - b.glctx.VertexAttribPointer(b.sr.Vertex, 2, gl.FLOAT, false, 0, 0) + b.glctx.EnableVertexAttribArray(b.shd.Vertex) + b.glctx.VertexAttribPointer(b.shd.Vertex, 2, gl.FLOAT, false, 0, 0) b.glctx.DrawArrays(mode, 4, len(pts)) - b.glctx.DisableVertexAttribArray(b.sr.Vertex) + b.glctx.DisableVertexAttribArray(b.shd.Vertex) b.glctx.ColorMask(true, true, true, true) b.glctx.StencilFunc(gl.EQUAL, 1, 0xFF) - vertex := b.useShader(style) + vertex, _ := b.useShader(style, false, 0) b.glctx.EnableVertexAttribArray(vertex) b.glctx.VertexAttribPointer(vertex, 2, gl.FLOAT, false, 0, 0) @@ -154,7 +160,7 @@ func (b *XMobileBackend) Fill(style *backendbase.FillStyle, pts [][2]float64, ca } if style.Blur > 0 { - b.drawBlurred(style.Blur) + b.drawBlurred(style.Blur, min, max) } } @@ -181,7 +187,7 @@ func (b *XMobileBackend) FillImageMask(style *backendbase.FillStyle, mask *image b.glctx.BindBuffer(gl.ARRAY_BUFFER, b.buf) - vertex, alphaTexCoord := b.useAlphaShader(style, 1) + vertex, alphaTexCoord := b.useShader(style, true, 1) b.glctx.EnableVertexAttribArray(vertex) b.glctx.EnableVertexAttribArray(alphaTexCoord) @@ -216,105 +222,103 @@ func (b *XMobileBackend) FillImageMask(style *backendbase.FillStyle, mask *image b.glctx.ActiveTexture(gl.TEXTURE0) if style.Blur > 0 { - b.drawBlurred(style.Blur) + min, max := extent(pts[:]) + b.drawBlurred(style.Blur, min, max) } } -func (b *XMobileBackend) drawBlurred(blur float64) { - b.glctx.BlendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA) +func (b *XMobileBackend) drawBlurred(size float64, min, max vec) { + b.offscr1.alpha = true + b.offscr2.alpha = true - var kernel []float32 - var kernelBuf [255]float32 - var gs *gaussianShader - if blur < 3 { - gs = &b.gauss15r - kernel = kernelBuf[:15] - } else if blur < 12 { - gs = &b.gauss63r - kernel = kernelBuf[:63] - } else { - gs = &b.gauss127r - kernel = kernelBuf[:127] + // calculate box blur size + fsize := math.Max(1, math.Floor(size)) + sizea := int(fsize) + sizeb := sizea + sizec := sizea + if size-fsize > 0.333333333 { + sizeb++ + } + if size-fsize > 0.666666666 { + sizec++ } - gaussianKernel(blur, kernel) + min[0] -= fsize * 3 + min[1] -= fsize * 3 + max[0] += fsize * 3 + max[1] += fsize * 3 + min[0] = math.Max(0.0, math.Min(b.fw, min[0])) + min[1] = math.Max(0.0, math.Min(b.fh, min[1])) + max[0] = math.Max(0.0, math.Min(b.fw, max[0])) + max[1] = math.Max(0.0, math.Min(b.fh, max[1])) + + b.glctx.BindBuffer(gl.ARRAY_BUFFER, b.shadowBuf) + data := [16]float32{ + float32(min[0]), float32(min[1]), + float32(min[0]), float32(max[1]), + float32(max[0]), float32(max[1]), + float32(max[0]), float32(min[1]), + float32(min[0] / b.fw), 1 - float32(min[1]/b.fh), + float32(min[0] / b.fw), 1 - float32(max[1]/b.fh), + float32(max[0] / b.fw), 1 - float32(max[1]/b.fh), + float32(max[0] / b.fw), 1 - float32(min[1]/b.fh), + } + b.glctx.BufferData(gl.ARRAY_BUFFER, byteSlice(unsafe.Pointer(&data[0]), len(data)*4), gl.STREAM_DRAW) + + b.glctx.UseProgram(b.shd.ID) + b.glctx.Uniform1i(b.shd.Image, 0) + b.glctx.Uniform2f(b.shd.CanvasSize, float32(b.fw), float32(b.fh)) + b.glctx.Uniform1i(b.shd.UseAlphaTex, 0) + b.glctx.Uniform1i(b.shd.Func, shdFuncBoxBlur) + + b.glctx.VertexAttribPointer(b.shd.Vertex, 2, gl.FLOAT, false, 0, 0) + b.glctx.VertexAttribPointer(b.shd.TexCoord, 2, gl.FLOAT, false, 0, 8*4) + b.glctx.EnableVertexAttribArray(b.shd.Vertex) + b.glctx.EnableVertexAttribArray(b.shd.TexCoord) + + b.glctx.Disable(gl.BLEND) + + b.glctx.ActiveTexture(gl.TEXTURE0) - b.offscr2.alpha = true - b.enableTextureRenderTarget(&b.offscr2) b.glctx.ClearColor(0, 0, 0, 0) - b.glctx.Clear(gl.COLOR_BUFFER_BIT | gl.STENCIL_BUFFER_BIT) - b.glctx.StencilFunc(gl.EQUAL, 0, 0xFF) - - b.glctx.BindBuffer(gl.ARRAY_BUFFER, b.shadowBuf) - data := [16]float32{0, 0, 0, float32(b.h), float32(b.w), float32(b.h), float32(b.w), 0, 0, 0, 0, 1, 1, 1, 1, 0} - b.glctx.BufferData(gl.ARRAY_BUFFER, byteSlice(unsafe.Pointer(&data[0]), len(data)*4), gl.STREAM_DRAW) - - b.glctx.ActiveTexture(gl.TEXTURE0) + b.enableTextureRenderTarget(&b.offscr2) b.glctx.BindTexture(gl.TEXTURE_2D, b.offscr1.tex) - - b.glctx.UseProgram(gs.ID) - b.glctx.Uniform1i(gs.Image, 0) - b.glctx.Uniform2f(gs.CanvasSize, float32(b.fw), float32(b.fh)) - b.glctx.Uniform2f(gs.KernelScale, 1.0/float32(b.fw), 0.0) - b.glctx.Uniform1fv(gs.Kernel, kernel) - b.glctx.VertexAttribPointer(gs.Vertex, 2, gl.FLOAT, false, 0, 0) - b.glctx.VertexAttribPointer(gs.TexCoord, 2, gl.FLOAT, false, 0, 8*4) - b.glctx.EnableVertexAttribArray(gs.Vertex) - b.glctx.EnableVertexAttribArray(gs.TexCoord) - b.glctx.DrawArrays(gl.TRIANGLE_FAN, 0, 4) - b.glctx.DisableVertexAttribArray(gs.Vertex) - b.glctx.DisableVertexAttribArray(gs.TexCoord) - - b.glctx.StencilFunc(gl.ALWAYS, 0, 0xFF) - - b.disableTextureRenderTarget() - - b.glctx.StencilFunc(gl.EQUAL, 0, 0xFF) - - b.glctx.BindBuffer(gl.ARRAY_BUFFER, b.shadowBuf) - data = [16]float32{0, 0, 0, float32(b.h), float32(b.w), float32(b.h), float32(b.w), 0, 0, 0, 0, 1, 1, 1, 1, 0} - b.glctx.BufferData(gl.ARRAY_BUFFER, byteSlice(unsafe.Pointer(&data[0]), len(data)*4), gl.STREAM_DRAW) - - b.glctx.ActiveTexture(gl.TEXTURE0) + b.glctx.Clear(gl.COLOR_BUFFER_BIT | gl.STENCIL_BUFFER_BIT) + b.box3(sizea, 0, false) + b.enableTextureRenderTarget(&b.offscr1) b.glctx.BindTexture(gl.TEXTURE_2D, b.offscr2.tex) + b.box3(sizeb, -0.5, false) + b.enableTextureRenderTarget(&b.offscr2) + b.glctx.BindTexture(gl.TEXTURE_2D, b.offscr1.tex) + b.box3(sizec, 0, false) + b.enableTextureRenderTarget(&b.offscr1) + b.glctx.BindTexture(gl.TEXTURE_2D, b.offscr2.tex) + b.box3(sizea, 0, true) + b.enableTextureRenderTarget(&b.offscr2) + b.glctx.BindTexture(gl.TEXTURE_2D, b.offscr1.tex) + b.box3(sizeb, -0.5, true) + b.glctx.Enable(gl.BLEND) + b.glctx.BlendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA) + b.disableTextureRenderTarget() + b.glctx.BindTexture(gl.TEXTURE_2D, b.offscr2.tex) + b.box3(sizec, 0, true) - b.glctx.UseProgram(gs.ID) - b.glctx.Uniform1i(gs.Image, 0) - b.glctx.Uniform2f(gs.CanvasSize, float32(b.fw), float32(b.fh)) - b.glctx.Uniform2f(gs.KernelScale, 0.0, 1.0/float32(b.fh)) - b.glctx.Uniform1fv(gs.Kernel, kernel) - b.glctx.VertexAttribPointer(gs.Vertex, 2, gl.FLOAT, false, 0, 0) - b.glctx.VertexAttribPointer(gs.TexCoord, 2, gl.FLOAT, false, 0, 8*4) - b.glctx.EnableVertexAttribArray(gs.Vertex) - b.glctx.EnableVertexAttribArray(gs.TexCoord) - b.glctx.DrawArrays(gl.TRIANGLE_FAN, 0, 4) - b.glctx.DisableVertexAttribArray(gs.Vertex) - b.glctx.DisableVertexAttribArray(gs.TexCoord) - - b.glctx.StencilFunc(gl.ALWAYS, 0, 0xFF) + b.glctx.DisableVertexAttribArray(b.shd.Vertex) + b.glctx.DisableVertexAttribArray(b.shd.TexCoord) b.glctx.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) } -func gaussianKernel(stddev float64, target []float32) { - stddevSqr := stddev * stddev - center := float64(len(target) / 2) - factor := 1.0 / math.Sqrt(2*math.Pi*stddevSqr) - for i := range target { - x := float64(i) - center - target[i] = float32(factor * math.Pow(math.E, -x*x/(2*stddevSqr))) - } - // normalizeKernel(target) -} - -func normalizeKernel(kernel []float32) { - var sum float32 - for _, v := range kernel { - sum += v - } - factor := 1.0 / sum - for i := range kernel { - kernel[i] *= factor +func (b *XMobileBackend) box3(size int, offset float32, vertical bool) { + b.glctx.Uniform1i(b.shd.BoxSize, size) + if vertical { + b.glctx.Uniform1i(b.shd.BoxVertical, 1) + b.glctx.Uniform1f(b.shd.BoxScale, 1/float32(b.fh)) + } else { + b.glctx.Uniform1i(b.shd.BoxVertical, 0) + b.glctx.Uniform1f(b.shd.BoxScale, 1/float32(b.fw)) } + b.glctx.Uniform1f(b.shd.BoxOffset, offset) + b.glctx.DrawArrays(gl.TRIANGLE_FAN, 0, 4) } diff --git a/backend/xmobilebackend/gen/gen.go b/backend/xmobilebackend/gen/gen.go index 303e3e9..9d388e8 100644 --- a/backend/xmobilebackend/gen/gen.go +++ b/backend/xmobilebackend/gen/gen.go @@ -142,6 +142,12 @@ func rewrite(filename, src string) (string, string) { params[2] = params[2][1 : len(params[2])-3] return "b.glctx.Uniform1fv(" + params[0] + ", " + params[2] + ")" }) + src = rewriteCalls(src, "b.glctx.Uniform1i", func(params []string) string { + if strings.HasPrefix(params[1], "int32(") { + params[1] = params[1][6 : len(params[1])-1] + } + return "b.glctx.Uniform1i(" + strings.Join(params, ",") + ")" + }) src = rewriteCalls(src, "b.glctx.UniformMatrix3fv", func(params []string) string { return "b.glctx.UniformMatrix3fv(" + params[0] + ", " + params[3][1:len(params[3])-3] + "[:])" }) @@ -364,23 +370,18 @@ func byteSlice(ptr unsafe.Pointer, size int) []byte { func rewriteShaders(src string) string { src = strings.Replace(src, - `import ( - "bytes" - "fmt" - "strings" -) + `package xmobilebackend `, - `import ( - "bytes" - "fmt" - "strings" + `package xmobilebackend +import ( "golang.org/x/mobile/gl" ) `, 1) src = strings.Replace(src, "uint32", "gl.Attrib", -1) src = strings.Replace(src, "int32", "gl.Uniform", -1) + src = strings.Replace(src, "shdFuncSolid gl.Uniform", "shdFuncSolid int", -1) return src } diff --git a/backend/xmobilebackend/gradients.go b/backend/xmobilebackend/gradients.go index 8163f64..9367dca 100755 --- a/backend/xmobilebackend/gradients.go +++ b/backend/xmobilebackend/gradients.go @@ -24,9 +24,8 @@ type RadialGradient struct { } type gradient struct { - b *XMobileBackend - tex gl.Texture - loaded bool + b *XMobileBackend + tex gl.Texture } func (b *XMobileBackend) LoadLinearGradient(data backendbase.Gradient) backendbase.LinearGradient { @@ -86,10 +85,6 @@ func (rg *RadialGradient) Replace(data backendbase.Gradient) { rg.load(data) } func (g *gradient) load(stops backendbase.Gradient) { b := g.b - if g.loaded { - return - } - g.b.activate() b.glctx.ActiveTexture(gl.TEXTURE0) @@ -106,5 +101,4 @@ func (g *gradient) load(stops backendbase.Gradient) { } b.glctx.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 2048, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixels[0:]) - g.loaded = true } diff --git a/backend/xmobilebackend/imagedata.go b/backend/xmobilebackend/imagedata.go index a119b5a..4e71591 100755 --- a/backend/xmobilebackend/imagedata.go +++ b/backend/xmobilebackend/imagedata.go @@ -85,15 +85,17 @@ func (b *XMobileBackend) PutImageData(img *image.RGBA, x, y int) { 0, 0, 1, 0, 1, 1, 0, 1} b.glctx.BufferData(gl.ARRAY_BUFFER, byteSlice(unsafe.Pointer(&data[0]), len(data)*4), gl.STREAM_DRAW) - b.glctx.UseProgram(b.ir.ID) - b.glctx.Uniform1i(b.ir.Image, 0) - b.glctx.Uniform2f(b.ir.CanvasSize, float32(b.fw), float32(b.fh)) - b.glctx.Uniform1f(b.ir.GlobalAlpha, 1) - b.glctx.VertexAttribPointer(b.ir.Vertex, 2, gl.FLOAT, false, 0, 0) - b.glctx.VertexAttribPointer(b.ir.TexCoord, 2, gl.FLOAT, false, 0, 8*4) - b.glctx.EnableVertexAttribArray(b.ir.Vertex) - b.glctx.EnableVertexAttribArray(b.ir.TexCoord) + b.glctx.UseProgram(b.shd.ID) + b.glctx.Uniform1i(b.shd.Image, 0) + b.glctx.Uniform2f(b.shd.CanvasSize, float32(b.fw), float32(b.fh)) + b.glctx.Uniform1f(b.shd.GlobalAlpha, 1) + b.glctx.Uniform1i(b.shd.UseAlphaTex, 0) + b.glctx.Uniform1i(b.shd.Func, shdFuncImage) + b.glctx.VertexAttribPointer(b.shd.Vertex, 2, gl.FLOAT, false, 0, 0) + b.glctx.VertexAttribPointer(b.shd.TexCoord, 2, gl.FLOAT, false, 0, 8*4) + b.glctx.EnableVertexAttribArray(b.shd.Vertex) + b.glctx.EnableVertexAttribArray(b.shd.TexCoord) b.glctx.DrawArrays(gl.TRIANGLE_FAN, 0, 4) - b.glctx.DisableVertexAttribArray(b.ir.Vertex) - b.glctx.DisableVertexAttribArray(b.ir.TexCoord) + b.glctx.DisableVertexAttribArray(b.shd.Vertex) + b.glctx.DisableVertexAttribArray(b.shd.TexCoord) } diff --git a/backend/xmobilebackend/images.go b/backend/xmobilebackend/images.go index 41d2751..541143a 100755 --- a/backend/xmobilebackend/images.go +++ b/backend/xmobilebackend/images.go @@ -196,17 +196,19 @@ func (b *XMobileBackend) DrawImage(dimg backendbase.Image, sx, sy, sw, sh float6 b.glctx.ActiveTexture(gl.TEXTURE0) b.glctx.BindTexture(gl.TEXTURE_2D, img.tex) - b.glctx.UseProgram(b.ir.ID) - b.glctx.Uniform1i(b.ir.Image, 0) - b.glctx.Uniform2f(b.ir.CanvasSize, float32(b.fw), float32(b.fh)) - b.glctx.Uniform1f(b.ir.GlobalAlpha, float32(alpha)) - b.glctx.VertexAttribPointer(b.ir.Vertex, 2, gl.FLOAT, false, 0, 0) - b.glctx.VertexAttribPointer(b.ir.TexCoord, 2, gl.FLOAT, false, 0, 8*4) - b.glctx.EnableVertexAttribArray(b.ir.Vertex) - b.glctx.EnableVertexAttribArray(b.ir.TexCoord) + b.glctx.UseProgram(b.shd.ID) + b.glctx.Uniform1i(b.shd.Image, 0) + b.glctx.Uniform2f(b.shd.CanvasSize, float32(b.fw), float32(b.fh)) + b.glctx.Uniform1f(b.shd.GlobalAlpha, float32(alpha)) + b.glctx.Uniform1i(b.shd.UseAlphaTex, 0) + b.glctx.Uniform1i(b.shd.Func, shdFuncImage) + b.glctx.VertexAttribPointer(b.shd.Vertex, 2, gl.FLOAT, false, 0, 0) + b.glctx.VertexAttribPointer(b.shd.TexCoord, 2, gl.FLOAT, false, 0, 8*4) + b.glctx.EnableVertexAttribArray(b.shd.Vertex) + b.glctx.EnableVertexAttribArray(b.shd.TexCoord) b.glctx.DrawArrays(gl.TRIANGLE_FAN, 0, 4) - b.glctx.DisableVertexAttribArray(b.ir.Vertex) - b.glctx.DisableVertexAttribArray(b.ir.TexCoord) + b.glctx.DisableVertexAttribArray(b.shd.Vertex) + b.glctx.DisableVertexAttribArray(b.shd.TexCoord) b.glctx.StencilFunc(gl.ALWAYS, 0, 0xFF) } diff --git a/backend/xmobilebackend/shaders.go b/backend/xmobilebackend/shaders.go index cae0b26..124eb8f 100755 --- a/backend/xmobilebackend/shaders.go +++ b/backend/xmobilebackend/shaders.go @@ -1,492 +1,158 @@ package xmobilebackend import ( - "bytes" - "fmt" - "strings" - "golang.org/x/mobile/gl" ) -var imageVS = ` +var unifiedVS = ` attribute vec2 vertex, texCoord; -uniform vec2 canvasSize; -varying vec2 v_texCoord; -void main() { - v_texCoord = texCoord; - vec2 glp = vertex * 2.0 / canvasSize - 1.0; - gl_Position = vec4(glp.x, -glp.y, 0.0, 1.0); -}` -var imageFS = ` -#ifdef GL_ES -precision mediump float; -#endif -varying vec2 v_texCoord; -uniform sampler2D image; -uniform float globalAlpha; -void main() { - vec4 col = texture2D(image, v_texCoord); - col.a *= globalAlpha; - gl_FragColor = col; -}` -var solidVS = ` -attribute vec2 vertex; uniform vec2 canvasSize; + +varying vec2 v_cp, v_tc; + void main() { + v_tc = texCoord; + v_cp = vertex; vec2 glp = vertex * 2.0 / canvasSize - 1.0; gl_Position = vec4(glp.x, -glp.y, 0.0, 1.0); -}` -var solidFS = ` +} +` +var unifiedFS = ` #ifdef GL_ES precision mediump float; #endif + +varying vec2 v_cp, v_tc; + +uniform int func; + uniform vec4 color; uniform float globalAlpha; + +uniform sampler2D gradient; +uniform vec2 from, dir, to; +uniform float len, radFrom, radTo; + +uniform vec2 imageSize; +uniform sampler2D image; +uniform mat3 imageTransform; +uniform vec2 repeat; + +uniform bool useAlphaTex; +uniform sampler2D alphaTex; + +uniform int boxSize; +uniform bool boxVertical; +uniform float boxScale; +uniform float boxOffset; + +bool isNaN(float v) { + return v < 0.0 || 0.0 < v || v == 0.0 ? false : true; +} + void main() { vec4 col = color; - col.a *= globalAlpha; - gl_FragColor = col; -}` -var linearGradientVS = ` -attribute vec2 vertex; -uniform vec2 canvasSize; -varying vec2 v_cp; -void main() { - v_cp = vertex; - vec2 glp = vertex * 2.0 / canvasSize - 1.0; - gl_Position = vec4(glp.x, -glp.y, 0.0, 1.0); -}` -var linearGradientFS = ` -#ifdef GL_ES -precision mediump float; -#endif -varying vec2 v_cp; -uniform sampler2D gradient; -uniform vec2 from, dir; -uniform float len; -uniform float globalAlpha; -void main() { - vec2 v = v_cp - from; - float r = dot(v, dir) / len; - r = clamp(r, 0.0, 1.0); - vec4 col = texture2D(gradient, vec2(r, 0.0)); - col.a *= globalAlpha; - gl_FragColor = col; -}` - -var radialGradientVS = ` -attribute vec2 vertex; -uniform vec2 canvasSize; -varying vec2 v_cp; -void main() { - v_cp = vertex; - vec2 glp = vertex * 2.0 / canvasSize - 1.0; - gl_Position = vec4(glp.x, -glp.y, 0.0, 1.0); -}` -var radialGradientFS = ` -#ifdef GL_ES -precision mediump float; -#endif -varying vec2 v_cp; -uniform sampler2D gradient; -uniform vec2 from, to; -uniform float radFrom, radTo; -uniform float globalAlpha; -bool isNaN(float v) { - return v < 0.0 || 0.0 < v || v == 0.0 ? false : true; -} -void main() { - float o_a = 0.5 * sqrt( - pow(-2.0*from.x*from.x+2.0*from.x*to.x+2.0*from.x*v_cp.x-2.0*to.x*v_cp.x-2.0*from.y*from.y+2.0*from.y*to.y+2.0*from.y*v_cp.y-2.0*to.y*v_cp.y+2.0*radFrom*radFrom-2.0*radFrom*radTo, 2.0) - -4.0*(from.x*from.x-2.0*from.x*v_cp.x+v_cp.x*v_cp.x+from.y*from.y-2.0*from.y*v_cp.y+v_cp.y*v_cp.y-radFrom*radFrom) - *(from.x*from.x-2.0*from.x*to.x+to.x*to.x+from.y*from.y-2.0*from.y*to.y+to.y*to.y-radFrom*radFrom+2.0*radFrom*radTo-radTo*radTo) - ); - float o_b = (from.x*from.x-from.x*to.x-from.x*v_cp.x+to.x*v_cp.x+from.y*from.y-from.y*to.y-from.y*v_cp.y+to.y*v_cp.y-radFrom*radFrom+radFrom*radTo); - float o_c = (from.x*from.x-2.0*from.x*to.x+to.x*to.x+from.y*from.y-2.0*from.y*to.y+to.y*to.y-radFrom*radFrom+2.0*radFrom*radTo-radTo*radTo); - float o1 = (-o_a + o_b) / o_c; - float o2 = (o_a + o_b) / o_c; - if (isNaN(o1) && isNaN(o2)) { - gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0); + if (func == 5) { + vec4 sum = vec4(0.0); + if (boxVertical) { + vec2 start = v_tc - vec2(0.0, (float(boxSize) * 0.5 + boxOffset) * boxScale); + for (int i=0; i <= boxSize; i++) { + sum += texture2D(image, start + vec2(0.0, float(i) * boxScale)); + } + } else { + vec2 start = v_tc - vec2((float(boxSize) * 0.5 + boxOffset) * boxScale, 0.0); + for (int i=0; i <= boxSize; i++) { + sum += texture2D(image, start + vec2(float(i) * boxScale, 0.0)); + } + } + gl_FragColor = sum / float(boxSize+1); return; } - float o = max(o1, o2); - //float r = radFrom + o * (radTo - radFrom); - vec4 col = texture2D(gradient, vec2(o, 0.0)); - col.a *= globalAlpha; - gl_FragColor = col; -}` -var imagePatternVS = ` -attribute vec2 vertex; -uniform vec2 canvasSize; -varying vec2 v_cp; -void main() { - v_cp = vertex; - vec2 glp = vertex * 2.0 / canvasSize - 1.0; - gl_Position = vec4(glp.x, -glp.y, 0.0, 1.0); -}` -var imagePatternFS = ` -#ifdef GL_ES -precision mediump float; -#endif -varying vec2 v_cp; -uniform vec2 imageSize; -uniform sampler2D image; -uniform mat3 imageTransform; -uniform vec2 repeat; -uniform float globalAlpha; -void main() { - vec3 tfpt = vec3(v_cp, 1.0) * imageTransform; - vec2 imgpt = tfpt.xy / imageSize; - vec4 col = texture2D(image, mod(imgpt, 1.0)); - if (imgpt.x < 0.0 || imgpt.x > 1.0) { - col *= repeat.x; + if (func == 1) { + vec2 v = v_cp - from; + float r = dot(v, dir) / len; + r = clamp(r, 0.0, 1.0); + col = texture2D(gradient, vec2(r, 0.0)); + } else if (func == 2) { + float o_a = 0.5 * sqrt( + pow(-2.0*from.x*from.x+2.0*from.x*to.x+2.0*from.x*v_cp.x-2.0*to.x*v_cp.x-2.0*from.y*from.y+2.0*from.y*to.y+2.0*from.y*v_cp.y-2.0*to.y*v_cp.y+2.0*radFrom*radFrom-2.0*radFrom*radTo, 2.0) + -4.0*(from.x*from.x-2.0*from.x*v_cp.x+v_cp.x*v_cp.x+from.y*from.y-2.0*from.y*v_cp.y+v_cp.y*v_cp.y-radFrom*radFrom) + *(from.x*from.x-2.0*from.x*to.x+to.x*to.x+from.y*from.y-2.0*from.y*to.y+to.y*to.y-radFrom*radFrom+2.0*radFrom*radTo-radTo*radTo) + ); + float o_b = (from.x*from.x-from.x*to.x-from.x*v_cp.x+to.x*v_cp.x+from.y*from.y-from.y*to.y-from.y*v_cp.y+to.y*v_cp.y-radFrom*radFrom+radFrom*radTo); + float o_c = (from.x*from.x-2.0*from.x*to.x+to.x*to.x+from.y*from.y-2.0*from.y*to.y+to.y*to.y-radFrom*radFrom+2.0*radFrom*radTo-radTo*radTo); + float o1 = (-o_a + o_b) / o_c; + float o2 = (o_a + o_b) / o_c; + if (isNaN(o1) && isNaN(o2)) { + gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0); + return; + } + float o = max(o1, o2); + o = clamp(o, 0.0, 1.0); + col = texture2D(gradient, vec2(o, 0.0)); + } else if (func == 3) { + vec3 tfpt = vec3(v_cp, 1.0) * imageTransform; + vec2 imgpt = tfpt.xy / imageSize; + col = texture2D(image, mod(imgpt, 1.0)); + if (imgpt.x < 0.0 || imgpt.x > 1.0) { + col *= repeat.x; + } + if (imgpt.y < 0.0 || imgpt.y > 1.0) { + col *= repeat.y; + } + } else if (func == 4) { + col = texture2D(image, v_tc); } - if (imgpt.y < 0.0 || imgpt.y > 1.0) { - col *= repeat.y; + + if (useAlphaTex) { + col.a *= texture2D(alphaTex, v_tc).a * globalAlpha; + } else { + col.a *= globalAlpha; } - col.a *= globalAlpha; - gl_FragColor = col; -}` -var solidAlphaVS = ` -attribute vec2 vertex, alphaTexCoord; -uniform vec2 canvasSize; -varying vec2 v_atc; -void main() { - v_atc = alphaTexCoord; - vec2 glp = vertex * 2.0 / canvasSize - 1.0; - gl_Position = vec4(glp.x, -glp.y, 0.0, 1.0); -}` -var solidAlphaFS = ` -#ifdef GL_ES -precision mediump float; -#endif -varying vec2 v_atc; -uniform vec4 color; -uniform sampler2D alphaTex; -uniform float globalAlpha; -void main() { - vec4 col = color; - col.a *= texture2D(alphaTex, v_atc).a * globalAlpha; gl_FragColor = col; -}` - -var linearGradientAlphaVS = ` -attribute vec2 vertex, alphaTexCoord; -uniform vec2 canvasSize; -varying vec2 v_cp; -varying vec2 v_atc; -void main() { - v_cp = vertex; - v_atc = alphaTexCoord; - vec2 glp = vertex * 2.0 / canvasSize - 1.0; - gl_Position = vec4(glp.x, -glp.y, 0.0, 1.0); -}` -var linearGradientAlphaFS = ` -#ifdef GL_ES -precision mediump float; -#endif -varying vec2 v_cp; -varying vec2 v_atc; -varying vec2 v_texCoord; -uniform sampler2D gradient; -uniform vec2 from, dir; -uniform float len; -uniform sampler2D alphaTex; -uniform float globalAlpha; -void main() { - vec2 v = v_cp - from; - float r = dot(v, dir) / len; - r = clamp(r, 0.0, 1.0); - vec4 col = texture2D(gradient, vec2(r, 0.0)); - col.a *= texture2D(alphaTex, v_atc).a * globalAlpha; - gl_FragColor = col; -}` - -var radialGradientAlphaVS = ` -attribute vec2 vertex, alphaTexCoord; -uniform vec2 canvasSize; -varying vec2 v_cp; -varying vec2 v_atc; -void main() { - v_cp = vertex; - v_atc = alphaTexCoord; - vec2 glp = vertex * 2.0 / canvasSize - 1.0; - gl_Position = vec4(glp.x, -glp.y, 0.0, 1.0); -}` -var radialGradientAlphaFS = ` -#ifdef GL_ES -precision mediump float; -#endif -varying vec2 v_cp; -varying vec2 v_atc; -uniform sampler2D gradient; -uniform vec2 from, to; -uniform float radFrom, radTo; -uniform sampler2D alphaTex; -uniform float globalAlpha; -bool isNaN(float v) { - return v < 0.0 || 0.0 < v || v == 0.0 ? false : true; } -void main() { - float o_a = 0.5 * sqrt( - pow(-2.0*from.x*from.x+2.0*from.x*to.x+2.0*from.x*v_cp.x-2.0*to.x*v_cp.x-2.0*from.y*from.y+2.0*from.y*to.y+2.0*from.y*v_cp.y-2.0*to.y*v_cp.y+2.0*radFrom*radFrom-2.0*radFrom*radTo, 2.0) - -4.0*(from.x*from.x-2.0*from.x*v_cp.x+v_cp.x*v_cp.x+from.y*from.y-2.0*from.y*v_cp.y+v_cp.y*v_cp.y-radFrom*radFrom) - *(from.x*from.x-2.0*from.x*to.x+to.x*to.x+from.y*from.y-2.0*from.y*to.y+to.y*to.y-radFrom*radFrom+2.0*radFrom*radTo-radTo*radTo) - ); - float o_b = (from.x*from.x-from.x*to.x-from.x*v_cp.x+to.x*v_cp.x+from.y*from.y-from.y*to.y-from.y*v_cp.y+to.y*v_cp.y-radFrom*radFrom+radFrom*radTo); - float o_c = (from.x*from.x-2.0*from.x*to.x+to.x*to.x+from.y*from.y-2.0*from.y*to.y+to.y*to.y-radFrom*radFrom+2.0*radFrom*radTo-radTo*radTo); - float o1 = (-o_a + o_b) / o_c; - float o2 = (o_a + o_b) / o_c; - if (isNaN(o1) && isNaN(o2)) { - gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0); - return; - } - float o = max(o1, o2); - //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; -}` +` -var imagePatternAlphaVS = ` -attribute vec2 vertex, alphaTexCoord; -uniform vec2 canvasSize; -varying vec2 v_cp; -varying vec2 v_atc; -void main() { - v_cp = vertex; - v_atc = alphaTexCoord; - vec2 glp = vertex * 2.0 / canvasSize - 1.0; - gl_Position = vec4(glp.x, -glp.y, 0.0, 1.0); -}` -var imagePatternAlphaFS = ` -#ifdef GL_ES -precision mediump float; -#endif -varying vec2 v_cp; -varying vec2 v_atc; -uniform vec2 imageSize; -uniform sampler2D image; -uniform mat3 imageTransform; -uniform vec2 repeat; -uniform sampler2D alphaTex; -uniform float globalAlpha; -void main() { - vec3 tfpt = vec3(v_cp, 1.0) * imageTransform; - vec2 imgpt = tfpt.xy / imageSize; - vec4 col = texture2D(image, mod(imgpt, 1.0)); - if (imgpt.x < 0.0 || imgpt.x > 1.0) { - col *= repeat.x; - } - if (imgpt.y < 0.0 || imgpt.y > 1.0) { - col *= repeat.y; - } - col.a *= texture2D(alphaTex, v_atc).a * globalAlpha; - gl_FragColor = col; -}` +const ( + shdFuncSolid int = iota + shdFuncLinearGradient + shdFuncRadialGradient + shdFuncImagePattern + shdFuncImage + shdFuncBoxBlur +) -var gaussian15VS = ` -attribute vec2 vertex, texCoord; -uniform vec2 canvasSize; -varying vec2 v_texCoord; -void main() { - v_texCoord = texCoord; - vec2 glp = vertex * 2.0 / canvasSize - 1.0; - gl_Position = vec4(glp.x, -glp.y, 0.0, 1.0); -}` -var gaussian15FS = ` -#ifdef GL_ES -precision mediump float; -#endif -varying vec2 v_texCoord; -uniform vec2 kernelScale; -uniform sampler2D image; -uniform float kernel[15]; -void main() { - vec4 color = vec4(0.0, 0.0, 0.0, 0.0); -_SUM_ - gl_FragColor = color; -}` - -var gaussian63VS = ` -attribute vec2 vertex, texCoord; -uniform vec2 canvasSize; -varying vec2 v_texCoord; -void main() { - v_texCoord = texCoord; - vec2 glp = vertex * 2.0 / canvasSize - 1.0; - gl_Position = vec4(glp.x, -glp.y, 0.0, 1.0); -}` -var gaussian63FS = ` -#ifdef GL_ES -precision mediump float; -#endif -varying vec2 v_texCoord; -uniform vec2 kernelScale; -uniform sampler2D image; -uniform float kernel[63]; -void main() { - vec4 color = vec4(0.0, 0.0, 0.0, 0.0); -_SUM_ - gl_FragColor = color; -}` - -var gaussian127VS = ` -attribute vec2 vertex, texCoord; -uniform vec2 canvasSize; -varying vec2 v_texCoord; -void main() { - v_texCoord = texCoord; - vec2 glp = vertex * 2.0 / canvasSize - 1.0; - gl_Position = vec4(glp.x, -glp.y, 0.0, 1.0); -}` -var gaussian127FS = ` -#ifdef GL_ES -precision mediump float; -#endif -varying vec2 v_texCoord; -uniform vec2 kernelScale; -uniform sampler2D image; -uniform float kernel[127]; -void main() { - vec4 color = vec4(0.0, 0.0, 0.0, 0.0); -_SUM_ - gl_FragColor = color; -}` - -func init() { - fstr := "\tcolor += texture2D(image, v_texCoord + vec2(%.1f * kernelScale.x, %.1f * kernelScale.y)) * kernel[%d];\n" - bb := bytes.Buffer{} - for i := 0; i < 127; i++ { - off := float64(i) - 63 - fmt.Fprintf(&bb, fstr, off, off, i) - } - gaussian127FS = strings.Replace(gaussian127FS, "_SUM_", bb.String(), -1) - bb.Reset() - for i := 0; i < 63; i++ { - off := float64(i) - 31 - fmt.Fprintf(&bb, fstr, off, off, i) - } - gaussian63FS = strings.Replace(gaussian63FS, "_SUM_", bb.String(), -1) - bb.Reset() - for i := 0; i < 15; i++ { - off := float64(i) - 7 - fmt.Fprintf(&bb, fstr, off, off, i) - } - gaussian15FS = strings.Replace(gaussian15FS, "_SUM_", bb.String(), -1) -} - -type solidShader struct { +type unifiedShader struct { shaderProgram - Vertex gl.Attrib + + Vertex gl.Attrib + TexCoord gl.Attrib + CanvasSize gl.Uniform Color gl.Uniform GlobalAlpha gl.Uniform -} -type imageShader struct { - shaderProgram - Vertex gl.Attrib - TexCoord gl.Attrib - CanvasSize gl.Uniform - Image gl.Uniform - GlobalAlpha gl.Uniform -} + Func gl.Uniform -type linearGradientShader struct { - shaderProgram - Vertex gl.Attrib - CanvasSize gl.Uniform - Gradient gl.Uniform - From gl.Uniform - Dir gl.Uniform - Len gl.Uniform - GlobalAlpha gl.Uniform -} + UseAlphaTex gl.Uniform + AlphaTex gl.Uniform -type radialGradientShader struct { - shaderProgram - Vertex gl.Attrib - CanvasSize gl.Uniform - Gradient gl.Uniform - From gl.Uniform - To gl.Uniform - RadFrom gl.Uniform - RadTo gl.Uniform - GlobalAlpha gl.Uniform -} + Gradient gl.Uniform + From, To, Dir gl.Uniform + Len gl.Uniform + RadFrom, RadTo gl.Uniform -type imagePatternShader struct { - shaderProgram - Vertex gl.Attrib - CanvasSize gl.Uniform ImageSize gl.Uniform Image gl.Uniform ImageTransform gl.Uniform Repeat gl.Uniform - GlobalAlpha gl.Uniform -} -type solidAlphaShader struct { - shaderProgram - Vertex gl.Attrib - AlphaTexCoord gl.Attrib - CanvasSize gl.Uniform - Color gl.Uniform - AlphaTex gl.Uniform - GlobalAlpha gl.Uniform -} - -type linearGradientAlphaShader struct { - shaderProgram - Vertex gl.Attrib - AlphaTexCoord gl.Attrib - CanvasSize gl.Uniform - Gradient gl.Uniform - From gl.Uniform - Dir gl.Uniform - Len gl.Uniform - AlphaTex gl.Uniform - GlobalAlpha gl.Uniform -} - -type radialGradientAlphaShader struct { - shaderProgram - Vertex gl.Attrib - AlphaTexCoord gl.Attrib - CanvasSize gl.Uniform - Gradient gl.Uniform - From gl.Uniform - To gl.Uniform - RadFrom gl.Uniform - RadTo gl.Uniform - AlphaTex gl.Uniform - GlobalAlpha gl.Uniform -} - -type imagePatternAlphaShader struct { - shaderProgram - Vertex gl.Attrib - AlphaTexCoord gl.Attrib - CanvasSize gl.Uniform - ImageSize gl.Uniform - Image gl.Uniform - ImageTransform gl.Uniform - Repeat gl.Uniform - AlphaTex gl.Uniform - GlobalAlpha gl.Uniform -} - -type gaussianShader struct { - shaderProgram - Vertex gl.Attrib - TexCoord gl.Attrib - CanvasSize gl.Uniform - KernelScale gl.Uniform - Image gl.Uniform - Kernel gl.Uniform + BoxSize gl.Uniform + BoxVertical gl.Uniform + BoxScale gl.Uniform + BoxOffset gl.Uniform } diff --git a/backend/xmobilebackend/xmobile.go b/backend/xmobilebackend/xmobile.go index 83a212f..9290cfc 100755 --- a/backend/xmobilebackend/xmobile.go +++ b/backend/xmobilebackend/xmobile.go @@ -2,7 +2,6 @@ package xmobilebackend import ( "fmt" - "image/color" "math" "reflect" "unsafe" @@ -24,18 +23,7 @@ type GLContext struct { shadowBuf gl.Buffer alphaTex gl.Texture - sr solidShader - lgr linearGradientShader - rgr radialGradientShader - ipr imagePatternShader - sar solidAlphaShader - rgar radialGradientAlphaShader - lgar linearGradientAlphaShader - ipar imagePatternAlphaShader - ir imageShader - gauss15r gaussianShader - gauss63r gaussianShader - gauss127r gaussianShader + shd unifiedShader offscr1 offscreenBuffer offscr2 offscreenBuffer @@ -64,110 +52,11 @@ func NewGLContext(glctx gl.Context) (*GLContext, error) { b.glctx.GetError() // clear error state - err = loadShader(b, solidVS, solidFS, &ctx.sr.shaderProgram) + err = loadShader(b, unifiedVS, unifiedFS, &ctx.shd.shaderProgram) if err != nil { return nil, err } - ctx.sr.shaderProgram.mustLoadLocations(&ctx.sr) - if err = glError(b); err != nil { - return nil, err - } - - err = loadShader(b, linearGradientVS, linearGradientFS, &ctx.lgr.shaderProgram) - if err != nil { - return nil, err - } - ctx.lgr.shaderProgram.mustLoadLocations(&ctx.lgr) - if err = glError(b); err != nil { - return nil, err - } - - err = loadShader(b, radialGradientVS, radialGradientFS, &ctx.rgr.shaderProgram) - if err != nil { - return nil, err - } - ctx.rgr.shaderProgram.mustLoadLocations(&ctx.rgr) - if err = glError(b); err != nil { - return nil, err - } - - err = loadShader(b, imagePatternVS, imagePatternFS, &ctx.ipr.shaderProgram) - if err != nil { - return nil, err - } - ctx.ipr.shaderProgram.mustLoadLocations(&ctx.ipr) - if err = glError(b); err != nil { - return nil, err - } - - err = loadShader(b, solidAlphaVS, solidAlphaFS, &ctx.sar.shaderProgram) - if err != nil { - return nil, err - } - ctx.sar.shaderProgram.mustLoadLocations(&ctx.sar) - if err = glError(b); err != nil { - return nil, err - } - - err = loadShader(b, linearGradientAlphaVS, linearGradientFS, &ctx.lgar.shaderProgram) - if err != nil { - return nil, err - } - ctx.lgar.shaderProgram.mustLoadLocations(&ctx.lgar) - if err = glError(b); err != nil { - return nil, err - } - - err = loadShader(b, radialGradientAlphaVS, radialGradientAlphaFS, &ctx.rgar.shaderProgram) - if err != nil { - return nil, err - } - ctx.rgar.shaderProgram.mustLoadLocations(&ctx.rgar) - if err = glError(b); err != nil { - return nil, err - } - - err = loadShader(b, imagePatternAlphaVS, imagePatternAlphaFS, &ctx.ipar.shaderProgram) - if err != nil { - return nil, err - } - ctx.ipar.shaderProgram.mustLoadLocations(&ctx.ipar) - if err = glError(b); err != nil { - return nil, err - } - - err = loadShader(b, imageVS, imageFS, &ctx.ir.shaderProgram) - if err != nil { - return nil, err - } - ctx.ir.shaderProgram.mustLoadLocations(&ctx.ir) - if err = glError(b); err != nil { - return nil, err - } - - err = loadShader(b, gaussian15VS, gaussian15FS, &ctx.gauss15r.shaderProgram) - if err != nil { - return nil, err - } - ctx.gauss15r.shaderProgram.mustLoadLocations(&ctx.gauss15r) - if err = glError(b); err != nil { - return nil, err - } - - err = loadShader(b, gaussian63VS, gaussian63FS, &ctx.gauss63r.shaderProgram) - if err != nil { - return nil, err - } - ctx.gauss63r.shaderProgram.mustLoadLocations(&ctx.gauss63r) - if err = glError(b); err != nil { - return nil, err - } - - err = loadShader(b, gaussian127VS, gaussian127FS, &ctx.gauss127r.shaderProgram) - if err != nil { - return nil, err - } - ctx.gauss127r.shaderProgram.mustLoadLocations(&ctx.gauss127r) + ctx.shd.shaderProgram.mustLoadLocations(&ctx.shd) if err = glError(b); err != nil { return nil, err } @@ -244,6 +133,7 @@ func New(x, y, w, h int, ctx *GLContext) (*XMobileBackend, error) { } b.disableTextureRenderTarget = func() { b.glctx.BindFramebuffer(gl.FRAMEBUFFER, gl.Framebuffer{Value: 0}) + b.glctx.Viewport(b.x, b.y, b.w, b.h) } return b, nil @@ -377,163 +267,81 @@ func (b *XMobileBackendOffscreen) AsImage() backendbase.Image { return &b.offscrImg } -type glColor struct { - r, g, b, a float64 -} +func (b *XMobileBackend) useShader(style *backendbase.FillStyle, useAlpha bool, alphaTexSlot int) (vertexLoc, alphaTexCoordLoc gl.Attrib) { + b.glctx.UseProgram(b.shd.ID) + b.glctx.Uniform2f(b.shd.CanvasSize, float32(b.fw), float32(b.fh)) + if useAlpha { + b.glctx.Uniform1i(b.shd.UseAlphaTex, 1) + b.glctx.Uniform1i(b.shd.AlphaTex, alphaTexSlot) + } else { + b.glctx.Uniform1i(b.shd.UseAlphaTex, 0) + } + b.glctx.Uniform1f(b.shd.GlobalAlpha, float32(style.Color.A)/255) -func colorGoToGL(c color.RGBA) glColor { - var glc glColor - glc.r = float64(c.R) / 255 - glc.g = float64(c.G) / 255 - glc.b = float64(c.B) / 255 - glc.a = float64(c.A) / 255 - return glc -} - -func (b *XMobileBackend) useShader(style *backendbase.FillStyle) (vertexLoc gl.Attrib) { if lg := style.LinearGradient; lg != nil { lg := lg.(*LinearGradient) b.glctx.ActiveTexture(gl.TEXTURE0) b.glctx.BindTexture(gl.TEXTURE_2D, lg.tex) - b.glctx.UseProgram(b.lgr.ID) from := vec{style.Gradient.X0, style.Gradient.Y0} to := vec{style.Gradient.X1, style.Gradient.Y1} dir := to.sub(from) length := dir.len() dir = dir.scale(1 / length) - b.glctx.Uniform2f(b.lgr.CanvasSize, float32(b.fw), float32(b.fh)) - b.glctx.Uniform2f(b.lgr.From, float32(from[0]), float32(from[1])) - b.glctx.Uniform2f(b.lgr.Dir, float32(dir[0]), float32(dir[1])) - b.glctx.Uniform1f(b.lgr.Len, float32(length)) - b.glctx.Uniform1i(b.lgr.Gradient, 0) - b.glctx.Uniform1f(b.lgr.GlobalAlpha, float32(style.Color.A)/255) - return b.lgr.Vertex + b.glctx.Uniform2f(b.shd.From, float32(from[0]), float32(from[1])) + b.glctx.Uniform2f(b.shd.Dir, float32(dir[0]), float32(dir[1])) + b.glctx.Uniform1f(b.shd.Len, float32(length)) + b.glctx.Uniform1i(b.shd.Gradient, 0) + b.glctx.Uniform1i(b.shd.Func, shdFuncLinearGradient) + return b.shd.Vertex, b.shd.TexCoord } if rg := style.RadialGradient; rg != nil { rg := rg.(*RadialGradient) b.glctx.ActiveTexture(gl.TEXTURE0) b.glctx.BindTexture(gl.TEXTURE_2D, rg.tex) - b.glctx.UseProgram(b.rgr.ID) from := vec{style.Gradient.X0, style.Gradient.Y0} to := vec{style.Gradient.X1, style.Gradient.Y1} - b.glctx.Uniform2f(b.rgr.CanvasSize, float32(b.fw), float32(b.fh)) - b.glctx.Uniform2f(b.rgr.From, float32(from[0]), float32(from[1])) - b.glctx.Uniform2f(b.rgr.To, float32(to[0]), float32(to[1])) - b.glctx.Uniform1f(b.rgr.RadFrom, float32(style.Gradient.RadFrom)) - b.glctx.Uniform1f(b.rgr.RadTo, float32(style.Gradient.RadTo)) - b.glctx.Uniform1i(b.rgr.Gradient, 0) - b.glctx.Uniform1f(b.rgr.GlobalAlpha, float32(style.Color.A)/255) - return b.rgr.Vertex + b.glctx.Uniform2f(b.shd.From, float32(from[0]), float32(from[1])) + b.glctx.Uniform2f(b.shd.To, float32(to[0]), float32(to[1])) + b.glctx.Uniform1f(b.shd.RadFrom, float32(style.Gradient.RadFrom)) + b.glctx.Uniform1f(b.shd.RadTo, float32(style.Gradient.RadTo)) + b.glctx.Uniform1i(b.shd.Gradient, 0) + b.glctx.Uniform1i(b.shd.Func, shdFuncRadialGradient) + return b.shd.Vertex, b.shd.TexCoord } if ip := style.ImagePattern; ip != nil { ipd := ip.(*ImagePattern).data img := ipd.Image.(*Image) - b.glctx.UseProgram(b.ipr.ID) b.glctx.ActiveTexture(gl.TEXTURE0) b.glctx.BindTexture(gl.TEXTURE_2D, img.tex) - b.glctx.Uniform2f(b.ipr.CanvasSize, float32(b.fw), float32(b.fh)) - b.glctx.Uniform2f(b.ipr.ImageSize, float32(img.w), float32(img.h)) - b.glctx.Uniform1i(b.ipr.Image, 0) + b.glctx.Uniform2f(b.shd.ImageSize, float32(img.w), float32(img.h)) + b.glctx.Uniform1i(b.shd.Image, 0) var f32mat [9]float32 for i, v := range ipd.Transform { f32mat[i] = float32(v) } - b.glctx.UniformMatrix3fv(b.ipr.ImageTransform, f32mat[:]) + b.glctx.UniformMatrix3fv(b.shd.ImageTransform, f32mat[:]) switch ipd.Repeat { case backendbase.Repeat: - b.glctx.Uniform2f(b.ipr.Repeat, 1, 1) + b.glctx.Uniform2f(b.shd.Repeat, 1, 1) case backendbase.RepeatX: - b.glctx.Uniform2f(b.ipr.Repeat, 1, 0) + b.glctx.Uniform2f(b.shd.Repeat, 1, 0) case backendbase.RepeatY: - b.glctx.Uniform2f(b.ipr.Repeat, 0, 1) + b.glctx.Uniform2f(b.shd.Repeat, 0, 1) case backendbase.NoRepeat: - b.glctx.Uniform2f(b.ipr.Repeat, 0, 0) + b.glctx.Uniform2f(b.shd.Repeat, 0, 0) } - b.glctx.Uniform1f(b.ipr.GlobalAlpha, float32(style.Color.A)/255) - return b.ipr.Vertex + b.glctx.Uniform1i(b.shd.Func, shdFuncImagePattern) + return b.shd.Vertex, b.shd.TexCoord } - b.glctx.UseProgram(b.sr.ID) - b.glctx.Uniform2f(b.sr.CanvasSize, float32(b.fw), float32(b.fh)) - c := colorGoToGL(style.Color) - b.glctx.Uniform4f(b.sr.Color, float32(c.r), float32(c.g), float32(c.b), float32(c.a)) - b.glctx.Uniform1f(b.sr.GlobalAlpha, 1) - return b.sr.Vertex -} - -func (b *XMobileBackend) useAlphaShader(style *backendbase.FillStyle, alphaTexSlot int) (vertexLoc, alphaTexCoordLoc gl.Attrib) { - if lg := style.LinearGradient; lg != nil { - lg := lg.(*LinearGradient) - b.glctx.ActiveTexture(gl.TEXTURE0) - b.glctx.BindTexture(gl.TEXTURE_2D, lg.tex) - b.glctx.UseProgram(b.lgar.ID) - from := vec{style.Gradient.X0, style.Gradient.Y0} - to := vec{style.Gradient.X1, style.Gradient.Y1} - dir := to.sub(from) - length := dir.len() - dir = dir.scale(1 / length) - b.glctx.Uniform2f(b.lgar.CanvasSize, float32(b.fw), float32(b.fh)) - b.glctx.Uniform2f(b.lgar.From, float32(from[0]), float32(from[1])) - b.glctx.Uniform2f(b.lgar.Dir, float32(dir[0]), float32(dir[1])) - b.glctx.Uniform1f(b.lgar.Len, float32(length)) - b.glctx.Uniform1i(b.lgar.Gradient, 0) - b.glctx.Uniform1i(b.lgar.AlphaTex, alphaTexSlot) - b.glctx.Uniform1f(b.lgar.GlobalAlpha, float32(style.Color.A)/255) - return b.lgar.Vertex, b.lgar.AlphaTexCoord - } - if rg := style.RadialGradient; rg != nil { - rg := rg.(*RadialGradient) - b.glctx.ActiveTexture(gl.TEXTURE0) - b.glctx.BindTexture(gl.TEXTURE_2D, rg.tex) - b.glctx.UseProgram(b.rgar.ID) - from := vec{style.Gradient.X0, style.Gradient.Y0} - to := vec{style.Gradient.X1, style.Gradient.Y1} - b.glctx.Uniform2f(b.rgar.CanvasSize, float32(b.fw), float32(b.fh)) - b.glctx.Uniform2f(b.rgar.From, float32(from[0]), float32(from[1])) - b.glctx.Uniform2f(b.rgar.To, float32(to[0]), float32(to[1])) - b.glctx.Uniform1f(b.rgar.RadFrom, float32(style.Gradient.RadFrom)) - b.glctx.Uniform1f(b.rgar.RadTo, float32(style.Gradient.RadTo)) - b.glctx.Uniform1i(b.rgar.Gradient, 0) - b.glctx.Uniform1i(b.rgar.AlphaTex, alphaTexSlot) - b.glctx.Uniform1f(b.rgar.GlobalAlpha, float32(style.Color.A)/255) - return b.rgar.Vertex, b.rgar.AlphaTexCoord - } - if ip := style.ImagePattern; ip != nil { - ipd := ip.(*ImagePattern).data - img := ipd.Image.(*Image) - b.glctx.UseProgram(b.ipar.ID) - b.glctx.ActiveTexture(gl.TEXTURE0) - b.glctx.BindTexture(gl.TEXTURE_2D, img.tex) - b.glctx.Uniform2f(b.ipar.CanvasSize, float32(b.fw), float32(b.fh)) - b.glctx.Uniform2f(b.ipar.ImageSize, float32(img.w), float32(img.h)) - b.glctx.Uniform1i(b.ipar.Image, 0) - var f32mat [9]float32 - for i, v := range ipd.Transform { - f32mat[i] = float32(v) - } - b.glctx.UniformMatrix3fv(b.ipr.ImageTransform, f32mat[:]) - switch ipd.Repeat { - case backendbase.Repeat: - b.glctx.Uniform2f(b.ipr.Repeat, 1, 1) - case backendbase.RepeatX: - b.glctx.Uniform2f(b.ipr.Repeat, 1, 0) - case backendbase.RepeatY: - b.glctx.Uniform2f(b.ipr.Repeat, 0, 1) - case backendbase.NoRepeat: - b.glctx.Uniform2f(b.ipr.Repeat, 0, 0) - } - b.glctx.Uniform1i(b.ipar.AlphaTex, alphaTexSlot) - b.glctx.Uniform1f(b.ipar.GlobalAlpha, float32(style.Color.A)/255) - return b.ipar.Vertex, b.ipar.AlphaTexCoord - } - - b.glctx.UseProgram(b.sar.ID) - b.glctx.Uniform2f(b.sar.CanvasSize, float32(b.fw), float32(b.fh)) - c := colorGoToGL(style.Color) - b.glctx.Uniform4f(b.sar.Color, float32(c.r), float32(c.g), float32(c.b), float32(c.a)) - b.glctx.Uniform1i(b.sar.AlphaTex, alphaTexSlot) - b.glctx.Uniform1f(b.sar.GlobalAlpha, 1) - return b.sar.Vertex, b.sar.AlphaTexCoord + cr := float32(style.Color.R) / 255 + cg := float32(style.Color.G) / 255 + cb := float32(style.Color.B) / 255 + ca := float32(style.Color.A) / 255 + b.glctx.Uniform4f(b.shd.Color, cr, cg, cb, ca) + b.glctx.Uniform1f(b.shd.GlobalAlpha, 1) + b.glctx.Uniform1i(b.shd.Func, shdFuncSolid) + return b.shd.Vertex, b.shd.TexCoord } func (b *XMobileBackend) enableTextureRenderTarget(offscr *offscreenBuffer) {