add fast VertexArray.SetVertex and VertexArray.Set methods

This commit is contained in:
faiface 2016-12-20 01:23:33 +01:00
parent 6986e8a000
commit 800add157d
2 changed files with 140 additions and 20 deletions

View File

@ -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})
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},
}
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[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}
}

View File

@ -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) {