From 2aaab88e070855b7b82102af1a8b631da53e3d46 Mon Sep 17 00:00:00 2001 From: faiface <faiface@ksp.sk> Date: Fri, 16 Dec 2016 00:28:52 +0100 Subject: [PATCH] adoprt universal AttrFormat --- graphics.go | 8 ++--- pixelgl/attr.go | 52 ++++++++++++++++++------------ pixelgl/interface.go | 2 +- pixelgl/shader.go | 77 ++++++++++++++++++-------------------------- pixelgl/vertex.go | 62 ++++++++++++----------------------- window.go | 40 +++++++++++------------ 6 files changed, 109 insertions(+), 132 deletions(-) diff --git a/graphics.go b/graphics.go index b0485bb..1eaf02c 100644 --- a/graphics.go +++ b/graphics.go @@ -191,7 +191,7 @@ func NewSprite(parent pixelgl.Doer, picture Picture) *Sprite { parent.Do(func(ctx pixelgl.Context) { var err error va, err = pixelgl.NewVertexArray( - picture.Texture(), + pixelgl.ContextHolder{Context: ctx}, ctx.Shader().VertexFormat(), pixelgl.DynamicUsage, 4, @@ -232,7 +232,7 @@ func NewLineColor(parent pixelgl.Doer, c color.Color, a, b Vec, width float64) * parent.Do(func(ctx pixelgl.Context) { var err error va, err = pixelgl.NewVertexArray( - parent, + pixelgl.ContextHolder{Context: ctx}, ctx.Shader().VertexFormat(), pixelgl.DynamicUsage, 4, @@ -313,7 +313,7 @@ func NewPolygonColor(parent pixelgl.Doer, c color.Color, points ...Vec) *Polygon parent.Do(func(ctx pixelgl.Context) { var err error va, err = pixelgl.NewVertexArray( - parent, + pixelgl.ContextHolder{Context: ctx}, ctx.Shader().VertexFormat(), pixelgl.DynamicUsage, len(points), @@ -377,7 +377,7 @@ func NewEllipseColor(parent pixelgl.Doer, c color.Color, radius Vec, fill float6 parent.Do(func(ctx pixelgl.Context) { var err error va, err = pixelgl.NewVertexArray( - parent, + pixelgl.ContextHolder{Context: ctx}, ctx.Shader().VertexFormat(), pixelgl.DynamicUsage, (n+1)*2, diff --git a/pixelgl/attr.go b/pixelgl/attr.go index b7f6b8c..7da5e4a 100644 --- a/pixelgl/attr.go +++ b/pixelgl/attr.go @@ -1,28 +1,40 @@ package pixelgl -// Attr represents an arbitrary OpenGL attribute, such as a vertex attribute or a shader uniform attribute. -type Attr struct { - Purpose AttrPurpose - Type AttrType +// AttrFormat defines names and types of OpenGL attributes (vertex format, uniform format, etc.). +// +// Example: +// AttrFormat{"position": Vec2, "color": Vec4, "texCoord": Vec2} +type AttrFormat map[string]AttrType + +// Contains checks whether a format contains a specific attribute. +// +// It does a little more than a hard check: e.g. if you query a Vec2 attribute, but the format contains Vec3, +// Contains returns true, because Vec2 is assignable to Vec3. Specifically, Float -> Vec2 -> Vec3 -> Vec4 (transitively). +// This however does not work for matrices or ints. +func (af AttrFormat) Contains(attr Attr) bool { + if typ, ok := af[attr.Name]; ok { + if (Float <= typ && typ <= Vec4) && (Float <= attr.Type && attr.Type <= typ) { + return true + } + return attr.Type == typ + } + return false } -// AttrPurpose specified a purpose of an attribute. Feel free to create your own purposes for your own needs. -type AttrPurpose int +// Size returns the total size of all attributes of an attribute format. +func (af AttrFormat) Size() int { + total := 0 + for _, typ := range af { + total += typ.Size() + } + return total +} -const ( - // Position of a vertex - Position AttrPurpose = iota - // Color of a vertex - Color - // TexCoord are texture coordinates - TexCoord - // Transform is an object transformation matrix - Transform - // MaskColor is a masking color. When drawing, each color gets multiplied by this color. - MaskColor - // NumStandardAttrPurposes is the number of standard attribute purposes - NumStandardAttrPurposes -) +// Attr represents an arbitrary OpenGL attribute, such as a vertex attribute or a shader uniform attribute. +type Attr struct { + Name string + Type AttrType +} // AttrType represents the type of an OpenGL attribute. type AttrType int diff --git a/pixelgl/interface.go b/pixelgl/interface.go index 7041322..874d070 100644 --- a/pixelgl/interface.go +++ b/pixelgl/interface.go @@ -59,7 +59,7 @@ type ContextHolder struct { } // Do calls sub and passes it the held context. -func (ch *ContextHolder) Do(sub func(ctx Context)) { +func (ch ContextHolder) Do(sub func(ctx Context)) { sub(ch.Context) } diff --git a/pixelgl/shader.go b/pixelgl/shader.go index ce638a3..666eed6 100644 --- a/pixelgl/shader.go +++ b/pixelgl/shader.go @@ -7,26 +7,19 @@ import ( "github.com/go-gl/mathgl/mgl32" ) -// UniformFormat defines names, purposes and types of uniform variables inside a shader. -// -// Example: -// -// UniformFormat{"transform": {Transform, Mat3}, "camera": {Camera, Mat3}} -type UniformFormat map[string]Attr - // Shader is an OpenGL shader program. type Shader struct { - parent Doer - program binder - vertexFormat VertexFormat - uniformFormat UniformFormat - uniforms map[Attr]int32 + parent Doer + program binder + vertexFmt AttrFormat + uniformFmt AttrFormat + uniforms map[string]int32 } // NewShader creates a new shader program from the specified vertex shader and fragment shader sources. // // Note that vertexShader and fragmentShader parameters must contain the source code, they're not filenames. -func NewShader(parent Doer, vertexFormat VertexFormat, uniformFormat UniformFormat, vertexShader, fragmentShader string) (*Shader, error) { +func NewShader(parent Doer, vertexFmt, uniformFmt AttrFormat, vertexShader, fragmentShader string) (*Shader, error) { shader := &Shader{ parent: parent, program: binder{ @@ -35,9 +28,9 @@ func NewShader(parent Doer, vertexFormat VertexFormat, uniformFormat UniformForm gl.UseProgram(obj) }, }, - vertexFormat: vertexFormat, - uniformFormat: uniformFormat, - uniforms: make(map[Attr]int32), + vertexFmt: vertexFmt, + uniformFmt: uniformFmt, + uniforms: make(map[string]int32), } var err error @@ -108,17 +101,9 @@ func NewShader(parent Doer, vertexFormat VertexFormat, uniformFormat UniformForm } // uniforms - for uname, utype := range uniformFormat { - ulocation := gl.GetUniformLocation(shader.program.obj, gl.Str(uname+"\x00")) - if ulocation == -1 { - gl.DeleteProgram(shader.program.obj) - return fmt.Errorf("shader does not contain uniform '%s'", uname) - } - if _, ok := shader.uniforms[utype]; ok { - gl.DeleteProgram(shader.program.obj) - return fmt.Errorf("failed to create shader: invalid uniform format: duplicate uniform attribute") - } - shader.uniforms[utype] = ulocation + for name := range uniformFmt { + loc := gl.GetUniformLocation(shader.program.obj, gl.Str(name+"\x00")) + shader.uniforms[name] = loc } return nil @@ -146,13 +131,13 @@ func (s *Shader) ID() uint32 { } // VertexFormat returns the vertex attribute format of this shader. Do not change it. -func (s *Shader) VertexFormat() VertexFormat { - return s.vertexFormat +func (s *Shader) VertexFormat() AttrFormat { + return s.vertexFmt } // UniformFormat returns the uniform attribute format of this shader. Do not change it. -func (s *Shader) UniformFormat() UniformFormat { - return s.uniformFormat +func (s *Shader) UniformFormat() AttrFormat { + return s.uniformFmt } // SetUniformAttr sets the value of a uniform attribute of a shader. @@ -176,7 +161,7 @@ func (s *Shader) UniformFormat() UniformFormat { // Attr{Type: Mat43}: mgl32.Mat4x3 // No other types are supported. func (s *Shader) SetUniformAttr(attr Attr, value interface{}) (ok bool) { - if _, ok := s.uniforms[attr]; !ok { + if !s.uniformFmt.Contains(attr) { return false } @@ -186,46 +171,46 @@ func (s *Shader) SetUniformAttr(attr Attr, value interface{}) (ok bool) { switch attr.Type { case Int: value := value.(int32) - gl.Uniform1iv(s.uniforms[attr], 1, &value) + gl.Uniform1iv(s.uniforms[attr.Name], 1, &value) case Float: value := value.(float32) - gl.Uniform1fv(s.uniforms[attr], 1, &value) + gl.Uniform1fv(s.uniforms[attr.Name], 1, &value) case Vec2: value := value.(mgl32.Vec2) - gl.Uniform2fv(s.uniforms[attr], 1, &value[0]) + gl.Uniform2fv(s.uniforms[attr.Name], 1, &value[0]) case Vec3: value := value.(mgl32.Vec3) - gl.Uniform3fv(s.uniforms[attr], 1, &value[0]) + gl.Uniform3fv(s.uniforms[attr.Name], 1, &value[0]) case Vec4: value := value.(mgl32.Vec4) - gl.Uniform4fv(s.uniforms[attr], 1, &value[0]) + gl.Uniform4fv(s.uniforms[attr.Name], 1, &value[0]) case Mat2: value := value.(mgl32.Mat2) - gl.UniformMatrix2fv(s.uniforms[attr], 1, false, &value[0]) + gl.UniformMatrix2fv(s.uniforms[attr.Name], 1, false, &value[0]) case Mat23: value := value.(mgl32.Mat2x3) - gl.UniformMatrix2x3fv(s.uniforms[attr], 1, false, &value[0]) + gl.UniformMatrix2x3fv(s.uniforms[attr.Name], 1, false, &value[0]) case Mat24: value := value.(mgl32.Mat2x4) - gl.UniformMatrix2x4fv(s.uniforms[attr], 1, false, &value[0]) + gl.UniformMatrix2x4fv(s.uniforms[attr.Name], 1, false, &value[0]) case Mat3: value := value.(mgl32.Mat3) - gl.UniformMatrix3fv(s.uniforms[attr], 1, false, &value[0]) + gl.UniformMatrix3fv(s.uniforms[attr.Name], 1, false, &value[0]) case Mat32: value := value.(mgl32.Mat3x2) - gl.UniformMatrix3x2fv(s.uniforms[attr], 1, false, &value[0]) + gl.UniformMatrix3x2fv(s.uniforms[attr.Name], 1, false, &value[0]) case Mat34: value := value.(mgl32.Mat3x4) - gl.UniformMatrix3x4fv(s.uniforms[attr], 1, false, &value[0]) + gl.UniformMatrix3x4fv(s.uniforms[attr.Name], 1, false, &value[0]) case Mat4: value := value.(mgl32.Mat4) - gl.UniformMatrix4fv(s.uniforms[attr], 1, false, &value[0]) + gl.UniformMatrix4fv(s.uniforms[attr.Name], 1, false, &value[0]) case Mat42: value := value.(mgl32.Mat4x2) - gl.UniformMatrix4x2fv(s.uniforms[attr], 1, false, &value[0]) + gl.UniformMatrix4x2fv(s.uniforms[attr.Name], 1, false, &value[0]) case Mat43: value := value.(mgl32.Mat4x3) - gl.UniformMatrix4x3fv(s.uniforms[attr], 1, false, &value[0]) + gl.UniformMatrix4x3fv(s.uniforms[attr.Name], 1, false, &value[0]) default: panic("set uniform attr: invalid attribute type") } diff --git a/pixelgl/vertex.go b/pixelgl/vertex.go index da0843d..7ff2ebf 100644 --- a/pixelgl/vertex.go +++ b/pixelgl/vertex.go @@ -8,24 +8,6 @@ import ( "github.com/pkg/errors" ) -// VertexFormat defines a data format in a vertex buffer. -// -// Example: -// -// VertexFormat{"position": {Position, Vec2}, "colr": {Color, Vec4}, "texCoord": {TexCoord, Vec2}} -// -// Note: vertex array currently doesn't support matrices in vertex format. -type VertexFormat []Attr - -// Size calculates the total size of a single vertex in this vertex format (sum of the sizes of all vertex attributes). -func (vf VertexFormat) Size() int { - total := 0 - for _, attr := range vf { - total += attr.Type.Size() - } - return total -} - // VertexUsage specifies how often the vertex array data will be updated. type VertexUsage int @@ -46,17 +28,17 @@ type VertexArray struct { parent Doer vao, vbo, ebo binder vertexNum, indexNum int - format VertexFormat + format AttrFormat usage VertexUsage stride int - attrs map[Attr]int + offset map[string]int } // NewVertexArray creates a new empty vertex array and wraps another Doer around it. // // You cannot specify vertex attributes in this constructor, only their count. Use SetVertexAttribute* methods to // set the vertex attributes. Use indices to specify how you want to combine vertices into triangles. -func NewVertexArray(parent Doer, format VertexFormat, usage VertexUsage, vertexNum int, indices []int) (*VertexArray, error) { +func NewVertexArray(parent Doer, format AttrFormat, usage VertexUsage, vertexNum int, indices []int) (*VertexArray, error) { va := &VertexArray{ parent: parent, vao: binder{ @@ -81,21 +63,18 @@ func NewVertexArray(parent Doer, format VertexFormat, usage VertexUsage, vertexN format: format, usage: usage, stride: format.Size(), - attrs: make(map[Attr]int), + offset: make(map[string]int), } offset := 0 - for _, attr := range format { - switch attr.Type { + for name, typ := range format { + switch typ { case Float, Vec2, Vec3, Vec4: default: return nil, errors.New("failed to create vertex array: invalid vertex format: invalid attribute type") } - if _, ok := va.attrs[attr]; ok { - return nil, errors.New("failed to create vertex array: invalid vertex format: duplicate vertex attribute") - } - va.attrs[attr] = offset - offset += attr.Type.Size() + va.offset[name] = offset + offset += typ.Size() } parent.Do(func(ctx Context) { @@ -112,10 +91,11 @@ func NewVertexArray(parent Doer, format VertexFormat, usage VertexUsage, vertexN gl.GenBuffers(1, &va.ebo.obj) defer va.ebo.bind().restore() - offset := 0 - for i, attr := range format { + for name, typ := range format { + loc := gl.GetAttribLocation(ctx.Shader().ID(), gl.Str(name+"\x00")) + var size int32 - switch attr.Type { + switch typ { case Float: size = 1 case Vec2: @@ -127,15 +107,14 @@ func NewVertexArray(parent Doer, format VertexFormat, usage VertexUsage, vertexN } gl.VertexAttribPointer( - uint32(i), + uint32(loc), size, gl.FLOAT, false, int32(va.stride), - gl.PtrOffset(offset), + gl.PtrOffset(va.offset[name]), ) - gl.EnableVertexAttribArray(uint32(i)) - offset += attr.Type.Size() + gl.EnableVertexAttribArray(uint32(loc)) } va.vao.restore() @@ -153,6 +132,7 @@ func (va *VertexArray) Delete() { DoNoBlock(func() { gl.DeleteVertexArrays(1, &va.vao.obj) gl.DeleteBuffers(1, &va.vbo.obj) + gl.DeleteBuffers(1, &va.ebo.obj) }) }) } @@ -170,7 +150,7 @@ func (va *VertexArray) VertexNum() int { // VertexFormat returns the format of the vertices inside a vertex array. // // Do not change this format! -func (va *VertexArray) VertexFormat() VertexFormat { +func (va *VertexArray) VertexFormat() AttrFormat { return va.format } @@ -219,14 +199,14 @@ func (va *VertexArray) SetVertexAttr(vertex int, attr Attr, value interface{}) ( panic("set vertex attr: invalid vertex index") } - if _, ok := va.attrs[attr]; !ok { + if !va.format.Contains(attr) { return false } DoNoBlock(func() { va.vbo.bind() - offset := va.stride*vertex + va.attrs[attr] + offset := va.stride*vertex + va.offset[attr.Name] switch attr.Type { case Float: @@ -262,14 +242,14 @@ func (va *VertexArray) VertexAttr(vertex int, attr Attr) (value interface{}, ok panic("vertex attr: invalid vertex index") } - if _, ok := va.attrs[attr]; !ok { + if !va.format.Contains(attr) { return nil, false } Do(func() { va.vbo.bind() - offset := va.stride*vertex + va.attrs[attr] + offset := va.stride*vertex + va.offset[attr.Name] switch attr.Type { case Float: diff --git a/window.go b/window.go index 35a556b..a6dd197 100644 --- a/window.go +++ b/window.go @@ -337,23 +337,23 @@ func (w *Window) Do(sub func(pixelgl.Context)) { w.enabled = false } -var defaultVertexFormat = pixelgl.VertexFormat{ - {Purpose: pixelgl.Position, Type: pixelgl.Vec2}, - {Purpose: pixelgl.Color, Type: pixelgl.Vec4}, - {Purpose: pixelgl.TexCoord, Type: pixelgl.Vec2}, +var defaultVertexFormat = pixelgl.AttrFormat{ + "position": pixelgl.Vec2, + "color": pixelgl.Vec4, + "texCoord": pixelgl.Vec2, } -var defaultUniformFormat = pixelgl.UniformFormat{ - "maskColor": {Purpose: pixelgl.MaskColor, Type: pixelgl.Vec4}, - "transform": {Purpose: pixelgl.Transform, Type: pixelgl.Mat3}, +var defaultUniformFormat = pixelgl.AttrFormat{ + "maskColor": pixelgl.Vec4, + "transform": pixelgl.Mat3, } var defaultVertexShader = ` #version 330 core -layout (location = 0) in vec2 position; -layout (location = 1) in vec4 color; -layout (location = 2) in vec2 texCoord; +in vec2 position; +in vec4 color; +in vec2 texCoord; out vec4 Color; out vec2 TexCoord; @@ -389,23 +389,23 @@ void main() { var ( positionVec2 = pixelgl.Attr{ - Purpose: pixelgl.Position, - Type: pixelgl.Vec2, + Name: "position", + Type: pixelgl.Vec2, } colorVec4 = pixelgl.Attr{ - Purpose: pixelgl.Color, - Type: pixelgl.Vec4, + Name: "color", + Type: pixelgl.Vec4, } texCoordVec2 = pixelgl.Attr{ - Purpose: pixelgl.TexCoord, - Type: pixelgl.Vec2, + Name: "texCoord", + Type: pixelgl.Vec2, } maskColorVec4 = pixelgl.Attr{ - Purpose: pixelgl.MaskColor, - Type: pixelgl.Vec4, + Name: "maskColor", + Type: pixelgl.Vec4, } transformMat3 = pixelgl.Attr{ - Purpose: pixelgl.Transform, - Type: pixelgl.Mat3, + Name: "transform", + Type: pixelgl.Mat3, } ) -- GitLab