use new attr

This commit is contained in:
faiface 2016-11-29 23:11:53 +01:00
parent 9d4111282e
commit 96f134d4c4
2 changed files with 155 additions and 71 deletions

69
pixelgl/attr.go Normal file
View File

@ -0,0 +1,69 @@
package pixelgl
// Attr represents an arbitrary OpenGL attribute, such as a vertex attribute or a shader uniform attribute.
type Attr struct {
Purpose AttrPurpose
Type AttrType
}
// AttrPurpose specified a purpose of an attribute. Feel free to create your own purposes for your own needs.
type AttrPurpose int
const (
// Position of a vertex
Position AttrPurpose = iota
// Color of a vertex
Color
// TexCoord are texture coordinates
TexCoord
// Transform is an object transformation matrix
Transform
// Camera is a camera view matrix
Camera
)
// AttrType represents the type of an OpenGL attribute.
//
// Important note: Int is 32-bit and Float is 64-bit.
type AttrType int
// List of all possible attribute types.
const (
Bool AttrType = iota
Int
Float
Vec2
Vec3
Vec4
Mat2
Mat23
Mat24
Mat3
Mat32
Mat34
Mat4
Mat42
Mat43
)
// Size returns the size of a type in bytes.
func (at AttrType) Size() int {
sizeOf := map[AttrType]int{
Bool: 1,
Int: 4,
Float: 8,
Vec2: 2 * 8,
Vec3: 3 * 8,
Vec4: 4 * 8,
Mat2: 2 * 2 * 8,
Mat23: 2 * 3 * 8,
Mat24: 2 * 4 * 8,
Mat3: 3 * 3 * 8,
Mat32: 3 * 2 * 8,
Mat34: 3 * 4 * 8,
Mat4: 4 * 4 * 8,
Mat42: 4 * 2 * 8,
Mat43: 4 * 3 * 8,
}
return sizeOf[at]
}

View File

@ -1,6 +1,8 @@
package pixelgl
import (
"unsafe"
"github.com/go-gl/gl/v3.3-core/gl"
"github.com/pkg/errors"
)
@ -9,44 +11,18 @@ import (
//
// Example:
//
// vf := VertexFormat{{Position, 2}, {Color, 4}, {TexCoord, 2}}
type VertexFormat []VertexAttribute
// VertexFormat{{Position, Vec2}, {Color, Vec4}, {TexCoord, Vec2}, {Visible, Bool}}
type VertexFormat []Attr
// Size returns the total size of all vertex attributes in a vertex format.
// Size calculates the total size of a single vertex in this vertex format (sum of the sizes of all vertex attributes).
func (vf VertexFormat) Size() int {
size := 0
for _, va := range vf {
size += va.Size
total := 0
for _, attr := range vf {
total += attr.Type.Size()
}
return size
return total
}
// VertexAttribute specifies a single attribute in a vertex buffer.
// All vertex attributes are composed of float64s.
//
// A vertex attribute has a Purpose (such as Position, Color, etc.) and Size. Size specifies
// the number of float64s the vertex attribute is composed of.
type VertexAttribute struct {
Purpose VertexAttributePurpose
Size int
}
// VertexAttributePurpose clarifies the purpose of a vertex attribute. This can be a color, position, texture
// coordinates or anything else.
//
// VertexAttributePurpose may be used to correctly assign data to a vertex buffer.
type VertexAttributePurpose int
// Position, Color and TexCoord are the standard vertex attributes.
//
// Feel free to define more vertex attribute purposes (e.g. in an effects library).
const (
Position VertexAttributePurpose = iota
Color
TexCoord
NumStandardVertexAttrib
)
// VertexUsage specifies how often the vertex array data will be updated.
type VertexUsage int
@ -94,34 +70,35 @@ type VertexArray struct {
format VertexFormat
stride int
count int
attrs map[VertexAttribute]int
attrs map[Attr]int
vao uint32
vbo uint32
mode VertexDrawMode
}
// NewVertexArray creates a new vertex array and wraps another Doer around it.
func NewVertexArray(parent Doer, format VertexFormat, mode VertexDrawMode, usage VertexUsage, data []float64) (*VertexArray, error) {
// NewVertexArray creates a new empty vertex array and wraps another Doer around it.
func NewVertexArray(parent Doer, format VertexFormat, mode VertexDrawMode, usage VertexUsage, count int) (*VertexArray, error) {
va := &VertexArray{
parent: parent,
format: format,
count: count,
stride: format.Size(),
count: len(data) / format.Size(),
attrs: make(map[VertexAttribute]int),
attrs: make(map[Attr]int),
mode: mode,
}
if len(data)%format.Size() != 0 {
return nil, errors.New("failed to create vertex array: data length not divisable by format size")
}
offset := 0
for _, attr := range format {
switch attr.Type {
case Bool, Int, Float, Vec2, Vec3, Vec4:
default:
return nil, errors.New("failed to create vertex array: invalid vertex format: invalid attribute type")
}
if _, ok := va.attrs[attr]; ok {
return nil, errors.New("failed to create vertex array: invalid vertex format: duplicate vertex attribute")
}
va.attrs[attr] = offset
offset += attr.Size
offset += attr.Type.Size()
}
var err error
@ -132,20 +109,46 @@ func NewVertexArray(parent Doer, format VertexFormat, mode VertexDrawMode, usage
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))
emptyData := make([]byte, count*va.stride)
gl.BufferData(gl.ARRAY_BUFFER, len(emptyData), gl.Ptr(emptyData), uint32(usage))
offset := 0
for i, attr := range format {
//XXX: ugly but OpenGL is so inconsistent
var size int32
switch attr.Type {
case Bool, Int, Float:
size = 1
case Vec2:
size = 2
case Vec3:
size = 3
case Vec4:
size = 4
}
var xtype uint32
switch attr.Type {
case Bool:
xtype = gl.BOOL
case Int:
xtype = gl.INT
case Float, Vec2, Vec3, Vec4:
xtype = gl.DOUBLE
}
gl.VertexAttribPointer(
uint32(i),
int32(attr.Size),
gl.DOUBLE,
size,
xtype,
false,
int32(8*va.stride),
gl.PtrOffset(8*offset),
int32(va.stride),
gl.PtrOffset(offset),
)
gl.EnableVertexAttribArray(uint32(i))
offset += attr.Size
offset += attr.Type.Size()
}
gl.BindBuffer(gl.ARRAY_BUFFER, 0)
@ -169,6 +172,11 @@ func (va *VertexArray) Delete() {
})
}
// Count returns the number of vertices in a vertex array.
func (va *VertexArray) Count() int {
return va.count
}
// VertexFormat returns the format of the vertices inside a vertex array.
//
// Do not change this format!
@ -196,33 +204,40 @@ func (va *VertexArray) Draw() {
va.Do(func(Context) {})
}
// Data returns a copy of data inside a vertex array (actually it's vertex buffer).
func (va *VertexArray) Data() []float64 {
data := make([]float64, va.count*va.format.Size())
Do(func() {
gl.BindBuffer(gl.ARRAY_BUFFER, va.vbo)
gl.GetBufferSubData(gl.ARRAY_BUFFER, 0, 8*len(data), gl.Ptr(data))
gl.BindBuffer(gl.ARRAY_BUFFER, 0)
})
return data
}
// SetVertexAttribute sets the value of the specified vertex attribute of the specified vertex.
func (va *VertexArray) SetVertexAttribute(vertex int, attr VertexAttribute, data []float64) {
if len(data) != attr.Size {
panic("set vertex attribute error: invalid data length")
}
// SetVertex sets the value of all attributes of a vertex.
// Argument data must point to a slice/array containing the new vertex data.
func (va *VertexArray) SetVertex(vertex int, data unsafe.Pointer) {
if vertex < 0 || vertex >= va.count {
panic("set vertex attribute error: invalid vertex index")
}
if _, ok := va.attrs[attr]; !ok {
panic("set vertex attribute error: invalid vertex attribute")
panic("set vertex error: invalid vertex index")
}
DoNoBlock(func() {
gl.BindBuffer(gl.ARRAY_BUFFER, va.vbo)
offset := 8*va.stride*vertex + 8*va.attrs[attr]
gl.BufferSubData(gl.ARRAY_BUFFER, offset, 8*len(data), gl.Ptr(data))
offset := va.stride * vertex
gl.BufferSubData(gl.ARRAY_BUFFER, offset, va.format.Size(), data)
gl.BindBuffer(gl.ARRAY_BUFFER, 0)
if err := getLastGLErr(); err != nil {
panic(errors.Wrap(err, "set vertex error"))
}
})
}
// SetVertexAttribute sets the value of the specified vertex attribute of the specified vertex.
// Argument data must point to a slice/array containing the new attribute data.
func (va *VertexArray) SetVertexAttribute(vertex int, attr Attr, data unsafe.Pointer) {
if vertex < 0 || vertex >= va.count {
panic("set vertex attribute error: invalid vertex index")
}
if _, ok := va.attrs[attr]; !ok {
return // ignore non-existing attributes
}
DoNoBlock(func() {
gl.BindBuffer(gl.ARRAY_BUFFER, va.vbo)
offset := va.stride*vertex + va.attrs[attr]
gl.BufferSubData(gl.ARRAY_BUFFER, offset, attr.Type.Size(), data)
gl.BindBuffer(gl.ARRAY_BUFFER, 0)