From 91763a9e1a4a3d5f67696c5d4babcafe09851aa5 Mon Sep 17 00:00:00 2001
From: faiface <faiface@ksp.sk>
Date: Wed, 23 Nov 2016 15:59:21 +0100
Subject: [PATCH] implement vertex array (vao+vbo)

---
 pixelgl/vertex.go | 152 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 152 insertions(+)

diff --git a/pixelgl/vertex.go b/pixelgl/vertex.go
index d0af0ed..edde8cb 100644
--- a/pixelgl/vertex.go
+++ b/pixelgl/vertex.go
@@ -1,5 +1,7 @@
 package pixelgl
 
+import "github.com/go-gl/gl/v3.3-core/gl"
+
 // VertexFormat defines a data format in a vertex buffer.
 //
 // Example:
@@ -7,6 +9,15 @@ package pixelgl
 //   vf := VertexFormat{{Position, 2}, {Color, 4}, {TexCoord, 2}}
 type VertexFormat []VertexAttribute
 
+// Size returns the total size of all vertex attributes in a vertex format.
+func (vf VertexFormat) Size() int {
+	size := 0
+	for _, va := range vf {
+		size += va.Size
+	}
+	return size
+}
+
 // VertexAttribute specifies a single attribute in a vertex buffer.
 // All vertex attributes are composed of float64s.
 //
@@ -32,3 +43,144 @@ const (
 	TexCoord
 	NumStandardVertexAttrib
 )
+
+// VertexUsage specifies how often the vertex array data will be updated.
+type VertexUsage int
+
+// Possible VertexUsage values are:
+// 1. StaticUsage - never or rarely updated
+// 2. DynamicUsage - often updated
+// 3. StreamUsage - updated every frame
+const (
+	StaticUsage  VertexUsage = gl.STATIC_DRAW
+	DynamicUsage             = gl.DYNAMIC_DRAW
+	StreamUsage              = gl.STREAM_DRAW
+)
+
+// VertexDrawMode specifies how should the vertices be drawn.
+type VertexDrawMode int
+
+// Possible VertexDrawMode values are:
+// 1. PointsDrawMode - just draw individual PointsDrawMode
+// 2. LinesDrawMode - take pairs of vertices and draw a line from each pair
+// 3. LineStripDrawMode - take each two subsequent vertices and draw a line from each two
+// 4. LineLoopDrawMode - same as line strip, but also draw a line between the first and the last vertex
+// 5. TrianglesDrawMode - take triples of vertices and draw a triangle from each triple
+// 6. TriangleStripDrawMode - take each three subsequent vertices and draw a triangle from each three
+// 7. TriangleFanDrawMode - take each two subsequent vertices excluding the first vertex and draw a triangle from the first vertex and the two
+const (
+	PointsDrawMode        VertexDrawMode = gl.POINTS
+	LinesDrawMode                        = gl.LINES
+	LineStripDrawMode                    = gl.LINE_STRIP
+	LineLoopDrawMode                     = gl.LINE_LOOP
+	TrianglesDrawMode                    = gl.TRIANGLES
+	TriangleStripDrawMode                = gl.TRIANGLE_STRIP
+	TriangleFanDrawMode                  = gl.TRIANGLE_FAN
+)
+
+// VertexArray is an OpenGL vertex array object that also holds it's own vertex buffer object.
+// From the user's points of view, VertexArray is an array of vertices that can be drawn.
+type VertexArray struct {
+	parent BeginEnder
+	format VertexFormat
+	vao    uint32
+	vbo    uint32
+	mode   VertexDrawMode
+	count  int
+}
+
+// NewVertexArray creates a new vertex array and wrap another BeginEnder around it.
+func NewVertexArray(parent BeginEnder, format VertexFormat, mode VertexDrawMode, usage VertexUsage, data []float64) *VertexArray {
+	va := &VertexArray{
+		parent: parent,
+		format: format,
+		mode:   mode,
+	}
+	Do(func() {
+		gl.GenVertexArrays(1, &va.vao)
+		gl.BindVertexArray(va.vao)
+
+		gl.GenBuffers(1, &va.vbo)
+		gl.BindBuffer(gl.ARRAY_BUFFER, va.vbo)
+		gl.BufferData(gl.ARRAY_BUFFER, 8*len(data), gl.Ptr(data), uint32(usage))
+
+		stride := format.Size()
+		va.count = len(data) / stride
+
+		offset := 0
+		for i, attr := range format {
+			gl.VertexAttribPointer(
+				uint32(i),
+				int32(attr.Size),
+				gl.DOUBLE,
+				false,
+				int32(stride),
+				gl.PtrOffset(8*offset),
+			)
+			gl.EnableVertexAttribArray(uint32(i))
+			offset += attr.Size
+		}
+
+		gl.BindBuffer(gl.ARRAY_BUFFER, 0)
+		gl.BindVertexArray(0)
+	})
+	return va
+}
+
+// VertexFormat returns the format of the vertices inside a vertex array.
+//
+// Do not change this format!
+func (va *VertexArray) VertexFormat() VertexFormat {
+	return va.format
+}
+
+// SetDrawMode sets the draw mode of a vertex array. Subsequent calls to Draw will use this draw mode.
+func (va *VertexArray) SetDrawMode(mode VertexDrawMode) {
+	Do(func() {
+		va.mode = mode
+	})
+}
+
+// DrawMode returns the most recently set draw mode of a vertex array.
+func (va *VertexArray) DrawMode() VertexDrawMode {
+	mode := DoVal(func() interface{} {
+		return va.mode
+	})
+	return mode.(VertexDrawMode)
+}
+
+// Draw draws a vertex array.
+func (va *VertexArray) Draw() {
+	va.Begin()
+	va.End()
+}
+
+// UpdateData overwrites the current vertex array data starting at the index offset.
+//
+// Offset is not a number of bytes, instead, it's an index in the array.
+func (va *VertexArray) UpdateData(offset int, data []float64) {
+	Do(func() {
+		gl.BindBuffer(gl.ARRAY_BUFFER, va.vbo)
+		gl.BufferSubData(gl.ARRAY_BUFFER, 8*offset, 8*len(data), gl.Ptr(data))
+		gl.BindBuffer(gl.ARRAY_BUFFER, 0)
+	})
+}
+
+// Begin binds a vertex array and it's associated vertex buffer.
+func (va *VertexArray) Begin() {
+	va.parent.Begin()
+	Do(func() {
+		gl.BindVertexArray(va.vao)
+		gl.BindBuffer(gl.ARRAY_BUFFER, va.vbo)
+	})
+}
+
+// End draws a vertex array and unbinds it alongside with it's associated vertex buffer.
+func (va *VertexArray) End() {
+	Do(func() {
+		gl.DrawArrays(uint32(va.mode), 0, int32(va.count))
+		gl.BindBuffer(gl.ARRAY_BUFFER, 0)
+		gl.BindVertexArray(0)
+	})
+	va.parent.End()
+}
-- 
GitLab