updated xmobile backend

This commit is contained in:
Thomas Friedel 2020-03-17 15:22:56 +01:00
parent a0ba7b2ad3
commit 896af05ba4
8 changed files with 309 additions and 830 deletions

View file

@ -33,13 +33,15 @@ func (b *XMobileBackend) Clip(pts [][2]float64) {
b.glctx.BindBuffer(gl.ARRAY_BUFFER, b.buf) 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.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.UseProgram(b.shd.ID)
b.glctx.Uniform4f(b.sr.Color, 1, 1, 1, 1) b.glctx.Uniform4f(b.shd.Color, 1, 1, 1, 1)
b.glctx.Uniform2f(b.sr.CanvasSize, float32(b.fw), float32(b.fh)) b.glctx.Uniform2f(b.shd.CanvasSize, float32(b.fw), float32(b.fh))
b.glctx.Uniform1f(b.sr.GlobalAlpha, 1) b.glctx.Uniform1f(b.shd.GlobalAlpha, 1)
b.glctx.EnableVertexAttribArray(b.sr.Vertex) 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) 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.StencilOp(gl.ZERO, gl.ZERO, gl.ZERO)
b.glctx.DrawArrays(gl.TRIANGLE_FAN, 0, 4) 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.ColorMask(true, true, true, true)
b.glctx.StencilOp(gl.KEEP, gl.KEEP, gl.KEEP) b.glctx.StencilOp(gl.KEEP, gl.KEEP, gl.KEEP)

View file

@ -33,10 +33,12 @@ func (b *XMobileBackend) Clear(pts [4][2]float64) {
float32(pts[2][0]), float32(pts[2][1]), float32(pts[2][0]), float32(pts[2][1]),
float32(pts[3][0]), float32(pts[3][1])} float32(pts[3][0]), float32(pts[3][1])}
b.glctx.UseProgram(b.sr.ID) b.glctx.UseProgram(b.shd.ID)
b.glctx.Uniform2f(b.sr.CanvasSize, float32(b.fw), float32(b.fh)) b.glctx.Uniform2f(b.shd.CanvasSize, float32(b.fw), float32(b.fh))
b.glctx.Uniform4f(b.sr.Color, 0, 0, 0, 0) b.glctx.Uniform4f(b.shd.Color, 0, 0, 0, 0)
b.glctx.Uniform1f(b.sr.GlobalAlpha, 1) 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) 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.StencilFunc(gl.EQUAL, 0, 0xFF)
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.EnableVertexAttribArray(b.sr.Vertex) b.glctx.EnableVertexAttribArray(b.shd.Vertex)
b.glctx.DrawArrays(gl.TRIANGLE_FAN, 0, 4) 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) 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) { func extent(pts [][2]float64) (min, max vec) {
max[0] = -math.MaxFloat64
max[1] = -math.MaxFloat64
min[0] = math.MaxFloat64 min[0] = math.MaxFloat64
min[1] = math.MaxFloat64 min[1] = math.MaxFloat64
for _, v := range pts { 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) 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) vertex, _ := b.useShader(style, false, 0)
b.glctx.StencilFunc(gl.EQUAL, 0, 0xFF) b.glctx.StencilFunc(gl.EQUAL, 0, 0xFF)
b.glctx.EnableVertexAttribArray(vertex) 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.StencilOp(gl.REPLACE, gl.REPLACE, gl.REPLACE)
b.glctx.StencilMask(0x01) b.glctx.StencilMask(0x01)
b.glctx.UseProgram(b.sr.ID) b.glctx.UseProgram(b.shd.ID)
b.glctx.Uniform4f(b.sr.Color, 0, 0, 0, 0) b.glctx.Uniform4f(b.shd.Color, 0, 0, 0, 0)
b.glctx.Uniform2f(b.sr.CanvasSize, float32(b.fw), float32(b.fh)) b.glctx.Uniform2f(b.shd.CanvasSize, float32(b.fw), float32(b.fh))
b.glctx.Uniform1f(b.sr.GlobalAlpha, 1) 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.EnableVertexAttribArray(b.shd.Vertex)
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.DrawArrays(mode, 4, len(pts)) 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.ColorMask(true, true, true, true)
b.glctx.StencilFunc(gl.EQUAL, 1, 0xFF) b.glctx.StencilFunc(gl.EQUAL, 1, 0xFF)
vertex := b.useShader(style) vertex, _ := b.useShader(style, 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)
@ -154,7 +160,7 @@ func (b *XMobileBackend) Fill(style *backendbase.FillStyle, pts [][2]float64, ca
} }
if style.Blur > 0 { 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) 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(vertex)
b.glctx.EnableVertexAttribArray(alphaTexCoord) b.glctx.EnableVertexAttribArray(alphaTexCoord)
@ -216,105 +222,103 @@ func (b *XMobileBackend) FillImageMask(style *backendbase.FillStyle, mask *image
b.glctx.ActiveTexture(gl.TEXTURE0) b.glctx.ActiveTexture(gl.TEXTURE0)
if style.Blur > 0 { if style.Blur > 0 {
b.drawBlurred(style.Blur) min, max := extent(pts[:])
b.drawBlurred(style.Blur, min, max)
} }
} }
func (b *XMobileBackend) drawBlurred(blur float64) { func (b *XMobileBackend) drawBlurred(size float64, min, max vec) {
b.glctx.BlendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA) b.offscr1.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]
}
gaussianKernel(blur, kernel)
b.offscr2.alpha = true b.offscr2.alpha = true
b.enableTextureRenderTarget(&b.offscr2)
// 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++
}
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.glctx.ClearColor(0, 0, 0, 0) 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.enableTextureRenderTarget(&b.offscr2)
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.BindTexture(gl.TEXTURE_2D, b.offscr1.tex) b.glctx.BindTexture(gl.TEXTURE_2D, b.offscr1.tex)
b.glctx.Clear(gl.COLOR_BUFFER_BIT | gl.STENCIL_BUFFER_BIT)
b.glctx.UseProgram(gs.ID) b.box3(sizea, 0, false)
b.glctx.Uniform1i(gs.Image, 0) b.enableTextureRenderTarget(&b.offscr1)
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.BindTexture(gl.TEXTURE_2D, b.offscr2.tex) 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.DisableVertexAttribArray(b.shd.Vertex)
b.glctx.Uniform1i(gs.Image, 0) b.glctx.DisableVertexAttribArray(b.shd.TexCoord)
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.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) b.glctx.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
} }
func gaussianKernel(stddev float64, target []float32) { func (b *XMobileBackend) box3(size int, offset float32, vertical bool) {
stddevSqr := stddev * stddev b.glctx.Uniform1i(b.shd.BoxSize, size)
center := float64(len(target) / 2) if vertical {
factor := 1.0 / math.Sqrt(2*math.Pi*stddevSqr) b.glctx.Uniform1i(b.shd.BoxVertical, 1)
for i := range target { b.glctx.Uniform1f(b.shd.BoxScale, 1/float32(b.fh))
x := float64(i) - center } else {
target[i] = float32(factor * math.Pow(math.E, -x*x/(2*stddevSqr))) b.glctx.Uniform1i(b.shd.BoxVertical, 0)
} b.glctx.Uniform1f(b.shd.BoxScale, 1/float32(b.fw))
// 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
} }
b.glctx.Uniform1f(b.shd.BoxOffset, offset)
b.glctx.DrawArrays(gl.TRIANGLE_FAN, 0, 4)
} }

View file

@ -142,6 +142,12 @@ func rewrite(filename, src string) (string, string) {
params[2] = params[2][1 : len(params[2])-3] params[2] = params[2][1 : len(params[2])-3]
return "b.glctx.Uniform1fv(" + params[0] + ", " + params[2] + ")" 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 { src = rewriteCalls(src, "b.glctx.UniformMatrix3fv", func(params []string) string {
return "b.glctx.UniformMatrix3fv(" + params[0] + ", " + params[3][1:len(params[3])-3] + "[:])" 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 { func rewriteShaders(src string) string {
src = strings.Replace(src, src = strings.Replace(src,
`import ( `package xmobilebackend
"bytes"
"fmt"
"strings"
)
`, `,
`import ( `package xmobilebackend
"bytes"
"fmt"
"strings"
import (
"golang.org/x/mobile/gl" "golang.org/x/mobile/gl"
) )
`, 1) `, 1)
src = strings.Replace(src, "uint32", "gl.Attrib", -1) src = strings.Replace(src, "uint32", "gl.Attrib", -1)
src = strings.Replace(src, "int32", "gl.Uniform", -1) src = strings.Replace(src, "int32", "gl.Uniform", -1)
src = strings.Replace(src, "shdFuncSolid gl.Uniform", "shdFuncSolid int", -1)
return src return src
} }

View file

@ -26,7 +26,6 @@ type RadialGradient struct {
type gradient struct { type gradient struct {
b *XMobileBackend b *XMobileBackend
tex gl.Texture tex gl.Texture
loaded bool
} }
func (b *XMobileBackend) LoadLinearGradient(data backendbase.Gradient) backendbase.LinearGradient { 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) { func (g *gradient) load(stops backendbase.Gradient) {
b := g.b b := g.b
if g.loaded {
return
}
g.b.activate() g.b.activate()
b.glctx.ActiveTexture(gl.TEXTURE0) 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:]) b.glctx.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 2048, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixels[0:])
g.loaded = true
} }

View file

@ -85,15 +85,17 @@ func (b *XMobileBackend) PutImageData(img *image.RGBA, x, y int) {
0, 0, 1, 0, 1, 1, 0, 1} 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.BufferData(gl.ARRAY_BUFFER, byteSlice(unsafe.Pointer(&data[0]), len(data)*4), gl.STREAM_DRAW)
b.glctx.UseProgram(b.ir.ID) b.glctx.UseProgram(b.shd.ID)
b.glctx.Uniform1i(b.ir.Image, 0) b.glctx.Uniform1i(b.shd.Image, 0)
b.glctx.Uniform2f(b.ir.CanvasSize, float32(b.fw), float32(b.fh)) b.glctx.Uniform2f(b.shd.CanvasSize, float32(b.fw), float32(b.fh))
b.glctx.Uniform1f(b.ir.GlobalAlpha, 1) b.glctx.Uniform1f(b.shd.GlobalAlpha, 1)
b.glctx.VertexAttribPointer(b.ir.Vertex, 2, gl.FLOAT, false, 0, 0) b.glctx.Uniform1i(b.shd.UseAlphaTex, 0)
b.glctx.VertexAttribPointer(b.ir.TexCoord, 2, gl.FLOAT, false, 0, 8*4) b.glctx.Uniform1i(b.shd.Func, shdFuncImage)
b.glctx.EnableVertexAttribArray(b.ir.Vertex) b.glctx.VertexAttribPointer(b.shd.Vertex, 2, gl.FLOAT, false, 0, 0)
b.glctx.EnableVertexAttribArray(b.ir.TexCoord) 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.DrawArrays(gl.TRIANGLE_FAN, 0, 4)
b.glctx.DisableVertexAttribArray(b.ir.Vertex) b.glctx.DisableVertexAttribArray(b.shd.Vertex)
b.glctx.DisableVertexAttribArray(b.ir.TexCoord) b.glctx.DisableVertexAttribArray(b.shd.TexCoord)
} }

View file

@ -196,17 +196,19 @@ func (b *XMobileBackend) DrawImage(dimg backendbase.Image, sx, sy, sw, sh float6
b.glctx.ActiveTexture(gl.TEXTURE0) b.glctx.ActiveTexture(gl.TEXTURE0)
b.glctx.BindTexture(gl.TEXTURE_2D, img.tex) b.glctx.BindTexture(gl.TEXTURE_2D, img.tex)
b.glctx.UseProgram(b.ir.ID) b.glctx.UseProgram(b.shd.ID)
b.glctx.Uniform1i(b.ir.Image, 0) b.glctx.Uniform1i(b.shd.Image, 0)
b.glctx.Uniform2f(b.ir.CanvasSize, float32(b.fw), float32(b.fh)) b.glctx.Uniform2f(b.shd.CanvasSize, float32(b.fw), float32(b.fh))
b.glctx.Uniform1f(b.ir.GlobalAlpha, float32(alpha)) b.glctx.Uniform1f(b.shd.GlobalAlpha, float32(alpha))
b.glctx.VertexAttribPointer(b.ir.Vertex, 2, gl.FLOAT, false, 0, 0) b.glctx.Uniform1i(b.shd.UseAlphaTex, 0)
b.glctx.VertexAttribPointer(b.ir.TexCoord, 2, gl.FLOAT, false, 0, 8*4) b.glctx.Uniform1i(b.shd.Func, shdFuncImage)
b.glctx.EnableVertexAttribArray(b.ir.Vertex) b.glctx.VertexAttribPointer(b.shd.Vertex, 2, gl.FLOAT, false, 0, 0)
b.glctx.EnableVertexAttribArray(b.ir.TexCoord) 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.DrawArrays(gl.TRIANGLE_FAN, 0, 4)
b.glctx.DisableVertexAttribArray(b.ir.Vertex) b.glctx.DisableVertexAttribArray(b.shd.Vertex)
b.glctx.DisableVertexAttribArray(b.ir.TexCoord) b.glctx.DisableVertexAttribArray(b.shd.TexCoord)
b.glctx.StencilFunc(gl.ALWAYS, 0, 0xFF) b.glctx.StencilFunc(gl.ALWAYS, 0, 0xFF)
} }

View file

@ -1,103 +1,82 @@
package xmobilebackend package xmobilebackend
import ( import (
"bytes"
"fmt"
"strings"
"golang.org/x/mobile/gl" "golang.org/x/mobile/gl"
) )
var imageVS = ` var unifiedVS = `
attribute vec2 vertex, texCoord; 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; uniform vec2 canvasSize;
varying vec2 v_cp, v_tc;
void main() { void main() {
v_tc = texCoord;
v_cp = vertex;
vec2 glp = vertex * 2.0 / canvasSize - 1.0; vec2 glp = vertex * 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);
}` }
var solidFS = ` `
var unifiedFS = `
#ifdef GL_ES #ifdef GL_ES
precision mediump float; precision mediump float;
#endif #endif
varying vec2 v_cp, v_tc;
uniform int func;
uniform vec4 color; uniform vec4 color;
uniform float globalAlpha; uniform float globalAlpha;
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 sampler2D gradient;
uniform vec2 from, dir; uniform vec2 from, dir, to;
uniform float len; uniform float len, radFrom, radTo;
uniform float globalAlpha;
void main() { uniform vec2 imageSize;
vec2 v = v_cp - from; uniform sampler2D image;
float r = dot(v, dir) / len; uniform mat3 imageTransform;
r = clamp(r, 0.0, 1.0); uniform vec2 repeat;
vec4 col = texture2D(gradient, vec2(r, 0.0));
col.a *= globalAlpha; uniform bool useAlphaTex;
gl_FragColor = col; uniform sampler2D alphaTex;
}`
uniform int boxSize;
uniform bool boxVertical;
uniform float boxScale;
uniform float boxOffset;
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) { bool isNaN(float v) {
return v < 0.0 || 0.0 < v || v == 0.0 ? false : true; return v < 0.0 || 0.0 < v || v == 0.0 ? false : true;
} }
void main() { void main() {
vec4 col = color;
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;
}
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( 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) 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) -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)
@ -112,381 +91,68 @@ void main() {
return; return;
} }
float o = max(o1, o2); float o = max(o1, o2);
//float r = radFrom + o * (radTo - radFrom); o = clamp(o, 0.0, 1.0);
vec4 col = texture2D(gradient, vec2(o, 0.0)); col = texture2D(gradient, vec2(o, 0.0));
col.a *= globalAlpha; } else if (func == 3) {
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; vec3 tfpt = vec3(v_cp, 1.0) * imageTransform;
vec2 imgpt = tfpt.xy / imageSize; vec2 imgpt = tfpt.xy / imageSize;
vec4 col = texture2D(image, mod(imgpt, 1.0)); col = texture2D(image, mod(imgpt, 1.0));
if (imgpt.x < 0.0 || imgpt.x > 1.0) { if (imgpt.x < 0.0 || imgpt.x > 1.0) {
col *= repeat.x; col *= repeat.x;
} }
if (imgpt.y < 0.0 || imgpt.y > 1.0) { if (imgpt.y < 0.0 || imgpt.y > 1.0) {
col *= repeat.y; col *= repeat.y;
} }
} else if (func == 4) {
col = texture2D(image, v_tc);
}
if (useAlphaTex) {
col.a *= texture2D(alphaTex, v_tc).a * globalAlpha;
} else {
col.a *= globalAlpha; col.a *= globalAlpha;
}
gl_FragColor = col; 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 = ` const (
attribute vec2 vertex, alphaTexCoord; shdFuncSolid int = iota
uniform vec2 canvasSize; shdFuncLinearGradient
varying vec2 v_cp; shdFuncRadialGradient
varying vec2 v_atc; shdFuncImagePattern
void main() { shdFuncImage
v_cp = vertex; shdFuncBoxBlur
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;
}`
var gaussian15VS = ` type unifiedShader struct {
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 {
shaderProgram shaderProgram
Vertex gl.Attrib Vertex gl.Attrib
TexCoord gl.Attrib
CanvasSize gl.Uniform CanvasSize gl.Uniform
Color gl.Uniform Color gl.Uniform
GlobalAlpha gl.Uniform GlobalAlpha gl.Uniform
}
type imageShader struct { Func gl.Uniform
shaderProgram
Vertex gl.Attrib UseAlphaTex gl.Uniform
TexCoord gl.Attrib AlphaTex gl.Uniform
CanvasSize gl.Uniform
Image gl.Uniform
GlobalAlpha gl.Uniform
}
type linearGradientShader struct {
shaderProgram
Vertex gl.Attrib
CanvasSize gl.Uniform
Gradient gl.Uniform Gradient gl.Uniform
From gl.Uniform From, To, Dir gl.Uniform
Dir gl.Uniform
Len gl.Uniform Len gl.Uniform
GlobalAlpha gl.Uniform RadFrom, RadTo 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
}
type imagePatternShader struct {
shaderProgram
Vertex gl.Attrib
CanvasSize gl.Uniform
ImageSize gl.Uniform ImageSize gl.Uniform
Image gl.Uniform Image gl.Uniform
ImageTransform gl.Uniform ImageTransform gl.Uniform
Repeat gl.Uniform Repeat gl.Uniform
GlobalAlpha gl.Uniform
}
type solidAlphaShader struct { BoxSize gl.Uniform
shaderProgram BoxVertical gl.Uniform
Vertex gl.Attrib BoxScale gl.Uniform
AlphaTexCoord gl.Attrib BoxOffset gl.Uniform
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
} }

View file

@ -2,7 +2,6 @@ package xmobilebackend
import ( import (
"fmt" "fmt"
"image/color"
"math" "math"
"reflect" "reflect"
"unsafe" "unsafe"
@ -24,18 +23,7 @@ type GLContext struct {
shadowBuf gl.Buffer shadowBuf gl.Buffer
alphaTex gl.Texture alphaTex gl.Texture
sr solidShader shd unifiedShader
lgr linearGradientShader
rgr radialGradientShader
ipr imagePatternShader
sar solidAlphaShader
rgar radialGradientAlphaShader
lgar linearGradientAlphaShader
ipar imagePatternAlphaShader
ir imageShader
gauss15r gaussianShader
gauss63r gaussianShader
gauss127r gaussianShader
offscr1 offscreenBuffer offscr1 offscreenBuffer
offscr2 offscreenBuffer offscr2 offscreenBuffer
@ -64,110 +52,11 @@ func NewGLContext(glctx gl.Context) (*GLContext, error) {
b.glctx.GetError() // clear error state 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 { if err != nil {
return nil, err return nil, err
} }
ctx.sr.shaderProgram.mustLoadLocations(&ctx.sr) ctx.shd.shaderProgram.mustLoadLocations(&ctx.shd)
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)
if err = glError(b); err != nil { if err = glError(b); err != nil {
return nil, err return nil, err
} }
@ -244,6 +133,7 @@ func New(x, y, w, h int, ctx *GLContext) (*XMobileBackend, error) {
} }
b.disableTextureRenderTarget = func() { b.disableTextureRenderTarget = func() {
b.glctx.BindFramebuffer(gl.FRAMEBUFFER, gl.Framebuffer{Value: 0}) b.glctx.BindFramebuffer(gl.FRAMEBUFFER, gl.Framebuffer{Value: 0})
b.glctx.Viewport(b.x, b.y, b.w, b.h)
} }
return b, nil return b, nil
@ -377,163 +267,81 @@ func (b *XMobileBackendOffscreen) AsImage() backendbase.Image {
return &b.offscrImg return &b.offscrImg
} }
type glColor struct { func (b *XMobileBackend) useShader(style *backendbase.FillStyle, useAlpha bool, alphaTexSlot int) (vertexLoc, alphaTexCoordLoc gl.Attrib) {
r, g, b, a float64 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 { if lg := style.LinearGradient; lg != nil {
lg := lg.(*LinearGradient) lg := lg.(*LinearGradient)
b.glctx.ActiveTexture(gl.TEXTURE0) b.glctx.ActiveTexture(gl.TEXTURE0)
b.glctx.BindTexture(gl.TEXTURE_2D, lg.tex) b.glctx.BindTexture(gl.TEXTURE_2D, lg.tex)
b.glctx.UseProgram(b.lgr.ID)
from := vec{style.Gradient.X0, style.Gradient.Y0} from := vec{style.Gradient.X0, style.Gradient.Y0}
to := vec{style.Gradient.X1, style.Gradient.Y1} to := vec{style.Gradient.X1, style.Gradient.Y1}
dir := to.sub(from) dir := to.sub(from)
length := dir.len() length := dir.len()
dir = dir.scale(1 / length) dir = dir.scale(1 / length)
b.glctx.Uniform2f(b.lgr.CanvasSize, float32(b.fw), float32(b.fh)) b.glctx.Uniform2f(b.shd.From, float32(from[0]), float32(from[1]))
b.glctx.Uniform2f(b.lgr.From, float32(from[0]), float32(from[1])) b.glctx.Uniform2f(b.shd.Dir, float32(dir[0]), float32(dir[1]))
b.glctx.Uniform2f(b.lgr.Dir, float32(dir[0]), float32(dir[1])) b.glctx.Uniform1f(b.shd.Len, float32(length))
b.glctx.Uniform1f(b.lgr.Len, float32(length)) b.glctx.Uniform1i(b.shd.Gradient, 0)
b.glctx.Uniform1i(b.lgr.Gradient, 0) b.glctx.Uniform1i(b.shd.Func, shdFuncLinearGradient)
b.glctx.Uniform1f(b.lgr.GlobalAlpha, float32(style.Color.A)/255) return b.shd.Vertex, b.shd.TexCoord
return b.lgr.Vertex
} }
if rg := style.RadialGradient; rg != nil { if rg := style.RadialGradient; rg != nil {
rg := rg.(*RadialGradient) rg := rg.(*RadialGradient)
b.glctx.ActiveTexture(gl.TEXTURE0) b.glctx.ActiveTexture(gl.TEXTURE0)
b.glctx.BindTexture(gl.TEXTURE_2D, rg.tex) b.glctx.BindTexture(gl.TEXTURE_2D, rg.tex)
b.glctx.UseProgram(b.rgr.ID)
from := vec{style.Gradient.X0, style.Gradient.Y0} from := vec{style.Gradient.X0, style.Gradient.Y0}
to := vec{style.Gradient.X1, style.Gradient.Y1} to := vec{style.Gradient.X1, style.Gradient.Y1}
b.glctx.Uniform2f(b.rgr.CanvasSize, float32(b.fw), float32(b.fh)) b.glctx.Uniform2f(b.shd.From, float32(from[0]), float32(from[1]))
b.glctx.Uniform2f(b.rgr.From, float32(from[0]), float32(from[1])) b.glctx.Uniform2f(b.shd.To, float32(to[0]), float32(to[1]))
b.glctx.Uniform2f(b.rgr.To, float32(to[0]), float32(to[1])) b.glctx.Uniform1f(b.shd.RadFrom, float32(style.Gradient.RadFrom))
b.glctx.Uniform1f(b.rgr.RadFrom, float32(style.Gradient.RadFrom)) b.glctx.Uniform1f(b.shd.RadTo, float32(style.Gradient.RadTo))
b.glctx.Uniform1f(b.rgr.RadTo, float32(style.Gradient.RadTo)) b.glctx.Uniform1i(b.shd.Gradient, 0)
b.glctx.Uniform1i(b.rgr.Gradient, 0) b.glctx.Uniform1i(b.shd.Func, shdFuncRadialGradient)
b.glctx.Uniform1f(b.rgr.GlobalAlpha, float32(style.Color.A)/255) return b.shd.Vertex, b.shd.TexCoord
return b.rgr.Vertex
} }
if ip := style.ImagePattern; ip != nil { if ip := style.ImagePattern; ip != nil {
ipd := ip.(*ImagePattern).data ipd := ip.(*ImagePattern).data
img := ipd.Image.(*Image) img := ipd.Image.(*Image)
b.glctx.UseProgram(b.ipr.ID)
b.glctx.ActiveTexture(gl.TEXTURE0) b.glctx.ActiveTexture(gl.TEXTURE0)
b.glctx.BindTexture(gl.TEXTURE_2D, img.tex) b.glctx.BindTexture(gl.TEXTURE_2D, img.tex)
b.glctx.Uniform2f(b.ipr.CanvasSize, float32(b.fw), float32(b.fh)) b.glctx.Uniform2f(b.shd.ImageSize, float32(img.w), float32(img.h))
b.glctx.Uniform2f(b.ipr.ImageSize, float32(img.w), float32(img.h)) b.glctx.Uniform1i(b.shd.Image, 0)
b.glctx.Uniform1i(b.ipr.Image, 0)
var f32mat [9]float32 var f32mat [9]float32
for i, v := range ipd.Transform { for i, v := range ipd.Transform {
f32mat[i] = float32(v) f32mat[i] = float32(v)
} }
b.glctx.UniformMatrix3fv(b.ipr.ImageTransform, f32mat[:]) b.glctx.UniformMatrix3fv(b.shd.ImageTransform, f32mat[:])
switch ipd.Repeat { switch ipd.Repeat {
case backendbase.Repeat: case backendbase.Repeat:
b.glctx.Uniform2f(b.ipr.Repeat, 1, 1) b.glctx.Uniform2f(b.shd.Repeat, 1, 1)
case backendbase.RepeatX: case backendbase.RepeatX:
b.glctx.Uniform2f(b.ipr.Repeat, 1, 0) b.glctx.Uniform2f(b.shd.Repeat, 1, 0)
case backendbase.RepeatY: case backendbase.RepeatY:
b.glctx.Uniform2f(b.ipr.Repeat, 0, 1) b.glctx.Uniform2f(b.shd.Repeat, 0, 1)
case backendbase.NoRepeat: 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) b.glctx.Uniform1i(b.shd.Func, shdFuncImagePattern)
return b.ipr.Vertex return b.shd.Vertex, b.shd.TexCoord
} }
b.glctx.UseProgram(b.sr.ID) cr := float32(style.Color.R) / 255
b.glctx.Uniform2f(b.sr.CanvasSize, float32(b.fw), float32(b.fh)) cg := float32(style.Color.G) / 255
c := colorGoToGL(style.Color) cb := float32(style.Color.B) / 255
b.glctx.Uniform4f(b.sr.Color, float32(c.r), float32(c.g), float32(c.b), float32(c.a)) ca := float32(style.Color.A) / 255
b.glctx.Uniform1f(b.sr.GlobalAlpha, 1) b.glctx.Uniform4f(b.shd.Color, cr, cg, cb, ca)
return b.sr.Vertex b.glctx.Uniform1f(b.shd.GlobalAlpha, 1)
} b.glctx.Uniform1i(b.shd.Func, shdFuncSolid)
return b.shd.Vertex, b.shd.TexCoord
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
} }
func (b *XMobileBackend) enableTextureRenderTarget(offscr *offscreenBuffer) { func (b *XMobileBackend) enableTextureRenderTarget(offscr *offscreenBuffer) {