From 800add157d29f6f4169d6b33f2382fc8e46ebf73 Mon Sep 17 00:00:00 2001 From: faiface <faiface@ksp.sk> Date: Tue, 20 Dec 2016 01:23:33 +0100 Subject: [PATCH] add fast VertexArray.SetVertex and VertexArray.Set methods --- graphics.go | 70 +++++++++++++++++++++++++----------- pixelgl/vertex.go | 92 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 141 insertions(+), 21 deletions(-) diff --git a/graphics.go b/graphics.go index f259c12..30a8335 100644 --- a/graphics.go +++ b/graphics.go @@ -209,6 +209,8 @@ func NewMultiShape(parent pixelgl.Doer, shapes ...*Shape) *MultiShape { } }) + //TODO: optimize with VertexArray.Set + offset = 0 for _, shape := range shapes { for i := 0; i < shape.VertexArray().VertexNum(); i++ { @@ -272,6 +274,8 @@ func NewSprite(parent pixelgl.Doer, picture *Picture) *Sprite { } }) + vertices := make([]map[pixelgl.Attr]interface{}, 4) + w, h := picture.Bounds().Size.XY() for i, p := range []Vec{V(0, 0), V(w, 0), V(w, h), V(0, h)} { texCoord := V( @@ -279,11 +283,15 @@ func NewSprite(parent pixelgl.Doer, picture *Picture) *Sprite { (picture.Bounds().Y()+p.Y())/float64(picture.Texture().Height()), ) - va.SetVertexAttr(i, positionVec2, mgl32.Vec2{float32(p.X()), float32(p.Y())}) - va.SetVertexAttr(i, colorVec4, mgl32.Vec4{1, 1, 1, 1}) - va.SetVertexAttr(i, texCoordVec2, mgl32.Vec2{float32(texCoord.X()), float32(texCoord.Y())}) + vertices[i] = map[pixelgl.Attr]interface{}{ + positionVec2: mgl32.Vec2{float32(p.X()), float32(p.Y())}, + colorVec4: mgl32.Vec4{1, 1, 1, 1}, + texCoordVec2: mgl32.Vec2{float32(texCoord.X()), float32(texCoord.Y())}, + } } + va.Set(vertices) + return &Sprite{NewShape(parent, picture, color.White, Position(0), va)} } @@ -312,11 +320,17 @@ func NewLineColor(parent pixelgl.Doer, c color.Color, a, b Vec, width float64) * } }) + vertices := make([]map[pixelgl.Attr]interface{}, 4) + for i := 0; i < 4; i++ { - va.SetVertexAttr(i, colorVec4, mgl32.Vec4{1, 1, 1, 1}) - va.SetVertexAttr(i, texCoordVec2, mgl32.Vec2{-1, -1}) + vertices[i] = map[pixelgl.Attr]interface{}{ + colorVec4: mgl32.Vec4{1, 1, 1, 1}, + texCoordVec2: mgl32.Vec2{-1, -1}, + } } + va.Set(vertices) + lc := &LineColor{NewShape(parent, nil, c, Position(0), va), a, b, width} lc.setPoints() return lc @@ -392,12 +406,18 @@ func NewPolygonColor(parent pixelgl.Doer, c color.Color, points ...Vec) *Polygon } }) + vertices := make([]map[pixelgl.Attr]interface{}, len(points)) + for i, p := range points { - va.SetVertexAttr(i, positionVec2, mgl32.Vec2{float32(p.X()), float32(p.Y())}) - va.SetVertexAttr(i, colorVec4, mgl32.Vec4{1, 1, 1, 1}) - va.SetVertexAttr(i, texCoordVec2, mgl32.Vec2{-1, -1}) + vertices[i] = map[pixelgl.Attr]interface{}{ + positionVec2: mgl32.Vec2{float32(p.X()), float32(p.Y())}, + colorVec4: mgl32.Vec4{1, 1, 1, 1}, + texCoordVec2: mgl32.Vec2{-1, -1}, + } } + va.Set(vertices) + return &PolygonColor{NewShape(parent, nil, c, Position(0), va), points} } @@ -455,25 +475,33 @@ func NewEllipseColor(parent pixelgl.Doer, c color.Color, radius Vec, fill float6 } }) + vertices := make([]map[pixelgl.Attr]interface{}, (n+1)*2) + for k := 0; k < n+1; k++ { i, j := k*2, k*2+1 angle := math.Pi * 2 * float64(k%n) / n - va.SetVertexAttr(i, positionVec2, mgl32.Vec2{ - float32(math.Cos(angle) * radius.X()), - float32(math.Sin(angle) * radius.Y()), - }) - va.SetVertexAttr(i, colorVec4, mgl32.Vec4{1, 1, 1, 1}) - va.SetVertexAttr(i, texCoordVec2, mgl32.Vec2{-1, -1}) - - va.SetVertexAttr(j, positionVec2, mgl32.Vec2{ - float32(math.Cos(angle) * radius.X() * (1 - fill)), - float32(math.Sin(angle) * radius.Y() * (1 - fill)), - }) - va.SetVertexAttr(j, colorVec4, mgl32.Vec4{1, 1, 1, 1}) - va.SetVertexAttr(j, texCoordVec2, mgl32.Vec2{-1, -1}) + vertices[i] = map[pixelgl.Attr]interface{}{ + positionVec2: mgl32.Vec2{ + float32(math.Cos(angle) * radius.X()), + float32(math.Sin(angle) * radius.Y()), + }, + colorVec4: mgl32.Vec4{1, 1, 1, 1}, + texCoordVec2: mgl32.Vec2{-1, -1}, + } + + vertices[j] = map[pixelgl.Attr]interface{}{ + positionVec2: mgl32.Vec2{ + float32(math.Cos(angle) * radius.X() * (1 - fill)), + float32(math.Sin(angle) * radius.Y() * (1 - fill)), + }, + colorVec4: mgl32.Vec4{1, 1, 1, 1}, + texCoordVec2: mgl32.Vec2{-1, -1}, + } } + va.Set(vertices) + return &EllipseColor{NewShape(parent, nil, c, Position(0), va), radius, fill} } diff --git a/pixelgl/vertex.go b/pixelgl/vertex.go index 5eb27e7..ed0d756 100644 --- a/pixelgl/vertex.go +++ b/pixelgl/vertex.go @@ -273,6 +273,98 @@ func (va *VertexArray) VertexAttr(vertex int, attr Attr) (value interface{}, ok return value, true } +// SetVertex sets values of the attributes specified in the supplied map. All other attributes will be set to zero. +// +// Not existing attributes are silently skipped. +func (va *VertexArray) SetVertex(vertex int, values map[Attr]interface{}) { + if vertex < 0 || vertex >= va.vertexNum { + panic("set vertex: invalid vertex index") + } + + data := make([]float32, va.format.Size()/4) + + for attr, value := range values { + if !va.format.Contains(attr) { + continue + } + + offset := va.offset[attr.Name] + + switch attr.Type { + case Float: + value := value.(float32) + copy(data[offset/4:offset/4+attr.Type.Size()/4], []float32{value}) + case Vec2: + value := value.(mgl32.Vec2) + copy(data[offset/4:offset/4+attr.Type.Size()/4], value[:]) + case Vec3: + value := value.(mgl32.Vec3) + copy(data[offset/4:offset/4+attr.Type.Size()/4], value[:]) + case Vec4: + value := value.(mgl32.Vec4) + copy(data[offset/4:offset/4+attr.Type.Size()/4], value[:]) + default: + panic("set vertex: invalid attribute type") + } + } + + DoNoBlock(func() { + va.vbo.bind() + + offset := va.stride * vertex + gl.BufferSubData(gl.ARRAY_BUFFER, offset, len(data)*4, gl.Ptr(data)) + + va.vbo.restore() + }) +} + +// Set sets values of vertex attributes of all vertices as specified in the supplied slice of maps. If the length of vertices +// does not match the number of vertices in the vertex array, this method panics. +// +// Not existing attributes are silently skipped. +func (va *VertexArray) Set(vertices []map[Attr]interface{}) { + if len(vertices) != va.vertexNum { + panic("set vertex array: wrong number of supplied vertices") + } + + data := make([]float32, va.vertexNum*va.format.Size()/4) + + for vertex := range vertices { + for attr, value := range vertices[vertex] { + if !va.format.Contains(attr) { + continue + } + + offset := va.stride*vertex + va.offset[attr.Name] + + switch attr.Type { + case Float: + value := value.(float32) + copy(data[offset/4:offset/4+attr.Type.Size()/4], []float32{value}) + case Vec2: + value := value.(mgl32.Vec2) + copy(data[offset/4:offset/4+attr.Type.Size()/4], value[:]) + case Vec3: + value := value.(mgl32.Vec3) + copy(data[offset/4:offset/4+attr.Type.Size()/4], value[:]) + case Vec4: + value := value.(mgl32.Vec4) + copy(data[offset/4:offset/4+attr.Type.Size()/4], value[:]) + default: + panic("set vertex: invalid attribute type") + } + } + } + + DoNoBlock(func() { + va.vbo.bind() + + gl.BufferSubData(gl.ARRAY_BUFFER, 0, len(data)*4, gl.Ptr(data)) + + va.vbo.restore() + }) +} + // Do binds a vertex arrray and it's associated vertex buffer, executes sub, and unbinds the vertex array and it's vertex buffer. func (va *VertexArray) Do(sub func(Context)) { va.parent.Do(func(ctx Context) { -- GitLab