diff --git a/pixelgl/shader.go b/pixelgl/shader.go index 38ebc56..4ee4301 100644 --- a/pixelgl/shader.go +++ b/pixelgl/shader.go @@ -17,20 +17,22 @@ type UniformFormat map[string]Attr // Shader is an OpenGL shader program. type Shader struct { - parent Doer - format UniformFormat - program uint32 - uniforms map[Attr]int32 + parent Doer + vertexFormat VertexFormat + uniformFormat UniformFormat + program uint32 + uniforms map[Attr]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, format UniformFormat, vertexShader, fragmentShader string) (*Shader, error) { +func NewShader(parent Doer, vertexFormat VertexFormat, uniformFormat UniformFormat, vertexShader, fragmentShader string) (*Shader, error) { shader := &Shader{ - parent: parent, - format: format, - uniforms: make(map[Attr]int32), + parent: parent, + vertexFormat: vertexFormat, + uniformFormat: uniformFormat, + uniforms: make(map[Attr]int32), } var err, glerr error @@ -100,7 +102,7 @@ func NewShader(parent Doer, format UniformFormat, vertexShader, fragmentShader s gl.DeleteShader(fshader) // uniforms - for uname, utype := range format { + for uname, utype := range uniformFormat { ulocation := gl.GetUniformLocation(shader.program, gl.Str(uname+"\x00")) if ulocation == -1 { return fmt.Errorf("shader does not contain uniform '%s'", uname) @@ -133,6 +135,21 @@ func (s *Shader) Delete() { }) } +// ID returns an OpenGL identifier of a shader program. +func (s *Shader) ID() uint32 { + return s.program +} + +// VertexFormat returns the vertex attribute format of this shader. Do not change it. +func (s *Shader) VertexFormat() VertexFormat { + return s.vertexFormat +} + +// UniformFormat returns the uniform attribute format of this shader. Do not change it. +func (s *Shader) UniformFormat() UniformFormat { + return s.uniformFormat +} + // SetUniformInt sets the value of an uniform attribute Attr{Purpose: purpose, Type: Int}. // // Returns false if the attribute does not exist. diff --git a/pixelgl/texture.go b/pixelgl/texture.go index 3f9f8c9..ae6d8a7 100644 --- a/pixelgl/texture.go +++ b/pixelgl/texture.go @@ -55,6 +55,11 @@ func (t *Texture) Delete() { }) } +// ID returns an OpenGL identifier of a texture. +func (t *Texture) ID() uint32 { + return t.tex +} + // Do bind a texture, executes sub, and unbinds the texture. func (t *Texture) Do(sub func(Context)) { t.parent.Do(func(ctx Context) { diff --git a/pixelgl/vertex.go b/pixelgl/vertex.go index c302be6..0743f16 100644 --- a/pixelgl/vertex.go +++ b/pixelgl/vertex.go @@ -1,6 +1,7 @@ package pixelgl import ( + "fmt" "unsafe" "github.com/go-gl/gl/v3.3-core/gl" @@ -12,10 +13,10 @@ import ( // // Example: // -// VertexFormat{{Position, Vec2}, {Color, Vec4}, {TexCoord, Vec2}} +// VertexFormat{"position": {Position, Vec2}, "colr": {Color, Vec4}, "texCoord": {TexCoord, Vec2}} // // Note: vertex array currently doesn't support matrices in vertex format. -type VertexFormat []Attr +type VertexFormat map[string]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 { @@ -104,9 +105,9 @@ func NewVertexArray(parent Doer, format VertexFormat, mode VertexDrawMode, usage offset += attr.Type.Size() } - var err error + var err, glerr error parent.Do(func(ctx Context) { - err = DoGLErr(func() { + err, glerr = DoErrGLErr(func() error { gl.GenVertexArrays(1, &va.vao) gl.BindVertexArray(va.vao) @@ -117,8 +118,11 @@ func NewVertexArray(parent Doer, format VertexFormat, mode VertexDrawMode, usage gl.BufferData(gl.ARRAY_BUFFER, len(emptyData), gl.Ptr(emptyData), uint32(usage)) offset := 0 - for i, attr := range format { - //XXX: ugly but OpenGL is so inconsistent + for name, attr := range format { + location := gl.GetAttribLocation(ctx.Shader().ID(), gl.Str(name+"\x00")) + if location == -1 { + return fmt.Errorf("shader does not contain vertex attribute '%s'", name) + } var size int32 switch attr.Type { @@ -141,23 +145,31 @@ func NewVertexArray(parent Doer, format VertexFormat, mode VertexDrawMode, usage } gl.VertexAttribPointer( - uint32(i), + uint32(location), size, xtype, false, int32(va.stride), gl.PtrOffset(offset), ) - gl.EnableVertexAttribArray(uint32(i)) + gl.EnableVertexAttribArray(uint32(location)) offset += attr.Type.Size() } gl.BindBuffer(gl.ARRAY_BUFFER, 0) gl.BindVertexArray(0) + + return nil }) }) + if err != nil && glerr != nil { + return nil, errors.Wrap(errors.Wrap(glerr, err.Error()), "failed to create vertex array") + } if err != nil { - return nil, errors.Wrap(err, "failed to create a vertex array") + return nil, errors.Wrap(err, "failed to create vertex array") + } + if glerr != nil { + return nil, errors.Wrap(glerr, "failed to create vertex array") } return va, nil @@ -173,6 +185,11 @@ func (va *VertexArray) Delete() { }) } +// ID returns an OpenGL identifier of a vertex array. +func (va *VertexArray) ID() uint32 { + return va.vao +} + // Count returns the number of vertices in a vertex array. func (va *VertexArray) Count() int { return va.count