gl: support (Create|Bind|Delete)VertexArray for GL ES 3

Change-Id: Ief6b7f4ab2450d7f1c3b961b19304b10b3680abd
Reviewed-on: https://go-review.googlesource.com/61370
Reviewed-by: Elias Naur <elias.naur@gmail.com>
Reviewed-by: David Crawshaw <crawshaw@golang.org>
diff --git a/gl/fn.go b/gl/fn.go
index 35c52c8..3f2f3ad 100644
--- a/gl/fn.go
+++ b/gl/fn.go
@@ -38,6 +38,7 @@
 	glfnBindFramebuffer
 	glfnBindRenderbuffer
 	glfnBindTexture
+	glfnBindVertexArray
 	glfnBlendColor
 	glfnBlendEquation
 	glfnBlendEquationSeparate
@@ -65,6 +66,7 @@
 	glfnDeleteRenderbuffer
 	glfnDeleteShader
 	glfnDeleteTexture
+	glfnDeleteVertexArray
 	glfnDepthFunc
 	glfnDepthRangef
 	glfnDepthMask
@@ -84,6 +86,7 @@
 	glfnGenFramebuffer
 	glfnGenRenderbuffer
 	glfnGenTexture
+	glfnGenVertexArray
 	glfnGenerateMipmap
 	glfnGetActiveAttrib
 	glfnGetActiveUniform
diff --git a/gl/gl.go b/gl/gl.go
index b4215de..9d249cc 100644
--- a/gl/gl.go
+++ b/gl/gl.go
@@ -90,6 +90,15 @@
 	})
 }
 
+func (ctx *context) BindVertexArray(va VertexArray) {
+	ctx.enqueue(call{
+		args: fnargs{
+			fn: glfnBindVertexArray,
+			a0: va.c(),
+		},
+	})
+}
+
 func (ctx *context) BlendColor(red, green, blue, alpha float32) {
 	ctx.enqueue(call{
 		args: fnargs{
@@ -380,6 +389,15 @@
 	}))}
 }
 
+func (ctx *context) CreateVertexArray() VertexArray {
+	return VertexArray{Value: uint32(ctx.enqueue(call{
+		args: fnargs{
+			fn: glfnGenVertexArray,
+		},
+		blocking: true,
+	}))}
+}
+
 func (ctx *context) CullFace(mode Enum) {
 	ctx.enqueue(call{
 		args: fnargs{
@@ -443,6 +461,15 @@
 	})
 }
 
+func (ctx *context) DeleteVertexArray(v VertexArray) {
+	ctx.enqueue(call{
+		args: fnargs{
+			fn: glfnDeleteVertexArray,
+			a0: uintptr(v.Value),
+		},
+	})
+}
+
 func (ctx *context) DepthFunc(fn Enum) {
 	ctx.enqueue(call{
 		args: fnargs{
diff --git a/gl/gldebug.go b/gl/gldebug.go
index a8d5798..48c69d3 100644
--- a/gl/gldebug.go
+++ b/gl/gldebug.go
@@ -1337,6 +1337,19 @@
 		blocking: true})
 }
 
+func (ctx *context) BindVertexArray(t VertexArray) {
+	defer func() {
+		errstr := ctx.errDrain()
+		log.Printf("gl.BindVertexArray(%v) %v", t, errstr)
+	}()
+	ctx.enqueueDebug(call{
+		args: fnargs{
+			fn: glfnBindVertexArray,
+			a0: t.c(),
+		},
+		blocking: true})
+}
+
 func (ctx *context) BlendColor(red, green, blue, alpha float32) {
 	defer func() {
 		errstr := ctx.errDrain()
@@ -1727,6 +1740,19 @@
 	}))}
 }
 
+func (ctx *context) CreateVertexArray() (r0 VertexArray) {
+	defer func() {
+		errstr := ctx.errDrain()
+		log.Printf("gl.CreateVertexArray() %v%v", r0, errstr)
+	}()
+	return VertexArray{Value: uint32(ctx.enqueue(call{
+		args: fnargs{
+			fn: glfnGenVertexArray,
+		},
+		blocking: true,
+	}))}
+}
+
 func (ctx *context) CullFace(mode Enum) {
 	defer func() {
 		errstr := ctx.errDrain()
@@ -1818,6 +1844,19 @@
 		blocking: true})
 }
 
+func (ctx *context) DeleteVertexArray(v VertexArray) {
+	defer func() {
+		errstr := ctx.errDrain()
+		log.Printf("gl.DeleteVertexArray(%v) %v", v, errstr)
+	}()
+	ctx.enqueueDebug(call{
+		args: fnargs{
+			fn: glfnDeleteVertexArray,
+			a0: v.c(),
+		},
+		blocking: true})
+}
+
 func (ctx *context) DepthFunc(fn Enum) {
 	defer func() {
 		errstr := ctx.errDrain()
diff --git a/gl/interface.go b/gl/interface.go
index 8c93954..2083327 100644
--- a/gl/interface.go
+++ b/gl/interface.go
@@ -56,6 +56,11 @@
 	// http://www.khronos.org/opengles/sdk/docs/man3/html/glBindTexture.xhtml
 	BindTexture(target Enum, t Texture)
 
+	// BindVertexArray binds a vertex array.
+	//
+	// http://www.khronos.org/opengles/sdk/docs/man3/html/glBindVertexArray.xhtml
+	BindVertexArray(rb VertexArray)
+
 	// BlendColor sets the blend color.
 	//
 	// http://www.khronos.org/opengles/sdk/docs/man3/html/glBlendColor.xhtml
@@ -187,6 +192,11 @@
 	// http://www.khronos.org/opengles/sdk/docs/man3/html/glGenTextures.xhtml
 	CreateTexture() Texture
 
+	// CreateTVertexArray creates a vertex array.
+	//
+	// http://www.khronos.org/opengles/sdk/docs/man3/html/glGenVertexArrays.xhtml
+	CreateVertexArray() VertexArray
+
 	// CullFace specifies which polygons are candidates for culling.
 	//
 	// Valid modes: FRONT, BACK, FRONT_AND_BACK.
@@ -224,6 +234,11 @@
 	// http://www.khronos.org/opengles/sdk/docs/man3/html/glDeleteTextures.xhtml
 	DeleteTexture(v Texture)
 
+	// DeleteVertexArray deletes the given render buffer object.
+	//
+	// http://www.khronos.org/opengles/sdk/docs/man3/html/glDeleteVertexArrays.xhtml
+	DeleteVertexArray(v VertexArray)
+
 	// DepthFunc sets the function used for depth buffer comparisons.
 	//
 	// Valid fn values:
diff --git a/gl/types_debug.go b/gl/types_debug.go
index dc251a0..35dea87 100644
--- a/gl/types_debug.go
+++ b/gl/types_debug.go
@@ -49,6 +49,10 @@
 	name  string
 }
 
+type VextexArray struct {
+	Value uint32
+}
+
 func (v Attrib) c() uintptr { return uintptr(v.Value) }
 func (v Enum) c() uintptr   { return uintptr(v) }
 func (v Program) c() uintptr {
@@ -65,6 +69,7 @@
 func (v Renderbuffer) c() uintptr { return uintptr(v.Value) }
 func (v Texture) c() uintptr      { return uintptr(v.Value) }
 func (v Uniform) c() uintptr      { return uintptr(v.Value) }
+func (v VextexArray) c() uintptr  { return uintptr(v.Value) }
 
 func (v Attrib) String() string       { return fmt.Sprintf("Attrib(%d:%s)", v.Value, v.name) }
 func (v Program) String() string      { return fmt.Sprintf("Program(%d)", v.Value) }
@@ -74,3 +79,4 @@
 func (v Renderbuffer) String() string { return fmt.Sprintf("Renderbuffer(%d)", v.Value) }
 func (v Texture) String() string      { return fmt.Sprintf("Texture(%d)", v.Value) }
 func (v Uniform) String() string      { return fmt.Sprintf("Uniform(%d:%s)", v.Value, v.name) }
+func (v VextexArray) String() string  { return fmt.Sprintf("VextexArray(%d)", v.Value) }
diff --git a/gl/types_prod.go b/gl/types_prod.go
index 35dc4c6..7fff27f 100644
--- a/gl/types_prod.go
+++ b/gl/types_prod.go
@@ -59,6 +59,11 @@
 	Value int32
 }
 
+// A VertexArray is a GL object that holds vertices in an internal format.
+type VertexArray struct {
+	Value uint32
+}
+
 func (v Attrib) c() uintptr { return uintptr(v.Value) }
 func (v Enum) c() uintptr   { return uintptr(v) }
 func (v Program) c() uintptr {
@@ -75,6 +80,7 @@
 func (v Renderbuffer) c() uintptr { return uintptr(v.Value) }
 func (v Texture) c() uintptr      { return uintptr(v.Value) }
 func (v Uniform) c() uintptr      { return uintptr(v.Value) }
+func (v VertexArray) c() uintptr  { return uintptr(v.Value) }
 
 func (v Attrib) String() string       { return fmt.Sprintf("Attrib(%d)", v.Value) }
 func (v Program) String() string      { return fmt.Sprintf("Program(%d)", v.Value) }
@@ -84,3 +90,4 @@
 func (v Renderbuffer) String() string { return fmt.Sprintf("Renderbuffer(%d)", v.Value) }
 func (v Texture) String() string      { return fmt.Sprintf("Texture(%d)", v.Value) }
 func (v Uniform) String() string      { return fmt.Sprintf("Uniform(%d)", v.Value) }
+func (v VertexArray) String() string  { return fmt.Sprintf("VertexArray(%d)", v.Value) }
diff --git a/gl/work.c b/gl/work.c
index 75380d0..235647f 100644
--- a/gl/work.c
+++ b/gl/work.c
@@ -30,6 +30,9 @@
 static void glUniform2uiv(GLint location, GLsizei count, const GLuint *value) { gles3missing(); }
 static void glUniform3uiv(GLint location, GLsizei count, const GLuint *value) { gles3missing(); }
 static void glUniform4uiv(GLint location, GLsizei count, const GLuint *value) { gles3missing(); }
+static void glBindVertexArray(GLuint array) { gles3missing(); }
+static void glGenVertexArrays(GLsizei n, GLuint *arrays) { gles3missing(); }
+static void glDeleteVertexArrays(GLsizei n, const GLuint *arrays) { gles3missing(); }
 #endif
 
 uintptr_t processFn(struct fnargs* args, char* parg) {
@@ -59,6 +62,9 @@
 	case glfnBindTexture:
 		glBindTexture((GLenum)args->a0, (GLint)args->a1);
 		break;
+	case glfnBindVertexArray:
+		glBindVertexArray((GLenum)args->a0);
+		break;
 	case glfnBlendColor:
 		glBlendColor(*(GLfloat*)&args->a0, *(GLfloat*)&args->a1, *(GLfloat*)&args->a2, *(GLfloat*)&args->a3);
 		break;
@@ -143,6 +149,9 @@
 	case glfnDeleteTexture:
 		glDeleteTextures(1, (const GLuint*)(&args->a0));
 		break;
+	case glfnDeleteVertexArray:
+		glDeleteVertexArrays(1, (const GLuint*)(&args->a0));
+		break;
 	case glfnDepthFunc:
 		glDepthFunc((GLenum)args->a0);
 		break;
@@ -200,6 +209,9 @@
 	case glfnGenTexture:
 		glGenTextures(1, (GLuint*)&ret);
 		break;
+	case glfnGenVertexArray:
+		glGenVertexArrays(1, (GLuint*)&ret);
+		break;
 	case glfnGenerateMipmap:
 		glGenerateMipmap((GLenum)args->a0);
 		break;
diff --git a/gl/work.h b/gl/work.h
index 9ba29ca..6403574 100644
--- a/gl/work.h
+++ b/gl/work.h
@@ -41,6 +41,7 @@
 	glfnBindFramebuffer,
 	glfnBindRenderbuffer,
 	glfnBindTexture,
+	glfnBindVertexArray,
 	glfnBlendColor,
 	glfnBlendEquation,
 	glfnBlendEquationSeparate,
@@ -68,6 +69,7 @@
 	glfnDeleteRenderbuffer,
 	glfnDeleteShader,
 	glfnDeleteTexture,
+	glfnDeleteVertexArray,
 	glfnDepthFunc,
 	glfnDepthRangef,
 	glfnDepthMask,
@@ -87,6 +89,7 @@
 	glfnGenFramebuffer,
 	glfnGenRenderbuffer,
 	glfnGenTexture,
+	glfnGenVertexArray,
 	glfnGenerateMipmap,
 	glfnGetActiveAttrib,
 	glfnGetActiveUniform,
diff --git a/gl/work_windows.go b/gl/work_windows.go
index 9c97213..5c30735 100644
--- a/gl/work_windows.go
+++ b/gl/work_windows.go
@@ -128,6 +128,8 @@
 		syscall.Syscall(glBindRenderbuffer.Addr(), 2, c.args.a0, c.args.a1, 0)
 	case glfnBindTexture:
 		syscall.Syscall(glBindTexture.Addr(), 2, c.args.a0, c.args.a1, 0)
+	case glfnBindVertexArray:
+		syscall.Syscall(glBindVertexArray.Addr(), 1, c.args.a0, 0)
 	case glfnBlendColor:
 		syscall.Syscall6(glBlendColor.Addr(), 4, c.args.a0, c.args.a1, c.args.a2, c.args.a3, 0, 0)
 	case glfnBlendEquation:
@@ -180,6 +182,8 @@
 		syscall.Syscall(glDeleteRenderbuffers.Addr(), 2, 1, uintptr(unsafe.Pointer(&c.args.a0)), 0)
 	case glfnDeleteShader:
 		syscall.Syscall(glDeleteShader.Addr(), 1, c.args.a0, 0, 0)
+	case glfnDeleteVertexArray:
+		syscall.Syscall(glDeleteVertexArrays.Addr(), 2, 1, uintptr(unsafe.Pointer(&c.args.a0)), 0)
 	case glfnDeleteTexture:
 		syscall.Syscall(glDeleteTextures.Addr(), 2, 1, uintptr(unsafe.Pointer(&c.args.a0)), 0)
 	case glfnDepthFunc:
@@ -218,6 +222,8 @@
 		syscall.Syscall(glGenFramebuffers.Addr(), 2, 1, uintptr(unsafe.Pointer(&ret)), 0)
 	case glfnGenRenderbuffer:
 		syscall.Syscall(glGenRenderbuffers.Addr(), 2, 1, uintptr(unsafe.Pointer(&ret)), 0)
+	case glfnGenVertexArray:
+		syscall.Syscall(glVertexArrays.Addr(), 2, 1, uintptr(unsafe.Pointer(&ret)), 0)
 	case glfnGenTexture:
 		syscall.Syscall(glGenTextures.Addr(), 2, 1, uintptr(unsafe.Pointer(&ret)), 0)
 	case glfnGenerateMipmap:
@@ -424,6 +430,7 @@
 	glBindFramebuffer                     = libGLESv2.NewProc("glBindFramebuffer")
 	glBindRenderbuffer                    = libGLESv2.NewProc("glBindRenderbuffer")
 	glBindTexture                         = libGLESv2.NewProc("glBindTexture")
+	glBindVertexArray                     = libGLESv2.NewProc("glBindVertexArray")
 	glBlendColor                          = libGLESv2.NewProc("glBlendColor")
 	glBlendEquation                       = libGLESv2.NewProc("glBlendEquation")
 	glBlendEquationSeparate               = libGLESv2.NewProc("glBlendEquationSeparate")
@@ -451,6 +458,7 @@
 	glDeleteRenderbuffers                 = libGLESv2.NewProc("glDeleteRenderbuffers")
 	glDeleteShader                        = libGLESv2.NewProc("glDeleteShader")
 	glDeleteTextures                      = libGLESv2.NewProc("glDeleteTextures")
+	glVertexArrays                        = libGLESv2.NewProc("glVertexArrays")
 	glDepthFunc                           = libGLESv2.NewProc("glDepthFunc")
 	glDepthRangef                         = libGLESv2.NewProc("glDepthRangef")
 	glDepthMask                           = libGLESv2.NewProc("glDepthMask")
@@ -470,6 +478,7 @@
 	glGenFramebuffers                     = libGLESv2.NewProc("glGenFramebuffers")
 	glGenRenderbuffers                    = libGLESv2.NewProc("glGenRenderbuffers")
 	glGenTextures                         = libGLESv2.NewProc("glGenTextures")
+	glGenVertexArrays                     = libGLESv2.NewProc("glGenVertexArrays")
 	glGenerateMipmap                      = libGLESv2.NewProc("glGenerateMipmap")
 	glGetActiveAttrib                     = libGLESv2.NewProc("glGetActiveAttrib")
 	glGetActiveUniform                    = libGLESv2.NewProc("glGetActiveUniform")