From 2de2dd26a47e6677a2ed0e384c4bc3e632ded499 Mon Sep 17 00:00:00 2001 From: Thomas Friedel Date: Thu, 8 Feb 2018 11:53:32 +0100 Subject: [PATCH] moved the canvas to gl coordinate transformation to the shaders; fixed some bugs along the way --- canvas.go | 51 ++----- imagedata.go | 29 ++-- images.go | 27 ++-- made_shaders.go | 396 ++++++++++++++++++++++++------------------------ paths.go | 145 +++++++----------- text.go | 17 ++- 6 files changed, 308 insertions(+), 357 deletions(-) diff --git a/canvas.go b/canvas.go index 83f4fa9..db4b0ce 100644 --- a/canvas.go +++ b/canvas.go @@ -91,24 +91,11 @@ func New(x, y, w, h int) *Canvas { return cv } -func (cv *Canvas) ptToGL(x, y float32) (fx, fy float32) { - return cv.vecToGL(lm.Vec2{x, y}) -} - -func (cv *Canvas) vecToGL(v lm.Vec2) (fx, fy float32) { - return v[0]*2/cv.fw - 1, -v[1]*2/cv.fh + 1 -} - func (cv *Canvas) tf(v lm.Vec2) lm.Vec2 { v, _ = v.MulMat3x3(cv.state.transform) return v } -func (cv *Canvas) tfToGL(x, y float32) (fx, fy float32) { - v := cv.tf(lm.Vec2{x, y}) - return v[0]*2/cv.fw - 1, -v[1]*2/cv.fh + 1 -} - // Activate makes the canvas active and sets the viewport. Only needs // to be called if any other GL code changes the viewport func (cv *Canvas) Activate() { @@ -193,8 +180,10 @@ func LoadGL(glimpl GL) (err error) { var solidVS = ` attribute vec2 vertex; +uniform vec2 canvasSize; void main() { - gl_Position = vec4(vertex, 0.0, 1.0); + vec2 glp = vertex * 2.0 / canvasSize - 1.0; + gl_Position = vec4(glp.x, -glp.y, 0.0, 1.0); }` var solidFS = ` #ifdef GL_ES @@ -207,10 +196,12 @@ void main() { var textureVS = ` attribute vec2 vertex, texCoord; +uniform vec2 canvasSize; varying vec2 v_texCoord; void main() { v_texCoord = texCoord; - gl_Position = vec4(vertex, 0.0, 1.0); + vec2 glp = vertex * 2.0 / canvasSize - 1.0; + gl_Position = vec4(glp.x, -glp.y, 0.0, 1.0); }` var textureFS = ` #ifdef GL_ES @@ -364,22 +355,21 @@ func (cv *Canvas) SetTransform(a, b, c, d, e, f float32) { func (cv *Canvas) FillRect(x, y, w, h float32) { cv.activate() + p0 := cv.tf(lm.Vec2{x, y}) + p1 := cv.tf(lm.Vec2{x, y + h}) + p2 := cv.tf(lm.Vec2{x + w, y + h}) + p3 := cv.tf(lm.Vec2{x + w, y}) + + gli.BindBuffer(gl_ARRAY_BUFFER, buf) + data := [8]float32{p0[0], p0[1], p1[0], p1[1], p2[0], p2[1], p3[0], p3[1]} + gli.BufferData(gl_ARRAY_BUFFER, len(data)*4, unsafe.Pointer(&data[0]), gl_STREAM_DRAW) + if lg := cv.state.fill.linearGradient; lg != nil { - p0 := cv.tf(lm.Vec2{x, y}) - p1 := cv.tf(lm.Vec2{x, y + h}) - p2 := cv.tf(lm.Vec2{x + w, y + h}) - p3 := cv.tf(lm.Vec2{x + w, y}) - - gli.BindBuffer(gl_ARRAY_BUFFER, buf) - data := [8]float32{p0[0], p0[1], p1[0], p1[1], p2[0], p2[1], p3[0], p3[1]} - gli.BufferData(gl_ARRAY_BUFFER, len(data)*4, unsafe.Pointer(&data[0]), gl_STREAM_DRAW) - lg.load() gli.UseProgram(lgr.id) gli.VertexAttribPointer(lgr.vertex, 2, gl_FLOAT, false, 0, nil) gli.ActiveTexture(gl_TEXTURE0) gli.BindTexture(gl_TEXTURE_1D, lg.tex) - gli.Uniform2f(lgr.canvasSize, cv.fw, cv.fh) from := cv.tf(lg.from) to := cv.tf(lg.to) @@ -389,23 +379,14 @@ func (cv *Canvas) FillRect(x, y, w, h float32) { gli.Uniform2f(lgr.from, from[0], from[1]) gli.Uniform2f(lgr.dir, dir[0], dir[1]) gli.Uniform1f(lgr.length, length) - gli.Uniform1i(lgr.gradient, 0) gli.EnableVertexAttribArray(lgr.vertex) gli.DrawArrays(gl_TRIANGLE_FAN, 0, 4) gli.DisableVertexAttribArray(lgr.vertex) } else { - x0f, y0f := cv.tfToGL(x, y) - x1f, y1f := cv.tfToGL(x, y+h) - x2f, y2f := cv.tfToGL(x+w, y+h) - x3f, y3f := cv.tfToGL(x+w, y) - - gli.BindBuffer(gl_ARRAY_BUFFER, buf) - data := [8]float32{x0f, y0f, x1f, y1f, x2f, y2f, x3f, y3f} - gli.BufferData(gl_ARRAY_BUFFER, len(data)*4, unsafe.Pointer(&data[0]), gl_STREAM_DRAW) - gli.UseProgram(sr.id) gli.VertexAttribPointer(sr.vertex, 2, gl_FLOAT, false, 0, nil) + gli.Uniform2f(sr.canvasSize, cv.fw, cv.fh) c := cv.state.fill.color gli.Uniform4f(sr.color, c.r, c.g, c.b, c.a) gli.EnableVertexAttribArray(lgr.vertex) diff --git a/imagedata.go b/imagedata.go index 7d789a3..70ea60f 100644 --- a/imagedata.go +++ b/imagedata.go @@ -45,15 +45,17 @@ func (cv *Canvas) GetImageData(x, y, w, h int) *image.RGBA { func (cv *Canvas) PutImageData(img *image.RGBA, x, y int) { cv.activate() + gli.ActiveTexture(gl_TEXTURE0) if imageBufTex == 0 { gli.GenTextures(1, &imageBufTex) + gli.BindTexture(gl_TEXTURE_2D, imageBufTex) + gli.TexParameteri(gl_TEXTURE_2D, gl_TEXTURE_MIN_FILTER, gl_LINEAR) + gli.TexParameteri(gl_TEXTURE_2D, gl_TEXTURE_MAG_FILTER, gl_LINEAR) + 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) + } else { + gli.BindTexture(gl_TEXTURE_2D, imageBufTex) } - gli.ActiveTexture(gl_TEXTURE0) - gli.BindTexture(gl_TEXTURE_2D, imageBufTex) - gli.TexParameteri(gl_TEXTURE_2D, gl_TEXTURE_MIN_FILTER, gl_LINEAR) - gli.TexParameteri(gl_TEXTURE_2D, gl_TEXTURE_MAG_FILTER, gl_LINEAR) - 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) w, h := img.Bounds().Dx(), img.Bounds().Dy() @@ -72,19 +74,14 @@ func (cv *Canvas) PutImageData(img *image.RGBA, x, y int) { dx, dy := float32(x), float32(y) dw, dh := float32(w), float32(h) - dx0, dy0 := dx*2/cv.fw-1, -dy*2/cv.fh+1 - dx1, dy1 := dx0, -(dy+dh)*2/cv.fh+1 - dx2, dy2 := (dx+dw)*2/cv.fw-1, dy1 - dx3, dy3 := dx2, dy0 + gli.BindBuffer(gl_ARRAY_BUFFER, buf) + data := [16]float32{dx, dy, dx + dw, dy, dx + dw, dy + dh, dx, dy + dh, + 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.BindBuffer(gl_ARRAY_BUFFER, buf) - data := [16]float32{dx0, dy0, dx1, dy1, dx2, dy2, dx3, dy3, - 0, 0, 0, 1, 1, 1, 1, 0} - gli.BufferData(gl_ARRAY_BUFFER, len(data)*4, unsafe.Pointer(&data[0]), gl_STREAM_DRAW) - + 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) diff --git a/images.go b/images.go index a3d3652..e26157e 100644 --- a/images.go +++ b/images.go @@ -7,6 +7,8 @@ import ( "io/ioutil" "runtime" "unsafe" + + "github.com/tfriedel6/lm" ) type Image struct { @@ -172,6 +174,8 @@ func (cv *Canvas) DrawImage(img *Image, coords ...float32) { return } + cv.activate() + var sx, sy, sw, sh, dx, dy, dw, dh float32 sw, sh = float32(img.w), float32(img.h) dw, dh = float32(img.w), float32(img.h) @@ -187,28 +191,27 @@ func (cv *Canvas) DrawImage(img *Image, coords ...float32) { dw, dh = coords[6], coords[7] } - dx0, dy0 := cv.tfToGL(dx, dy) - dx1, dy1 := cv.tfToGL(dx, dy+dh) - dx2, dy2 := cv.tfToGL(dx+dw, dy+dh) - dx3, dy3 := cv.tfToGL(dx+dw, dy) sx /= float32(img.w) sy /= float32(img.h) sw /= float32(img.w) sh /= float32(img.h) - cv.activate() - - gli.UseProgram(tr.id) - - gli.ActiveTexture(gl_TEXTURE0) - gli.BindTexture(gl_TEXTURE_2D, img.tex) - gli.Uniform1i(tr.image, 0) + p0 := cv.tf(lm.Vec2{dx, dy}) + p1 := cv.tf(lm.Vec2{dx, dy + dh}) + p2 := cv.tf(lm.Vec2{dx + dw, dy + dh}) + p3 := cv.tf(lm.Vec2{dx + dw, dy}) gli.BindBuffer(gl_ARRAY_BUFFER, buf) - data := [16]float32{dx0, dy0, dx1, dy1, dx2, dy2, dx3, dy3, + data := [16]float32{p0[0], p0[1], p1[0], p1[1], p2[0], p2[1], p3[0], p3[1], sx, sy, sx, sy + sh, sx + sw, sy + sh, sx + sw, sy} gli.BufferData(gl_ARRAY_BUFFER, len(data)*4, unsafe.Pointer(&data[0]), gl_STREAM_DRAW) + 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) diff --git a/made_shaders.go b/made_shaders.go index 943f181..3c1761d 100755 --- a/made_shaders.go +++ b/made_shaders.go @@ -6,6 +6,206 @@ import ( "strings" ) +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:\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(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:\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 := &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 textureShader struct { + id uint32 + vertex uint32 + texCoord uint32 + canvasSize int32 + image int32 +} + +func loadTextureShader() (*textureShader, error) { + var vs, fs, program uint32 + + { + csource, freeFunc := gli.Strs(textureVS + "\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(textureFS + "\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 := &textureShader{} + 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 +} + type linearGradientShader struct { id uint32 vertex uint32 @@ -110,199 +310,3 @@ func loadLinearGradientShader() (*linearGradientShader, error) { return result, nil } - -type solidShader struct { - id uint32 - vertex uint32 - 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:\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(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:\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 := &solidShader{} - result.id = program - result.vertex = uint32(gli.GetAttribLocation(program, gli.Str("vertex\x00"))) - result.color = gli.GetUniformLocation(program, gli.Str("color\x00")) - - return result, nil -} - -type textureShader struct { - id uint32 - vertex uint32 - texCoord uint32 - image int32 -} - -func loadTextureShader() (*textureShader, error) { - var vs, fs, program uint32 - - { - csource, freeFunc := gli.Strs(textureVS + "\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(textureFS + "\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 := &textureShader{} - result.id = program - result.vertex = uint32(gli.GetAttribLocation(program, gli.Str("vertex\x00"))) - result.texCoord = uint32(gli.GetAttribLocation(program, gli.Str("texCoord\x00"))) - result.image = gli.GetUniformLocation(program, gli.Str("image\x00")) - - return result, nil -} diff --git a/paths.go b/paths.go index 4dc7be4..dadb78b 100644 --- a/paths.go +++ b/paths.go @@ -86,9 +86,8 @@ func (cv *Canvas) Arc(x, y, radius, startAngle, endAngle float32, anticlockwise } if !anticlockwise && endAngle <= startAngle { endAngle += math.Pi * 2 - } else if anticlockwise && startAngle <= endAngle { - startAngle += math.Pi * 2 - startAngle, endAngle = endAngle, startAngle + } else if anticlockwise && endAngle >= startAngle { + endAngle -= math.Pi * 2 } tr := cv.tf(lm.Vec2{radius, radius}) step := 6 / fmath.Max(tr[0], tr[1]) @@ -165,16 +164,11 @@ func (cv *Canvas) Stroke() { gli.StencilOp(gl_KEEP, gl_KEEP, gl_REPLACE) gli.StencilMask(0x01) - gli.UseProgram(sr.id) - c := cv.state.stroke.color - gli.Uniform4f(sr.color, c.r, c.g, c.b, c.a) - gli.EnableVertexAttribArray(sr.vertex) - gli.BindBuffer(gl_ARRAY_BUFFER, buf) var buf [1000]float32 tris := buf[:0] - tris = append(tris, -1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, -1) + tris = append(tris, 0, 0, cv.fw, 0, cv.fw, cv.fh, 0, 0, cv.fw, cv.fh, 0, cv.fh) start := true var p0 lm.Vec2 @@ -190,18 +184,18 @@ func (cv *Canvas) Stroke() { v1 := lm.Vec2{v0[1], -v0[0]}.MulF(cv.state.stroke.lineWidth * 0.5) v0 = v0.MulF(cv.state.stroke.lineWidth * 0.5) - l0p0 := p0.Add(v1) - l0p1 := p1.Add(v1) - l0p2 := p0.Sub(v1) - l0p3 := p1.Sub(v1) + lp0 := p0.Add(v1) + lp1 := p1.Add(v1) + lp2 := p0.Sub(v1) + lp3 := p1.Sub(v1) if start { switch cv.state.lineEnd { case Butt: // no need to do anything case Square: - l0p0 = l0p0.Sub(v0) - l0p2 = l0p2.Sub(v0) + lp0 = lp0.Sub(v0) + lp2 = lp2.Sub(v0) case Round: tris = cv.addCircleTris(p0, cv.state.stroke.lineWidth*0.5, tris) } @@ -212,24 +206,19 @@ func (cv *Canvas) Stroke() { case Butt: // no need to do anything case Square: - l0p1 = l0p1.Add(v0) - l0p3 = l0p3.Add(v0) + lp1 = lp1.Add(v0) + lp3 = lp3.Add(v0) case Round: tris = cv.addCircleTris(p1, cv.state.stroke.lineWidth*0.5, tris) } } - l0x0f, l0y0f := cv.vecToGL(l0p0) - l0x1f, l0y1f := cv.vecToGL(l0p1) - l0x2f, l0y2f := cv.vecToGL(l0p2) - l0x3f, l0y3f := cv.vecToGL(l0p3) - tris = append(tris, - l0x0f, l0y0f, l0x1f, l0y1f, l0x3f, l0y3f, - l0x0f, l0y0f, l0x3f, l0y3f, l0x2f, l0y2f) + lp0[0], lp0[1], lp1[0], lp1[1], lp3[0], lp3[1], + lp0[0], lp0[1], lp3[0], lp3[1], lp2[0], lp2[1]) if p.attach { - tris = cv.lineJoint(p, p0, p1, p.next, l0p0, l0p1, l0p2, l0p3, tris) + tris = cv.lineJoint(p, p0, p1, p.next, lp0, lp1, lp2, lp3, tris) } p0 = p1 @@ -237,10 +226,20 @@ func (cv *Canvas) Stroke() { } gli.BufferData(gl_ARRAY_BUFFER, len(tris)*4, unsafe.Pointer(&tris[0]), gl_STREAM_DRAW) + + gli.UseProgram(sr.id) + c := cv.state.stroke.color + gli.Uniform4f(sr.color, c.r, c.g, c.b, c.a) + gli.Uniform2f(sr.canvasSize, cv.fw, cv.fh) + + gli.ColorMask(false, false, false, false) + + gli.EnableVertexAttribArray(sr.vertex) gli.VertexAttribPointer(sr.vertex, 2, gl_FLOAT, false, 0, nil) gli.DrawArrays(gl_TRIANGLES, 6, int32(len(tris)/2-6)) gli.ColorMask(true, true, true, true) + gli.StencilFunc(gl_EQUAL, 1, 0xFF) gli.StencilMask(0xFF) @@ -248,7 +247,6 @@ func (cv *Canvas) Stroke() { gli.DisableVertexAttribArray(sr.vertex) - gli.ColorMask(true, true, true, true) gli.StencilOp(gl_KEEP, gl_KEEP, gl_KEEP) gli.StencilFunc(gl_EQUAL, 0, 0xFF) @@ -261,9 +259,6 @@ func (cv *Canvas) lineJoint(p pathPoint, p0, p1, p2, l0p0, l0p1, l0p2, l0p3 lm.V v2 := p1.Sub(p2).Norm() v3 := lm.Vec2{v2[1], -v2[0]}.MulF(cv.state.stroke.lineWidth * 0.5) - l0x1f, l0y1f := cv.vecToGL(l0p1) - l0x3f, l0y3f := cv.vecToGL(l0p3) - switch cv.state.lineJoin { case Miter: l1p0 := p2.Sub(v3) @@ -271,33 +266,21 @@ func (cv *Canvas) lineJoint(p pathPoint, p0, p1, p2, l0p0, l0p1, l0p2, l0p3 lm.V l1p2 := p2.Add(v3) l1p3 := p1.Add(v3) - l1x1f, l1y1f := cv.vecToGL(l1p1) - l1x3f, l1y3f := cv.vecToGL(l1p3) - ip0 := lineIntersection(l0p0, l0p1, l1p1, l1p0) ip1 := lineIntersection(l0p2, l0p3, l1p3, l1p2) - cxf, cyf := cv.vecToGL(p1) - ix0f, iy0f := cv.vecToGL(ip0) - ix1f, iy1f := cv.vecToGL(ip1) - tris = append(tris, - cxf, cyf, l0x1f, l0y1f, ix0f, iy0f, - cxf, cyf, ix0f, iy0f, l1x1f, l1y1f, - cxf, cyf, l1x3f, l1y3f, ix1f, iy1f, - cxf, cyf, ix1f, iy1f, l0x3f, l0y3f) + p1[0], p1[1], l0p1[0], l0p1[1], ip0[0], ip0[1], + p1[0], p1[1], ip0[0], ip0[1], l1p1[0], l1p1[1], + p1[0], p1[1], l1p3[0], l1p3[1], ip1[0], ip1[1], + p1[0], p1[1], ip1[0], ip1[1], l0p3[0], l0p3[1]) case Bevel: l1p1 := p1.Sub(v3) l1p3 := p1.Add(v3) - l1x1f, l1y1f := cv.vecToGL(l1p1) - l1x3f, l1y3f := cv.vecToGL(l1p3) - - cxf, cyf := cv.vecToGL(p1) - tris = append(tris, - cxf, cyf, l0x1f, l0y1f, l1x1f, l1y1f, - cxf, cyf, l1x3f, l1y3f, l0x3f, l0y3f) + p1[0], p1[1], l0p1[0], l0p1[1], l1p1[0], l1p1[1], + p1[0], p1[1], l1p3[0], l1p3[1], l0p3[0], l0p3[1]) case Round: tris = cv.addCircleTris(p1, cv.state.stroke.lineWidth*0.5, tris) } @@ -305,9 +288,8 @@ func (cv *Canvas) lineJoint(p pathPoint, p0, p1, p2, l0p0, l0p1, l0p2, l0p3 lm.V return tris } -func (cv *Canvas) addCircleTris(p lm.Vec2, radius float32, tris []float32) []float32 { - cxf, cyf := cv.vecToGL(p) - p0x, p0y := cv.vecToGL(lm.Vec2{p[0], p[1] + radius}) +func (cv *Canvas) addCircleTris(center lm.Vec2, radius float32, tris []float32) []float32 { + p0 := lm.Vec2{center[0], center[1] + radius} step := 6 / radius if step > 0.8 { step = 0.8 @@ -316,9 +298,9 @@ func (cv *Canvas) addCircleTris(p lm.Vec2, radius float32, tris []float32) []flo } for angle := step; angle <= math.Pi*2+step; angle += step { s, c := fmath.Sincos(angle) - p1x, p1y := cv.vecToGL(lm.Vec2{p[0] + s*radius, p[1] + c*radius}) - tris = append(tris, cxf, cyf, p0x, p0y, p1x, p1y) - p0x, p0y = p1x, p1y + p1 := lm.Vec2{center[0] + s*radius, center[1] + c*radius} + tris = append(tris, center[0], center[1], p0[0], p0[1], p1[0], p1[1]) + p0 = p1 } return tris } @@ -352,28 +334,18 @@ func (cv *Canvas) Fill() { cv.activate() + gli.BindBuffer(gl_ARRAY_BUFFER, buf) + var buf [1000]float32 + tris := triangulatePath(path, buf[:0]) + gli.BufferData(gl_ARRAY_BUFFER, len(tris)*4, unsafe.Pointer(&tris[0]), gl_STREAM_DRAW) + gli.UseProgram(sr.id) c := cv.state.fill.color gli.Uniform4f(sr.color, c.r, c.g, c.b, c.a) + gli.Uniform2f(sr.canvasSize, cv.fw, cv.fh) gli.EnableVertexAttribArray(sr.vertex) - - gli.BindBuffer(gl_ARRAY_BUFFER, buf) - - var buf [1000]float32 - tris := buf[:0] - tris = append(tris) - - tris = triangulatePath(path, tris) - total := len(tris) - for i := 0; i < total; i += 2 { - x, y := tris[i], tris[i+1] - tris[i], tris[i+1] = cv.ptToGL(x, y) - } - - gli.BufferData(gl_ARRAY_BUFFER, len(tris)*4, unsafe.Pointer(&tris[0]), gl_STREAM_DRAW) gli.VertexAttribPointer(sr.vertex, 2, gl_FLOAT, false, 0, nil) gli.DrawArrays(gl_TRIANGLES, 0, int32(len(tris)/2)) - gli.DisableVertexAttribArray(sr.vertex) } @@ -388,33 +360,26 @@ func (cv *Canvas) Clip() { func (cv *Canvas) clip(path []pathPoint) { cv.activate() + gli.BindBuffer(gl_ARRAY_BUFFER, buf) + var buf [1000]float32 + tris := buf[:0] + tris = append(tris, 0, 0, cv.fw, 0, cv.fw, cv.fh, 0, 0, cv.fw, cv.fh, 0, cv.fh) + tris = triangulatePath(path, tris) + gli.BufferData(gl_ARRAY_BUFFER, len(tris)*4, unsafe.Pointer(&tris[0]), gl_STREAM_DRAW) + gli.VertexAttribPointer(sr.vertex, 2, gl_FLOAT, false, 0, nil) + + gli.UseProgram(sr.id) + c := cv.state.fill.color + gli.Uniform4f(sr.color, c.r, c.g, c.b, c.a) + gli.Uniform2f(sr.canvasSize, cv.fw, cv.fh) + gli.EnableVertexAttribArray(sr.vertex) + gli.ColorMask(false, false, false, false) gli.StencilFunc(gl_ALWAYS, 2, 0xFF) gli.StencilOp(gl_KEEP, gl_KEEP, gl_REPLACE) gli.StencilMask(0x02) gli.Clear(gl_STENCIL_BUFFER_BIT) - gli.UseProgram(sr.id) - c := cv.state.fill.color - gli.Uniform4f(sr.color, c.r, c.g, c.b, c.a) - gli.EnableVertexAttribArray(sr.vertex) - - gli.BindBuffer(gl_ARRAY_BUFFER, buf) - - var buf [1000]float32 - tris := buf[:0] - tris = append(tris, -1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, -1) - - tris = triangulatePath(path, tris) - total := len(tris) - for i := 12; i < total; i += 2 { - x, y := tris[i], tris[i+1] - tris[i], tris[i+1] = cv.ptToGL(x, y) - } - - gli.BufferData(gl_ARRAY_BUFFER, len(tris)*4, unsafe.Pointer(&tris[0]), gl_STREAM_DRAW) - gli.VertexAttribPointer(sr.vertex, 2, gl_FLOAT, false, 0, nil) - gli.DrawArrays(gl_TRIANGLES, 0, 6) gli.StencilFunc(gl_ALWAYS, 0, 0xFF) gli.DrawArrays(gl_TRIANGLES, 6, int32(len(tris)/2-6)) diff --git a/text.go b/text.go index bf8a706..928201c 100644 --- a/text.go +++ b/text.go @@ -8,6 +8,7 @@ import ( "github.com/golang/freetype" "github.com/golang/freetype/truetype" + "github.com/tfriedel6/lm" "golang.org/x/image/math/fixed" ) @@ -82,20 +83,20 @@ func (cv *Canvas) FillText(str string, x, y float32) { } } - gli.UseProgram(tr.id) - gli.Uniform1i(tr.image, 0) - gli.BindBuffer(gl_ARRAY_BUFFER, buf) - dx0, dy0 := cv.ptToGL(float32(bounds.Min.X), float32(bounds.Min.Y)) - dx1, dy1 := cv.ptToGL(float32(bounds.Min.X), float32(bounds.Max.Y)) - dx2, dy2 := cv.ptToGL(float32(bounds.Max.X), float32(bounds.Max.Y)) - dx3, dy3 := cv.ptToGL(float32(bounds.Max.X), float32(bounds.Min.Y)) + 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{dx0, dy0, dx1, dy1, dx2, dy2, dx3, dy3, + 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.Uniform1i(tr.image, 0) + 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)