diff --git a/canvas.go b/canvas.go index 798a088..db47b02 100644 --- a/canvas.go +++ b/canvas.go @@ -39,6 +39,7 @@ type drawState struct { color glColor radialGradient *RadialGradient linearGradient *LinearGradient + image *Image } stroke struct { color glColor @@ -128,6 +129,7 @@ var ( tr *textureShader lgr *linearGradientShader rgr *radialGradientShader + ipr *imagePatternShader glChan = make(chan func()) ) @@ -172,6 +174,15 @@ func LoadGL(glimpl GL) (err error) { return } + ipr, err = loadImagePatternShader() + if err != nil { + return + } + err = glError() + if err != nil { + return + } + gli.GenBuffers(1, &buf) err = glError() if err != nil { @@ -285,6 +296,26 @@ void main() { 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 sampler2D image; +void main() { + gl_FragColor = texture2D(image, mod(v_cp / imageSize, 1.0)); + //gl_FragColor = vec4(v_cp * 0.1, 0.0, 1.0); +}` func glError() error { glErr := gli.GetError() @@ -299,6 +330,7 @@ func (cv *Canvas) SetFillStyle(value ...interface{}) { cv.state.fill.color = glColor{} cv.state.fill.linearGradient = nil cv.state.fill.radialGradient = nil + cv.state.fill.image = nil if len(value) == 1 { switch v := value[0].(type) { case *LinearGradient: @@ -307,6 +339,9 @@ func (cv *Canvas) SetFillStyle(value ...interface{}) { case *RadialGradient: cv.state.fill.radialGradient = v return + case *Image: + cv.state.fill.image = v + return } } c, ok := parseColor(value...) @@ -458,6 +493,17 @@ func (cv *Canvas) FillRect(x, y, w, h float32) { gli.EnableVertexAttribArray(rgr.vertex) gli.DrawArrays(gl_TRIANGLE_FAN, 0, 4) gli.DisableVertexAttribArray(rgr.vertex) + } else if img := cv.state.fill.image; img != nil { + gli.UseProgram(ipr.id) + gli.VertexAttribPointer(ipr.vertex, 2, gl_FLOAT, false, 0, nil) + gli.ActiveTexture(gl_TEXTURE0) + gli.BindTexture(gl_TEXTURE_1D, img.tex) + gli.Uniform2f(ipr.canvasSize, cv.fw, cv.fh) + gli.Uniform2f(ipr.imageSize, float32(img.w), float32(img.h)) + gli.Uniform1i(ipr.image, 0) + gli.EnableVertexAttribArray(ipr.vertex) + gli.DrawArrays(gl_TRIANGLE_FAN, 0, 4) + gli.DisableVertexAttribArray(ipr.vertex) } else { gli.UseProgram(sr.id) gli.VertexAttribPointer(sr.vertex, 2, gl_FLOAT, false, 0, nil) diff --git a/made_shaders.go b/made_shaders.go index bdc490b..33b3618 100755 --- a/made_shaders.go +++ b/made_shaders.go @@ -6,6 +6,107 @@ import ( "strings" ) +type imagePatternShader struct { + id uint32 + vertex uint32 + canvasSize int32 + imageSize int32 + image int32 +} + +func loadImagePatternShader() (*imagePatternShader, error) { + var vs, fs, program uint32 + + { + csource, freeFunc := gli.Strs(imagePatternVS + "\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:\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") + } + if glErr := gli.GetError(); glErr != gl_NO_ERROR { + return nil, errors.New("error compiling shader part, glError: " + fmt.Sprint(glErr)) + } + } + + { + csource, freeFunc := gli.Strs(imagePatternFS + "\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:\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") + } + if glErr := gli.GetError(); glErr != gl_NO_ERROR { + return nil, errors.New("error compiling shader part, 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:\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") + } + if glErr := gli.GetError(); glErr != gl_NO_ERROR { + return nil, errors.New("error linking shader, glError: " + fmt.Sprint(glErr)) + } + } + + result := &imagePatternShader{} + result.id = program + result.vertex = uint32(gli.GetAttribLocation(program, gli.Str("vertex\x00"))) + result.canvasSize = gli.GetUniformLocation(program, gli.Str("canvasSize\x00")) + result.imageSize = gli.GetUniformLocation(program, gli.Str("imageSize\x00")) + result.image = gli.GetUniformLocation(program, gli.Str("image\x00")) + + return result, nil +} + type textureShader struct { id uint32 vertex uint32 @@ -107,6 +208,117 @@ func loadTextureShader() (*textureShader, error) { return result, nil } +type radialGradientShader struct { + id uint32 + vertex uint32 + canvasSize int32 + gradient int32 + from int32 + to int32 + dir int32 + radFrom int32 + radTo int32 + len int32 +} + +func loadRadialGradientShader() (*radialGradientShader, error) { + var vs, fs, program uint32 + + { + csource, freeFunc := gli.Strs(radialGradientVS + "\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:\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") + } + if glErr := gli.GetError(); glErr != gl_NO_ERROR { + return nil, errors.New("error compiling shader part, glError: " + fmt.Sprint(glErr)) + } + } + + { + csource, freeFunc := gli.Strs(radialGradientFS + "\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:\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") + } + if glErr := gli.GetError(); glErr != gl_NO_ERROR { + return nil, errors.New("error compiling shader part, 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:\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") + } + if glErr := gli.GetError(); glErr != gl_NO_ERROR { + return nil, errors.New("error linking shader, glError: " + fmt.Sprint(glErr)) + } + } + + result := &radialGradientShader{} + result.id = program + result.vertex = uint32(gli.GetAttribLocation(program, gli.Str("vertex\x00"))) + result.canvasSize = gli.GetUniformLocation(program, gli.Str("canvasSize\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")) + + return result, nil +} + type solidShader struct { id uint32 vertex uint32 @@ -310,114 +522,3 @@ func loadLinearGradientShader() (*linearGradientShader, error) { return result, nil } - -type radialGradientShader struct { - id uint32 - vertex uint32 - canvasSize int32 - gradient int32 - from int32 - to int32 - dir int32 - radFrom int32 - radTo int32 - len int32 -} - -func loadRadialGradientShader() (*radialGradientShader, error) { - var vs, fs, program uint32 - - { - csource, freeFunc := gli.Strs(radialGradientVS + "\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:\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") - } - if glErr := gli.GetError(); glErr != gl_NO_ERROR { - return nil, errors.New("error compiling shader part, glError: " + fmt.Sprint(glErr)) - } - } - - { - csource, freeFunc := gli.Strs(radialGradientFS + "\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:\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") - } - if glErr := gli.GetError(); glErr != gl_NO_ERROR { - return nil, errors.New("error compiling shader part, 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:\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") - } - if glErr := gli.GetError(); glErr != gl_NO_ERROR { - return nil, errors.New("error linking shader, glError: " + fmt.Sprint(glErr)) - } - } - - result := &radialGradientShader{} - result.id = program - result.vertex = uint32(gli.GetAttribLocation(program, gli.Str("vertex\x00"))) - result.canvasSize = gli.GetUniformLocation(program, gli.Str("canvasSize\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")) - - return result, nil -}