From 91763a9e1a4a3d5f67696c5d4babcafe09851aa5 Mon Sep 17 00:00:00 2001 From: faiface 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() +}