rework VertexSlice for better performance
This commit is contained in:
parent
43bdd39739
commit
3b39cc60e9
13
graphics.go
13
graphics.go
|
@ -25,13 +25,14 @@ func (td *TrianglesData) Draw() {
|
||||||
|
|
||||||
func (td *TrianglesData) resize(len int) {
|
func (td *TrianglesData) resize(len int) {
|
||||||
if len > td.Len() {
|
if len > td.Len() {
|
||||||
newData := make(TrianglesData, len-td.Len())
|
needAppend := len - td.Len()
|
||||||
// default values
|
for i := 0; i < needAppend; i++ {
|
||||||
for i := range newData {
|
*td = append(*td, struct {
|
||||||
newData[i].Color = NRGBA{1, 1, 1, 1}
|
Position Vec
|
||||||
newData[i].Texture = V(-1, -1)
|
Color NRGBA
|
||||||
|
Texture Vec
|
||||||
|
}{V(0, 0), NRGBA{1, 1, 1, 1}, V(-1, -1)})
|
||||||
}
|
}
|
||||||
*td = append(*td, newData...)
|
|
||||||
}
|
}
|
||||||
if len < td.Len() {
|
if len < td.Len() {
|
||||||
*td = (*td)[:len]
|
*td = (*td)[:len]
|
||||||
|
|
|
@ -3,29 +3,14 @@ package pixelgl
|
||||||
// AttrFormat defines names and types of OpenGL attributes (vertex format, uniform format, etc.).
|
// AttrFormat defines names and types of OpenGL attributes (vertex format, uniform format, etc.).
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
// AttrFormat{"position": Vec2, "color": Vec4, "texCoord": Vec2}
|
// AttrFormat{{"position", Vec2}, {"color", Vec4}, {"texCoord": Vec2}}
|
||||||
type AttrFormat map[string]AttrType
|
type AttrFormat []Attr
|
||||||
|
|
||||||
// Contains checks whether a format contains a specific attribute.
|
|
||||||
//
|
|
||||||
// It does a little more than a hard check: e.g. if you query a Vec2 attribute, but the format
|
|
||||||
// contains Vec3, Contains returns true, because Vec2 is assignable to Vec3. Specifically,
|
|
||||||
// Float -> Vec2 -> Vec3 -> Vec4 (transitively). This however does not work for matrices or ints.
|
|
||||||
func (af AttrFormat) Contains(attr Attr) bool {
|
|
||||||
if typ, ok := af[attr.Name]; ok {
|
|
||||||
if (Float <= typ && typ <= Vec4) && (Float <= attr.Type && attr.Type <= typ) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return attr.Type == typ
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Size returns the total size of all attributes of an attribute format.
|
// Size returns the total size of all attributes of an attribute format.
|
||||||
func (af AttrFormat) Size() int {
|
func (af AttrFormat) Size() int {
|
||||||
total := 0
|
total := 0
|
||||||
for _, typ := range af {
|
for _, attr := range af {
|
||||||
total += typ.Size()
|
total += attr.Type.Size()
|
||||||
}
|
}
|
||||||
return total
|
return total
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ type Shader struct {
|
||||||
program binder
|
program binder
|
||||||
vertexFmt AttrFormat
|
vertexFmt AttrFormat
|
||||||
uniformFmt AttrFormat
|
uniformFmt AttrFormat
|
||||||
uniforms map[string]int32
|
uniformLoc []int32
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewShader creates a new shader program from the specified vertex shader and fragment shader
|
// NewShader creates a new shader program from the specified vertex shader and fragment shader
|
||||||
|
@ -31,7 +31,7 @@ func NewShader(vertexFmt, uniformFmt AttrFormat, vertexShader, fragmentShader st
|
||||||
},
|
},
|
||||||
vertexFmt: vertexFmt,
|
vertexFmt: vertexFmt,
|
||||||
uniformFmt: uniformFmt,
|
uniformFmt: uniformFmt,
|
||||||
uniforms: make(map[string]int32),
|
uniformLoc: make([]int32, len(uniformFmt)),
|
||||||
}
|
}
|
||||||
|
|
||||||
var vshader, fshader uint32
|
var vshader, fshader uint32
|
||||||
|
@ -99,9 +99,9 @@ func NewShader(vertexFmt, uniformFmt AttrFormat, vertexShader, fragmentShader st
|
||||||
}
|
}
|
||||||
|
|
||||||
// uniforms
|
// uniforms
|
||||||
for name := range uniformFmt {
|
for i, uniform := range uniformFmt {
|
||||||
loc := gl.GetUniformLocation(shader.program.obj, gl.Str(name+"\x00"))
|
loc := gl.GetUniformLocation(shader.program.obj, gl.Str(uniform.Name+"\x00"))
|
||||||
shader.uniforms[name] = loc
|
shader.uniformLoc[i] = loc
|
||||||
}
|
}
|
||||||
|
|
||||||
runtime.SetFinalizer(shader, (*Shader).delete)
|
runtime.SetFinalizer(shader, (*Shader).delete)
|
||||||
|
@ -125,9 +125,10 @@ func (s *Shader) UniformFormat() AttrFormat {
|
||||||
return s.uniformFmt
|
return s.uniformFmt
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetUniformAttr sets the value of a uniform attribute of a shader.
|
// SetUniformAttr sets the value of a uniform attribute of a shader. The attribute is
|
||||||
|
// specified by the index in the Shader's uniform format.
|
||||||
//
|
//
|
||||||
// If the attribute does not exist, this method returns false.
|
// If the uniform attribute does not exist in the Shader, this method returns false.
|
||||||
//
|
//
|
||||||
// Supplied value must correspond to the type of the attribute. Correct types are these
|
// Supplied value must correspond to the type of the attribute. Correct types are these
|
||||||
// (right-hand is the type of the value):
|
// (right-hand is the type of the value):
|
||||||
|
@ -148,54 +149,54 @@ func (s *Shader) UniformFormat() AttrFormat {
|
||||||
// No other types are supported.
|
// No other types are supported.
|
||||||
//
|
//
|
||||||
// The shader must be bound before calling this method.
|
// The shader must be bound before calling this method.
|
||||||
func (s *Shader) SetUniformAttr(attr Attr, value interface{}) (ok bool) {
|
func (s *Shader) SetUniformAttr(uniform int, value interface{}) (ok bool) {
|
||||||
if !s.uniformFmt.Contains(attr) {
|
if s.uniformLoc[uniform] < 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
switch attr.Type {
|
switch s.uniformFmt[uniform].Type {
|
||||||
case Int:
|
case Int:
|
||||||
value := value.(int32)
|
value := value.(int32)
|
||||||
gl.Uniform1iv(s.uniforms[attr.Name], 1, &value)
|
gl.Uniform1iv(s.uniformLoc[uniform], 1, &value)
|
||||||
case Float:
|
case Float:
|
||||||
value := value.(float32)
|
value := value.(float32)
|
||||||
gl.Uniform1fv(s.uniforms[attr.Name], 1, &value)
|
gl.Uniform1fv(s.uniformLoc[uniform], 1, &value)
|
||||||
case Vec2:
|
case Vec2:
|
||||||
value := value.(mgl32.Vec2)
|
value := value.(mgl32.Vec2)
|
||||||
gl.Uniform2fv(s.uniforms[attr.Name], 1, &value[0])
|
gl.Uniform2fv(s.uniformLoc[uniform], 1, &value[0])
|
||||||
case Vec3:
|
case Vec3:
|
||||||
value := value.(mgl32.Vec3)
|
value := value.(mgl32.Vec3)
|
||||||
gl.Uniform3fv(s.uniforms[attr.Name], 1, &value[0])
|
gl.Uniform3fv(s.uniformLoc[uniform], 1, &value[0])
|
||||||
case Vec4:
|
case Vec4:
|
||||||
value := value.(mgl32.Vec4)
|
value := value.(mgl32.Vec4)
|
||||||
gl.Uniform4fv(s.uniforms[attr.Name], 1, &value[0])
|
gl.Uniform4fv(s.uniformLoc[uniform], 1, &value[0])
|
||||||
case Mat2:
|
case Mat2:
|
||||||
value := value.(mgl32.Mat2)
|
value := value.(mgl32.Mat2)
|
||||||
gl.UniformMatrix2fv(s.uniforms[attr.Name], 1, false, &value[0])
|
gl.UniformMatrix2fv(s.uniformLoc[uniform], 1, false, &value[0])
|
||||||
case Mat23:
|
case Mat23:
|
||||||
value := value.(mgl32.Mat2x3)
|
value := value.(mgl32.Mat2x3)
|
||||||
gl.UniformMatrix2x3fv(s.uniforms[attr.Name], 1, false, &value[0])
|
gl.UniformMatrix2x3fv(s.uniformLoc[uniform], 1, false, &value[0])
|
||||||
case Mat24:
|
case Mat24:
|
||||||
value := value.(mgl32.Mat2x4)
|
value := value.(mgl32.Mat2x4)
|
||||||
gl.UniformMatrix2x4fv(s.uniforms[attr.Name], 1, false, &value[0])
|
gl.UniformMatrix2x4fv(s.uniformLoc[uniform], 1, false, &value[0])
|
||||||
case Mat3:
|
case Mat3:
|
||||||
value := value.(mgl32.Mat3)
|
value := value.(mgl32.Mat3)
|
||||||
gl.UniformMatrix3fv(s.uniforms[attr.Name], 1, false, &value[0])
|
gl.UniformMatrix3fv(s.uniformLoc[uniform], 1, false, &value[0])
|
||||||
case Mat32:
|
case Mat32:
|
||||||
value := value.(mgl32.Mat3x2)
|
value := value.(mgl32.Mat3x2)
|
||||||
gl.UniformMatrix3x2fv(s.uniforms[attr.Name], 1, false, &value[0])
|
gl.UniformMatrix3x2fv(s.uniformLoc[uniform], 1, false, &value[0])
|
||||||
case Mat34:
|
case Mat34:
|
||||||
value := value.(mgl32.Mat3x4)
|
value := value.(mgl32.Mat3x4)
|
||||||
gl.UniformMatrix3x4fv(s.uniforms[attr.Name], 1, false, &value[0])
|
gl.UniformMatrix3x4fv(s.uniformLoc[uniform], 1, false, &value[0])
|
||||||
case Mat4:
|
case Mat4:
|
||||||
value := value.(mgl32.Mat4)
|
value := value.(mgl32.Mat4)
|
||||||
gl.UniformMatrix4fv(s.uniforms[attr.Name], 1, false, &value[0])
|
gl.UniformMatrix4fv(s.uniformLoc[uniform], 1, false, &value[0])
|
||||||
case Mat42:
|
case Mat42:
|
||||||
value := value.(mgl32.Mat4x2)
|
value := value.(mgl32.Mat4x2)
|
||||||
gl.UniformMatrix4x2fv(s.uniforms[attr.Name], 1, false, &value[0])
|
gl.UniformMatrix4x2fv(s.uniformLoc[uniform], 1, false, &value[0])
|
||||||
case Mat43:
|
case Mat43:
|
||||||
value := value.(mgl32.Mat4x3)
|
value := value.(mgl32.Mat4x3)
|
||||||
gl.UniformMatrix4x3fv(s.uniforms[attr.Name], 1, false, &value[0])
|
gl.UniformMatrix4x3fv(s.uniformLoc[uniform], 1, false, &value[0])
|
||||||
default:
|
default:
|
||||||
panic("set uniform attr: invalid attribute type")
|
panic("set uniform attr: invalid attribute type")
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,22 +1,13 @@
|
||||||
package pixelgl
|
package pixelgl
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
"github.com/go-gl/gl/v3.3-core/gl"
|
"github.com/go-gl/gl/v3.3-core/gl"
|
||||||
"github.com/go-gl/mathgl/mgl32"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// VertexData holds data of one vertex stored in vertex attributes. The values must match attribute
|
|
||||||
// types precisely. Here's the table of correct types (no other types are valid):
|
|
||||||
//
|
|
||||||
// Attr{Type: Float}: float32
|
|
||||||
// Attr{Type: Vec2}: mgl32.Vec2
|
|
||||||
// Attr{Type: Vec3}: mgl32.Vec3
|
|
||||||
// Attr{Type: Vec4}: mgl32.Vec4
|
|
||||||
type VertexData map[Attr]interface{}
|
|
||||||
|
|
||||||
// VertexSlice points to a portion of (or possibly whole) vertex array. It is used as a pointer,
|
// VertexSlice points to a portion of (or possibly whole) vertex array. It is used as a pointer,
|
||||||
// contrary to Go's builtin slices. This is, so that append can be 'in-place'. That's for the good,
|
// contrary to Go's builtin slices. This is, so that append can be 'in-place'. That's for the good,
|
||||||
// because Begin/End-ing a VertexSlice would become super confusing, if append returned a new
|
// because Begin/End-ing a VertexSlice would become super confusing, if append returned a new
|
||||||
|
@ -53,6 +44,11 @@ func (vs *VertexSlice) VertexFormat() AttrFormat {
|
||||||
return vs.va.format
|
return vs.va.format
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Stride returns the number of float32 elements occupied by one vertex.
|
||||||
|
func (vs *VertexSlice) Stride() int {
|
||||||
|
return vs.va.stride / 4
|
||||||
|
}
|
||||||
|
|
||||||
// Len returns the length of the VertexSlice.
|
// Len returns the length of the VertexSlice.
|
||||||
func (vs *VertexSlice) Len() int {
|
func (vs *VertexSlice) Len() int {
|
||||||
return vs.j - vs.i
|
return vs.j - vs.i
|
||||||
|
@ -117,26 +113,36 @@ func (vs VertexSlice) grow(len int) VertexSlice {
|
||||||
// is not sufficient, a new, larger underlying vertex array will be allocated. The content of the
|
// is not sufficient, a new, larger underlying vertex array will be allocated. The content of the
|
||||||
// original VertexSlice will be copied to the new underlying vertex array.
|
// original VertexSlice will be copied to the new underlying vertex array.
|
||||||
//
|
//
|
||||||
|
// The data is in the same format as with SetVertexData.
|
||||||
|
//
|
||||||
// The VertexSlice is appended 'in-place', contrary Go's builtin slices.
|
// The VertexSlice is appended 'in-place', contrary Go's builtin slices.
|
||||||
func (vs *VertexSlice) Append(vertices ...VertexData) {
|
func (vs *VertexSlice) Append(data []float32) {
|
||||||
vs.End() // vs must have been Begin-ed before calling this method
|
vs.End() // vs must have been Begin-ed before calling this method
|
||||||
*vs = vs.grow(vs.Len() + len(vertices))
|
*vs = vs.grow(vs.Len() + len(data)/vs.Stride())
|
||||||
vs.Begin()
|
vs.Begin()
|
||||||
vs.Slice(vs.Len()-len(vertices), vs.Len()).SetVertexData(vertices)
|
vs.Slice(vs.Len()-len(data)/vs.Stride(), vs.Len()).SetVertexData(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetVertexData sets the contents of the VertexSlice.
|
// SetVertexData sets the contents of the VertexSlice.
|
||||||
//
|
//
|
||||||
|
// The data is a slice of float32's, where each vertex attribute occupies a certain number of
|
||||||
|
// elements. Namely, Float occupies 1, Vec2 occupies 2, Vec3 occupies 3 and Vec4 occupies 4. The
|
||||||
|
// attribues in the data slice must be in the same order as in the vertex format of this Vertex
|
||||||
|
// Slice.
|
||||||
|
//
|
||||||
// If the length of vertices does not match the length of the VertexSlice, this methdo panics.
|
// If the length of vertices does not match the length of the VertexSlice, this methdo panics.
|
||||||
func (vs *VertexSlice) SetVertexData(vertices []VertexData) {
|
func (vs *VertexSlice) SetVertexData(data []float32) {
|
||||||
if len(vertices) != vs.Len() {
|
if len(data)/vs.Stride() != vs.Len() {
|
||||||
|
fmt.Println(len(data)/vs.Stride(), vs.Len())
|
||||||
panic("set vertex data: wrong length of vertices")
|
panic("set vertex data: wrong length of vertices")
|
||||||
}
|
}
|
||||||
vs.va.setVertexData(vs.i, vs.j, vertices)
|
vs.va.setVertexData(vs.i, vs.j, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// VertexData returns the contents of the VertexSlice.
|
// VertexData returns the contents of the VertexSlice.
|
||||||
func (vs *VertexSlice) VertexData() []VertexData {
|
//
|
||||||
|
// The data is in the same format as with SetVertexData.
|
||||||
|
func (vs *VertexSlice) VertexData() []float32 {
|
||||||
return vs.va.vertexData(vs.i, vs.j)
|
return vs.va.vertexData(vs.i, vs.j)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,7 +166,7 @@ type vertexArray struct {
|
||||||
cap int
|
cap int
|
||||||
format AttrFormat
|
format AttrFormat
|
||||||
stride int
|
stride int
|
||||||
offset map[string]int
|
offset []int
|
||||||
shader *Shader
|
shader *Shader
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,19 +193,19 @@ func newVertexArray(shader *Shader, cap int) *vertexArray {
|
||||||
cap: cap,
|
cap: cap,
|
||||||
format: shader.VertexFormat(),
|
format: shader.VertexFormat(),
|
||||||
stride: shader.VertexFormat().Size(),
|
stride: shader.VertexFormat().Size(),
|
||||||
offset: make(map[string]int),
|
offset: make([]int, len(shader.VertexFormat())),
|
||||||
shader: shader,
|
shader: shader,
|
||||||
}
|
}
|
||||||
|
|
||||||
offset := 0
|
offset := 0
|
||||||
for name, typ := range va.format {
|
for i, attr := range va.format {
|
||||||
switch typ {
|
switch attr.Type {
|
||||||
case Float, Vec2, Vec3, Vec4:
|
case Float, Vec2, Vec3, Vec4:
|
||||||
default:
|
default:
|
||||||
panic(errors.New("failed to create vertex array: invalid attribute type"))
|
panic(errors.New("failed to create vertex array: invalid attribute type"))
|
||||||
}
|
}
|
||||||
va.offset[name] = offset
|
va.offset[i] = offset
|
||||||
offset += typ.Size()
|
offset += attr.Type.Size()
|
||||||
}
|
}
|
||||||
|
|
||||||
gl.GenVertexArrays(1, &va.vao.obj)
|
gl.GenVertexArrays(1, &va.vao.obj)
|
||||||
|
@ -212,11 +218,11 @@ func newVertexArray(shader *Shader, cap int) *vertexArray {
|
||||||
emptyData := make([]byte, cap*va.stride)
|
emptyData := make([]byte, cap*va.stride)
|
||||||
gl.BufferData(gl.ARRAY_BUFFER, len(emptyData), gl.Ptr(emptyData), gl.DYNAMIC_DRAW)
|
gl.BufferData(gl.ARRAY_BUFFER, len(emptyData), gl.Ptr(emptyData), gl.DYNAMIC_DRAW)
|
||||||
|
|
||||||
for name, typ := range va.format {
|
for i, attr := range va.format {
|
||||||
loc := gl.GetAttribLocation(shader.program.obj, gl.Str(name+"\x00"))
|
loc := gl.GetAttribLocation(shader.program.obj, gl.Str(attr.Name+"\x00"))
|
||||||
|
|
||||||
var size int32
|
var size int32
|
||||||
switch typ {
|
switch attr.Type {
|
||||||
case Float:
|
case Float:
|
||||||
size = 1
|
size = 1
|
||||||
case Vec2:
|
case Vec2:
|
||||||
|
@ -233,7 +239,7 @@ func newVertexArray(shader *Shader, cap int) *vertexArray {
|
||||||
gl.FLOAT,
|
gl.FLOAT,
|
||||||
false,
|
false,
|
||||||
int32(va.stride),
|
int32(va.stride),
|
||||||
gl.PtrOffset(va.offset[name]),
|
gl.PtrOffset(va.offset[i]),
|
||||||
)
|
)
|
||||||
gl.EnableVertexAttribArray(uint32(loc))
|
gl.EnableVertexAttribArray(uint32(loc))
|
||||||
}
|
}
|
||||||
|
@ -266,82 +272,20 @@ func (va *vertexArray) draw(i, j int) {
|
||||||
gl.DrawArrays(gl.TRIANGLES, int32(i), int32(i+j))
|
gl.DrawArrays(gl.TRIANGLES, int32(i), int32(i+j))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (va *vertexArray) setVertexData(i, j int, vertices []VertexData) {
|
func (va *vertexArray) setVertexData(i, j int, data []float32) {
|
||||||
if j-i == 0 {
|
if j-i == 0 {
|
||||||
// avoid setting 0 bytes of buffer data
|
// avoid setting 0 bytes of buffer data
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
data := make([]float32, (j-i)*va.stride/4)
|
|
||||||
|
|
||||||
for vertex := i; vertex < j; vertex++ {
|
|
||||||
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:
|
|
||||||
data[offset/4] = value.(float32)
|
|
||||||
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")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
gl.BufferSubData(gl.ARRAY_BUFFER, i*va.stride, len(data)*4, gl.Ptr(data))
|
gl.BufferSubData(gl.ARRAY_BUFFER, i*va.stride, len(data)*4, gl.Ptr(data))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (va *vertexArray) vertexData(i, j int) []VertexData {
|
func (va *vertexArray) vertexData(i, j int) []float32 {
|
||||||
if j-i == 0 {
|
if j-i == 0 {
|
||||||
// avoid getting 0 bytes of buffer data
|
// avoid getting 0 bytes of buffer data
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
data := make([]float32, (j-i)*va.stride/4)
|
data := make([]float32, (j-i)*va.stride/4)
|
||||||
|
|
||||||
gl.GetBufferSubData(gl.ARRAY_BUFFER, i*va.stride, len(data)*4, gl.Ptr(data))
|
gl.GetBufferSubData(gl.ARRAY_BUFFER, i*va.stride, len(data)*4, gl.Ptr(data))
|
||||||
|
return data
|
||||||
vertices := make([]VertexData, 0, (j - i))
|
|
||||||
|
|
||||||
for vertex := i; vertex < j; vertex++ {
|
|
||||||
values := make(map[Attr]interface{})
|
|
||||||
|
|
||||||
for name, typ := range va.format {
|
|
||||||
attr := Attr{name, typ}
|
|
||||||
offset := va.stride*vertex + va.offset[attr.Name]
|
|
||||||
|
|
||||||
switch attr.Type {
|
|
||||||
case Float:
|
|
||||||
values[attr] = data[offset/4]
|
|
||||||
case Vec2:
|
|
||||||
var value mgl32.Vec2
|
|
||||||
copy(value[:], data[offset/4:offset/4+attr.Type.Size()/4])
|
|
||||||
values[attr] = value
|
|
||||||
case Vec3:
|
|
||||||
var value mgl32.Vec3
|
|
||||||
copy(value[:], data[offset/4:offset/4+attr.Type.Size()/4])
|
|
||||||
values[attr] = value
|
|
||||||
case Vec4:
|
|
||||||
var value mgl32.Vec4
|
|
||||||
copy(value[:], data[offset/4:offset/4+attr.Type.Size()/4])
|
|
||||||
values[attr] = value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vertices = append(vertices, values)
|
|
||||||
}
|
|
||||||
|
|
||||||
return vertices
|
|
||||||
}
|
}
|
||||||
|
|
117
window.go
117
window.go
|
@ -363,11 +363,11 @@ func (w *Window) end() {
|
||||||
type windowTriangles struct {
|
type windowTriangles struct {
|
||||||
w *Window
|
w *Window
|
||||||
vs *pixelgl.VertexSlice
|
vs *pixelgl.VertexSlice
|
||||||
data []pixelgl.VertexData
|
data []float32
|
||||||
}
|
}
|
||||||
|
|
||||||
func (wt *windowTriangles) Len() int {
|
func (wt *windowTriangles) Len() int {
|
||||||
return len(wt.data)
|
return len(wt.data) / wt.vs.Stride()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (wt *windowTriangles) Draw() {
|
func (wt *windowTriangles) Draw() {
|
||||||
|
@ -397,15 +397,14 @@ func (wt *windowTriangles) Draw() {
|
||||||
|
|
||||||
func (wt *windowTriangles) resize(len int) {
|
func (wt *windowTriangles) resize(len int) {
|
||||||
if len > wt.Len() {
|
if len > wt.Len() {
|
||||||
newData := make([]pixelgl.VertexData, len-wt.Len())
|
needAppend := len - wt.Len()
|
||||||
// default values
|
for i := 0; i < needAppend; i++ {
|
||||||
for i := range newData {
|
wt.data = append(wt.data,
|
||||||
newData[i] = pixelgl.VertexData{
|
0, 0,
|
||||||
colorVec4: mgl32.Vec4{1, 1, 1, 1},
|
1, 1, 1, 1,
|
||||||
textureVec2: mgl32.Vec2{-1, -1},
|
-1, -1,
|
||||||
}
|
)
|
||||||
}
|
}
|
||||||
wt.data = append(wt.data, newData...)
|
|
||||||
}
|
}
|
||||||
if len < wt.Len() {
|
if len < wt.Len() {
|
||||||
wt.data = wt.data[:len]
|
wt.data = wt.data[:len]
|
||||||
|
@ -416,30 +415,24 @@ func (wt *windowTriangles) updateData(offset int, t Triangles) {
|
||||||
if t, ok := t.(TrianglesPosition); ok {
|
if t, ok := t.(TrianglesPosition); ok {
|
||||||
for i := offset; i < offset+t.Len(); i++ {
|
for i := offset; i < offset+t.Len(); i++ {
|
||||||
px, py := t.Position(i).XY()
|
px, py := t.Position(i).XY()
|
||||||
wt.data[i][positionVec2] = mgl32.Vec2{
|
wt.data[i*wt.vs.Stride()+0] = float32(px)
|
||||||
float32(px),
|
wt.data[i*wt.vs.Stride()+1] = float32(py)
|
||||||
float32(py),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if t, ok := t.(TrianglesColor); ok {
|
if t, ok := t.(TrianglesColor); ok {
|
||||||
for i := offset; i < offset+t.Len(); i++ {
|
for i := offset; i < offset+t.Len(); i++ {
|
||||||
col := t.Color(i)
|
col := t.Color(i)
|
||||||
wt.data[i][colorVec4] = mgl32.Vec4{
|
wt.data[i*wt.vs.Stride()+2] = float32(col.R)
|
||||||
float32(col.R),
|
wt.data[i*wt.vs.Stride()+3] = float32(col.G)
|
||||||
float32(col.G),
|
wt.data[i*wt.vs.Stride()+4] = float32(col.B)
|
||||||
float32(col.B),
|
wt.data[i*wt.vs.Stride()+5] = float32(col.A)
|
||||||
float32(col.A),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if t, ok := t.(TrianglesTexture); ok {
|
if t, ok := t.(TrianglesTexture); ok {
|
||||||
for i := offset; i < offset+t.Len(); i++ {
|
for i := offset; i < offset+t.Len(); i++ {
|
||||||
tx, ty := t.Texture(i).XY()
|
tx, ty := t.Texture(i).XY()
|
||||||
wt.data[i][textureVec2] = mgl32.Vec2{
|
wt.data[i*wt.vs.Stride()+6] = float32(tx)
|
||||||
float32(tx),
|
wt.data[i*wt.vs.Stride()+7] = float32(ty)
|
||||||
float32(ty),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -448,11 +441,12 @@ func (wt *windowTriangles) submitData() {
|
||||||
data := wt.data // avoid race condition
|
data := wt.data // avoid race condition
|
||||||
pixelgl.DoNoBlock(func() {
|
pixelgl.DoNoBlock(func() {
|
||||||
wt.vs.Begin()
|
wt.vs.Begin()
|
||||||
if len(wt.data) > wt.vs.Len() {
|
dataLen := len(data) / wt.vs.Stride()
|
||||||
wt.vs.Append(make([]pixelgl.VertexData, len(data)-wt.vs.Len())...)
|
if dataLen > wt.vs.Len() {
|
||||||
|
wt.vs.Append(make([]float32, (dataLen-wt.vs.Len())*wt.vs.Stride()))
|
||||||
}
|
}
|
||||||
if len(wt.data) < wt.vs.Len() {
|
if dataLen < wt.vs.Len() {
|
||||||
wt.vs = wt.vs.Slice(0, len(wt.data))
|
wt.vs = wt.vs.Slice(0, dataLen)
|
||||||
}
|
}
|
||||||
wt.vs.SetVertexData(wt.data)
|
wt.vs.SetVertexData(wt.data)
|
||||||
wt.vs.End()
|
wt.vs.End()
|
||||||
|
@ -481,23 +475,28 @@ func (wt *windowTriangles) Copy() Triangles {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (wt *windowTriangles) Position(i int) Vec {
|
func (wt *windowTriangles) Position(i int) Vec {
|
||||||
v := wt.data[i][positionVec2].(mgl32.Vec2)
|
px := wt.data[i*wt.vs.Stride()+0]
|
||||||
return V(float64(v.X()), float64(v.Y()))
|
py := wt.data[i*wt.vs.Stride()+1]
|
||||||
|
return V(float64(px), float64(py))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (wt *windowTriangles) Color(i int) NRGBA {
|
func (wt *windowTriangles) Color(i int) NRGBA {
|
||||||
c := wt.data[i][colorVec4].(mgl32.Vec4)
|
r := wt.data[i*wt.vs.Stride()+2]
|
||||||
|
g := wt.data[i*wt.vs.Stride()+3]
|
||||||
|
b := wt.data[i*wt.vs.Stride()+4]
|
||||||
|
a := wt.data[i*wt.vs.Stride()+5]
|
||||||
return NRGBA{
|
return NRGBA{
|
||||||
R: float64(c.X()),
|
R: float64(r),
|
||||||
G: float64(c.Y()),
|
G: float64(g),
|
||||||
B: float64(c.Z()),
|
B: float64(b),
|
||||||
A: float64(c.W()),
|
A: float64(a),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (wt *windowTriangles) Texture(i int) Vec {
|
func (wt *windowTriangles) Texture(i int) Vec {
|
||||||
t := wt.data[i][textureVec2].(mgl32.Vec2)
|
tx := wt.data[i*wt.vs.Stride()+6]
|
||||||
return V(float64(t.X()), float64(t.Y()))
|
ty := wt.data[i*wt.vs.Stride()+7]
|
||||||
|
return V(float64(tx), float64(ty))
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeTriangles generates a specialized copy of the supplied triangles that will draw onto this
|
// MakeTriangles generates a specialized copy of the supplied triangles that will draw onto this
|
||||||
|
@ -538,15 +537,26 @@ func (w *Window) SetMaskColor(c color.Color) {
|
||||||
w.col = mgl32.Vec4{r, g, b, a}
|
w.col = mgl32.Vec4{r, g, b, a}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
positionVec2 int = iota
|
||||||
|
colorVec4
|
||||||
|
textureVec2
|
||||||
|
)
|
||||||
|
|
||||||
var defaultVertexFormat = pixelgl.AttrFormat{
|
var defaultVertexFormat = pixelgl.AttrFormat{
|
||||||
"position": pixelgl.Vec2,
|
positionVec2: {Name: "position", Type: pixelgl.Vec2},
|
||||||
"color": pixelgl.Vec4,
|
colorVec4: {Name: "color", Type: pixelgl.Vec4},
|
||||||
"texture": pixelgl.Vec2,
|
textureVec2: {Name: "texture", Type: pixelgl.Vec2},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
maskColorVec4 int = iota
|
||||||
|
transformMat3
|
||||||
|
)
|
||||||
|
|
||||||
var defaultUniformFormat = pixelgl.AttrFormat{
|
var defaultUniformFormat = pixelgl.AttrFormat{
|
||||||
"maskColor": pixelgl.Vec4,
|
{Name: "maskColor", Type: pixelgl.Vec4},
|
||||||
"transform": pixelgl.Mat3,
|
{Name: "transform", Type: pixelgl.Mat3},
|
||||||
}
|
}
|
||||||
|
|
||||||
var defaultVertexShader = `
|
var defaultVertexShader = `
|
||||||
|
@ -587,26 +597,3 @@ void main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
var (
|
|
||||||
positionVec2 = pixelgl.Attr{
|
|
||||||
Name: "position",
|
|
||||||
Type: pixelgl.Vec2,
|
|
||||||
}
|
|
||||||
colorVec4 = pixelgl.Attr{
|
|
||||||
Name: "color",
|
|
||||||
Type: pixelgl.Vec4,
|
|
||||||
}
|
|
||||||
textureVec2 = pixelgl.Attr{
|
|
||||||
Name: "texture",
|
|
||||||
Type: pixelgl.Vec2,
|
|
||||||
}
|
|
||||||
maskColorVec4 = pixelgl.Attr{
|
|
||||||
Name: "maskColor",
|
|
||||||
Type: pixelgl.Vec4,
|
|
||||||
}
|
|
||||||
transformMat3 = pixelgl.Attr{
|
|
||||||
Name: "transform",
|
|
||||||
Type: pixelgl.Mat3,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
Loading…
Reference in New Issue