mirror of
https://github.com/bloeys/nmage.git
synced 2025-12-29 05:18:21 +00:00
Struct to ubo support
This commit is contained in:
@ -1,6 +1,9 @@
|
||||
package buffers
|
||||
|
||||
import (
|
||||
"math"
|
||||
"reflect"
|
||||
|
||||
"github.com/bloeys/gglm/gglm"
|
||||
"github.com/bloeys/nmage/assert"
|
||||
"github.com/bloeys/nmage/logging"
|
||||
@ -141,6 +144,217 @@ func (ub *UniformBuffer) SetMat4(fieldId uint16, val *gglm.Mat4) {
|
||||
gl.BufferSubData(gl.UNIFORM_BUFFER, int(f.AlignedOffset), 4*16, gl.Ptr(&val.Data[0][0]))
|
||||
}
|
||||
|
||||
func (ub *UniformBuffer) SetStruct(inputStruct any) {
|
||||
|
||||
if inputStruct == nil {
|
||||
logging.ErrLog.Panicf("UniformBuffer.SetStruct called with a value that is nil")
|
||||
}
|
||||
|
||||
structVal := reflect.ValueOf(inputStruct)
|
||||
if structVal.Kind() != reflect.Struct {
|
||||
logging.ErrLog.Panicf("UniformBuffer.SetStruct called with a value that is not a struct. Val=%v\n", inputStruct)
|
||||
}
|
||||
|
||||
if structVal.NumField() != len(ub.Fields) {
|
||||
logging.ErrLog.Panicf("struct fields must match uniform buffer fields, but uniform buffer contains %d fields, while the passed struct has %d fields\n", len(ub.Fields), structVal.NumField())
|
||||
}
|
||||
|
||||
writeIndex := 0
|
||||
buf := make([]byte, ub.Size)
|
||||
for i := 0; i < len(ub.Fields); i++ {
|
||||
|
||||
ubField := &ub.Fields[i]
|
||||
valField := structVal.Field(i)
|
||||
|
||||
if valField.Kind() == reflect.Pointer {
|
||||
valField = valField.Elem()
|
||||
}
|
||||
|
||||
typeMatches := false
|
||||
writeIndex = int(ubField.AlignedOffset)
|
||||
|
||||
switch ubField.Type {
|
||||
|
||||
case DataTypeUint32:
|
||||
t := valField.Type()
|
||||
typeMatches = t.Name() == "uint32"
|
||||
|
||||
if typeMatches {
|
||||
Write32BitIntegerToByteBuf(buf, &writeIndex, uint32(valField.Uint()))
|
||||
}
|
||||
|
||||
case DataTypeFloat32:
|
||||
t := valField.Type()
|
||||
typeMatches = t.Name() == "float32"
|
||||
|
||||
if typeMatches {
|
||||
WriteF32ToByteBuf(buf, &writeIndex, float32(valField.Float()))
|
||||
}
|
||||
|
||||
case DataTypeInt32:
|
||||
t := valField.Type()
|
||||
typeMatches = t.Name() == "int32"
|
||||
|
||||
if typeMatches {
|
||||
Write32BitIntegerToByteBuf(buf, &writeIndex, uint32(valField.Int()))
|
||||
}
|
||||
|
||||
case DataTypeVec2:
|
||||
|
||||
v2, ok := valField.Interface().(gglm.Vec2)
|
||||
typeMatches = ok
|
||||
|
||||
if typeMatches {
|
||||
WriteF32SliceToByteBuf(buf, &writeIndex, v2.Data[:])
|
||||
}
|
||||
|
||||
case DataTypeVec3:
|
||||
v3, ok := valField.Interface().(gglm.Vec3)
|
||||
typeMatches = ok
|
||||
|
||||
if typeMatches {
|
||||
WriteF32SliceToByteBuf(buf, &writeIndex, v3.Data[:])
|
||||
}
|
||||
|
||||
case DataTypeVec4:
|
||||
v4, ok := valField.Interface().(gglm.Vec4)
|
||||
typeMatches = ok
|
||||
|
||||
if typeMatches {
|
||||
WriteF32SliceToByteBuf(buf, &writeIndex, v4.Data[:])
|
||||
}
|
||||
|
||||
case DataTypeMat2:
|
||||
m2, ok := valField.Interface().(gglm.Mat2)
|
||||
typeMatches = ok
|
||||
|
||||
if typeMatches {
|
||||
WriteF32SliceToByteBuf(buf, &writeIndex, m2.Data[0][:])
|
||||
WriteF32SliceToByteBuf(buf, &writeIndex, m2.Data[1][:])
|
||||
}
|
||||
|
||||
case DataTypeMat3:
|
||||
m3, ok := valField.Interface().(gglm.Mat3)
|
||||
typeMatches = ok
|
||||
|
||||
if typeMatches {
|
||||
WriteF32SliceToByteBuf(buf, &writeIndex, m3.Data[0][:])
|
||||
WriteF32SliceToByteBuf(buf, &writeIndex, m3.Data[1][:])
|
||||
WriteF32SliceToByteBuf(buf, &writeIndex, m3.Data[2][:])
|
||||
}
|
||||
|
||||
case DataTypeMat4:
|
||||
m4, ok := valField.Interface().(gglm.Mat4)
|
||||
typeMatches = ok
|
||||
|
||||
if typeMatches {
|
||||
WriteF32SliceToByteBuf(buf, &writeIndex, m4.Data[0][:])
|
||||
WriteF32SliceToByteBuf(buf, &writeIndex, m4.Data[1][:])
|
||||
WriteF32SliceToByteBuf(buf, &writeIndex, m4.Data[2][:])
|
||||
WriteF32SliceToByteBuf(buf, &writeIndex, m4.Data[3][:])
|
||||
}
|
||||
|
||||
default:
|
||||
assert.T(false, "Unknown uniform buffer data type passed. DataType '%d'", ubField.Type)
|
||||
}
|
||||
|
||||
if !typeMatches {
|
||||
logging.ErrLog.Panicf("Struct field ordering and types must match uniform buffer fields, but at field index %d got UniformBufferField=%v but a struct field of %s\n", i, ubField, valField.String())
|
||||
}
|
||||
}
|
||||
|
||||
if writeIndex == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
gl.BufferSubData(gl.UNIFORM_BUFFER, 0, writeIndex, gl.Ptr(&buf[0]))
|
||||
}
|
||||
|
||||
func Write32BitIntegerToByteBuf[T uint32 | int32](buf []byte, startIndex *int, val T) {
|
||||
|
||||
assert.T(*startIndex+4 <= len(buf), "failed to write uint32/int32 to buffer because the buffer doesn't have enough space. Start index=%d, Buffer length=%d", *startIndex, len(buf))
|
||||
|
||||
buf[*startIndex] = byte(val)
|
||||
buf[*startIndex+1] = byte(val >> 8)
|
||||
buf[*startIndex+2] = byte(val >> 16)
|
||||
buf[*startIndex+3] = byte(val >> 24)
|
||||
|
||||
*startIndex += 4
|
||||
}
|
||||
|
||||
func WriteF32ToByteBuf(buf []byte, startIndex *int, val float32) {
|
||||
|
||||
assert.T(*startIndex+4 <= len(buf), "failed to write float32 to buffer because the buffer doesn't have enough space. Start index=%d, Buffer length=%d", *startIndex, len(buf))
|
||||
|
||||
bits := math.Float32bits(val)
|
||||
|
||||
buf[*startIndex] = byte(bits)
|
||||
buf[*startIndex+1] = byte(bits >> 8)
|
||||
buf[*startIndex+2] = byte(bits >> 16)
|
||||
buf[*startIndex+3] = byte(bits >> 24)
|
||||
|
||||
*startIndex += 4
|
||||
}
|
||||
|
||||
func WriteF32SliceToByteBuf(buf []byte, startIndex *int, vals []float32) {
|
||||
|
||||
assert.T(*startIndex+4 <= len(buf), "failed to write slice of float32 to buffer because the buffer doesn't have enough space. Start index=%d, Buffer length=%d, but needs %d bytes free", *startIndex, len(buf), len(vals)*4)
|
||||
|
||||
for i := 0; i < len(vals); i++ {
|
||||
|
||||
bits := math.Float32bits(vals[i])
|
||||
|
||||
buf[*startIndex] = byte(bits)
|
||||
buf[*startIndex+1] = byte(bits >> 8)
|
||||
buf[*startIndex+2] = byte(bits >> 16)
|
||||
buf[*startIndex+3] = byte(bits >> 24)
|
||||
|
||||
*startIndex += 4
|
||||
}
|
||||
}
|
||||
|
||||
func ReflectValueMatchesUniformBufferField(v reflect.Value, ubField *UniformBufferField) bool {
|
||||
|
||||
if v.Kind() == reflect.Pointer {
|
||||
v = v.Elem()
|
||||
}
|
||||
|
||||
switch ubField.Type {
|
||||
|
||||
case DataTypeUint32:
|
||||
t := v.Type()
|
||||
return t.Name() == "uint32"
|
||||
case DataTypeFloat32:
|
||||
t := v.Type()
|
||||
return t.Name() == "float32"
|
||||
case DataTypeInt32:
|
||||
t := v.Type()
|
||||
return t.Name() == "int32"
|
||||
case DataTypeVec2:
|
||||
_, ok := v.Interface().(gglm.Vec2)
|
||||
return ok
|
||||
case DataTypeVec3:
|
||||
_, ok := v.Interface().(gglm.Vec3)
|
||||
return ok
|
||||
case DataTypeVec4:
|
||||
_, ok := v.Interface().(gglm.Vec4)
|
||||
return ok
|
||||
case DataTypeMat2:
|
||||
_, ok := v.Interface().(gglm.Mat2)
|
||||
return ok
|
||||
case DataTypeMat3:
|
||||
_, ok := v.Interface().(gglm.Mat3)
|
||||
return ok
|
||||
case DataTypeMat4:
|
||||
_, ok := v.Interface().(gglm.Mat4)
|
||||
return ok
|
||||
|
||||
default:
|
||||
assert.T(false, "Unknown uniform buffer data type passed. DataType '%d'", ubField.Type)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func NewUniformBuffer(fields []UniformBufferFieldInput) UniformBuffer {
|
||||
|
||||
ub := UniformBuffer{}
|
||||
|
||||
75
main.go
75
main.go
@ -671,41 +671,64 @@ func (g *Game) Init() {
|
||||
updateAllProjViewMats(cam.ProjMat, cam.ViewMat)
|
||||
|
||||
// Ubos
|
||||
// testUbos()
|
||||
testUbos()
|
||||
}
|
||||
|
||||
// func testUbos() {
|
||||
func testUbos() {
|
||||
|
||||
// ubo := buffers.NewUniformBuffer([]buffers.UniformBufferFieldInput{
|
||||
// {Id: 0, Type: buffers.DataTypeFloat32}, // 04 00
|
||||
// {Id: 1, Type: buffers.DataTypeVec3}, // 16 16
|
||||
// {Id: 2, Type: buffers.DataTypeFloat32}, // 04 32
|
||||
// {Id: 3, Type: buffers.DataTypeMat2}, // 32 48
|
||||
// }) // Total size: 48+32 = 80
|
||||
ubo := buffers.NewUniformBuffer([]buffers.UniformBufferFieldInput{
|
||||
{Id: 0, Type: buffers.DataTypeFloat32}, // 04 00
|
||||
{Id: 1, Type: buffers.DataTypeVec3}, // 16 16
|
||||
{Id: 2, Type: buffers.DataTypeFloat32}, // 04 32
|
||||
{Id: 3, Type: buffers.DataTypeMat2}, // 32 48
|
||||
}) // Total size: 48+32 = 80
|
||||
|
||||
// println("!!!!!!!!!!!!! Id:", ubo.Id, "; Size:", ubo.Size)
|
||||
// fmt.Printf("%+v\n", ubo.Fields)
|
||||
println("!!!!!!!!!!!!! Id:", ubo.Id, "; Size:", ubo.Size)
|
||||
fmt.Printf("%+v\n", ubo.Fields)
|
||||
|
||||
// ubo.Bind()
|
||||
// ubo.SetFloat32(0, 99)
|
||||
// ubo.SetFloat32(2, 199)
|
||||
// ubo.SetVec3(1, &gglm.Vec3{Data: [3]float32{33, 33, 33}})
|
||||
ubo.Bind()
|
||||
ubo.SetFloat32(0, 99)
|
||||
ubo.SetFloat32(2, 199)
|
||||
ubo.SetVec3(1, &gglm.Vec3{Data: [3]float32{33, 33, 33}})
|
||||
|
||||
// ubo.SetMat2(3, &gglm.Mat2{Data: [2][2]float32{{1, 3}, {2, 4}}})
|
||||
ubo.SetMat2(3, &gglm.Mat2{Data: [2][2]float32{{1, 3}, {2, 4}}})
|
||||
|
||||
// var v gglm.Vec3
|
||||
// var m2 gglm.Mat2
|
||||
// var x, x2 float32
|
||||
// gl.GetBufferSubData(gl.UNIFORM_BUFFER, 0, 4, gl.Ptr(&x))
|
||||
// gl.GetBufferSubData(gl.UNIFORM_BUFFER, 32, 4, gl.Ptr(&x2))
|
||||
// gl.GetBufferSubData(gl.UNIFORM_BUFFER, 16, 12, gl.Ptr(&v.Data[0]))
|
||||
// gl.GetBufferSubData(gl.UNIFORM_BUFFER, 48, 16, gl.Ptr(&m2.Data[0][0]))
|
||||
var v gglm.Vec3
|
||||
var m2 gglm.Mat2
|
||||
var x, x2 float32
|
||||
gl.GetBufferSubData(gl.UNIFORM_BUFFER, 0, 4, gl.Ptr(&x))
|
||||
gl.GetBufferSubData(gl.UNIFORM_BUFFER, 32, 4, gl.Ptr(&x2))
|
||||
gl.GetBufferSubData(gl.UNIFORM_BUFFER, 16, 12, gl.Ptr(&v.Data[0]))
|
||||
gl.GetBufferSubData(gl.UNIFORM_BUFFER, 48, 16, gl.Ptr(&m2.Data[0][0]))
|
||||
|
||||
// fmt.Printf("x=%f; x2=%f; v3=%s; m2=%s\n", x, x2, v.String(), m2.String())
|
||||
fmt.Printf("x=%f; x2=%f; v3=%s; m2=%s\n", x, x2, v.String(), m2.String())
|
||||
|
||||
// ubo.SetVec3(1, &gglm.Vec3{Data: [3]float32{-123, 33, 33}})
|
||||
// gl.GetBufferSubData(gl.UNIFORM_BUFFER, 16, 12, gl.Ptr(&v.Data[0]))
|
||||
// }
|
||||
ubo.SetVec3(1, &gglm.Vec3{Data: [3]float32{-123, 33, 33}})
|
||||
gl.GetBufferSubData(gl.UNIFORM_BUFFER, 16, 12, gl.Ptr(&v.Data[0]))
|
||||
|
||||
type TestUBO struct {
|
||||
FirstF32 float32
|
||||
V3 gglm.Vec3
|
||||
SecondF32 float32
|
||||
M2 gglm.Mat2
|
||||
}
|
||||
|
||||
s := TestUBO{
|
||||
FirstF32: 1.5,
|
||||
V3: gglm.Vec3{Data: [3]float32{11, 22, 33}},
|
||||
SecondF32: 9.5,
|
||||
M2: gglm.Mat2{Data: [2][2]float32{{6, 8}, {7, 9}}},
|
||||
}
|
||||
|
||||
ubo.SetStruct(s)
|
||||
|
||||
gl.GetBufferSubData(gl.UNIFORM_BUFFER, 0, 4, gl.Ptr(&x))
|
||||
gl.GetBufferSubData(gl.UNIFORM_BUFFER, 32, 4, gl.Ptr(&x2))
|
||||
gl.GetBufferSubData(gl.UNIFORM_BUFFER, 16, 12, gl.Ptr(&v.Data[0]))
|
||||
gl.GetBufferSubData(gl.UNIFORM_BUFFER, 48, 16, gl.Ptr(&m2.Data[0][0]))
|
||||
|
||||
fmt.Printf("x=%f; x2=%f; v3=%s; m2=%s\n", x, x2, v.String(), m2.String())
|
||||
}
|
||||
|
||||
func (g *Game) initFbos() {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user