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.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)

View file

@ -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)
}

View file

@ -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
}

View file

@ -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
}

View file

@ -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)
}

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.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)
}

View file

@ -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
}

View file

@ -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) {