From 55d3a6ab00241955c98bd7159415a1a4bb5eec6e Mon Sep 17 00:00:00 2001 From: Brandon Date: Tue, 2 Oct 2018 08:59:37 -0600 Subject: [PATCH 1/5] implemented custom fragment shader support --- pixelgl/attr.go | 102 +++++++++++++++++++++++++++++ pixelgl/canvas.go | 159 +++++++++++++++++---------------------------- pixelgl/shader.go | 162 ++++++++++++++++++++++++++++++++++++++++++++++ pixelgl/window.go | 5 ++ 4 files changed, 330 insertions(+), 98 deletions(-) create mode 100644 pixelgl/attr.go create mode 100644 pixelgl/shader.go diff --git a/pixelgl/attr.go b/pixelgl/attr.go new file mode 100644 index 0000000..c540bd1 --- /dev/null +++ b/pixelgl/attr.go @@ -0,0 +1,102 @@ +package pixelgl + +import "github.com/go-gl/mathgl/mgl32" + +// AttrType is the attribute's identifier +type AttrType int + +// List of all possible attribute types. +const ( + Int AttrType = iota + Float + Vec2 + Vec3 + Vec4 + Mat2 + Mat23 + Mat24 + Mat3 + Mat32 + Mat34 + Mat4 + Mat42 + Mat43 + Intp // pointers + Floatp + Vec2p + Vec3p + Vec4p + Mat2p + Mat23p + Mat24p + Mat3p + Mat32p + Mat34p + Mat4p + Mat42p + Mat43p +) + +// Returns the type identifier for any (supported) variable type +func getAttrType(v interface{}) AttrType { + switch v.(type) { + case int32: + return Int + case float32: + return Float + case mgl32.Vec2: + return Vec2 + case mgl32.Vec3: + return Vec3 + case mgl32.Vec4: + return Vec4 + case mgl32.Mat2: + return Mat2 + case mgl32.Mat2x3: + return Mat23 + case mgl32.Mat2x4: + return Mat24 + case mgl32.Mat3: + return Mat3 + case mgl32.Mat3x2: + return Mat32 + case mgl32.Mat3x4: + return Mat34 + case mgl32.Mat4: + return Mat4 + case mgl32.Mat4x2: + return Mat42 + case mgl32.Mat4x3: + return Mat43 + case *mgl32.Vec2: + return Vec2p + case *mgl32.Vec3: + return Vec3p + case *mgl32.Vec4: + return Vec4p + case *mgl32.Mat2: + return Mat2p + case *mgl32.Mat2x3: + return Mat23p + case *mgl32.Mat2x4: + return Mat24p + case *mgl32.Mat3: + return Mat3p + case *mgl32.Mat3x2: + return Mat32p + case *mgl32.Mat3x4: + return Mat34p + case *mgl32.Mat4: + return Mat4p + case *mgl32.Mat4x2: + return Mat42p + case *mgl32.Mat4x3: + return Mat43p + case *int32: + return Intp + case *float32: + return Floatp + default: + panic("invalid AttrType") + } +} diff --git a/pixelgl/canvas.go b/pixelgl/canvas.go index b8e4057..66c2ac4 100644 --- a/pixelgl/canvas.go +++ b/pixelgl/canvas.go @@ -17,7 +17,7 @@ import ( // It supports TrianglesPosition, TrianglesColor, TrianglesPicture and PictureColor. type Canvas struct { gf *GLFrame - shader *glhf.Shader + shader *GLShader cmp pixel.ComposeMethod mat mgl32.Mat3 @@ -37,32 +37,37 @@ func NewCanvas(bounds pixel.Rect) *Canvas { col: mgl32.Vec4{1, 1, 1, 1}, } + baseShader(c) c.SetBounds(bounds) - - var shader *glhf.Shader - mainthread.Call(func() { - var err error - shader, err = glhf.NewShader( - canvasVertexFormat, - canvasUniformFormat, - canvasVertexShader, - canvasFragmentShader, - ) - if err != nil { - panic(errors.Wrap(err, "failed to create Canvas, there's a bug in the shader")) - } - }) - c.shader = shader - + c.shader.update() return c } +// BindUniform will add a uniform with any supported underlying variable +// if the uniform already exists, including defaults, they will be reassigned +// to the new value +func (c *Canvas) BindUniform(Name string, Value interface{}) { + c.shader.AddUniform(Name, Value) +} + +// UpdateShader needs to be called after any changes to the underlying GLShader +// are made (ie, BindUniform(), SetFragmentShader()...) +func (c *Canvas) UpdateShader() { + c.shader.update() +} + +// SetFragmentShader allows you to define a new fragment shader on the underlying +// GLShader. fs is the GLSL source, not a filename +func (c *Canvas) SetFragmentShader(fs string) { + c.shader.fs = fs +} + // MakeTriangles creates a specialized copy of the supplied Triangles that draws onto this Canvas. // // TrianglesPosition, TrianglesColor and TrianglesPicture are supported. func (c *Canvas) MakeTriangles(t pixel.Triangles) pixel.TargetTriangles { return &canvasTriangles{ - GLTriangles: NewGLTriangles(c.shader, t), + GLTriangles: NewGLTriangles(c.shader.s, t), dst: c, } } @@ -184,6 +189,25 @@ func setBlendFunc(cmp pixel.ComposeMethod) { } } +// updates all uniform values for gl to consume +func (c *Canvas) setUniforms(texbounds pixel.Rect) { + mat := c.mat + col := c.col + c.shader.uniformDefaults.transform = mat + c.shader.uniformDefaults.colormask = col + dstBounds := c.Bounds() + c.shader.uniformDefaults.bounds = mgl32.Vec4{ + float32(dstBounds.Min.X), + float32(dstBounds.Min.Y), + float32(dstBounds.W()), + float32(dstBounds.H()), + } + + for loc, u := range c.shader.uniforms { + c.shader.s.SetUniformAttr(loc, u.Value) + } +} + // Clear fills the whole Canvas with a single color. func (c *Canvas) Clear(color color.Color) { c.gf.Dirty() @@ -279,29 +303,41 @@ func (ct *canvasTriangles) draw(tex *glhf.Texture, bounds pixel.Rect) { // save the current state vars to avoid race condition cmp := ct.dst.cmp + smt := ct.dst.smooth mat := ct.dst.mat col := ct.dst.col - smt := ct.dst.smooth mainthread.CallNonBlock(func() { ct.dst.setGlhfBounds() setBlendFunc(cmp) frame := ct.dst.gf.Frame() - shader := ct.dst.shader + shader := ct.dst.shader.s frame.Begin() shader.Begin() + ct.dst.shader.uniformDefaults.transform = mat + ct.dst.shader.uniformDefaults.colormask = col dstBounds := ct.dst.Bounds() - shader.SetUniformAttr(canvasBounds, mgl32.Vec4{ + ct.dst.shader.uniformDefaults.bounds = mgl32.Vec4{ float32(dstBounds.Min.X), float32(dstBounds.Min.Y), float32(dstBounds.W()), float32(dstBounds.H()), - }) - shader.SetUniformAttr(canvasTransform, mat) - shader.SetUniformAttr(canvasColorMask, col) + } + + bx, by, bw, bh := intBounds(bounds) + ct.dst.shader.uniformDefaults.texbounds = mgl32.Vec4{ + float32(bx), + float32(by), + float32(bw), + float32(bh), + } + + for loc, u := range ct.dst.shader.uniforms { + ct.dst.shader.s.SetUniformAttr(loc, u.Value) + } if tex == nil { ct.vs.Begin() @@ -310,14 +346,6 @@ func (ct *canvasTriangles) draw(tex *glhf.Texture, bounds pixel.Rect) { } else { tex.Begin() - bx, by, bw, bh := intBounds(bounds) - shader.SetUniformAttr(canvasTexBounds, mgl32.Vec4{ - float32(bx), - float32(by), - float32(bw), - float32(bh), - }) - if tex.Smooth() != smt { tex.SetSmooth(smt) } @@ -358,74 +386,9 @@ const ( canvasIntensity ) -var canvasVertexFormat = glhf.AttrFormat{ +var defaultCanvasVertexFormat = glhf.AttrFormat{ canvasPosition: {Name: "position", Type: glhf.Vec2}, canvasColor: {Name: "color", Type: glhf.Vec4}, canvasTexCoords: {Name: "texCoords", Type: glhf.Vec2}, canvasIntensity: {Name: "intensity", Type: glhf.Float}, } - -const ( - canvasTransform int = iota - canvasColorMask - canvasBounds - canvasTexBounds -) - -var canvasUniformFormat = glhf.AttrFormat{ - canvasTransform: {Name: "transform", Type: glhf.Mat3}, - canvasColorMask: {Name: "colorMask", Type: glhf.Vec4}, - canvasBounds: {Name: "bounds", Type: glhf.Vec4}, - canvasTexBounds: {Name: "texBounds", Type: glhf.Vec4}, -} - -var canvasVertexShader = ` -#version 330 core - -in vec2 position; -in vec4 color; -in vec2 texCoords; -in float intensity; - -out vec4 Color; -out vec2 TexCoords; -out float Intensity; - -uniform mat3 transform; -uniform vec4 bounds; - -void main() { - vec2 transPos = (transform * vec3(position, 1.0)).xy; - vec2 normPos = (transPos - bounds.xy) / bounds.zw * 2 - vec2(1, 1); - gl_Position = vec4(normPos, 0.0, 1.0); - Color = color; - TexCoords = texCoords; - Intensity = intensity; -} -` - -var canvasFragmentShader = ` -#version 330 core - -in vec4 Color; -in vec2 TexCoords; -in float Intensity; - -out vec4 color; - -uniform vec4 colorMask; -uniform vec4 texBounds; -uniform sampler2D tex; - -void main() { - if (Intensity == 0) { - color = colorMask * Color; - } else { - color = vec4(0, 0, 0, 0); - color += (1 - Intensity) * Color; - vec2 t = (TexCoords - texBounds.xy) / texBounds.zw; - color += Intensity * Color * texture(tex, t); - color *= colorMask; - } -} -` diff --git a/pixelgl/shader.go b/pixelgl/shader.go new file mode 100644 index 0000000..9d2e8fe --- /dev/null +++ b/pixelgl/shader.go @@ -0,0 +1,162 @@ +package pixelgl + +import ( + "github.com/faiface/glhf" + "github.com/faiface/mainthread" + "github.com/go-gl/mathgl/mgl32" + "github.com/pkg/errors" +) + +// GLShader is a type to assist with managing a canvas's underlying +// shader configuration. This allows for customization of shaders on +// a per canvas basis. +type ( + GLShader struct { + s *glhf.Shader + vf, uf glhf.AttrFormat + vs, fs string + + uniforms []gsUniformAttr + + uniformDefaults struct { + transform mgl32.Mat3 + colormask mgl32.Vec4 + bounds mgl32.Vec4 + texbounds mgl32.Vec4 + } + } + + gsUniformAttr struct { + Name string + Type AttrType + Value interface{} + } +) + +// reinitialize GLShader data and recompile the underlying gl shader object +func (gs *GLShader) update() { + gs.uf = nil + for _, u := range gs.uniforms { + gs.uf = append(gs.uf, glhf.Attr{ + Name: u.Name, + Type: glhf.AttrType(u.Type), + }) + } + var shader *glhf.Shader + mainthread.Call(func() { + var err error + shader, err = glhf.NewShader( + gs.vf, + gs.uf, + gs.vs, + gs.fs, + ) + if err != nil { + panic(errors.Wrap(err, "failed to create Canvas, there's a bug in the shader")) + } + }) + + gs.s = shader +} + +// gets the uniform index from GLShader +func (gs *GLShader) getUniform(Name string) int { + for i, u := range gs.uniforms { + if u.Name == Name { + return i + } + } + return -1 +} + +// AddUniform appends a custom uniform name and value to the shader +// +// To add a time uniform for example: +// +// utime := float32(time.Since(starttime)).Seconds()) +// mycanvas.shader.AddUniform("u_time", &utime) +// +func (gs *GLShader) AddUniform(Name string, Value interface{}) { + Type := getAttrType(Value) + if loc := gs.getUniform(Name); loc > -1 { + gs.uniforms[loc].Name = Name + gs.uniforms[loc].Type = Type + gs.uniforms[loc].Value = Value + return + } + gs.uniforms = append(gs.uniforms, gsUniformAttr{ + Name: Name, + Type: Type, + Value: Value, + }) +} + +// Sets up a base shader with everything needed for a pixel +// canvas to render correctly. The defaults can be overridden +// by simply using AddUniform() +func baseShader(c *Canvas) { + gs := &GLShader{ + vf: defaultCanvasVertexFormat, + vs: defaultCanvasVertexShader, + fs: baseCanvasFragmentShader, + } + + gs.AddUniform("u_transform", &gs.uniformDefaults.transform) + gs.AddUniform("u_colormask", &gs.uniformDefaults.colormask) + gs.AddUniform("u_bounds", &gs.uniformDefaults.bounds) + gs.AddUniform("u_texbounds", &gs.uniformDefaults.texbounds) + + c.shader = gs +} + +var defaultCanvasVertexShader = ` +#version 330 core + +in vec2 position; +in vec4 color; +in vec2 texCoords; +in float intensity; +out vec4 Color; +out vec2 texcoords; +out vec2 glpos; +out float Intensity; + +uniform mat3 u_transform; +uniform vec4 u_bounds; + +void main() { + vec2 transPos = (u_transform * vec3(position, 1.0)).xy; + vec2 normPos = (transPos - u_bounds.xy) / u_bounds.zw * 2 - vec2(1, 1); + gl_Position = vec4(normPos, 0.0, 1.0); + Color = color; + texcoords = texCoords; + Intensity = intensity; + glpos = transPos; +} +` + +var baseCanvasFragmentShader = ` +#version 330 core + +in vec4 Color; +in vec2 texcoords; +in float Intensity; + +out vec4 fragColor; + +uniform vec4 u_colormask; +uniform vec4 u_texbounds; +uniform sampler2D u_texture; + +void main() { + if (Intensity == 0) { + fragColor = u_colormask * Color; + } else { + fragColor = vec4(0, 0, 0, 0); + fragColor += (1 - Intensity) * Color; + vec2 t = (texcoords - u_texbounds.xy) / u_texbounds.zw; + fragColor += Intensity * Color * texture(u_texture, t); + fragColor *= u_colormask; + } +} +` diff --git a/pixelgl/window.go b/pixelgl/window.go index ddc5426..de7bb0d 100644 --- a/pixelgl/window.go +++ b/pixelgl/window.go @@ -424,3 +424,8 @@ func (w *Window) Clear(c color.Color) { func (w *Window) Color(at pixel.Vec) pixel.RGBA { return w.canvas.Color(at) } + +// GetCanvas returns the window's underlying Canvas +func (w *Window) GetCanvas() *Canvas { + return w.canvas +} From 45642083a28be7f53cffd27b91b8eeb02fb9e060 Mon Sep 17 00:00:00 2001 From: Brandon Date: Wed, 3 Oct 2018 09:37:10 -0600 Subject: [PATCH 2/5] renamed file shader.go to glshader.go --- pixelgl/{shader.go => glshader.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename pixelgl/{shader.go => glshader.go} (100%) diff --git a/pixelgl/shader.go b/pixelgl/glshader.go similarity index 100% rename from pixelgl/shader.go rename to pixelgl/glshader.go From a25a444cbf5e1bbdf762ced1a7f8cc4467a5d32f Mon Sep 17 00:00:00 2001 From: Brandon Date: Wed, 3 Oct 2018 13:02:10 -0600 Subject: [PATCH 3/5] pr 141 review #1 changes, see https://github.com/faiface/pixel/pull/141#pullrequestreview-161208458 --- pixelgl/attr.go | 102 -------------------------- pixelgl/canvas.go | 18 ++--- pixelgl/glshader.go | 170 +++++++++++++++++++++++++++++++++++--------- pixelgl/window.go | 4 +- 4 files changed, 149 insertions(+), 145 deletions(-) delete mode 100644 pixelgl/attr.go diff --git a/pixelgl/attr.go b/pixelgl/attr.go deleted file mode 100644 index c540bd1..0000000 --- a/pixelgl/attr.go +++ /dev/null @@ -1,102 +0,0 @@ -package pixelgl - -import "github.com/go-gl/mathgl/mgl32" - -// AttrType is the attribute's identifier -type AttrType int - -// List of all possible attribute types. -const ( - Int AttrType = iota - Float - Vec2 - Vec3 - Vec4 - Mat2 - Mat23 - Mat24 - Mat3 - Mat32 - Mat34 - Mat4 - Mat42 - Mat43 - Intp // pointers - Floatp - Vec2p - Vec3p - Vec4p - Mat2p - Mat23p - Mat24p - Mat3p - Mat32p - Mat34p - Mat4p - Mat42p - Mat43p -) - -// Returns the type identifier for any (supported) variable type -func getAttrType(v interface{}) AttrType { - switch v.(type) { - case int32: - return Int - case float32: - return Float - case mgl32.Vec2: - return Vec2 - case mgl32.Vec3: - return Vec3 - case mgl32.Vec4: - return Vec4 - case mgl32.Mat2: - return Mat2 - case mgl32.Mat2x3: - return Mat23 - case mgl32.Mat2x4: - return Mat24 - case mgl32.Mat3: - return Mat3 - case mgl32.Mat3x2: - return Mat32 - case mgl32.Mat3x4: - return Mat34 - case mgl32.Mat4: - return Mat4 - case mgl32.Mat4x2: - return Mat42 - case mgl32.Mat4x3: - return Mat43 - case *mgl32.Vec2: - return Vec2p - case *mgl32.Vec3: - return Vec3p - case *mgl32.Vec4: - return Vec4p - case *mgl32.Mat2: - return Mat2p - case *mgl32.Mat2x3: - return Mat23p - case *mgl32.Mat2x4: - return Mat24p - case *mgl32.Mat3: - return Mat3p - case *mgl32.Mat3x2: - return Mat32p - case *mgl32.Mat3x4: - return Mat34p - case *mgl32.Mat4: - return Mat4p - case *mgl32.Mat4x2: - return Mat42p - case *mgl32.Mat4x3: - return Mat43p - case *int32: - return Intp - case *float32: - return Floatp - default: - panic("invalid AttrType") - } -} diff --git a/pixelgl/canvas.go b/pixelgl/canvas.go index 66c2ac4..1e82fee 100644 --- a/pixelgl/canvas.go +++ b/pixelgl/canvas.go @@ -43,21 +43,21 @@ func NewCanvas(bounds pixel.Rect) *Canvas { return c } -// BindUniform will add a uniform with any supported underlying variable -// if the uniform already exists, including defaults, they will be reassigned -// to the new value -func (c *Canvas) BindUniform(Name string, Value interface{}) { +// SetUniform will update the named uniform with the value of any supported underlying +// attribute variable. If the uniform already exists, including defaults, they will be reassigned +// to the new value. The value can be a pointer. +func (c *Canvas) SetUniform(Name string, Value interface{}) { c.shader.AddUniform(Name, Value) } // UpdateShader needs to be called after any changes to the underlying GLShader -// are made (ie, BindUniform(), SetFragmentShader()...) +// are made, such as, SetUniform, SetFragmentShader... func (c *Canvas) UpdateShader() { c.shader.update() } -// SetFragmentShader allows you to define a new fragment shader on the underlying -// GLShader. fs is the GLSL source, not a filename +// SetFragmentShader allows you to set a new fragment shader on the underlying +// framebuffer. Argument "fs" is the GLSL source, not a filename. func (c *Canvas) SetFragmentShader(fs string) { c.shader.fs = fs } @@ -204,7 +204,7 @@ func (c *Canvas) setUniforms(texbounds pixel.Rect) { } for loc, u := range c.shader.uniforms { - c.shader.s.SetUniformAttr(loc, u.Value) + c.shader.s.SetUniformAttr(loc, u.Value()) } } @@ -336,7 +336,7 @@ func (ct *canvasTriangles) draw(tex *glhf.Texture, bounds pixel.Rect) { } for loc, u := range ct.dst.shader.uniforms { - ct.dst.shader.s.SetUniformAttr(loc, u.Value) + ct.dst.shader.s.SetUniformAttr(loc, u.Value()) } if tex == nil { diff --git a/pixelgl/glshader.go b/pixelgl/glshader.go index 9d2e8fe..865c6fd 100644 --- a/pixelgl/glshader.go +++ b/pixelgl/glshader.go @@ -10,28 +10,27 @@ import ( // GLShader is a type to assist with managing a canvas's underlying // shader configuration. This allows for customization of shaders on // a per canvas basis. -type ( - GLShader struct { - s *glhf.Shader - vf, uf glhf.AttrFormat - vs, fs string +type GLShader struct { + s *glhf.Shader + vf, uf glhf.AttrFormat + vs, fs string - uniforms []gsUniformAttr + uniforms []gsUniformAttr - uniformDefaults struct { - transform mgl32.Mat3 - colormask mgl32.Vec4 - bounds mgl32.Vec4 - texbounds mgl32.Vec4 - } + uniformDefaults struct { + transform mgl32.Mat3 + colormask mgl32.Vec4 + bounds mgl32.Vec4 + texbounds mgl32.Vec4 } +} - gsUniformAttr struct { - Name string - Type AttrType - Value interface{} - } -) +type gsUniformAttr struct { + Name string + Type glhf.AttrType + value interface{} + ispointer bool +} // reinitialize GLShader data and recompile the underlying gl shader object func (gs *GLShader) update() { @@ -39,7 +38,7 @@ func (gs *GLShader) update() { for _, u := range gs.uniforms { gs.uf = append(gs.uf, glhf.Attr{ Name: u.Name, - Type: glhf.AttrType(u.Type), + Type: u.Type, }) } var shader *glhf.Shader @@ -69,31 +68,33 @@ func (gs *GLShader) getUniform(Name string) int { return -1 } -// AddUniform appends a custom uniform name and value to the shader +// AddUniform appends a custom uniform name and value to the shader. +// if the uniform already exists, it will simply be overwritten. // -// To add a time uniform for example: -// -// utime := float32(time.Since(starttime)).Seconds()) -// mycanvas.shader.AddUniform("u_time", &utime) +// example: // +// utime := float32(time.Since(starttime)).Seconds()) +// mycanvas.shader.AddUniform("u_time", &utime) func (gs *GLShader) AddUniform(Name string, Value interface{}) { - Type := getAttrType(Value) + t, p := getAttrType(Value) if loc := gs.getUniform(Name); loc > -1 { gs.uniforms[loc].Name = Name - gs.uniforms[loc].Type = Type - gs.uniforms[loc].Value = Value + gs.uniforms[loc].Type = t + gs.uniforms[loc].ispointer = p + gs.uniforms[loc].value = Value return } gs.uniforms = append(gs.uniforms, gsUniformAttr{ - Name: Name, - Type: Type, - Value: Value, + Name: Name, + Type: t, + ispointer: p, + value: Value, }) } -// Sets up a base shader with everything needed for a pixel +// Sets up a base shader with everything needed for a Pixel // canvas to render correctly. The defaults can be overridden -// by simply using AddUniform() +// by simply using the AddUniform function. func baseShader(c *Canvas) { gs := &GLShader{ vf: defaultCanvasVertexFormat, @@ -109,6 +110,111 @@ func baseShader(c *Canvas) { c.shader = gs } +// Value returns the attribute's concrete value. If the stored value +// is a pointer, we return the dereferenced value. +func (gu *gsUniformAttr) Value() interface{} { + if !gu.ispointer { + return gu.value + } + switch gu.Type { + case glhf.Vec2: + return *gu.value.(*mgl32.Vec2) + case glhf.Vec3: + return *gu.value.(*mgl32.Vec3) + case glhf.Vec4: + return *gu.value.(*mgl32.Vec4) + case glhf.Mat2: + return *gu.value.(*mgl32.Mat2) + case glhf.Mat23: + return *gu.value.(*mgl32.Mat2x3) + case glhf.Mat24: + return *gu.value.(*mgl32.Mat2x4) + case glhf.Mat3: + return *gu.value.(*mgl32.Mat3) + case glhf.Mat32: + return *gu.value.(*mgl32.Mat3x2) + case glhf.Mat34: + return *gu.value.(*mgl32.Mat3x4) + case glhf.Mat4: + return *gu.value.(*mgl32.Mat4) + case glhf.Mat42: + return *gu.value.(*mgl32.Mat4x2) + case glhf.Mat43: + return *gu.value.(*mgl32.Mat4x3) + case glhf.Int: + return *gu.value.(*int32) + case glhf.Float: + return *gu.value.(*float32) + default: + panic("invalid attrtype") + } +} + +// Returns the type identifier for any (supported) attribute variable type +// and whether or not it is a pointer of that type. +func getAttrType(v interface{}) (glhf.AttrType, bool) { + switch v.(type) { + case int32: + return glhf.Int, false + case float32: + return glhf.Float, false + case mgl32.Vec2: + return glhf.Vec2, false + case mgl32.Vec3: + return glhf.Vec3, false + case mgl32.Vec4: + return glhf.Vec4, false + case mgl32.Mat2: + return glhf.Mat2, false + case mgl32.Mat2x3: + return glhf.Mat23, false + case mgl32.Mat2x4: + return glhf.Mat24, false + case mgl32.Mat3: + return glhf.Mat3, false + case mgl32.Mat3x2: + return glhf.Mat32, false + case mgl32.Mat3x4: + return glhf.Mat34, false + case mgl32.Mat4: + return glhf.Mat4, false + case mgl32.Mat4x2: + return glhf.Mat42, false + case mgl32.Mat4x3: + return glhf.Mat43, false + case *mgl32.Vec2: + return glhf.Vec2, true + case *mgl32.Vec3: + return glhf.Vec3, true + case *mgl32.Vec4: + return glhf.Vec4, true + case *mgl32.Mat2: + return glhf.Mat2, true + case *mgl32.Mat2x3: + return glhf.Mat23, true + case *mgl32.Mat2x4: + return glhf.Mat24, true + case *mgl32.Mat3: + return glhf.Mat3, true + case *mgl32.Mat3x2: + return glhf.Mat32, true + case *mgl32.Mat3x4: + return glhf.Mat34, true + case *mgl32.Mat4: + return glhf.Mat4, true + case *mgl32.Mat4x2: + return glhf.Mat42, true + case *mgl32.Mat4x3: + return glhf.Mat43, true + case *int32: + return glhf.Int, true + case *float32: + return glhf.Float, true + default: + panic("invalid AttrType") + } +} + var defaultCanvasVertexShader = ` #version 330 core diff --git a/pixelgl/window.go b/pixelgl/window.go index de7bb0d..2d646c5 100644 --- a/pixelgl/window.go +++ b/pixelgl/window.go @@ -425,7 +425,7 @@ func (w *Window) Color(at pixel.Vec) pixel.RGBA { return w.canvas.Color(at) } -// GetCanvas returns the window's underlying Canvas -func (w *Window) GetCanvas() *Canvas { +// Canvas returns the window's underlying Canvas +func (w *Window) Canvas() *Canvas { return w.canvas } From fa10844351cb8bddc575b17aa917605a5d94ba98 Mon Sep 17 00:00:00 2001 From: Brandon Date: Sat, 6 Oct 2018 10:01:05 -0600 Subject: [PATCH 4/5] pr 141 review #2 changes, see https://github.com/faiface/pixel/pull/141#pullrequestreview-162259357 --- pixelgl/canvas.go | 30 +++--------------------------- pixelgl/glshader.go | 24 ++++++++++++------------ 2 files changed, 15 insertions(+), 39 deletions(-) diff --git a/pixelgl/canvas.go b/pixelgl/canvas.go index 1e82fee..c66ab03 100644 --- a/pixelgl/canvas.go +++ b/pixelgl/canvas.go @@ -17,7 +17,7 @@ import ( // It supports TrianglesPosition, TrianglesColor, TrianglesPicture and PictureColor. type Canvas struct { gf *GLFrame - shader *GLShader + shader *glShader cmp pixel.ComposeMethod mat mgl32.Mat3 @@ -47,19 +47,14 @@ func NewCanvas(bounds pixel.Rect) *Canvas { // attribute variable. If the uniform already exists, including defaults, they will be reassigned // to the new value. The value can be a pointer. func (c *Canvas) SetUniform(Name string, Value interface{}) { - c.shader.AddUniform(Name, Value) -} - -// UpdateShader needs to be called after any changes to the underlying GLShader -// are made, such as, SetUniform, SetFragmentShader... -func (c *Canvas) UpdateShader() { - c.shader.update() + c.shader.SetUniform(Name, Value) } // SetFragmentShader allows you to set a new fragment shader on the underlying // framebuffer. Argument "fs" is the GLSL source, not a filename. func (c *Canvas) SetFragmentShader(fs string) { c.shader.fs = fs + c.shader.update() } // MakeTriangles creates a specialized copy of the supplied Triangles that draws onto this Canvas. @@ -189,25 +184,6 @@ func setBlendFunc(cmp pixel.ComposeMethod) { } } -// updates all uniform values for gl to consume -func (c *Canvas) setUniforms(texbounds pixel.Rect) { - mat := c.mat - col := c.col - c.shader.uniformDefaults.transform = mat - c.shader.uniformDefaults.colormask = col - dstBounds := c.Bounds() - c.shader.uniformDefaults.bounds = mgl32.Vec4{ - float32(dstBounds.Min.X), - float32(dstBounds.Min.Y), - float32(dstBounds.W()), - float32(dstBounds.H()), - } - - for loc, u := range c.shader.uniforms { - c.shader.s.SetUniformAttr(loc, u.Value()) - } -} - // Clear fills the whole Canvas with a single color. func (c *Canvas) Clear(color color.Color) { c.gf.Dirty() diff --git a/pixelgl/glshader.go b/pixelgl/glshader.go index 865c6fd..2f7544c 100644 --- a/pixelgl/glshader.go +++ b/pixelgl/glshader.go @@ -7,10 +7,10 @@ import ( "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 // a per canvas basis. -type GLShader struct { +type glShader struct { s *glhf.Shader vf, uf glhf.AttrFormat vs, fs string @@ -33,7 +33,7 @@ type gsUniformAttr struct { } // reinitialize GLShader data and recompile the underlying gl shader object -func (gs *GLShader) update() { +func (gs *glShader) update() { gs.uf = nil for _, u := range gs.uniforms { gs.uf = append(gs.uf, glhf.Attr{ @@ -59,7 +59,7 @@ func (gs *GLShader) update() { } // 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 { if u.Name == Name { return i @@ -68,14 +68,14 @@ func (gs *GLShader) getUniform(Name string) int { return -1 } -// AddUniform appends a custom uniform name and value to the shader. +// SetUniform appends a custom uniform name and value to the shader. // if the uniform already exists, it will simply be overwritten. // // example: // // utime := float32(time.Since(starttime)).Seconds()) // mycanvas.shader.AddUniform("u_time", &utime) -func (gs *GLShader) AddUniform(Name string, Value interface{}) { +func (gs *glShader) SetUniform(Name string, Value interface{}) { t, p := getAttrType(Value) if loc := gs.getUniform(Name); loc > -1 { gs.uniforms[loc].Name = Name @@ -94,18 +94,18 @@ func (gs *GLShader) AddUniform(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 AddUniform function. +// by simply using the SetUniform function. func baseShader(c *Canvas) { - gs := &GLShader{ + gs := &glShader{ vf: defaultCanvasVertexFormat, vs: defaultCanvasVertexShader, fs: baseCanvasFragmentShader, } - gs.AddUniform("u_transform", &gs.uniformDefaults.transform) - gs.AddUniform("u_colormask", &gs.uniformDefaults.colormask) - gs.AddUniform("u_bounds", &gs.uniformDefaults.bounds) - gs.AddUniform("u_texbounds", &gs.uniformDefaults.texbounds) + gs.SetUniform("u_transform", &gs.uniformDefaults.transform) + gs.SetUniform("u_colormask", &gs.uniformDefaults.colormask) + gs.SetUniform("u_bounds", &gs.uniformDefaults.bounds) + gs.SetUniform("u_texbounds", &gs.uniformDefaults.texbounds) c.shader = gs } From e9dfd22ffa4b6722d34870b6c2f1a51c9b052975 Mon Sep 17 00:00:00 2001 From: Brandon Date: Sat, 6 Oct 2018 10:27:47 -0600 Subject: [PATCH 5/5] pr 141 review #3 changes, see https://github.com/faiface/pixel/pull/141#pullrequestreview-162261776 --- pixelgl/canvas.go | 8 ++++---- pixelgl/glshader.go | 22 +++++++++++----------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/pixelgl/canvas.go b/pixelgl/canvas.go index c66ab03..8a5be0b 100644 --- a/pixelgl/canvas.go +++ b/pixelgl/canvas.go @@ -47,13 +47,13 @@ func NewCanvas(bounds pixel.Rect) *Canvas { // attribute variable. If the uniform already exists, including defaults, they will be reassigned // to the new value. The value can be a pointer. 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 -// framebuffer. Argument "fs" is the GLSL source, not a filename. -func (c *Canvas) SetFragmentShader(fs string) { - c.shader.fs = fs +// framebuffer. Argument "src" is the GLSL source, not a filename. +func (c *Canvas) SetFragmentShader(src string) { + c.shader.fs = src c.shader.update() } diff --git a/pixelgl/glshader.go b/pixelgl/glshader.go index 2f7544c..d1eb3a3 100644 --- a/pixelgl/glshader.go +++ b/pixelgl/glshader.go @@ -75,20 +75,20 @@ func (gs *glShader) getUniform(Name string) int { // // utime := float32(time.Since(starttime)).Seconds()) // mycanvas.shader.AddUniform("u_time", &utime) -func (gs *glShader) SetUniform(Name string, Value interface{}) { - t, p := getAttrType(Value) - if loc := gs.getUniform(Name); loc > -1 { - gs.uniforms[loc].Name = Name +func (gs *glShader) setUniform(name string, value interface{}) { + t, p := getAttrType(value) + if loc := gs.getUniform(name); loc > -1 { + gs.uniforms[loc].Name = name gs.uniforms[loc].Type = t gs.uniforms[loc].ispointer = p - gs.uniforms[loc].value = Value + gs.uniforms[loc].value = value return } gs.uniforms = append(gs.uniforms, gsUniformAttr{ - Name: Name, + Name: name, Type: t, ispointer: p, - value: Value, + value: value, }) } @@ -102,10 +102,10 @@ func baseShader(c *Canvas) { fs: baseCanvasFragmentShader, } - gs.SetUniform("u_transform", &gs.uniformDefaults.transform) - gs.SetUniform("u_colormask", &gs.uniformDefaults.colormask) - gs.SetUniform("u_bounds", &gs.uniformDefaults.bounds) - gs.SetUniform("u_texbounds", &gs.uniformDefaults.texbounds) + gs.setUniform("u_transform", &gs.uniformDefaults.transform) + gs.setUniform("u_colormask", &gs.uniformDefaults.colormask) + gs.setUniform("u_bounds", &gs.uniformDefaults.bounds) + gs.setUniform("u_texbounds", &gs.uniformDefaults.texbounds) c.shader = gs }