From da6538b1e33bab57de90a19d7b082c0ab3a4bf48 Mon Sep 17 00:00:00 2001 From: Thomas Friedel Date: Mon, 26 Feb 2018 15:40:48 +0100 Subject: [PATCH] shaders are now in their own file; text fill now uses font rendering more directly and supports fill styles --- canvas.go | 285 +++++++++++------------ imagedata.go | 18 +- images.go | 18 +- made_shaders.go | 592 +++++++++++++++++++++++++++++++++++++++++------- make_shaders.go | 15 +- shaders.go | 257 +++++++++++++++++++++ text.go | 119 +++++----- 7 files changed, 996 insertions(+), 308 deletions(-) create mode 100644 shaders.go diff --git a/canvas.go b/canvas.go index 0f96c86..9ba13e7 100644 --- a/canvas.go +++ b/canvas.go @@ -2,13 +2,15 @@ package canvas import ( "fmt" - "image" "unsafe" "github.com/golang/freetype/truetype" "github.com/tfriedel6/lm" ) +//go:generate go run make_shaders.go +//go:generate go fmt + // Canvas represents an area on the viewport on which to draw // using a set of functions very similar to the HTML5 canvas type Canvas struct { @@ -17,10 +19,6 @@ type Canvas struct { polyPath []pathPoint linePath []pathPoint - text struct { - target *image.RGBA - tex uint32 - } state drawState stateStack []drawState @@ -133,15 +131,22 @@ loop: } } +const bufferTextureSize = 2048 + var ( - gli GL - buf uint32 - sr *solidShader - tr *textureShader - lgr *linearGradientShader - rgr *radialGradientShader - ipr *imagePatternShader - glChan = make(chan func()) + gli GL + buf uint32 + alphaTex uint32 + sr *solidShader + lgr *linearGradientShader + rgr *radialGradientShader + ipr *imagePatternShader + sar *solidAlphaShader + rgar *radialGradientAlphaShader + lgar *linearGradientAlphaShader + ipar *imagePatternAlphaShader + ir *imageShader + glChan = make(chan func()) ) func LoadGL(glimpl GL) (err error) { @@ -158,15 +163,6 @@ func LoadGL(glimpl GL) (err error) { return } - tr, err = loadTextureShader() - if err != nil { - return - } - err = glError() - if err != nil { - return - } - lgr, err = loadLinearGradientShader() if err != nil { return @@ -194,12 +190,66 @@ func LoadGL(glimpl GL) (err error) { return } + sar, err = loadSolidAlphaShader() + if err != nil { + return + } + err = glError() + if err != nil { + return + } + + lgar, err = loadLinearGradientAlphaShader() + if err != nil { + return + } + err = glError() + if err != nil { + return + } + + rgar, err = loadRadialGradientAlphaShader() + if err != nil { + return + } + err = glError() + if err != nil { + return + } + + ipar, err = loadImagePatternAlphaShader() + if err != nil { + return + } + err = glError() + if err != nil { + return + } + + ir, err = loadImageShader() + if err != nil { + return + } + err = glError() + if err != nil { + return + } + gli.GenBuffers(1, &buf) err = glError() if err != nil { return } + gli.ActiveTexture(gl_TEXTURE0) + gli.GenTextures(1, &alphaTex) + gli.BindTexture(gl_TEXTURE_2D, alphaTex) + gli.TexParameteri(gl_TEXTURE_2D, gl_TEXTURE_MIN_FILTER, gl_NEAREST) + gli.TexParameteri(gl_TEXTURE_2D, gl_TEXTURE_MAG_FILTER, gl_NEAREST) + gli.TexParameteri(gl_TEXTURE_2D, gl_TEXTURE_WRAP_S, gl_CLAMP_TO_EDGE) + gli.TexParameteri(gl_TEXTURE_2D, gl_TEXTURE_WRAP_T, gl_CLAMP_TO_EDGE) + gli.TexImage2D(gl_TEXTURE_2D, 0, gl_ALPHA, bufferTextureSize, bufferTextureSize, 0, gl_ALPHA, gl_UNSIGNED_BYTE, nil) + gli.Enable(gl_BLEND) gli.BlendFunc(gl_SRC_ALPHA, gl_ONE_MINUS_SRC_ALPHA) gli.Enable(gl_STENCIL_TEST) @@ -208,132 +258,6 @@ func LoadGL(glimpl GL) (err error) { return } -//go:generate go run make_shaders.go -//go:generate go fmt - -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; -void main() { - gl_FragColor = color; -}` - -var textureVS = ` -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 textureFS = ` -#ifdef GL_ES -precision mediump float; -#endif -varying vec2 v_texCoord; -uniform sampler2D image; -void main() { - gl_FragColor = texture2D(image, v_texCoord); -}` -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 mat3 invmat; -uniform sampler1D gradient; -uniform vec2 from, dir; -uniform float len; -void main() { - vec3 untf = vec3(v_cp, 1.0) * invmat; - vec2 v = untf.xy - from; - float r = dot(v, dir) / len; - r = clamp(r, 0.0, 1.0); - gl_FragColor = texture1D(gradient, r); -}` -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 mat3 invmat; -uniform sampler1D gradient; -uniform vec2 from, to, dir; -uniform float radFrom, radTo; -uniform float len; -bool isNaN(float v) { - return v < 0.0 || 0.0 < v || v == 0.0 ? false : true; -} -void main() { - vec3 untf = vec3(v_cp, 1.0) * invmat; - float o_a = 0.5 * sqrt( - pow(-2.0*from.x*from.x+2.0*from.x*to.x+2.0*from.x*untf.x-2.0*to.x*untf.x-2.0*from.y*from.y+2.0*from.y*to.y+2.0*from.y*untf.y-2.0*to.y*untf.y+2.0*radFrom*radFrom-2.0*radFrom*radTo, 2.0) - -4.0*(from.x*from.x-2.0*from.x*untf.x+untf.x*untf.x+from.y*from.y-2.0*from.y*untf.y+untf.y*untf.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*untf.x+to.x*untf.x+from.y*from.y-from.y*to.y-from.y*untf.y+to.y*untf.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); - gl_FragColor = texture1D(gradient, o); -}` -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 mat3 invmat; -uniform sampler2D image; -void main() { - vec3 untf = vec3(v_cp, 1.0) * invmat; - gl_FragColor = texture2D(image, mod(untf.xy / imageSize, 1.0)); - //gl_FragColor = vec4(v_cp * 0.1, 0.0, 1.0); -}` - func glError() error { glErr := gli.GetError() if glErr != gl_NO_ERROR { @@ -439,6 +363,71 @@ func (cv *Canvas) useShader(style *drawStyle) (vertexLoc uint32) { return sr.vertex } +func (cv *Canvas) useAlphaShader(style *drawStyle, alphaTexSlot int32) (vertexLoc, alphaTexCoordLoc uint32) { + if lg := style.linearGradient; lg != nil { + lg.load() + gli.ActiveTexture(gl_TEXTURE0) + gli.BindTexture(gl_TEXTURE_1D, lg.tex) + gli.UseProgram(lgar.id) + from := cv.tf(lg.from) + to := cv.tf(lg.to) + dir := to.Sub(from) + length := dir.Len() + dir = dir.DivF(length) + gli.Uniform2f(lgar.canvasSize, cv.fw, cv.fh) + inv := cv.state.transform.Invert() + gli.UniformMatrix3fv(lgar.invmat, 1, false, &inv[0]) + gli.Uniform2f(lgar.from, from[0], from[1]) + gli.Uniform2f(lgar.dir, dir[0], dir[1]) + gli.Uniform1f(lgar.len, length) + gli.Uniform1i(lgar.gradient, 0) + gli.Uniform1i(lgar.alphaTex, alphaTexSlot) + return lgar.vertex, lgar.alphaTexCoord + } + if rg := style.radialGradient; rg != nil { + rg.load() + gli.ActiveTexture(gl_TEXTURE0) + gli.BindTexture(gl_TEXTURE_1D, rg.tex) + gli.UseProgram(rgar.id) + from := cv.tf(rg.from) + to := cv.tf(rg.to) + dir := to.Sub(from) + length := dir.Len() + dir = dir.DivF(length) + gli.Uniform2f(rgar.canvasSize, cv.fw, cv.fh) + inv := cv.state.transform.Invert() + gli.UniformMatrix3fv(rgar.invmat, 1, false, &inv[0]) + gli.Uniform2f(rgar.from, from[0], from[1]) + gli.Uniform2f(rgar.to, to[0], to[1]) + gli.Uniform2f(rgar.dir, dir[0], dir[1]) + gli.Uniform1f(rgar.radFrom, rg.radFrom) + gli.Uniform1f(rgar.radTo, rg.radTo) + gli.Uniform1f(rgar.len, length) + gli.Uniform1i(rgar.gradient, 0) + gli.Uniform1i(rgar.alphaTex, alphaTexSlot) + return rgar.vertex, rgar.alphaTexCoord + } + if img := style.image; img != nil { + gli.UseProgram(ipar.id) + gli.ActiveTexture(gl_TEXTURE0) + gli.BindTexture(gl_TEXTURE_2D, img.tex) + gli.Uniform2f(ipar.canvasSize, cv.fw, cv.fh) + inv := cv.state.transform.Invert() + gli.UniformMatrix3fv(ipar.invmat, 1, false, &inv[0]) + gli.Uniform2f(ipar.imageSize, float32(img.w), float32(img.h)) + gli.Uniform1i(ipar.image, 0) + gli.Uniform1i(ipar.alphaTex, alphaTexSlot) + return ipar.vertex, ipar.alphaTexCoord + } + + gli.UseProgram(sar.id) + gli.Uniform2f(sar.canvasSize, cv.fw, cv.fh) + c := style.color + gli.Uniform4f(sar.color, c.r, c.g, c.b, c.a) + gli.Uniform1i(sar.alphaTex, alphaTexSlot) + return sar.vertex, sar.alphaTexCoord +} + // SetLineWidth sets the line width for any line drawing calls func (cv *Canvas) SetLineWidth(width float32) { cv.state.lineWidth = width diff --git a/imagedata.go b/imagedata.go index 70ea60f..6a890af 100644 --- a/imagedata.go +++ b/imagedata.go @@ -79,14 +79,14 @@ func (cv *Canvas) PutImageData(img *image.RGBA, x, y int) { 0, 0, 1, 0, 1, 1, 0, 1} gli.BufferData(gl_ARRAY_BUFFER, len(data)*4, unsafe.Pointer(&data[0]), gl_STREAM_DRAW) - gli.UseProgram(tr.id) - gli.Uniform1i(tr.image, 0) - gli.Uniform2f(tr.canvasSize, cv.fw, cv.fh) - gli.VertexAttribPointer(tr.vertex, 2, gl_FLOAT, false, 0, nil) - gli.VertexAttribPointer(tr.texCoord, 2, gl_FLOAT, false, 0, gli.PtrOffset(8*4)) - gli.EnableVertexAttribArray(tr.vertex) - gli.EnableVertexAttribArray(tr.texCoord) + gli.UseProgram(ir.id) + gli.Uniform1i(ir.image, 0) + gli.Uniform2f(ir.canvasSize, cv.fw, cv.fh) + gli.VertexAttribPointer(ir.vertex, 2, gl_FLOAT, false, 0, nil) + gli.VertexAttribPointer(ir.texCoord, 2, gl_FLOAT, false, 0, gli.PtrOffset(8*4)) + gli.EnableVertexAttribArray(ir.vertex) + gli.EnableVertexAttribArray(ir.texCoord) gli.DrawArrays(gl_TRIANGLE_FAN, 0, 4) - gli.DisableVertexAttribArray(tr.vertex) - gli.DisableVertexAttribArray(tr.texCoord) + gli.DisableVertexAttribArray(ir.vertex) + gli.DisableVertexAttribArray(ir.texCoord) } diff --git a/images.go b/images.go index 74ad926..27d5965 100644 --- a/images.go +++ b/images.go @@ -233,14 +233,14 @@ func (cv *Canvas) DrawImage(image interface{}, coords ...float32) { gli.ActiveTexture(gl_TEXTURE0) gli.BindTexture(gl_TEXTURE_2D, img.tex) - gli.UseProgram(tr.id) - gli.Uniform1i(tr.image, 0) - gli.Uniform2f(tr.canvasSize, cv.fw, cv.fh) - gli.VertexAttribPointer(tr.vertex, 2, gl_FLOAT, false, 0, nil) - gli.VertexAttribPointer(tr.texCoord, 2, gl_FLOAT, false, 0, gli.PtrOffset(8*4)) - gli.EnableVertexAttribArray(tr.vertex) - gli.EnableVertexAttribArray(tr.texCoord) + gli.UseProgram(ir.id) + gli.Uniform1i(ir.image, 0) + gli.Uniform2f(ir.canvasSize, cv.fw, cv.fh) + gli.VertexAttribPointer(ir.vertex, 2, gl_FLOAT, false, 0, nil) + gli.VertexAttribPointer(ir.texCoord, 2, gl_FLOAT, false, 0, gli.PtrOffset(8*4)) + gli.EnableVertexAttribArray(ir.vertex) + gli.EnableVertexAttribArray(ir.texCoord) gli.DrawArrays(gl_TRIANGLE_FAN, 0, 4) - gli.DisableVertexAttribArray(tr.vertex) - gli.DisableVertexAttribArray(tr.texCoord) + gli.DisableVertexAttribArray(ir.vertex) + gli.DisableVertexAttribArray(ir.texCoord) } diff --git a/made_shaders.go b/made_shaders.go index 4ea2bac..3a0c677 100755 --- a/made_shaders.go +++ b/made_shaders.go @@ -6,19 +6,22 @@ import ( "strings" ) -type textureShader struct { +type linearGradientShader struct { id uint32 vertex uint32 - texCoord uint32 canvasSize int32 - image int32 + invmat int32 + gradient int32 + from int32 + dir int32 + len int32 } -func loadTextureShader() (*textureShader, error) { +func loadLinearGradientShader() (*linearGradientShader, error) { var vs, fs, program uint32 { - csource, freeFunc := gli.Strs(textureVS + "\x00") + csource, freeFunc := gli.Strs(linearGradientVS + "\x00") defer freeFunc() vs = gli.CreateShader(gl_VERTEX_SHADER) @@ -30,22 +33,22 @@ func loadTextureShader() (*textureShader, error) { if logLength > 0 { shLog := strings.Repeat("\x00", int(logLength+1)) gli.GetShaderInfoLog(vs, logLength, nil, gli.Str(shLog)) - fmt.Printf("VERTEX_SHADER compilation log:\n\n%s\n", shLog) + fmt.Printf("VERTEX_SHADER compilation log for linearGradientVS:\n\n%s\n", shLog) } var status int32 gli.GetShaderiv(vs, gl_COMPILE_STATUS, &status) if status != gl_TRUE { gli.DeleteShader(vs) - return nil, errors.New("Error compiling GL_VERTEX_SHADER shader part") + return nil, errors.New("Error compiling GL_VERTEX_SHADER shader part for linearGradientVS") } if glErr := gli.GetError(); glErr != gl_NO_ERROR { - return nil, errors.New("error compiling shader part, glError: " + fmt.Sprint(glErr)) + return nil, errors.New("error compiling shader part for linearGradientVS, glError: " + fmt.Sprint(glErr)) } } { - csource, freeFunc := gli.Strs(textureFS + "\x00") + csource, freeFunc := gli.Strs(linearGradientFS + "\x00") defer freeFunc() fs = gli.CreateShader(gl_FRAGMENT_SHADER) @@ -57,17 +60,17 @@ func loadTextureShader() (*textureShader, error) { if logLength > 0 { shLog := strings.Repeat("\x00", int(logLength+1)) gli.GetShaderInfoLog(fs, logLength, nil, gli.Str(shLog)) - fmt.Printf("FRAGMENT_SHADER compilation log:\n\n%s\n", shLog) + fmt.Printf("FRAGMENT_SHADER compilation log for linearGradientFS:\n\n%s\n", shLog) } var status int32 gli.GetShaderiv(fs, gl_COMPILE_STATUS, &status) if status != gl_TRUE { gli.DeleteShader(fs) - return nil, errors.New("Error compiling GL_FRAGMENT_SHADER shader part") + return nil, errors.New("Error compiling GL_FRAGMENT_SHADER shader part for linearGradientFS") } if glErr := gli.GetError(); glErr != gl_NO_ERROR { - return nil, errors.New("error compiling shader part, glError: " + fmt.Sprint(glErr)) + return nil, errors.New("error compiling shader part for linearGradientFS, glError: " + fmt.Sprint(glErr)) } } @@ -82,7 +85,7 @@ func loadTextureShader() (*textureShader, error) { if logLength > 0 { shLog := strings.Repeat("\x00", int(logLength+1)) gli.GetProgramInfoLog(program, logLength, nil, gli.Str(shLog)) - fmt.Printf("Shader link log:\n\n%s\n", shLog) + fmt.Printf("Shader link log for linearGradientFS:\n\n%s\n", shLog) } var status int32 @@ -90,35 +93,44 @@ func loadTextureShader() (*textureShader, error) { if status != gl_TRUE { gli.DeleteShader(vs) gli.DeleteShader(fs) - return nil, errors.New("error linking shader") + return nil, errors.New("error linking shader for linearGradientFS") } if glErr := gli.GetError(); glErr != gl_NO_ERROR { - return nil, errors.New("error linking shader, glError: " + fmt.Sprint(glErr)) + return nil, errors.New("error linking shader for linearGradientFS, glError: " + fmt.Sprint(glErr)) } } - result := &textureShader{} + result := &linearGradientShader{} result.id = program result.vertex = uint32(gli.GetAttribLocation(program, gli.Str("vertex\x00"))) - result.texCoord = uint32(gli.GetAttribLocation(program, gli.Str("texCoord\x00"))) result.canvasSize = gli.GetUniformLocation(program, gli.Str("canvasSize\x00")) - result.image = gli.GetUniformLocation(program, gli.Str("image\x00")) + result.invmat = gli.GetUniformLocation(program, gli.Str("invmat\x00")) + result.gradient = gli.GetUniformLocation(program, gli.Str("gradient\x00")) + result.from = gli.GetUniformLocation(program, gli.Str("from\x00")) + result.dir = gli.GetUniformLocation(program, gli.Str("dir\x00")) + result.len = gli.GetUniformLocation(program, gli.Str("len\x00")) return result, nil } -type solidShader struct { - id uint32 - vertex uint32 - canvasSize int32 - color int32 +type linearGradientAlphaShader struct { + id uint32 + vertex uint32 + alphaTexCoord uint32 + canvasSize int32 + invmat int32 + gradient int32 + from int32 + dir int32 + len int32 + alphaTex int32 } -func loadSolidShader() (*solidShader, error) { +func loadLinearGradientAlphaShader() (*linearGradientAlphaShader, error) { var vs, fs, program uint32 { - csource, freeFunc := gli.Strs(solidVS + "\x00") + csource, freeFunc := gli.Strs(linearGradientAlphaVS + "\x00") defer freeFunc() vs = gli.CreateShader(gl_VERTEX_SHADER) @@ -130,22 +142,22 @@ func loadSolidShader() (*solidShader, error) { if logLength > 0 { shLog := strings.Repeat("\x00", int(logLength+1)) gli.GetShaderInfoLog(vs, logLength, nil, gli.Str(shLog)) - fmt.Printf("VERTEX_SHADER compilation log:\n\n%s\n", shLog) + fmt.Printf("VERTEX_SHADER compilation log for linearGradientAlphaVS:\n\n%s\n", shLog) } var status int32 gli.GetShaderiv(vs, gl_COMPILE_STATUS, &status) if status != gl_TRUE { gli.DeleteShader(vs) - return nil, errors.New("Error compiling GL_VERTEX_SHADER shader part") + return nil, errors.New("Error compiling GL_VERTEX_SHADER shader part for linearGradientAlphaVS") } if glErr := gli.GetError(); glErr != gl_NO_ERROR { - return nil, errors.New("error compiling shader part, glError: " + fmt.Sprint(glErr)) + return nil, errors.New("error compiling shader part for linearGradientAlphaVS, glError: " + fmt.Sprint(glErr)) } } { - csource, freeFunc := gli.Strs(solidFS + "\x00") + csource, freeFunc := gli.Strs(linearGradientAlphaFS + "\x00") defer freeFunc() fs = gli.CreateShader(gl_FRAGMENT_SHADER) @@ -157,17 +169,17 @@ func loadSolidShader() (*solidShader, error) { if logLength > 0 { shLog := strings.Repeat("\x00", int(logLength+1)) gli.GetShaderInfoLog(fs, logLength, nil, gli.Str(shLog)) - fmt.Printf("FRAGMENT_SHADER compilation log:\n\n%s\n", shLog) + fmt.Printf("FRAGMENT_SHADER compilation log for linearGradientAlphaFS:\n\n%s\n", shLog) } var status int32 gli.GetShaderiv(fs, gl_COMPILE_STATUS, &status) if status != gl_TRUE { gli.DeleteShader(fs) - return nil, errors.New("Error compiling GL_FRAGMENT_SHADER shader part") + return nil, errors.New("Error compiling GL_FRAGMENT_SHADER shader part for linearGradientAlphaFS") } if glErr := gli.GetError(); glErr != gl_NO_ERROR { - return nil, errors.New("error compiling shader part, glError: " + fmt.Sprint(glErr)) + return nil, errors.New("error compiling shader part for linearGradientAlphaFS, glError: " + fmt.Sprint(glErr)) } } @@ -182,7 +194,7 @@ func loadSolidShader() (*solidShader, error) { if logLength > 0 { shLog := strings.Repeat("\x00", int(logLength+1)) gli.GetProgramInfoLog(program, logLength, nil, gli.Str(shLog)) - fmt.Printf("Shader link log:\n\n%s\n", shLog) + fmt.Printf("Shader link log for linearGradientAlphaFS:\n\n%s\n", shLog) } var status int32 @@ -190,18 +202,131 @@ func loadSolidShader() (*solidShader, error) { if status != gl_TRUE { gli.DeleteShader(vs) gli.DeleteShader(fs) - return nil, errors.New("error linking shader") + return nil, errors.New("error linking shader for linearGradientAlphaFS") } if glErr := gli.GetError(); glErr != gl_NO_ERROR { - return nil, errors.New("error linking shader, glError: " + fmt.Sprint(glErr)) + return nil, errors.New("error linking shader for linearGradientAlphaFS, glError: " + fmt.Sprint(glErr)) } } - result := &solidShader{} + result := &linearGradientAlphaShader{} result.id = program result.vertex = uint32(gli.GetAttribLocation(program, gli.Str("vertex\x00"))) + result.alphaTexCoord = uint32(gli.GetAttribLocation(program, gli.Str("alphaTexCoord\x00"))) result.canvasSize = gli.GetUniformLocation(program, gli.Str("canvasSize\x00")) - result.color = gli.GetUniformLocation(program, gli.Str("color\x00")) + result.invmat = gli.GetUniformLocation(program, gli.Str("invmat\x00")) + result.gradient = gli.GetUniformLocation(program, gli.Str("gradient\x00")) + result.from = gli.GetUniformLocation(program, gli.Str("from\x00")) + result.dir = gli.GetUniformLocation(program, gli.Str("dir\x00")) + result.len = gli.GetUniformLocation(program, gli.Str("len\x00")) + result.alphaTex = gli.GetUniformLocation(program, gli.Str("alphaTex\x00")) + + return result, nil +} + +type imagePatternAlphaShader struct { + id uint32 + vertex uint32 + alphaTexCoord uint32 + canvasSize int32 + imageSize int32 + invmat int32 + image int32 + alphaTex int32 +} + +func loadImagePatternAlphaShader() (*imagePatternAlphaShader, error) { + var vs, fs, program uint32 + + { + csource, freeFunc := gli.Strs(imagePatternAlphaVS + "\x00") + defer freeFunc() + + vs = gli.CreateShader(gl_VERTEX_SHADER) + gli.ShaderSource(vs, 1, csource, nil) + gli.CompileShader(vs) + + var logLength int32 + gli.GetShaderiv(vs, gl_INFO_LOG_LENGTH, &logLength) + if logLength > 0 { + shLog := strings.Repeat("\x00", int(logLength+1)) + gli.GetShaderInfoLog(vs, logLength, nil, gli.Str(shLog)) + fmt.Printf("VERTEX_SHADER compilation log for imagePatternAlphaVS:\n\n%s\n", shLog) + } + + var status int32 + gli.GetShaderiv(vs, gl_COMPILE_STATUS, &status) + if status != gl_TRUE { + gli.DeleteShader(vs) + return nil, errors.New("Error compiling GL_VERTEX_SHADER shader part for imagePatternAlphaVS") + } + if glErr := gli.GetError(); glErr != gl_NO_ERROR { + return nil, errors.New("error compiling shader part for imagePatternAlphaVS, glError: " + fmt.Sprint(glErr)) + } + } + + { + csource, freeFunc := gli.Strs(imagePatternAlphaFS + "\x00") + defer freeFunc() + + fs = gli.CreateShader(gl_FRAGMENT_SHADER) + gli.ShaderSource(fs, 1, csource, nil) + gli.CompileShader(fs) + + var logLength int32 + gli.GetShaderiv(fs, gl_INFO_LOG_LENGTH, &logLength) + if logLength > 0 { + shLog := strings.Repeat("\x00", int(logLength+1)) + gli.GetShaderInfoLog(fs, logLength, nil, gli.Str(shLog)) + fmt.Printf("FRAGMENT_SHADER compilation log for imagePatternAlphaFS:\n\n%s\n", shLog) + } + + var status int32 + gli.GetShaderiv(fs, gl_COMPILE_STATUS, &status) + if status != gl_TRUE { + gli.DeleteShader(fs) + return nil, errors.New("Error compiling GL_FRAGMENT_SHADER shader part for imagePatternAlphaFS") + } + if glErr := gli.GetError(); glErr != gl_NO_ERROR { + return nil, errors.New("error compiling shader part for imagePatternAlphaFS, glError: " + fmt.Sprint(glErr)) + } + } + + { + program = gli.CreateProgram() + gli.AttachShader(program, vs) + gli.AttachShader(program, fs) + gli.LinkProgram(program) + + var logLength int32 + gli.GetProgramiv(program, gl_INFO_LOG_LENGTH, &logLength) + if logLength > 0 { + shLog := strings.Repeat("\x00", int(logLength+1)) + gli.GetProgramInfoLog(program, logLength, nil, gli.Str(shLog)) + fmt.Printf("Shader link log for imagePatternAlphaFS:\n\n%s\n", shLog) + } + + var status int32 + gli.GetProgramiv(program, gl_LINK_STATUS, &status) + if status != gl_TRUE { + gli.DeleteShader(vs) + gli.DeleteShader(fs) + return nil, errors.New("error linking shader for imagePatternAlphaFS") + } + if glErr := gli.GetError(); glErr != gl_NO_ERROR { + return nil, errors.New("error linking shader for imagePatternAlphaFS, glError: " + fmt.Sprint(glErr)) + } + } + + result := &imagePatternAlphaShader{} + result.id = program + result.vertex = uint32(gli.GetAttribLocation(program, gli.Str("vertex\x00"))) + result.alphaTexCoord = uint32(gli.GetAttribLocation(program, gli.Str("alphaTexCoord\x00"))) + result.canvasSize = gli.GetUniformLocation(program, gli.Str("canvasSize\x00")) + result.imageSize = gli.GetUniformLocation(program, gli.Str("imageSize\x00")) + result.invmat = gli.GetUniformLocation(program, gli.Str("invmat\x00")) + result.image = gli.GetUniformLocation(program, gli.Str("image\x00")) + result.alphaTex = gli.GetUniformLocation(program, gli.Str("alphaTex\x00")) return result, nil } @@ -231,17 +356,17 @@ func loadImagePatternShader() (*imagePatternShader, error) { if logLength > 0 { shLog := strings.Repeat("\x00", int(logLength+1)) gli.GetShaderInfoLog(vs, logLength, nil, gli.Str(shLog)) - fmt.Printf("VERTEX_SHADER compilation log:\n\n%s\n", shLog) + fmt.Printf("VERTEX_SHADER compilation log for imagePatternVS:\n\n%s\n", shLog) } var status int32 gli.GetShaderiv(vs, gl_COMPILE_STATUS, &status) if status != gl_TRUE { gli.DeleteShader(vs) - return nil, errors.New("Error compiling GL_VERTEX_SHADER shader part") + return nil, errors.New("Error compiling GL_VERTEX_SHADER shader part for imagePatternVS") } if glErr := gli.GetError(); glErr != gl_NO_ERROR { - return nil, errors.New("error compiling shader part, glError: " + fmt.Sprint(glErr)) + return nil, errors.New("error compiling shader part for imagePatternVS, glError: " + fmt.Sprint(glErr)) } } @@ -258,17 +383,17 @@ func loadImagePatternShader() (*imagePatternShader, error) { if logLength > 0 { shLog := strings.Repeat("\x00", int(logLength+1)) gli.GetShaderInfoLog(fs, logLength, nil, gli.Str(shLog)) - fmt.Printf("FRAGMENT_SHADER compilation log:\n\n%s\n", shLog) + fmt.Printf("FRAGMENT_SHADER compilation log for imagePatternFS:\n\n%s\n", shLog) } var status int32 gli.GetShaderiv(fs, gl_COMPILE_STATUS, &status) if status != gl_TRUE { gli.DeleteShader(fs) - return nil, errors.New("Error compiling GL_FRAGMENT_SHADER shader part") + return nil, errors.New("Error compiling GL_FRAGMENT_SHADER shader part for imagePatternFS") } if glErr := gli.GetError(); glErr != gl_NO_ERROR { - return nil, errors.New("error compiling shader part, glError: " + fmt.Sprint(glErr)) + return nil, errors.New("error compiling shader part for imagePatternFS, glError: " + fmt.Sprint(glErr)) } } @@ -283,7 +408,7 @@ func loadImagePatternShader() (*imagePatternShader, error) { if logLength > 0 { shLog := strings.Repeat("\x00", int(logLength+1)) gli.GetProgramInfoLog(program, logLength, nil, gli.Str(shLog)) - fmt.Printf("Shader link log:\n\n%s\n", shLog) + fmt.Printf("Shader link log for imagePatternFS:\n\n%s\n", shLog) } var status int32 @@ -291,10 +416,10 @@ func loadImagePatternShader() (*imagePatternShader, error) { if status != gl_TRUE { gli.DeleteShader(vs) gli.DeleteShader(fs) - return nil, errors.New("error linking shader") + return nil, errors.New("error linking shader for imagePatternFS") } if glErr := gli.GetError(); glErr != gl_NO_ERROR { - return nil, errors.New("error linking shader, glError: " + fmt.Sprint(glErr)) + return nil, errors.New("error linking shader for imagePatternFS, glError: " + fmt.Sprint(glErr)) } } @@ -309,22 +434,20 @@ func loadImagePatternShader() (*imagePatternShader, error) { return result, nil } -type linearGradientShader struct { - id uint32 - vertex uint32 - canvasSize int32 - invmat int32 - gradient int32 - from int32 - dir int32 - len int32 +type solidAlphaShader struct { + id uint32 + vertex uint32 + alphaTexCoord uint32 + canvasSize int32 + color int32 + alphaTex int32 } -func loadLinearGradientShader() (*linearGradientShader, error) { +func loadSolidAlphaShader() (*solidAlphaShader, error) { var vs, fs, program uint32 { - csource, freeFunc := gli.Strs(linearGradientVS + "\x00") + csource, freeFunc := gli.Strs(solidAlphaVS + "\x00") defer freeFunc() vs = gli.CreateShader(gl_VERTEX_SHADER) @@ -336,22 +459,22 @@ func loadLinearGradientShader() (*linearGradientShader, error) { if logLength > 0 { shLog := strings.Repeat("\x00", int(logLength+1)) gli.GetShaderInfoLog(vs, logLength, nil, gli.Str(shLog)) - fmt.Printf("VERTEX_SHADER compilation log:\n\n%s\n", shLog) + fmt.Printf("VERTEX_SHADER compilation log for solidAlphaVS:\n\n%s\n", shLog) } var status int32 gli.GetShaderiv(vs, gl_COMPILE_STATUS, &status) if status != gl_TRUE { gli.DeleteShader(vs) - return nil, errors.New("Error compiling GL_VERTEX_SHADER shader part") + return nil, errors.New("Error compiling GL_VERTEX_SHADER shader part for solidAlphaVS") } if glErr := gli.GetError(); glErr != gl_NO_ERROR { - return nil, errors.New("error compiling shader part, glError: " + fmt.Sprint(glErr)) + return nil, errors.New("error compiling shader part for solidAlphaVS, glError: " + fmt.Sprint(glErr)) } } { - csource, freeFunc := gli.Strs(linearGradientFS + "\x00") + csource, freeFunc := gli.Strs(solidAlphaFS + "\x00") defer freeFunc() fs = gli.CreateShader(gl_FRAGMENT_SHADER) @@ -363,17 +486,17 @@ func loadLinearGradientShader() (*linearGradientShader, error) { if logLength > 0 { shLog := strings.Repeat("\x00", int(logLength+1)) gli.GetShaderInfoLog(fs, logLength, nil, gli.Str(shLog)) - fmt.Printf("FRAGMENT_SHADER compilation log:\n\n%s\n", shLog) + fmt.Printf("FRAGMENT_SHADER compilation log for solidAlphaFS:\n\n%s\n", shLog) } var status int32 gli.GetShaderiv(fs, gl_COMPILE_STATUS, &status) if status != gl_TRUE { gli.DeleteShader(fs) - return nil, errors.New("Error compiling GL_FRAGMENT_SHADER shader part") + return nil, errors.New("Error compiling GL_FRAGMENT_SHADER shader part for solidAlphaFS") } if glErr := gli.GetError(); glErr != gl_NO_ERROR { - return nil, errors.New("error compiling shader part, glError: " + fmt.Sprint(glErr)) + return nil, errors.New("error compiling shader part for solidAlphaFS, glError: " + fmt.Sprint(glErr)) } } @@ -388,7 +511,7 @@ func loadLinearGradientShader() (*linearGradientShader, error) { if logLength > 0 { shLog := strings.Repeat("\x00", int(logLength+1)) gli.GetProgramInfoLog(program, logLength, nil, gli.Str(shLog)) - fmt.Printf("Shader link log:\n\n%s\n", shLog) + fmt.Printf("Shader link log for solidAlphaFS:\n\n%s\n", shLog) } var status int32 @@ -396,22 +519,337 @@ func loadLinearGradientShader() (*linearGradientShader, error) { if status != gl_TRUE { gli.DeleteShader(vs) gli.DeleteShader(fs) - return nil, errors.New("error linking shader") + return nil, errors.New("error linking shader for solidAlphaFS") } if glErr := gli.GetError(); glErr != gl_NO_ERROR { - return nil, errors.New("error linking shader, glError: " + fmt.Sprint(glErr)) + return nil, errors.New("error linking shader for solidAlphaFS, glError: " + fmt.Sprint(glErr)) } } - result := &linearGradientShader{} + result := &solidAlphaShader{} result.id = program result.vertex = uint32(gli.GetAttribLocation(program, gli.Str("vertex\x00"))) + result.alphaTexCoord = uint32(gli.GetAttribLocation(program, gli.Str("alphaTexCoord\x00"))) + result.canvasSize = gli.GetUniformLocation(program, gli.Str("canvasSize\x00")) + result.color = gli.GetUniformLocation(program, gli.Str("color\x00")) + result.alphaTex = gli.GetUniformLocation(program, gli.Str("alphaTex\x00")) + + return result, nil +} + +type radialGradientAlphaShader struct { + id uint32 + vertex uint32 + alphaTexCoord uint32 + canvasSize int32 + invmat int32 + gradient int32 + from int32 + to int32 + dir int32 + radFrom int32 + radTo int32 + len int32 + alphaTex int32 +} + +func loadRadialGradientAlphaShader() (*radialGradientAlphaShader, error) { + var vs, fs, program uint32 + + { + csource, freeFunc := gli.Strs(radialGradientAlphaVS + "\x00") + defer freeFunc() + + vs = gli.CreateShader(gl_VERTEX_SHADER) + gli.ShaderSource(vs, 1, csource, nil) + gli.CompileShader(vs) + + var logLength int32 + gli.GetShaderiv(vs, gl_INFO_LOG_LENGTH, &logLength) + if logLength > 0 { + shLog := strings.Repeat("\x00", int(logLength+1)) + gli.GetShaderInfoLog(vs, logLength, nil, gli.Str(shLog)) + fmt.Printf("VERTEX_SHADER compilation log for radialGradientAlphaVS:\n\n%s\n", shLog) + } + + var status int32 + gli.GetShaderiv(vs, gl_COMPILE_STATUS, &status) + if status != gl_TRUE { + gli.DeleteShader(vs) + return nil, errors.New("Error compiling GL_VERTEX_SHADER shader part for radialGradientAlphaVS") + } + if glErr := gli.GetError(); glErr != gl_NO_ERROR { + return nil, errors.New("error compiling shader part for radialGradientAlphaVS, glError: " + fmt.Sprint(glErr)) + } + } + + { + csource, freeFunc := gli.Strs(radialGradientAlphaFS + "\x00") + defer freeFunc() + + fs = gli.CreateShader(gl_FRAGMENT_SHADER) + gli.ShaderSource(fs, 1, csource, nil) + gli.CompileShader(fs) + + var logLength int32 + gli.GetShaderiv(fs, gl_INFO_LOG_LENGTH, &logLength) + if logLength > 0 { + shLog := strings.Repeat("\x00", int(logLength+1)) + gli.GetShaderInfoLog(fs, logLength, nil, gli.Str(shLog)) + fmt.Printf("FRAGMENT_SHADER compilation log for radialGradientAlphaFS:\n\n%s\n", shLog) + } + + var status int32 + gli.GetShaderiv(fs, gl_COMPILE_STATUS, &status) + if status != gl_TRUE { + gli.DeleteShader(fs) + return nil, errors.New("Error compiling GL_FRAGMENT_SHADER shader part for radialGradientAlphaFS") + } + if glErr := gli.GetError(); glErr != gl_NO_ERROR { + return nil, errors.New("error compiling shader part for radialGradientAlphaFS, glError: " + fmt.Sprint(glErr)) + } + } + + { + program = gli.CreateProgram() + gli.AttachShader(program, vs) + gli.AttachShader(program, fs) + gli.LinkProgram(program) + + var logLength int32 + gli.GetProgramiv(program, gl_INFO_LOG_LENGTH, &logLength) + if logLength > 0 { + shLog := strings.Repeat("\x00", int(logLength+1)) + gli.GetProgramInfoLog(program, logLength, nil, gli.Str(shLog)) + fmt.Printf("Shader link log for radialGradientAlphaFS:\n\n%s\n", shLog) + } + + var status int32 + gli.GetProgramiv(program, gl_LINK_STATUS, &status) + if status != gl_TRUE { + gli.DeleteShader(vs) + gli.DeleteShader(fs) + return nil, errors.New("error linking shader for radialGradientAlphaFS") + } + if glErr := gli.GetError(); glErr != gl_NO_ERROR { + return nil, errors.New("error linking shader for radialGradientAlphaFS, glError: " + fmt.Sprint(glErr)) + } + } + + result := &radialGradientAlphaShader{} + result.id = program + result.vertex = uint32(gli.GetAttribLocation(program, gli.Str("vertex\x00"))) + result.alphaTexCoord = uint32(gli.GetAttribLocation(program, gli.Str("alphaTexCoord\x00"))) result.canvasSize = gli.GetUniformLocation(program, gli.Str("canvasSize\x00")) result.invmat = gli.GetUniformLocation(program, gli.Str("invmat\x00")) result.gradient = gli.GetUniformLocation(program, gli.Str("gradient\x00")) result.from = gli.GetUniformLocation(program, gli.Str("from\x00")) + result.to = gli.GetUniformLocation(program, gli.Str("to\x00")) result.dir = gli.GetUniformLocation(program, gli.Str("dir\x00")) + result.radFrom = gli.GetUniformLocation(program, gli.Str("radFrom\x00")) + result.radTo = gli.GetUniformLocation(program, gli.Str("radTo\x00")) result.len = gli.GetUniformLocation(program, gli.Str("len\x00")) + result.alphaTex = gli.GetUniformLocation(program, gli.Str("alphaTex\x00")) + + return result, nil +} + +type solidShader struct { + id uint32 + vertex uint32 + canvasSize int32 + color int32 +} + +func loadSolidShader() (*solidShader, error) { + var vs, fs, program uint32 + + { + csource, freeFunc := gli.Strs(solidVS + "\x00") + defer freeFunc() + + vs = gli.CreateShader(gl_VERTEX_SHADER) + gli.ShaderSource(vs, 1, csource, nil) + gli.CompileShader(vs) + + var logLength int32 + gli.GetShaderiv(vs, gl_INFO_LOG_LENGTH, &logLength) + if logLength > 0 { + shLog := strings.Repeat("\x00", int(logLength+1)) + gli.GetShaderInfoLog(vs, logLength, nil, gli.Str(shLog)) + fmt.Printf("VERTEX_SHADER compilation log for solidVS:\n\n%s\n", shLog) + } + + var status int32 + gli.GetShaderiv(vs, gl_COMPILE_STATUS, &status) + if status != gl_TRUE { + gli.DeleteShader(vs) + return nil, errors.New("Error compiling GL_VERTEX_SHADER shader part for solidVS") + } + if glErr := gli.GetError(); glErr != gl_NO_ERROR { + return nil, errors.New("error compiling shader part for solidVS, glError: " + fmt.Sprint(glErr)) + } + } + + { + csource, freeFunc := gli.Strs(solidFS + "\x00") + defer freeFunc() + + fs = gli.CreateShader(gl_FRAGMENT_SHADER) + gli.ShaderSource(fs, 1, csource, nil) + gli.CompileShader(fs) + + var logLength int32 + gli.GetShaderiv(fs, gl_INFO_LOG_LENGTH, &logLength) + if logLength > 0 { + shLog := strings.Repeat("\x00", int(logLength+1)) + gli.GetShaderInfoLog(fs, logLength, nil, gli.Str(shLog)) + fmt.Printf("FRAGMENT_SHADER compilation log for solidFS:\n\n%s\n", shLog) + } + + var status int32 + gli.GetShaderiv(fs, gl_COMPILE_STATUS, &status) + if status != gl_TRUE { + gli.DeleteShader(fs) + return nil, errors.New("Error compiling GL_FRAGMENT_SHADER shader part for solidFS") + } + if glErr := gli.GetError(); glErr != gl_NO_ERROR { + return nil, errors.New("error compiling shader part for solidFS, glError: " + fmt.Sprint(glErr)) + } + } + + { + program = gli.CreateProgram() + gli.AttachShader(program, vs) + gli.AttachShader(program, fs) + gli.LinkProgram(program) + + var logLength int32 + gli.GetProgramiv(program, gl_INFO_LOG_LENGTH, &logLength) + if logLength > 0 { + shLog := strings.Repeat("\x00", int(logLength+1)) + gli.GetProgramInfoLog(program, logLength, nil, gli.Str(shLog)) + fmt.Printf("Shader link log for solidFS:\n\n%s\n", shLog) + } + + var status int32 + gli.GetProgramiv(program, gl_LINK_STATUS, &status) + if status != gl_TRUE { + gli.DeleteShader(vs) + gli.DeleteShader(fs) + return nil, errors.New("error linking shader for solidFS") + } + if glErr := gli.GetError(); glErr != gl_NO_ERROR { + return nil, errors.New("error linking shader for solidFS, glError: " + fmt.Sprint(glErr)) + } + } + + result := &solidShader{} + result.id = program + result.vertex = uint32(gli.GetAttribLocation(program, gli.Str("vertex\x00"))) + result.canvasSize = gli.GetUniformLocation(program, gli.Str("canvasSize\x00")) + result.color = gli.GetUniformLocation(program, gli.Str("color\x00")) + + return result, nil +} + +type imageShader struct { + id uint32 + vertex uint32 + texCoord uint32 + canvasSize int32 + image int32 +} + +func loadImageShader() (*imageShader, error) { + var vs, fs, program uint32 + + { + csource, freeFunc := gli.Strs(imageVS + "\x00") + defer freeFunc() + + vs = gli.CreateShader(gl_VERTEX_SHADER) + gli.ShaderSource(vs, 1, csource, nil) + gli.CompileShader(vs) + + var logLength int32 + gli.GetShaderiv(vs, gl_INFO_LOG_LENGTH, &logLength) + if logLength > 0 { + shLog := strings.Repeat("\x00", int(logLength+1)) + gli.GetShaderInfoLog(vs, logLength, nil, gli.Str(shLog)) + fmt.Printf("VERTEX_SHADER compilation log for imageVS:\n\n%s\n", shLog) + } + + var status int32 + gli.GetShaderiv(vs, gl_COMPILE_STATUS, &status) + if status != gl_TRUE { + gli.DeleteShader(vs) + return nil, errors.New("Error compiling GL_VERTEX_SHADER shader part for imageVS") + } + if glErr := gli.GetError(); glErr != gl_NO_ERROR { + return nil, errors.New("error compiling shader part for imageVS, glError: " + fmt.Sprint(glErr)) + } + } + + { + csource, freeFunc := gli.Strs(imageFS + "\x00") + defer freeFunc() + + fs = gli.CreateShader(gl_FRAGMENT_SHADER) + gli.ShaderSource(fs, 1, csource, nil) + gli.CompileShader(fs) + + var logLength int32 + gli.GetShaderiv(fs, gl_INFO_LOG_LENGTH, &logLength) + if logLength > 0 { + shLog := strings.Repeat("\x00", int(logLength+1)) + gli.GetShaderInfoLog(fs, logLength, nil, gli.Str(shLog)) + fmt.Printf("FRAGMENT_SHADER compilation log for imageFS:\n\n%s\n", shLog) + } + + var status int32 + gli.GetShaderiv(fs, gl_COMPILE_STATUS, &status) + if status != gl_TRUE { + gli.DeleteShader(fs) + return nil, errors.New("Error compiling GL_FRAGMENT_SHADER shader part for imageFS") + } + if glErr := gli.GetError(); glErr != gl_NO_ERROR { + return nil, errors.New("error compiling shader part for imageFS, glError: " + fmt.Sprint(glErr)) + } + } + + { + program = gli.CreateProgram() + gli.AttachShader(program, vs) + gli.AttachShader(program, fs) + gli.LinkProgram(program) + + var logLength int32 + gli.GetProgramiv(program, gl_INFO_LOG_LENGTH, &logLength) + if logLength > 0 { + shLog := strings.Repeat("\x00", int(logLength+1)) + gli.GetProgramInfoLog(program, logLength, nil, gli.Str(shLog)) + fmt.Printf("Shader link log for imageFS:\n\n%s\n", shLog) + } + + var status int32 + gli.GetProgramiv(program, gl_LINK_STATUS, &status) + if status != gl_TRUE { + gli.DeleteShader(vs) + gli.DeleteShader(fs) + return nil, errors.New("error linking shader for imageFS") + } + if glErr := gli.GetError(); glErr != gl_NO_ERROR { + return nil, errors.New("error linking shader for imageFS, glError: " + fmt.Sprint(glErr)) + } + } + + result := &imageShader{} + result.id = program + result.vertex = uint32(gli.GetAttribLocation(program, gli.Str("vertex\x00"))) + result.texCoord = uint32(gli.GetAttribLocation(program, gli.Str("texCoord\x00"))) + result.canvasSize = gli.GetUniformLocation(program, gli.Str("canvasSize\x00")) + result.image = gli.GetUniformLocation(program, gli.Str("image\x00")) return result, nil } @@ -446,17 +884,17 @@ func loadRadialGradientShader() (*radialGradientShader, error) { if logLength > 0 { shLog := strings.Repeat("\x00", int(logLength+1)) gli.GetShaderInfoLog(vs, logLength, nil, gli.Str(shLog)) - fmt.Printf("VERTEX_SHADER compilation log:\n\n%s\n", shLog) + fmt.Printf("VERTEX_SHADER compilation log for radialGradientVS:\n\n%s\n", shLog) } var status int32 gli.GetShaderiv(vs, gl_COMPILE_STATUS, &status) if status != gl_TRUE { gli.DeleteShader(vs) - return nil, errors.New("Error compiling GL_VERTEX_SHADER shader part") + return nil, errors.New("Error compiling GL_VERTEX_SHADER shader part for radialGradientVS") } if glErr := gli.GetError(); glErr != gl_NO_ERROR { - return nil, errors.New("error compiling shader part, glError: " + fmt.Sprint(glErr)) + return nil, errors.New("error compiling shader part for radialGradientVS, glError: " + fmt.Sprint(glErr)) } } @@ -473,17 +911,17 @@ func loadRadialGradientShader() (*radialGradientShader, error) { if logLength > 0 { shLog := strings.Repeat("\x00", int(logLength+1)) gli.GetShaderInfoLog(fs, logLength, nil, gli.Str(shLog)) - fmt.Printf("FRAGMENT_SHADER compilation log:\n\n%s\n", shLog) + fmt.Printf("FRAGMENT_SHADER compilation log for radialGradientFS:\n\n%s\n", shLog) } var status int32 gli.GetShaderiv(fs, gl_COMPILE_STATUS, &status) if status != gl_TRUE { gli.DeleteShader(fs) - return nil, errors.New("Error compiling GL_FRAGMENT_SHADER shader part") + return nil, errors.New("Error compiling GL_FRAGMENT_SHADER shader part for radialGradientFS") } if glErr := gli.GetError(); glErr != gl_NO_ERROR { - return nil, errors.New("error compiling shader part, glError: " + fmt.Sprint(glErr)) + return nil, errors.New("error compiling shader part for radialGradientFS, glError: " + fmt.Sprint(glErr)) } } @@ -498,7 +936,7 @@ func loadRadialGradientShader() (*radialGradientShader, error) { if logLength > 0 { shLog := strings.Repeat("\x00", int(logLength+1)) gli.GetProgramInfoLog(program, logLength, nil, gli.Str(shLog)) - fmt.Printf("Shader link log:\n\n%s\n", shLog) + fmt.Printf("Shader link log for radialGradientFS:\n\n%s\n", shLog) } var status int32 @@ -506,10 +944,10 @@ func loadRadialGradientShader() (*radialGradientShader, error) { if status != gl_TRUE { gli.DeleteShader(vs) gli.DeleteShader(fs) - return nil, errors.New("error linking shader") + return nil, errors.New("error linking shader for radialGradientFS") } if glErr := gli.GetError(); glErr != gl_NO_ERROR { - return nil, errors.New("error linking shader, glError: " + fmt.Sprint(glErr)) + return nil, errors.New("error linking shader for radialGradientFS, glError: " + fmt.Sprint(glErr)) } } diff --git a/make_shaders.go b/make_shaders.go index 84f4bdb..4f9f68a 100644 --- a/make_shaders.go +++ b/make_shaders.go @@ -212,17 +212,17 @@ const compilePart = ` if logLength > 0 { shLog := strings.Repeat("\x00", int(logLength+1)) gli.GetShaderInfoLog(SHADER_VAR, logLength, nil, gli.Str(shLog)) - fmt.Printf("SHADER_TYPE compilation log:\n\n%s\n", shLog) + fmt.Printf("SHADER_TYPE compilation log for SHADER_SRC:\n\n%s\n", shLog) } var status int32 gli.GetShaderiv(SHADER_VAR, gl_COMPILE_STATUS, &status) if status != gl_TRUE { gli.DeleteShader(SHADER_VAR) - return nil, errors.New("Error compiling GL_SHADER_TYPE shader part") + return nil, errors.New("Error compiling GL_SHADER_TYPE shader part for SHADER_SRC") } if glErr := gli.GetError(); glErr != gl_NO_ERROR { - return nil, errors.New("error compiling shader part, glError: " + fmt.Sprint(glErr)) + return nil, errors.New("error compiling shader part for SHADER_SRC, glError: " + fmt.Sprint(glErr)) } } ` @@ -238,7 +238,7 @@ const linkPart = ` if logLength > 0 { shLog := strings.Repeat("\x00", int(logLength+1)) gli.GetProgramInfoLog(program, logLength, nil, gli.Str(shLog)) - fmt.Printf("Shader link log:\n\n%s\n", shLog) + fmt.Printf("Shader link log for SHADER_SRC:\n\n%s\n", shLog) } var status int32 @@ -246,10 +246,10 @@ const linkPart = ` if status != gl_TRUE { gli.DeleteShader(vs) gli.DeleteShader(fs) - return nil, errors.New("error linking shader") + return nil, errors.New("error linking shader for SHADER_SRC") } if glErr := gli.GetError(); glErr != gl_NO_ERROR { - return nil, errors.New("error linking shader, glError: " + fmt.Sprint(glErr)) + return nil, errors.New("error linking shader for SHADER_SRC, glError: " + fmt.Sprint(glErr)) } } ` @@ -297,7 +297,8 @@ func buildCode(buf *bytes.Buffer, baseName string, inputs []ShaderInput) { part = strings.Replace(part, "SHADER_VAR", "fs", -1) fmt.Fprint(buf, part) - fmt.Fprint(buf, linkPart) + part = strings.Replace(linkPart, "SHADER_SRC", fsName, -1) + fmt.Fprint(buf, part) fmt.Fprint(buf, "\n") fmt.Fprintf(buf, "\tresult := &%s{}\n", shaderName) diff --git a/shaders.go b/shaders.go new file mode 100644 index 0000000..97a1525 --- /dev/null +++ b/shaders.go @@ -0,0 +1,257 @@ +package canvas + +var imageVS = ` +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; +void main() { + gl_FragColor = texture2D(image, v_texCoord); +}` + +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; +void main() { + gl_FragColor = color; +}` + +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 mat3 invmat; +uniform sampler1D gradient; +uniform vec2 from, dir; +uniform float len; +void main() { + vec3 untf = vec3(v_cp, 1.0) * invmat; + vec2 v = untf.xy - from; + float r = dot(v, dir) / len; + r = clamp(r, 0.0, 1.0); + gl_FragColor = texture1D(gradient, r); +}` + +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 mat3 invmat; +uniform sampler1D gradient; +uniform vec2 from, to, dir; +uniform float radFrom, radTo; +uniform float len; +bool isNaN(float v) { + return v < 0.0 || 0.0 < v || v == 0.0 ? false : true; +} +void main() { + vec3 untf = vec3(v_cp, 1.0) * invmat; + float o_a = 0.5 * sqrt( + pow(-2.0*from.x*from.x+2.0*from.x*to.x+2.0*from.x*untf.x-2.0*to.x*untf.x-2.0*from.y*from.y+2.0*from.y*to.y+2.0*from.y*untf.y-2.0*to.y*untf.y+2.0*radFrom*radFrom-2.0*radFrom*radTo, 2.0) + -4.0*(from.x*from.x-2.0*from.x*untf.x+untf.x*untf.x+from.y*from.y-2.0*from.y*untf.y+untf.y*untf.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*untf.x+to.x*untf.x+from.y*from.y-from.y*to.y-from.y*untf.y+to.y*untf.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); + gl_FragColor = texture1D(gradient, o); +}` + +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 mat3 invmat; +uniform sampler2D image; +void main() { + vec3 untf = vec3(v_cp, 1.0) * invmat; + gl_FragColor = texture2D(image, mod(untf.xy / imageSize, 1.0)); +}` + +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; +void main() { + vec4 col = color; + col.a *= texture2D(alphaTex, v_atc).a; + 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 mat3 invmat; +uniform sampler1D gradient; +uniform vec2 from, dir; +uniform float len; +uniform sampler2D alphaTex; +void main() { + vec3 untf = vec3(v_cp, 1.0) * invmat; + vec2 v = untf.xy - from; + float r = dot(v, dir) / len; + r = clamp(r, 0.0, 1.0); + vec4 col = texture1D(gradient, r); + col.a *= texture2D(alphaTex, v_atc).a; + 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 mat3 invmat; +uniform sampler1D gradient; +uniform vec2 from, to, dir; +uniform float radFrom, radTo; +uniform float len; +uniform sampler2D alphaTex; +bool isNaN(float v) { + return v < 0.0 || 0.0 < v || v == 0.0 ? false : true; +} +void main() { + vec3 untf = vec3(v_cp, 1.0) * invmat; + float o_a = 0.5 * sqrt( + pow(-2.0*from.x*from.x+2.0*from.x*to.x+2.0*from.x*untf.x-2.0*to.x*untf.x-2.0*from.y*from.y+2.0*from.y*to.y+2.0*from.y*untf.y-2.0*to.y*untf.y+2.0*radFrom*radFrom-2.0*radFrom*radTo, 2.0) + -4.0*(from.x*from.x-2.0*from.x*untf.x+untf.x*untf.x+from.y*from.y-2.0*from.y*untf.y+untf.y*untf.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*untf.x+to.x*untf.x+from.y*from.y-from.y*to.y-from.y*untf.y+to.y*untf.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 = texture1D(gradient, o); + col.a *= texture2D(alphaTex, v_atc).a; + 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 mat3 invmat; +uniform sampler2D image; +uniform sampler2D alphaTex; +void main() { + vec3 untf = vec3(v_cp, 1.0) * invmat; + vec4 col = texture2D(image, mod(untf.xy / imageSize, 1.0)); + col.a *= texture2D(alphaTex, v_atc).a; + gl_FragColor = col; +}` diff --git a/text.go b/text.go index 4410bcc..c5bc0f2 100644 --- a/text.go +++ b/text.go @@ -2,13 +2,13 @@ package canvas import ( "errors" - "image" "io/ioutil" "unsafe" "github.com/golang/freetype" "github.com/golang/freetype/truetype" "github.com/tfriedel6/lm" + "golang.org/x/image/font" "golang.org/x/image/math/fixed" ) @@ -53,66 +53,69 @@ func LoadFont(src interface{}, name string) (*Font, error) { func (cv *Canvas) FillText(str string, x, y float32) { cv.activate() - if cv.text.target == nil || cv.text.target.Bounds().Dx() != cv.w || cv.text.target.Bounds().Dy() != cv.h { - if cv.text.tex != 0 { - gli.DeleteTextures(1, &cv.text.tex) - } - cv.text.target = image.NewRGBA(image.Rect(0, 0, cv.w, cv.h)) - gli.GenTextures(1, &cv.text.tex) - gli.ActiveTexture(gl_TEXTURE0) - gli.BindTexture(gl_TEXTURE_2D, cv.text.tex) - gli.TexParameteri(gl_TEXTURE_2D, gl_TEXTURE_MIN_FILTER, gl_NEAREST) - gli.TexParameteri(gl_TEXTURE_2D, gl_TEXTURE_MAG_FILTER, gl_NEAREST) - gli.TexParameteri(gl_TEXTURE_2D, gl_TEXTURE_WRAP_S, gl_CLAMP_TO_EDGE) - gli.TexParameteri(gl_TEXTURE_2D, gl_TEXTURE_WRAP_T, gl_CLAMP_TO_EDGE) - gli.TexImage2D(gl_TEXTURE_2D, 0, gl_RGBA, int32(cv.w), int32(cv.h), 0, gl_RGBA, gl_UNSIGNED_BYTE, nil) - } - - fontRenderingContext.setFont(cv.state.font.font) - fontRenderingContext.setFontSize(float64(cv.state.fontSize)) - fontRenderingContext.setSrc(image.NewUniform(colorGLToGo(cv.state.fill.color))) - fontRenderingContext.setDst(cv.text.target) - fontRenderingContext.setClip(cv.text.target.Bounds()) - _, bounds, _ := fontRenderingContext.drawString(str, fixed.Point26_6{X: fixed.Int26_6(x*64 + 0.5), Y: fixed.Int26_6(y*64 + 0.5)}) - subImg := cv.text.target.SubImage(bounds).(*image.RGBA) - - gli.BlendFunc(gl_ONE, gl_ONE_MINUS_SRC_ALPHA) - - gli.ActiveTexture(gl_TEXTURE0) - gli.BindTexture(gl_TEXTURE_2D, cv.text.tex) - - for y, w, h := 0, bounds.Dx(), bounds.Dy(); y < h; y++ { - off := y * subImg.Stride - pix := subImg.Pix - gli.TexSubImage2D(gl_TEXTURE_2D, 0, 0, int32(cv.h-1-y), int32(w), 1, gl_RGBA, gl_UNSIGNED_BYTE, gli.Ptr(&pix[off])) - for b := w * 4; b > 0; b-- { - pix[off] = 0 - off++ - } - } + frc := fontRenderingContext + frc.setFont(cv.state.font.font) + frc.setFontSize(float64(cv.state.fontSize)) gli.BindBuffer(gl_ARRAY_BUFFER, buf) - p0 := cv.tf(lm.Vec2{float32(bounds.Min.X), float32(bounds.Min.Y)}) - p1 := cv.tf(lm.Vec2{float32(bounds.Min.X), float32(bounds.Max.Y)}) - p2 := cv.tf(lm.Vec2{float32(bounds.Max.X), float32(bounds.Max.Y)}) - p3 := cv.tf(lm.Vec2{float32(bounds.Max.X), float32(bounds.Min.Y)}) - tw := float32(bounds.Max.X-bounds.Min.X) / cv.fw - th := float32(bounds.Max.Y-bounds.Min.Y) / cv.fh - data := [16]float32{p0[0], p0[1], p1[0], p1[1], p2[0], p2[1], p3[0], p3[1], - 0, 1, 0, 1 - th, tw, 1 - th, tw, 1} - gli.BufferData(gl_ARRAY_BUFFER, len(data)*4, unsafe.Pointer(&data[0]), gl_STREAM_DRAW) - gli.UseProgram(tr.id) - gli.Uniform2f(tr.canvasSize, cv.fw, cv.fh) - gli.Uniform1i(tr.image, 0) + vertex, alphaTexCoord := cv.useAlphaShader(&cv.state.fill, 1) - gli.VertexAttribPointer(tr.vertex, 2, gl_FLOAT, false, 0, nil) - gli.VertexAttribPointer(tr.texCoord, 2, gl_FLOAT, false, 0, gli.PtrOffset(8*4)) - gli.EnableVertexAttribArray(tr.vertex) - gli.EnableVertexAttribArray(tr.texCoord) - gli.DrawArrays(gl_TRIANGLE_FAN, 0, 4) - gli.DisableVertexAttribArray(tr.vertex) - gli.DisableVertexAttribArray(tr.texCoord) + gli.ActiveTexture(gl_TEXTURE1) + gli.BindTexture(gl_TEXTURE_2D, alphaTex) - gli.BlendFunc(gl_SRC_ALPHA, gl_ONE_MINUS_SRC_ALPHA) + gli.EnableVertexAttribArray(vertex) + gli.EnableVertexAttribArray(alphaTexCoord) + + fnt := cv.state.font.font + + prev, hasPrev := truetype.Index(0), false + for _, rn := range str { + idx := fnt.Index(rn) + if idx == 0 { + prev = 0 + hasPrev = false + continue + } + if hasPrev { + kern := fnt.Kern(frc.scale, prev, idx) + if frc.hinting != font.HintingNone { + kern = (kern + 32) &^ 63 + } + x += float32(kern) / 64 + } + advance, mask, offset, err := frc.glyph(idx, fixed.Point26_6{}) + if err != nil { + prev = 0 + hasPrev = false + continue + } + bounds := mask.Bounds().Add(offset) + + for y, w, h := 0, bounds.Dx(), bounds.Dy(); y < h; y++ { + off := y * mask.Stride + gli.TexSubImage2D(gl_TEXTURE_2D, 0, 0, int32(bufferTextureSize-1-y), int32(w), 1, gl_ALPHA, gl_UNSIGNED_BYTE, gli.Ptr(&mask.Pix[off])) + } + + p0 := cv.tf(lm.Vec2{float32(bounds.Min.X) + x, float32(bounds.Min.Y) + y}) + p1 := cv.tf(lm.Vec2{float32(bounds.Min.X) + x, float32(bounds.Max.Y) + y}) + p2 := cv.tf(lm.Vec2{float32(bounds.Max.X) + x, float32(bounds.Max.Y) + y}) + p3 := cv.tf(lm.Vec2{float32(bounds.Max.X) + x, float32(bounds.Min.Y) + y}) + tw := float32(bounds.Dx()) / bufferTextureSize + th := float32(bounds.Dy()) / bufferTextureSize + data := [16]float32{p0[0], p0[1], p1[0], p1[1], p2[0], p2[1], p3[0], p3[1], + 0, 1, 0, 1 - th, tw, 1 - th, tw, 1} + gli.BufferData(gl_ARRAY_BUFFER, len(data)*4, unsafe.Pointer(&data[0]), gl_STREAM_DRAW) + + gli.VertexAttribPointer(vertex, 2, gl_FLOAT, false, 0, nil) + gli.VertexAttribPointer(alphaTexCoord, 2, gl_FLOAT, false, 0, gli.PtrOffset(8*4)) + gli.DrawArrays(gl_TRIANGLE_FAN, 0, 4) + + x += float32(advance) / 64 + } + + gli.DisableVertexAttribArray(vertex) + gli.DisableVertexAttribArray(alphaTexCoord) + + gli.ActiveTexture(gl_TEXTURE0) }