Merge pull request #246 from dusk125/tri_shader

#244 GLTriangle's fragment shader is used when rendered by the Canvas.
This commit is contained in:
Alex R. Delp 2020-11-21 20:22:37 -08:00 committed by GitHub
commit 6e34aae429
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 62 additions and 55 deletions

View File

@ -19,7 +19,7 @@ import (
// It supports TrianglesPosition, TrianglesColor, TrianglesPicture and PictureColor. // It supports TrianglesPosition, TrianglesColor, TrianglesPicture and PictureColor.
type Canvas struct { type Canvas struct {
gf *GLFrame gf *GLFrame
shader *glShader shader *GLShader
cmp pixel.ComposeMethod cmp pixel.ComposeMethod
mat mgl32.Mat3 mat mgl32.Mat3
@ -39,9 +39,8 @@ func NewCanvas(bounds pixel.Rect) *Canvas {
col: mgl32.Vec4{1, 1, 1, 1}, col: mgl32.Vec4{1, 1, 1, 1},
} }
baseShader(c) c.shader = NewGLShader(baseCanvasFragmentShader)
c.SetBounds(bounds) c.SetBounds(bounds)
c.shader.update()
return c return c
} }
@ -49,22 +48,28 @@ func NewCanvas(bounds pixel.Rect) *Canvas {
// attribute variable. If the uniform already exists, including defaults, they will be reassigned // attribute variable. If the uniform already exists, including defaults, they will be reassigned
// to the new value. The value can be a pointer. // to the new value. The value can be a pointer.
func (c *Canvas) SetUniform(name string, value interface{}) { func (c *Canvas) SetUniform(name string, value interface{}) {
c.shader.setUniform(name, value) c.shader.SetUniform(name, value)
} }
// SetFragmentShader allows you to set a new fragment shader on the underlying // SetFragmentShader allows you to set a new fragment shader on the underlying
// framebuffer. Argument "src" is the GLSL source, not a filename. // framebuffer. Argument "src" is the GLSL source, not a filename.
func (c *Canvas) SetFragmentShader(src string) { func (c *Canvas) SetFragmentShader(src string) {
c.shader.fs = src c.shader.fs = src
c.shader.update() c.shader.Update()
} }
// MakeTriangles creates a specialized copy of the supplied Triangles that draws onto this Canvas. // MakeTriangles creates a specialized copy of the supplied Triangles that draws onto this Canvas.
// //
// TrianglesPosition, TrianglesColor and TrianglesPicture are supported. // TrianglesPosition, TrianglesColor and TrianglesPicture are supported.
func (c *Canvas) MakeTriangles(t pixel.Triangles) pixel.TargetTriangles { func (c *Canvas) MakeTriangles(t pixel.Triangles) pixel.TargetTriangles {
if gt, ok := t.(*GLTriangles); ok {
return &canvasTriangles{
GLTriangles: gt,
dst: c,
}
}
return &canvasTriangles{ return &canvasTriangles{
GLTriangles: NewGLTriangles(c.shader.s, t), GLTriangles: NewGLTriangles(c.shader, t),
dst: c, dst: c,
} }
} }
@ -290,15 +295,15 @@ func (ct *canvasTriangles) draw(tex *glhf.Texture, bounds pixel.Rect) {
setBlendFunc(cmp) setBlendFunc(cmp)
frame := ct.dst.gf.Frame() frame := ct.dst.gf.Frame()
shader := ct.dst.shader.s shader := ct.shader.s
frame.Begin() frame.Begin()
shader.Begin() shader.Begin()
ct.dst.shader.uniformDefaults.transform = mat ct.shader.uniformDefaults.transform = mat
ct.dst.shader.uniformDefaults.colormask = col ct.shader.uniformDefaults.colormask = col
dstBounds := ct.dst.Bounds() dstBounds := ct.dst.Bounds()
ct.dst.shader.uniformDefaults.bounds = mgl32.Vec4{ ct.shader.uniformDefaults.bounds = mgl32.Vec4{
float32(dstBounds.Min.X), float32(dstBounds.Min.X),
float32(dstBounds.Min.Y), float32(dstBounds.Min.Y),
float32(dstBounds.W()), float32(dstBounds.W()),
@ -306,15 +311,15 @@ func (ct *canvasTriangles) draw(tex *glhf.Texture, bounds pixel.Rect) {
} }
bx, by, bw, bh := intBounds(bounds) bx, by, bw, bh := intBounds(bounds)
ct.dst.shader.uniformDefaults.texbounds = mgl32.Vec4{ ct.shader.uniformDefaults.texbounds = mgl32.Vec4{
float32(bx), float32(bx),
float32(by), float32(by),
float32(bw), float32(bw),
float32(bh), float32(bh),
} }
for loc, u := range ct.dst.shader.uniforms { for loc, u := range ct.shader.uniforms {
ct.dst.shader.s.SetUniformAttr(loc, u.Value()) ct.shader.s.SetUniformAttr(loc, u.Value())
} }
if clip, has := ct.ClipRect(); has { if clip, has := ct.ClipRect(); has {
@ -360,17 +365,3 @@ func (cp *canvasPicture) Draw(t pixel.TargetTriangles) {
} }
ct.draw(cp.GLPicture.Texture(), cp.GLPicture.Bounds()) ct.draw(cp.GLPicture.Texture(), cp.GLPicture.Bounds())
} }
const (
canvasPosition int = iota
canvasColor
canvasTexCoords
canvasIntensity
)
var defaultCanvasVertexFormat = glhf.AttrFormat{
canvasPosition: {Name: "aPosition", Type: glhf.Vec2},
canvasColor: {Name: "aColor", Type: glhf.Vec4},
canvasTexCoords: {Name: "aTexCoords", Type: glhf.Vec2},
canvasIntensity: {Name: "aIntensity", Type: glhf.Float},
}

View File

@ -7,10 +7,10 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
) )
// glShader is a type to assist with managing a canvas's underlying // GLShader is a type to assist with managing a canvas's underlying
// shader configuration. This allows for customization of shaders on // shader configuration. This allows for customization of shaders on
// a per canvas basis. // a per canvas basis.
type glShader struct { type GLShader struct {
s *glhf.Shader s *glhf.Shader
vf, uf glhf.AttrFormat vf, uf glhf.AttrFormat
vs, fs string vs, fs string
@ -32,8 +32,42 @@ type gsUniformAttr struct {
ispointer bool ispointer bool
} }
// reinitialize GLShader data and recompile the underlying gl shader object const (
func (gs *glShader) update() { canvasPosition int = iota
canvasColor
canvasTexCoords
canvasIntensity
)
var defaultCanvasVertexFormat = glhf.AttrFormat{
canvasPosition: {Name: "aPosition", Type: glhf.Vec2},
canvasColor: {Name: "aColor", Type: glhf.Vec4},
canvasTexCoords: {Name: "aTexCoords", Type: glhf.Vec2},
canvasIntensity: {Name: "aIntensity", Type: glhf.Float},
}
// Sets up a base shader with everything needed for a Pixel
// canvas to render correctly. The defaults can be overridden
// by simply using the SetUniform function.
func NewGLShader(fragmentShader string) *GLShader {
gs := &GLShader{
vf: defaultCanvasVertexFormat,
vs: baseCanvasVertexShader,
fs: fragmentShader,
}
gs.SetUniform("uTransform", &gs.uniformDefaults.transform)
gs.SetUniform("uColorMask", &gs.uniformDefaults.colormask)
gs.SetUniform("uBounds", &gs.uniformDefaults.bounds)
gs.SetUniform("uTexBounds", &gs.uniformDefaults.texbounds)
gs.Update()
return gs
}
// Update reinitialize GLShader data and recompile the underlying gl shader object
func (gs *GLShader) Update() {
gs.uf = nil gs.uf = nil
for _, u := range gs.uniforms { for _, u := range gs.uniforms {
gs.uf = append(gs.uf, glhf.Attr{ gs.uf = append(gs.uf, glhf.Attr{
@ -59,7 +93,7 @@ func (gs *glShader) update() {
} }
// gets the uniform index from GLShader // gets the uniform index from GLShader
func (gs *glShader) getUniform(Name string) int { func (gs *GLShader) getUniform(Name string) int {
for i, u := range gs.uniforms { for i, u := range gs.uniforms {
if u.Name == Name { if u.Name == Name {
return i return i
@ -75,7 +109,7 @@ func (gs *glShader) getUniform(Name string) int {
// //
// utime := float32(time.Since(starttime)).Seconds()) // utime := float32(time.Since(starttime)).Seconds())
// mycanvas.shader.AddUniform("u_time", &utime) // mycanvas.shader.AddUniform("u_time", &utime)
func (gs *glShader) setUniform(name string, value interface{}) { func (gs *GLShader) SetUniform(name string, value interface{}) {
t, p := getAttrType(value) t, p := getAttrType(value)
if loc := gs.getUniform(name); loc > -1 { if loc := gs.getUniform(name); loc > -1 {
gs.uniforms[loc].Name = name gs.uniforms[loc].Name = name
@ -92,24 +126,6 @@ func (gs *glShader) setUniform(name string, value interface{}) {
}) })
} }
// Sets up a base shader with everything needed for a Pixel
// canvas to render correctly. The defaults can be overridden
// by simply using the SetUniform function.
func baseShader(c *Canvas) {
gs := &glShader{
vf: defaultCanvasVertexFormat,
vs: baseCanvasVertexShader,
fs: baseCanvasFragmentShader,
}
gs.setUniform("uTransform", &gs.uniformDefaults.transform)
gs.setUniform("uColorMask", &gs.uniformDefaults.colormask)
gs.setUniform("uBounds", &gs.uniformDefaults.bounds)
gs.setUniform("uTexBounds", &gs.uniformDefaults.texbounds)
c.shader = gs
}
// Value returns the attribute's concrete value. If the stored value // Value returns the attribute's concrete value. If the stored value
// is a pointer, we return the dereferenced value. // is a pointer, we return the dereferenced value.
func (gu *gsUniformAttr) Value() interface{} { func (gu *gsUniformAttr) Value() interface{} {

View File

@ -15,7 +15,7 @@ import (
type GLTriangles struct { type GLTriangles struct {
vs *glhf.VertexSlice vs *glhf.VertexSlice
data []float32 data []float32
shader *glhf.Shader shader *GLShader
clip pixel.Rect clip pixel.Rect
} }
@ -28,11 +28,11 @@ var (
// NewGLTriangles returns GLTriangles initialized with the data from the supplied Triangles. // NewGLTriangles returns GLTriangles initialized with the data from the supplied Triangles.
// //
// Only draw the Triangles using the provided Shader. // Only draw the Triangles using the provided Shader.
func NewGLTriangles(shader *glhf.Shader, t pixel.Triangles) *GLTriangles { func NewGLTriangles(shader *GLShader, t pixel.Triangles) *GLTriangles {
var gt *GLTriangles var gt *GLTriangles
mainthread.Call(func() { mainthread.Call(func() {
gt = &GLTriangles{ gt = &GLTriangles{
vs: glhf.MakeVertexSlice(shader, 0, t.Len()), vs: glhf.MakeVertexSlice(shader.s, 0, t.Len()),
shader: shader, shader: shader,
} }
}) })
@ -49,7 +49,7 @@ func (gt *GLTriangles) VertexSlice() *glhf.VertexSlice {
} }
// Shader returns the GLTriangles's associated shader. // Shader returns the GLTriangles's associated shader.
func (gt *GLTriangles) Shader() *glhf.Shader { func (gt *GLTriangles) Shader() *GLShader {
return gt.shader return gt.shader
} }