prepared radial gradients, but they don't work yet
This commit is contained in:
parent
2de2dd26a4
commit
9c7a01b8b8
3 changed files with 217 additions and 30 deletions
65
canvas.go
65
canvas.go
|
@ -37,6 +37,7 @@ type drawState struct {
|
|||
transform lm.Mat3x3
|
||||
fill struct {
|
||||
color glColor
|
||||
radialGradient *RadialGradient
|
||||
linearGradient *LinearGradient
|
||||
}
|
||||
stroke struct {
|
||||
|
@ -126,6 +127,7 @@ var (
|
|||
sr *solidShader
|
||||
tr *textureShader
|
||||
lgr *linearGradientShader
|
||||
rgr *radialGradientShader
|
||||
glChan = make(chan func())
|
||||
)
|
||||
|
||||
|
@ -161,6 +163,15 @@ func LoadGL(glimpl GL) (err error) {
|
|||
return
|
||||
}
|
||||
|
||||
rgr, err = loadRadialGradientShader()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = glError()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
gli.GenBuffers(1, &buf)
|
||||
err = glError()
|
||||
if err != nil {
|
||||
|
@ -212,7 +223,6 @@ uniform sampler2D image;
|
|||
void main() {
|
||||
gl_FragColor = texture2D(image, v_texCoord);
|
||||
}`
|
||||
|
||||
var linearGradientVS = `
|
||||
attribute vec2 vertex;
|
||||
uniform vec2 canvasSize;
|
||||
|
@ -229,10 +239,34 @@ precision mediump float;
|
|||
varying vec2 v_cp;
|
||||
uniform sampler1D gradient;
|
||||
uniform vec2 from, dir;
|
||||
uniform float length;
|
||||
uniform float len;
|
||||
void main() {
|
||||
vec2 v = v_cp - from;
|
||||
float r = dot(v, dir) / length;
|
||||
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 sampler1D gradient;
|
||||
uniform vec2 from, dir;
|
||||
uniform float len;
|
||||
void main() {
|
||||
vec2 v0 = v_cp - from;
|
||||
//vec2 v1 = v_cp - (from + dir);
|
||||
float r = length(v0) / len;
|
||||
r = clamp(r, 0.0, 1.0);
|
||||
gl_FragColor = texture1D(gradient, r);
|
||||
}`
|
||||
|
@ -249,11 +283,15 @@ func glError() error {
|
|||
func (cv *Canvas) SetFillStyle(value ...interface{}) {
|
||||
cv.state.fill.color = glColor{}
|
||||
cv.state.fill.linearGradient = nil
|
||||
cv.state.fill.radialGradient = nil
|
||||
if len(value) == 1 {
|
||||
switch v := value[0].(type) {
|
||||
case *LinearGradient:
|
||||
cv.state.fill.linearGradient = v
|
||||
return
|
||||
case *RadialGradient:
|
||||
cv.state.fill.radialGradient = v
|
||||
return
|
||||
}
|
||||
}
|
||||
c, ok := parseColor(value...)
|
||||
|
@ -378,11 +416,30 @@ func (cv *Canvas) FillRect(x, y, w, h float32) {
|
|||
dir = dir.DivF(length)
|
||||
gli.Uniform2f(lgr.from, from[0], from[1])
|
||||
gli.Uniform2f(lgr.dir, dir[0], dir[1])
|
||||
gli.Uniform1f(lgr.length, length)
|
||||
gli.Uniform1f(lgr.len, length)
|
||||
gli.Uniform1i(lgr.gradient, 0)
|
||||
gli.EnableVertexAttribArray(lgr.vertex)
|
||||
gli.DrawArrays(gl_TRIANGLE_FAN, 0, 4)
|
||||
gli.DisableVertexAttribArray(lgr.vertex)
|
||||
} else if rg := cv.state.fill.radialGradient; rg != nil {
|
||||
rg.load()
|
||||
gli.UseProgram(rgr.id)
|
||||
gli.VertexAttribPointer(rgr.vertex, 2, gl_FLOAT, false, 0, nil)
|
||||
gli.ActiveTexture(gl_TEXTURE0)
|
||||
gli.BindTexture(gl_TEXTURE_1D, rg.tex)
|
||||
gli.Uniform2f(rgr.canvasSize, cv.fw, cv.fh)
|
||||
from := cv.tf(rg.from)
|
||||
to := cv.tf(rg.to)
|
||||
dir := to.Sub(from)
|
||||
length := dir.Len()
|
||||
dir = dir.DivF(length)
|
||||
gli.Uniform2f(rgr.from, from[0], from[1])
|
||||
gli.Uniform2f(rgr.dir, dir[0], dir[1])
|
||||
gli.Uniform1f(rgr.len, length)
|
||||
gli.Uniform1i(rgr.gradient, 0)
|
||||
gli.EnableVertexAttribArray(rgr.vertex)
|
||||
gli.DrawArrays(gl_TRIANGLE_FAN, 0, 4)
|
||||
gli.DisableVertexAttribArray(rgr.vertex)
|
||||
} else {
|
||||
gli.UseProgram(sr.id)
|
||||
gli.VertexAttribPointer(sr.vertex, 2, gl_FLOAT, false, 0, nil)
|
||||
|
|
73
gradients.go
73
gradients.go
|
@ -8,6 +8,15 @@ import (
|
|||
)
|
||||
|
||||
type LinearGradient struct {
|
||||
gradient
|
||||
}
|
||||
|
||||
type RadialGradient struct {
|
||||
gradient
|
||||
radFrom, radTo float32
|
||||
}
|
||||
|
||||
type gradient struct {
|
||||
from, to lm.Vec2
|
||||
stops []gradientStop
|
||||
tex uint32
|
||||
|
@ -21,7 +30,7 @@ type gradientStop struct {
|
|||
}
|
||||
|
||||
func NewLinearGradient(x0, y0, x1, y1 float32) *LinearGradient {
|
||||
lg := &LinearGradient{from: lm.Vec2{x0, y0}, to: lm.Vec2{x1, y1}}
|
||||
lg := &LinearGradient{gradient: gradient{from: lm.Vec2{x0, y0}, to: lm.Vec2{x1, y1}}}
|
||||
gli.GenTextures(1, &lg.tex)
|
||||
gli.ActiveTexture(gl_TEXTURE0)
|
||||
gli.BindTexture(gl_TEXTURE_1D, lg.tex)
|
||||
|
@ -36,21 +45,37 @@ func NewLinearGradient(x0, y0, x1, y1 float32) *LinearGradient {
|
|||
return lg
|
||||
}
|
||||
|
||||
func (lg *LinearGradient) Delete() {
|
||||
gli.DeleteTextures(1, &lg.tex)
|
||||
func NewRadialGradient(x0, y0, r0, x1, y1, r1 float32) *RadialGradient {
|
||||
rg := &RadialGradient{gradient: gradient{from: lm.Vec2{x0, y0}, to: lm.Vec2{x1, y1}}, radFrom: r0, radTo: r1}
|
||||
gli.GenTextures(1, &rg.tex)
|
||||
gli.ActiveTexture(gl_TEXTURE0)
|
||||
gli.BindTexture(gl_TEXTURE_1D, rg.tex)
|
||||
gli.TexParameteri(gl_TEXTURE_1D, gl_TEXTURE_MIN_FILTER, gl_LINEAR)
|
||||
gli.TexParameteri(gl_TEXTURE_1D, gl_TEXTURE_MAG_FILTER, gl_LINEAR)
|
||||
gli.TexParameteri(gl_TEXTURE_1D, gl_TEXTURE_WRAP_S, gl_CLAMP_TO_EDGE)
|
||||
runtime.SetFinalizer(rg, func(rg *RadialGradient) {
|
||||
glChan <- func() {
|
||||
gli.DeleteTextures(1, &rg.tex)
|
||||
}
|
||||
})
|
||||
return rg
|
||||
}
|
||||
|
||||
func (lg *LinearGradient) load() {
|
||||
if lg.loaded {
|
||||
func (g *gradient) Delete() {
|
||||
gli.DeleteTextures(1, &g.tex)
|
||||
}
|
||||
|
||||
func (g *gradient) load() {
|
||||
if g.loaded {
|
||||
return
|
||||
}
|
||||
|
||||
gli.ActiveTexture(gl_TEXTURE0)
|
||||
gli.BindTexture(gl_TEXTURE_1D, lg.tex)
|
||||
gli.BindTexture(gl_TEXTURE_1D, g.tex)
|
||||
var pixels [2048 * 4]byte
|
||||
pp := 0
|
||||
for i := 0; i < 2048; i++ {
|
||||
c := lg.colorAt(float32(i) / 2047)
|
||||
c := g.colorAt(float32(i) / 2047)
|
||||
pixels[pp] = byte(fmath.Floor(c.r*255 + 0.5))
|
||||
pixels[pp+1] = byte(fmath.Floor(c.g*255 + 0.5))
|
||||
pixels[pp+2] = byte(fmath.Floor(c.b*255 + 0.5))
|
||||
|
@ -58,17 +83,17 @@ func (lg *LinearGradient) load() {
|
|||
pp += 4
|
||||
}
|
||||
gli.TexImage1D(gl_TEXTURE_1D, 0, gl_RGBA, 2048, 0, gl_RGBA, gl_UNSIGNED_BYTE, gli.Ptr(&pixels[0]))
|
||||
lg.loaded = true
|
||||
g.loaded = true
|
||||
}
|
||||
|
||||
func (lg *LinearGradient) colorAt(pos float32) glColor {
|
||||
if len(lg.stops) == 0 {
|
||||
func (g *gradient) colorAt(pos float32) glColor {
|
||||
if len(g.stops) == 0 {
|
||||
return glColor{}
|
||||
} else if len(lg.stops) == 1 {
|
||||
return lg.stops[0].color
|
||||
} else if len(g.stops) == 1 {
|
||||
return g.stops[0].color
|
||||
}
|
||||
beforeIdx, afterIdx := -1, -1
|
||||
for i, stop := range lg.stops {
|
||||
for i, stop := range g.stops {
|
||||
if stop.pos > pos {
|
||||
afterIdx = i
|
||||
break
|
||||
|
@ -76,11 +101,11 @@ func (lg *LinearGradient) colorAt(pos float32) glColor {
|
|||
beforeIdx = i
|
||||
}
|
||||
if beforeIdx == -1 {
|
||||
return lg.stops[0].color
|
||||
return g.stops[0].color
|
||||
} else if afterIdx == -1 {
|
||||
return lg.stops[len(lg.stops)-1].color
|
||||
return g.stops[len(g.stops)-1].color
|
||||
}
|
||||
before, after := lg.stops[beforeIdx], lg.stops[afterIdx]
|
||||
before, after := g.stops[beforeIdx], g.stops[afterIdx]
|
||||
p := (pos - before.pos) / (after.pos - before.pos)
|
||||
var c glColor
|
||||
c.r = (after.color.r-before.color.r)*p + before.color.r
|
||||
|
@ -90,19 +115,19 @@ func (lg *LinearGradient) colorAt(pos float32) glColor {
|
|||
return c
|
||||
}
|
||||
|
||||
func (lg *LinearGradient) AddColorStop(pos float32, color ...interface{}) {
|
||||
func (g *gradient) AddColorStop(pos float32, color ...interface{}) {
|
||||
c, _ := parseColor(color...)
|
||||
insert := len(lg.stops)
|
||||
for i, stop := range lg.stops {
|
||||
insert := len(g.stops)
|
||||
for i, stop := range g.stops {
|
||||
if stop.pos > pos {
|
||||
insert = i
|
||||
break
|
||||
}
|
||||
}
|
||||
lg.stops = append(lg.stops, gradientStop{})
|
||||
if insert < len(lg.stops)-1 {
|
||||
copy(lg.stops[insert+1:], lg.stops[insert:len(lg.stops)-1])
|
||||
g.stops = append(g.stops, gradientStop{})
|
||||
if insert < len(g.stops)-1 {
|
||||
copy(g.stops[insert+1:], g.stops[insert:len(g.stops)-1])
|
||||
}
|
||||
lg.stops[insert] = gradientStop{pos: pos, color: c}
|
||||
lg.loaded = false
|
||||
g.stops[insert] = gradientStop{pos: pos, color: c}
|
||||
g.loaded = false
|
||||
}
|
||||
|
|
109
made_shaders.go
109
made_shaders.go
|
@ -213,7 +213,7 @@ type linearGradientShader struct {
|
|||
gradient int32
|
||||
from int32
|
||||
dir int32
|
||||
length int32
|
||||
len int32
|
||||
}
|
||||
|
||||
func loadLinearGradientShader() (*linearGradientShader, error) {
|
||||
|
@ -306,7 +306,112 @@ func loadLinearGradientShader() (*linearGradientShader, error) {
|
|||
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.length = gli.GetUniformLocation(program, gli.Str("length\x00"))
|
||||
result.len = gli.GetUniformLocation(program, gli.Str("len\x00"))
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type radialGradientShader struct {
|
||||
id uint32
|
||||
vertex uint32
|
||||
canvasSize int32
|
||||
gradient int32
|
||||
from int32
|
||||
dir 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.dir = gli.GetUniformLocation(program, gli.Str("dir\x00"))
|
||||
result.len = gli.GetUniformLocation(program, gli.Str("len\x00"))
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue