moved the canvas to gl coordinate transformation to the shaders; fixed some bugs along the way

This commit is contained in:
Thomas Friedel 2018-02-08 11:53:32 +01:00
parent 7edac03910
commit 2de2dd26a4
6 changed files with 308 additions and 357 deletions

View file

@ -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,7 +355,6 @@ func (cv *Canvas) SetTransform(a, b, c, d, e, f float32) {
func (cv *Canvas) FillRect(x, y, w, h float32) {
cv.activate()
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})
@ -374,12 +364,12 @@ func (cv *Canvas) FillRect(x, y, w, h float32) {
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 {
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)

View file

@ -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.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)
} else {
gli.BindTexture(gl_TEXTURE_2D, imageBufTex)
}
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)

View file

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

View file

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

145
paths.go
View file

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

17
text.go
View file

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