diff --git a/backend/goglbackend/clip.go b/backend/goglbackend/clip.go index b38b65e..d6414c5 100644 --- a/backend/goglbackend/clip.go +++ b/backend/goglbackend/clip.go @@ -33,13 +33,17 @@ func (b *GoGLBackend) Clip(pts [][2]float64) { gl.BindBuffer(gl.ARRAY_BUFFER, b.buf) gl.BufferData(gl.ARRAY_BUFFER, len(b.ptsBuf)*4, unsafe.Pointer(&b.ptsBuf[0]), gl.STREAM_DRAW) - gl.VertexAttribPointer(b.sr.Vertex, 2, gl.FLOAT, false, 0, nil) + gl.VertexAttribPointer(b.shd.Vertex, 2, gl.FLOAT, false, 0, nil) - gl.UseProgram(b.sr.ID) - gl.Uniform4f(b.sr.Color, 1, 1, 1, 1) - gl.Uniform2f(b.sr.CanvasSize, float32(b.fw), float32(b.fh)) - gl.Uniform1f(b.sr.GlobalAlpha, 1) - gl.EnableVertexAttribArray(b.sr.Vertex) + gl.UseProgram(b.shd.ID) + gl.Uniform4f(b.shd.Color, 1, 1, 1, 1) + gl.Uniform2f(b.shd.CanvasSize, float32(b.fw), float32(b.fh)) + gl.Uniform1f(b.shd.GlobalAlpha, 1) + gl.Uniform1i(b.shd.UseAlphaTex, 0) + gl.Uniform1i(b.shd.UseLinearGradient, 0) + gl.Uniform1i(b.shd.UseRadialGradient, 0) + gl.Uniform1i(b.shd.UseImagePattern, 0) + gl.EnableVertexAttribArray(b.shd.Vertex) gl.ColorMask(false, false, false, false) @@ -61,7 +65,7 @@ func (b *GoGLBackend) Clip(pts [][2]float64) { gl.StencilOp(gl.ZERO, gl.ZERO, gl.ZERO) gl.DrawArrays(gl.TRIANGLE_FAN, 0, 4) - gl.DisableVertexAttribArray(b.sr.Vertex) + gl.DisableVertexAttribArray(b.shd.Vertex) gl.ColorMask(true, true, true, true) gl.StencilOp(gl.KEEP, gl.KEEP, gl.KEEP) diff --git a/backend/goglbackend/fill.go b/backend/goglbackend/fill.go index 01c531a..f454acf 100644 --- a/backend/goglbackend/fill.go +++ b/backend/goglbackend/fill.go @@ -33,10 +33,14 @@ func (b *GoGLBackend) Clear(pts [4][2]float64) { float32(pts[2][0]), float32(pts[2][1]), float32(pts[3][0]), float32(pts[3][1])} - gl.UseProgram(b.sr.ID) - gl.Uniform2f(b.sr.CanvasSize, float32(b.fw), float32(b.fh)) - gl.Uniform4f(b.sr.Color, 0, 0, 0, 0) - gl.Uniform1f(b.sr.GlobalAlpha, 1) + gl.UseProgram(b.shd.ID) + gl.Uniform2f(b.shd.CanvasSize, float32(b.fw), float32(b.fh)) + gl.Uniform4f(b.shd.Color, 0, 0, 0, 0) + gl.Uniform1f(b.shd.GlobalAlpha, 1) + gl.Uniform1i(b.shd.UseAlphaTex, 0) + gl.Uniform1i(b.shd.UseLinearGradient, 0) + gl.Uniform1i(b.shd.UseRadialGradient, 0) + gl.Uniform1i(b.shd.UseImagePattern, 0) gl.Disable(gl.BLEND) @@ -45,10 +49,10 @@ func (b *GoGLBackend) Clear(pts [4][2]float64) { gl.StencilFunc(gl.EQUAL, 0, 0xFF) - gl.VertexAttribPointer(b.sr.Vertex, 2, gl.FLOAT, false, 0, nil) - gl.EnableVertexAttribArray(b.sr.Vertex) + gl.VertexAttribPointer(b.shd.Vertex, 2, gl.FLOAT, false, 0, nil) + gl.EnableVertexAttribArray(b.shd.Vertex) gl.DrawArrays(gl.TRIANGLE_FAN, 0, 4) - gl.DisableVertexAttribArray(b.sr.Vertex) + gl.DisableVertexAttribArray(b.shd.Vertex) gl.StencilFunc(gl.ALWAYS, 0, 0xFF) @@ -111,7 +115,7 @@ func (b *GoGLBackend) Fill(style *backendbase.FillStyle, pts [][2]float64, canOv gl.BufferData(gl.ARRAY_BUFFER, len(b.ptsBuf)*4, unsafe.Pointer(&b.ptsBuf[0]), gl.STREAM_DRAW) if !canOverlap || style.Color.A >= 255 { - vertex := b.useShader(style) + vertex, _ := b.useShader(style, false, 0) gl.StencilFunc(gl.EQUAL, 0, 0xFF) gl.EnableVertexAttribArray(vertex) @@ -125,21 +129,25 @@ func (b *GoGLBackend) Fill(style *backendbase.FillStyle, pts [][2]float64, canOv gl.StencilOp(gl.REPLACE, gl.REPLACE, gl.REPLACE) gl.StencilMask(0x01) - gl.UseProgram(b.sr.ID) - gl.Uniform4f(b.sr.Color, 0, 0, 0, 0) - gl.Uniform2f(b.sr.CanvasSize, float32(b.fw), float32(b.fh)) - gl.Uniform1f(b.sr.GlobalAlpha, 1) + gl.UseProgram(b.shd.ID) + gl.Uniform4f(b.shd.Color, 0, 0, 0, 0) + gl.Uniform2f(b.shd.CanvasSize, float32(b.fw), float32(b.fh)) + gl.Uniform1f(b.shd.GlobalAlpha, 1) + gl.Uniform1i(b.shd.UseAlphaTex, 0) + gl.Uniform1i(b.shd.UseLinearGradient, 0) + gl.Uniform1i(b.shd.UseRadialGradient, 0) + gl.Uniform1i(b.shd.UseImagePattern, 0) - gl.EnableVertexAttribArray(b.sr.Vertex) - gl.VertexAttribPointer(b.sr.Vertex, 2, gl.FLOAT, false, 0, nil) + gl.EnableVertexAttribArray(b.shd.Vertex) + gl.VertexAttribPointer(b.shd.Vertex, 2, gl.FLOAT, false, 0, nil) gl.DrawArrays(mode, 4, int32(len(pts))) - gl.DisableVertexAttribArray(b.sr.Vertex) + gl.DisableVertexAttribArray(b.shd.Vertex) gl.ColorMask(true, true, true, true) gl.StencilFunc(gl.EQUAL, 1, 0xFF) - vertex := b.useShader(style) + vertex, _ := b.useShader(style, false, 0) gl.EnableVertexAttribArray(vertex) gl.VertexAttribPointer(vertex, 2, gl.FLOAT, false, 0, nil) @@ -181,7 +189,7 @@ func (b *GoGLBackend) FillImageMask(style *backendbase.FillStyle, mask *image.Al gl.BindBuffer(gl.ARRAY_BUFFER, b.buf) - vertex, alphaTexCoord := b.useAlphaShader(style, 1) + vertex, alphaTexCoord := b.useShader(style, true, 1) gl.EnableVertexAttribArray(vertex) gl.EnableVertexAttribArray(alphaTexCoord) diff --git a/backend/goglbackend/gogl.go b/backend/goglbackend/gogl.go index 0df4950..8473d97 100644 --- a/backend/goglbackend/gogl.go +++ b/backend/goglbackend/gogl.go @@ -20,14 +20,7 @@ type GLContext struct { shadowBuf uint32 alphaTex uint32 - sr solidShader - lgr linearGradientShader - rgr radialGradientShader - ipr imagePatternShader - sar solidAlphaShader - rgar radialGradientAlphaShader - lgar linearGradientAlphaShader - ipar imagePatternAlphaShader + shd unifiedShader ir imageShader gauss15r gaussianShader gauss63r gaussianShader @@ -59,74 +52,11 @@ func NewGLContext() (*GLContext, error) { gl.GetError() // clear error state - err = loadShader(solidVS, solidFS, &ctx.sr.shaderProgram) + err = loadShader(unifiedVS, unifiedFS, &ctx.shd.shaderProgram) if err != nil { return nil, err } - ctx.sr.shaderProgram.mustLoadLocations(&ctx.sr) - if err = glError(); err != nil { - return nil, err - } - - err = loadShader(linearGradientVS, linearGradientFS, &ctx.lgr.shaderProgram) - if err != nil { - return nil, err - } - ctx.lgr.shaderProgram.mustLoadLocations(&ctx.lgr) - if err = glError(); err != nil { - return nil, err - } - - err = loadShader(radialGradientVS, radialGradientFS, &ctx.rgr.shaderProgram) - if err != nil { - return nil, err - } - ctx.rgr.shaderProgram.mustLoadLocations(&ctx.rgr) - if err = glError(); err != nil { - return nil, err - } - - err = loadShader(imagePatternVS, imagePatternFS, &ctx.ipr.shaderProgram) - if err != nil { - return nil, err - } - ctx.ipr.shaderProgram.mustLoadLocations(&ctx.ipr) - if err = glError(); err != nil { - return nil, err - } - - err = loadShader(solidAlphaVS, solidAlphaFS, &ctx.sar.shaderProgram) - if err != nil { - return nil, err - } - ctx.sar.shaderProgram.mustLoadLocations(&ctx.sar) - if err = glError(); err != nil { - return nil, err - } - - err = loadShader(linearGradientAlphaVS, linearGradientFS, &ctx.lgar.shaderProgram) - if err != nil { - return nil, err - } - ctx.lgar.shaderProgram.mustLoadLocations(&ctx.lgar) - if err = glError(); err != nil { - return nil, err - } - - err = loadShader(radialGradientAlphaVS, radialGradientAlphaFS, &ctx.rgar.shaderProgram) - if err != nil { - return nil, err - } - ctx.rgar.shaderProgram.mustLoadLocations(&ctx.rgar) - if err = glError(); err != nil { - return nil, err - } - - err = loadShader(imagePatternAlphaVS, imagePatternAlphaFS, &ctx.ipar.shaderProgram) - if err != nil { - return nil, err - } - ctx.ipar.shaderProgram.mustLoadLocations(&ctx.ipar) + ctx.shd.shaderProgram.mustLoadLocations(&ctx.shd) if err = glError(); err != nil { return nil, err } @@ -397,150 +327,99 @@ func colorGoToGL(c color.RGBA) glColor { return glc } -func (b *GoGLBackend) useShader(style *backendbase.FillStyle) (vertexLoc uint32) { +func (b *GoGLBackend) useShader(style *backendbase.FillStyle, useAlpha bool, alphaTexSlot int32) (vertexLoc, alphaTexCoordLoc uint32) { + var alphaVal int32 + if useAlpha { + alphaVal = 1 + } if lg := style.LinearGradient; lg != nil { lg := lg.(*LinearGradient) gl.ActiveTexture(gl.TEXTURE0) gl.BindTexture(gl.TEXTURE_2D, lg.tex) - gl.UseProgram(b.lgr.ID) + gl.UseProgram(b.shd.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) - gl.Uniform2f(b.lgr.CanvasSize, float32(b.fw), float32(b.fh)) - gl.Uniform2f(b.lgr.From, float32(from[0]), float32(from[1])) - gl.Uniform2f(b.lgr.Dir, float32(dir[0]), float32(dir[1])) - gl.Uniform1f(b.lgr.Len, float32(length)) - gl.Uniform1i(b.lgr.Gradient, 0) - gl.Uniform1f(b.lgr.GlobalAlpha, float32(style.Color.A)/255) - return b.lgr.Vertex + gl.Uniform2f(b.shd.CanvasSize, float32(b.fw), float32(b.fh)) + gl.Uniform2f(b.shd.From, float32(from[0]), float32(from[1])) + gl.Uniform2f(b.shd.Dir, float32(dir[0]), float32(dir[1])) + gl.Uniform1f(b.shd.Len, float32(length)) + gl.Uniform1i(b.shd.Gradient, 0) + gl.Uniform1f(b.shd.GlobalAlpha, float32(style.Color.A)/255) + gl.Uniform1i(b.shd.AlphaTex, alphaTexSlot) + gl.Uniform1i(b.shd.UseAlphaTex, alphaVal) + gl.Uniform1i(b.shd.UseLinearGradient, 1) + gl.Uniform1i(b.shd.UseRadialGradient, 0) + gl.Uniform1i(b.shd.UseImagePattern, 0) + return b.shd.Vertex, b.shd.AlphaTexCoord } if rg := style.RadialGradient; rg != nil { rg := rg.(*RadialGradient) gl.ActiveTexture(gl.TEXTURE0) gl.BindTexture(gl.TEXTURE_2D, rg.tex) - gl.UseProgram(b.rgr.ID) + gl.UseProgram(b.shd.ID) from := vec{style.Gradient.X0, style.Gradient.Y0} to := vec{style.Gradient.X1, style.Gradient.Y1} - gl.Uniform2f(b.rgr.CanvasSize, float32(b.fw), float32(b.fh)) - gl.Uniform2f(b.rgr.From, float32(from[0]), float32(from[1])) - gl.Uniform2f(b.rgr.To, float32(to[0]), float32(to[1])) - gl.Uniform1f(b.rgr.RadFrom, float32(style.Gradient.RadFrom)) - gl.Uniform1f(b.rgr.RadTo, float32(style.Gradient.RadTo)) - gl.Uniform1i(b.rgr.Gradient, 0) - gl.Uniform1f(b.rgr.GlobalAlpha, float32(style.Color.A)/255) - return b.rgr.Vertex + gl.Uniform2f(b.shd.CanvasSize, float32(b.fw), float32(b.fh)) + gl.Uniform2f(b.shd.From, float32(from[0]), float32(from[1])) + gl.Uniform2f(b.shd.To, float32(to[0]), float32(to[1])) + gl.Uniform1f(b.shd.RadFrom, float32(style.Gradient.RadFrom)) + gl.Uniform1f(b.shd.RadTo, float32(style.Gradient.RadTo)) + gl.Uniform1i(b.shd.Gradient, 0) + gl.Uniform1f(b.shd.GlobalAlpha, float32(style.Color.A)/255) + gl.Uniform1i(b.shd.AlphaTex, alphaTexSlot) + gl.Uniform1i(b.shd.UseAlphaTex, alphaVal) + gl.Uniform1i(b.shd.UseLinearGradient, 0) + gl.Uniform1i(b.shd.UseRadialGradient, 1) + gl.Uniform1i(b.shd.UseImagePattern, 0) + return b.shd.Vertex, b.shd.AlphaTexCoord } if ip := style.ImagePattern; ip != nil { ipd := ip.(*ImagePattern).data img := ipd.Image.(*Image) - gl.UseProgram(b.ipr.ID) + gl.UseProgram(b.shd.ID) gl.ActiveTexture(gl.TEXTURE0) gl.BindTexture(gl.TEXTURE_2D, img.tex) - gl.Uniform2f(b.ipr.CanvasSize, float32(b.fw), float32(b.fh)) - gl.Uniform2f(b.ipr.ImageSize, float32(img.w), float32(img.h)) - gl.Uniform1i(b.ipr.Image, 0) + gl.Uniform2f(b.shd.CanvasSize, float32(b.fw), float32(b.fh)) + gl.Uniform2f(b.shd.ImageSize, float32(img.w), float32(img.h)) + gl.Uniform1i(b.shd.Image, 0) var f32mat [9]float32 for i, v := range ipd.Transform { f32mat[i] = float32(v) } - gl.UniformMatrix3fv(b.ipr.ImageTransform, 1, false, &f32mat[0]) + gl.UniformMatrix3fv(b.shd.ImageTransform, 1, false, &f32mat[0]) switch ipd.Repeat { case backendbase.Repeat: - gl.Uniform2f(b.ipr.Repeat, 1, 1) + gl.Uniform2f(b.shd.Repeat, 1, 1) case backendbase.RepeatX: - gl.Uniform2f(b.ipr.Repeat, 1, 0) + gl.Uniform2f(b.shd.Repeat, 1, 0) case backendbase.RepeatY: - gl.Uniform2f(b.ipr.Repeat, 0, 1) + gl.Uniform2f(b.shd.Repeat, 0, 1) case backendbase.NoRepeat: - gl.Uniform2f(b.ipr.Repeat, 0, 0) + gl.Uniform2f(b.shd.Repeat, 0, 0) } - gl.Uniform1f(b.ipr.GlobalAlpha, float32(style.Color.A)/255) - return b.ipr.Vertex + gl.Uniform1f(b.shd.GlobalAlpha, float32(style.Color.A)/255) + gl.Uniform1i(b.shd.AlphaTex, alphaTexSlot) + gl.Uniform1i(b.shd.UseAlphaTex, alphaVal) + gl.Uniform1i(b.shd.UseLinearGradient, 0) + gl.Uniform1i(b.shd.UseRadialGradient, 0) + gl.Uniform1i(b.shd.UseImagePattern, 1) + return b.shd.Vertex, b.shd.AlphaTexCoord } - gl.UseProgram(b.sr.ID) - gl.Uniform2f(b.sr.CanvasSize, float32(b.fw), float32(b.fh)) + gl.UseProgram(b.shd.ID) + gl.Uniform2f(b.shd.CanvasSize, float32(b.fw), float32(b.fh)) c := colorGoToGL(style.Color) - gl.Uniform4f(b.sr.Color, float32(c.r), float32(c.g), float32(c.b), float32(c.a)) - gl.Uniform1f(b.sr.GlobalAlpha, 1) - return b.sr.Vertex -} - -func (b *GoGLBackend) useAlphaShader(style *backendbase.FillStyle, alphaTexSlot int32) (vertexLoc, alphaTexCoordLoc uint32) { - if lg := style.LinearGradient; lg != nil { - lg := lg.(*LinearGradient) - gl.ActiveTexture(gl.TEXTURE0) - gl.BindTexture(gl.TEXTURE_2D, lg.tex) - gl.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) - gl.Uniform2f(b.lgar.CanvasSize, float32(b.fw), float32(b.fh)) - gl.Uniform2f(b.lgar.From, float32(from[0]), float32(from[1])) - gl.Uniform2f(b.lgar.Dir, float32(dir[0]), float32(dir[1])) - gl.Uniform1f(b.lgar.Len, float32(length)) - gl.Uniform1i(b.lgar.Gradient, 0) - gl.Uniform1i(b.lgar.AlphaTex, alphaTexSlot) - gl.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) - gl.ActiveTexture(gl.TEXTURE0) - gl.BindTexture(gl.TEXTURE_2D, rg.tex) - gl.UseProgram(b.rgar.ID) - from := vec{style.Gradient.X0, style.Gradient.Y0} - to := vec{style.Gradient.X1, style.Gradient.Y1} - gl.Uniform2f(b.rgar.CanvasSize, float32(b.fw), float32(b.fh)) - gl.Uniform2f(b.rgar.From, float32(from[0]), float32(from[1])) - gl.Uniform2f(b.rgar.To, float32(to[0]), float32(to[1])) - gl.Uniform1f(b.rgar.RadFrom, float32(style.Gradient.RadFrom)) - gl.Uniform1f(b.rgar.RadTo, float32(style.Gradient.RadTo)) - gl.Uniform1i(b.rgar.Gradient, 0) - gl.Uniform1i(b.rgar.AlphaTex, alphaTexSlot) - gl.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) - gl.UseProgram(b.ipar.ID) - gl.ActiveTexture(gl.TEXTURE0) - gl.BindTexture(gl.TEXTURE_2D, img.tex) - gl.Uniform2f(b.ipar.CanvasSize, float32(b.fw), float32(b.fh)) - gl.Uniform2f(b.ipar.ImageSize, float32(img.w), float32(img.h)) - gl.Uniform1i(b.ipar.Image, 0) - var f32mat [9]float32 - for i, v := range ipd.Transform { - f32mat[i] = float32(v) - } - gl.UniformMatrix3fv(b.ipr.ImageTransform, 1, false, &f32mat[0]) - switch ipd.Repeat { - case backendbase.Repeat: - gl.Uniform2f(b.ipr.Repeat, 1, 1) - case backendbase.RepeatX: - gl.Uniform2f(b.ipr.Repeat, 1, 0) - case backendbase.RepeatY: - gl.Uniform2f(b.ipr.Repeat, 0, 1) - case backendbase.NoRepeat: - gl.Uniform2f(b.ipr.Repeat, 0, 0) - } - gl.Uniform1i(b.ipar.AlphaTex, alphaTexSlot) - gl.Uniform1f(b.ipar.GlobalAlpha, float32(style.Color.A)/255) - return b.ipar.Vertex, b.ipar.AlphaTexCoord - } - - gl.UseProgram(b.sar.ID) - gl.Uniform2f(b.sar.CanvasSize, float32(b.fw), float32(b.fh)) - c := colorGoToGL(style.Color) - gl.Uniform4f(b.sar.Color, float32(c.r), float32(c.g), float32(c.b), float32(c.a)) - gl.Uniform1i(b.sar.AlphaTex, alphaTexSlot) - gl.Uniform1f(b.sar.GlobalAlpha, 1) - return b.sar.Vertex, b.sar.AlphaTexCoord + gl.Uniform4f(b.shd.Color, float32(c.r), float32(c.g), float32(c.b), float32(c.a)) + gl.Uniform1f(b.shd.GlobalAlpha, 1) + gl.Uniform1i(b.shd.AlphaTex, alphaTexSlot) + gl.Uniform1i(b.shd.UseAlphaTex, alphaVal) + gl.Uniform1i(b.shd.UseLinearGradient, 0) + gl.Uniform1i(b.shd.UseRadialGradient, 0) + gl.Uniform1i(b.shd.UseImagePattern, 0) + return b.shd.Vertex, b.shd.AlphaTexCoord } func (b *GoGLBackend) enableTextureRenderTarget(offscr *offscreenBuffer) { diff --git a/backend/goglbackend/shaders.go b/backend/goglbackend/shaders.go index 83ebadb..2fba576 100755 --- a/backend/goglbackend/shaders.go +++ b/backend/goglbackend/shaders.go @@ -6,6 +6,96 @@ import ( "strings" ) +var unifiedVS = ` +attribute vec2 vertex, alphaTexCoord; + +uniform vec2 canvasSize; + +varying vec2 v_cp, v_atc; + +void main() { + v_atc = alphaTexCoord; + v_cp = vertex; + vec2 glp = vertex * 2.0 / canvasSize - 1.0; + gl_Position = vec4(glp.x, -glp.y, 0.0, 1.0); +} +` +var unifiedFS = ` +#ifdef GL_ES +precision mediump float; +#endif + +varying vec2 v_cp, v_atc; + +uniform vec4 color; +uniform float globalAlpha; + +uniform bool useLinearGradient; +uniform bool useRadialGradient; +uniform sampler2D gradient; +uniform vec2 from, dir, to; +uniform float len, radFrom, radTo; + +uniform bool useImagePattern; +uniform vec2 imageSize; +uniform sampler2D image; +uniform mat3 imageTransform; +uniform vec2 repeat; + +uniform bool useAlphaTex; +uniform sampler2D alphaTex; + +bool isNaN(float v) { + return v < 0.0 || 0.0 < v || v == 0.0 ? false : true; +} + +void main() { + vec4 col = color; + + if (useLinearGradient) { + 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 (useRadialGradient) { + 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 (useImagePattern) { + 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; + } + } + + if (useAlphaTex) { + col.a *= texture2D(alphaTex, v_atc).a * globalAlpha; + } else { + col.a *= globalAlpha; + } + + gl_FragColor = col; +} +` + var imageVS = ` attribute vec2 vertex, texCoord; uniform vec2 canvasSize; @@ -28,265 +118,6 @@ void main() { gl_FragColor = col; }` -var solidVS = ` -attribute vec2 vertex; -uniform vec2 canvasSize; -void main() { - vec2 glp = vertex * 2.0 / canvasSize - 1.0; - gl_Position = vec4(glp.x, -glp.y, 0.0, 1.0); -}` -var solidFS = ` -#ifdef GL_ES -precision mediump float; -#endif -uniform vec4 color; -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 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); - 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 (imgpt.y < 0.0 || imgpt.y > 1.0) { - col *= repeat.y; - } - 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; -}` - var gaussian15VS = ` attribute vec2 vertex, texCoord; uniform vec2 canvasSize; @@ -378,12 +209,31 @@ func init() { gaussian15FS = strings.Replace(gaussian15FS, "_SUM_", bb.String(), -1) } -type solidShader struct { +type unifiedShader struct { shaderProgram - Vertex uint32 + + Vertex uint32 + AlphaTexCoord uint32 + CanvasSize int32 Color int32 GlobalAlpha int32 + + UseAlphaTex int32 + AlphaTex int32 + + UseLinearGradient int32 + UseRadialGradient int32 + Gradient int32 + From, To, Dir int32 + Len int32 + RadFrom, RadTo int32 + + UseImagePattern int32 + ImageSize int32 + Image int32 + ImageTransform int32 + Repeat int32 } type imageShader struct { @@ -395,90 +245,6 @@ type imageShader struct { GlobalAlpha int32 } -type linearGradientShader struct { - shaderProgram - Vertex uint32 - CanvasSize int32 - Gradient int32 - From int32 - Dir int32 - Len int32 - GlobalAlpha int32 -} - -type radialGradientShader struct { - shaderProgram - Vertex uint32 - CanvasSize int32 - Gradient int32 - From int32 - To int32 - RadFrom int32 - RadTo int32 - GlobalAlpha int32 -} - -type imagePatternShader struct { - shaderProgram - Vertex uint32 - CanvasSize int32 - ImageSize int32 - Image int32 - ImageTransform int32 - Repeat int32 - GlobalAlpha int32 -} - -type solidAlphaShader struct { - shaderProgram - Vertex uint32 - AlphaTexCoord uint32 - CanvasSize int32 - Color int32 - AlphaTex int32 - GlobalAlpha int32 -} - -type linearGradientAlphaShader struct { - shaderProgram - Vertex uint32 - AlphaTexCoord uint32 - CanvasSize int32 - Gradient int32 - From int32 - Dir int32 - Len int32 - AlphaTex int32 - GlobalAlpha int32 -} - -type radialGradientAlphaShader struct { - shaderProgram - Vertex uint32 - AlphaTexCoord uint32 - CanvasSize int32 - Gradient int32 - From int32 - To int32 - RadFrom int32 - RadTo int32 - AlphaTex int32 - GlobalAlpha int32 -} - -type imagePatternAlphaShader struct { - shaderProgram - Vertex uint32 - AlphaTexCoord uint32 - CanvasSize int32 - ImageSize int32 - Image int32 - ImageTransform int32 - Repeat int32 - AlphaTex int32 - GlobalAlpha int32 -} - type gaussianShader struct { shaderProgram Vertex uint32