From e009011c370eaefcacc71b48f83125729b984bc0 Mon Sep 17 00:00:00 2001
From: faiface <faiface@ksp.sk>
Date: Fri, 2 Dec 2016 18:03:51 +0100
Subject: [PATCH] change vertex format to include names + add vertex format to
 shader + ID methods

---
 pixelgl/shader.go  | 35 ++++++++++++++++++++++++++---------
 pixelgl/texture.go |  5 +++++
 pixelgl/vertex.go  | 35 ++++++++++++++++++++++++++---------
 3 files changed, 57 insertions(+), 18 deletions(-)

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
-- 
GitLab