mirror of
https://github.com/bloeys/nmage.git
synced 2025-12-29 13:28:20 +00:00
Compare commits
8 Commits
v0.27.0
...
f2b757c606
| Author | SHA1 | Date | |
|---|---|---|---|
| f2b757c606 | |||
| 3be4ad9c45 | |||
| bbc8652292 | |||
| 0d34e0fe6e | |||
| 870653019c | |||
| 79cb6805c4 | |||
| ff7fe4e531 | |||
| cb20e8ba8b |
@ -1,9 +1,8 @@
|
||||
package buffers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/bloeys/nmage/assert"
|
||||
"github.com/bloeys/nmage/logging"
|
||||
"github.com/go-gl/gl/v4.1-core/gl"
|
||||
)
|
||||
|
||||
@ -14,10 +13,11 @@ type Element struct {
|
||||
}
|
||||
|
||||
// ElementType is the type of an element thats makes up a buffer (e.g. Vec3)
|
||||
type ElementType int
|
||||
type ElementType uint8
|
||||
|
||||
const (
|
||||
DataTypeUnknown ElementType = iota
|
||||
|
||||
DataTypeUint32
|
||||
DataTypeInt32
|
||||
DataTypeFloat32
|
||||
@ -25,35 +25,54 @@ const (
|
||||
DataTypeVec2
|
||||
DataTypeVec3
|
||||
DataTypeVec4
|
||||
|
||||
DataTypeMat2
|
||||
DataTypeMat3
|
||||
DataTypeMat4
|
||||
|
||||
DataTypeStruct
|
||||
)
|
||||
|
||||
func (dt ElementType) GLType() uint32 {
|
||||
|
||||
switch dt {
|
||||
|
||||
case DataTypeUint32:
|
||||
return gl.UNSIGNED_INT
|
||||
case DataTypeInt32:
|
||||
return gl.INT
|
||||
|
||||
case DataTypeFloat32:
|
||||
fallthrough
|
||||
|
||||
case DataTypeVec2:
|
||||
fallthrough
|
||||
case DataTypeVec3:
|
||||
fallthrough
|
||||
case DataTypeVec4:
|
||||
fallthrough
|
||||
case DataTypeMat2:
|
||||
fallthrough
|
||||
case DataTypeMat3:
|
||||
fallthrough
|
||||
case DataTypeMat4:
|
||||
return gl.FLOAT
|
||||
|
||||
case DataTypeStruct:
|
||||
logging.ErrLog.Fatalf("ElementType.GLType of DataTypeStruct is not supported")
|
||||
return 0
|
||||
|
||||
default:
|
||||
assert.T(false, fmt.Sprintf("Unknown data type passed. DataType '%v'", dt))
|
||||
assert.T(false, "Unknown data type passed. DataType '%d'", dt)
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
//CompSize returns the size in bytes for one component of the type (e.g. for Vec2 its 4)
|
||||
// CompSize returns the size in bytes for one component of the type (e.g. for Vec2 its 4).
|
||||
// Bools return 1, although in layout=std140 its 4
|
||||
func (dt ElementType) CompSize() int32 {
|
||||
|
||||
switch dt {
|
||||
|
||||
case DataTypeUint32:
|
||||
fallthrough
|
||||
case DataTypeFloat32:
|
||||
@ -65,10 +84,20 @@ func (dt ElementType) CompSize() int32 {
|
||||
case DataTypeVec3:
|
||||
fallthrough
|
||||
case DataTypeVec4:
|
||||
fallthrough
|
||||
case DataTypeMat2:
|
||||
fallthrough
|
||||
case DataTypeMat3:
|
||||
fallthrough
|
||||
case DataTypeMat4:
|
||||
return 4
|
||||
|
||||
case DataTypeStruct:
|
||||
logging.ErrLog.Fatalf("ElementType.CompSize of DataTypeStruct is not supported")
|
||||
return 0
|
||||
|
||||
default:
|
||||
assert.T(false, fmt.Sprintf("Unknown data type passed. DataType '%v'", dt))
|
||||
assert.T(false, "Unknown data type passed. DataType '%d'", dt)
|
||||
return 0
|
||||
}
|
||||
}
|
||||
@ -91,8 +120,19 @@ func (dt ElementType) CompCount() int32 {
|
||||
case DataTypeVec4:
|
||||
return 4
|
||||
|
||||
case DataTypeMat2:
|
||||
return 2 * 2
|
||||
case DataTypeMat3:
|
||||
return 3 * 3
|
||||
case DataTypeMat4:
|
||||
return 4 * 4
|
||||
|
||||
case DataTypeStruct:
|
||||
logging.ErrLog.Fatalf("ElementType.CompCount of DataTypeStruct is not supported")
|
||||
return 0
|
||||
|
||||
default:
|
||||
assert.T(false, fmt.Sprintf("Unknown data type passed. DataType '%v'", dt))
|
||||
assert.T(false, "Unknown data type passed. DataType '%d'", dt)
|
||||
return 0
|
||||
}
|
||||
}
|
||||
@ -101,6 +141,7 @@ func (dt ElementType) CompCount() int32 {
|
||||
func (dt ElementType) Size() int32 {
|
||||
|
||||
switch dt {
|
||||
|
||||
case DataTypeUint32:
|
||||
fallthrough
|
||||
case DataTypeFloat32:
|
||||
@ -115,8 +156,123 @@ func (dt ElementType) Size() int32 {
|
||||
case DataTypeVec4:
|
||||
return 4 * 4
|
||||
|
||||
case DataTypeMat2:
|
||||
return 2 * 2 * 4
|
||||
case DataTypeMat3:
|
||||
return 3 * 3 * 4
|
||||
case DataTypeMat4:
|
||||
return 4 * 4 * 4
|
||||
|
||||
case DataTypeStruct:
|
||||
logging.ErrLog.Fatalf("ElementType.Size of DataTypeStruct is not supported")
|
||||
return 0
|
||||
|
||||
default:
|
||||
assert.T(false, fmt.Sprintf("Unknown data type passed. DataType '%v'", dt))
|
||||
assert.T(false, "Unknown data type passed. DataType '%d'", dt)
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func (dt ElementType) GlStd140BaseAlignment() uint8 {
|
||||
|
||||
switch dt {
|
||||
|
||||
case DataTypeUint32:
|
||||
fallthrough
|
||||
case DataTypeFloat32:
|
||||
fallthrough
|
||||
case DataTypeInt32:
|
||||
return 4
|
||||
|
||||
case DataTypeVec2:
|
||||
return 4 * 2
|
||||
|
||||
// Vec3 has the same alignment as vec4
|
||||
case DataTypeVec3:
|
||||
fallthrough
|
||||
case DataTypeVec4:
|
||||
return 4 * 4
|
||||
|
||||
// Matrices follow: (vec4Alignment) * numColumns
|
||||
case DataTypeMat2:
|
||||
return (4 * 4) * 2
|
||||
case DataTypeMat3:
|
||||
return (4 * 4) * 3
|
||||
case DataTypeMat4:
|
||||
return (4 * 4) * 4
|
||||
|
||||
case DataTypeStruct:
|
||||
logging.ErrLog.Fatalf("ElementType.GlStd140BaseAlignment of DataTypeStruct is not supported")
|
||||
return 0
|
||||
|
||||
default:
|
||||
assert.T(false, "Unknown data type passed. DataType '%d'", dt)
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func (dt ElementType) GlStd140AlignmentBoundary() uint16 {
|
||||
|
||||
switch dt {
|
||||
|
||||
case DataTypeUint32:
|
||||
fallthrough
|
||||
case DataTypeFloat32:
|
||||
fallthrough
|
||||
case DataTypeInt32:
|
||||
return 4
|
||||
|
||||
case DataTypeVec2:
|
||||
return 8
|
||||
|
||||
case DataTypeVec3:
|
||||
fallthrough
|
||||
case DataTypeVec4:
|
||||
fallthrough
|
||||
case DataTypeMat2:
|
||||
fallthrough
|
||||
case DataTypeMat3:
|
||||
fallthrough
|
||||
case DataTypeMat4:
|
||||
fallthrough
|
||||
case DataTypeStruct:
|
||||
return 16
|
||||
|
||||
default:
|
||||
assert.T(false, "Unknown data type passed. DataType '%d'", dt)
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func (dt ElementType) String() string {
|
||||
|
||||
switch dt {
|
||||
|
||||
case DataTypeUint32:
|
||||
return "uint32"
|
||||
case DataTypeFloat32:
|
||||
return "float32"
|
||||
case DataTypeInt32:
|
||||
return "int32"
|
||||
|
||||
case DataTypeVec2:
|
||||
return "Vec2"
|
||||
case DataTypeVec3:
|
||||
return "Vec3"
|
||||
case DataTypeVec4:
|
||||
return "Vec4"
|
||||
|
||||
case DataTypeMat2:
|
||||
return "Mat2"
|
||||
case DataTypeMat3:
|
||||
return "Mat3"
|
||||
case DataTypeMat4:
|
||||
return "Mat4"
|
||||
|
||||
case DataTypeStruct:
|
||||
return "Struct"
|
||||
|
||||
default:
|
||||
return "Unknown"
|
||||
}
|
||||
}
|
||||
|
||||
702
buffers/uniform_buffer.go
Executable file
702
buffers/uniform_buffer.go
Executable file
@ -0,0 +1,702 @@
|
||||
package buffers
|
||||
|
||||
import (
|
||||
"math"
|
||||
"reflect"
|
||||
|
||||
"github.com/bloeys/gglm/gglm"
|
||||
"github.com/bloeys/nmage/assert"
|
||||
"github.com/bloeys/nmage/logging"
|
||||
"github.com/go-gl/gl/v4.1-core/gl"
|
||||
)
|
||||
|
||||
type UniformBufferFieldInput struct {
|
||||
Id uint16
|
||||
Type ElementType
|
||||
// Count should be set in case this field is an array of type `[Count]Type`.
|
||||
// Count=0 is valid and is equivalent to Count=1, which means the type is NOT an array, but a single field.
|
||||
Count uint16
|
||||
|
||||
// Subfields is used when type is a struct, in which case it holds the fields of the struct.
|
||||
// Ids do not have to be unique across structs.
|
||||
Subfields []UniformBufferFieldInput
|
||||
}
|
||||
|
||||
type UniformBufferField struct {
|
||||
Id uint16
|
||||
AlignedOffset uint16
|
||||
// Count should be set in case this field is an array of type `[Count]Type`.
|
||||
// Count=0 is valid and is equivalent to Count=1, which means the type is NOT an array, but a single field.
|
||||
Count uint16
|
||||
Type ElementType
|
||||
|
||||
// Subfields is used when type is a struct, in which case it holds the fields of the struct.
|
||||
// Ids do not have to be unique across structs.
|
||||
Subfields []UniformBufferField
|
||||
}
|
||||
|
||||
type UniformBuffer struct {
|
||||
Id uint32
|
||||
// Size is the allocated memory in bytes on the GPU for this uniform buffer
|
||||
Size uint32
|
||||
Fields []UniformBufferField
|
||||
}
|
||||
|
||||
func (ub *UniformBuffer) Bind() {
|
||||
gl.BindBuffer(gl.UNIFORM_BUFFER, ub.Id)
|
||||
}
|
||||
|
||||
func (ub *UniformBuffer) UnBind() {
|
||||
gl.BindBuffer(gl.UNIFORM_BUFFER, 0)
|
||||
}
|
||||
|
||||
func (ub *UniformBuffer) SetBindPoint(bindPointIndex uint32) {
|
||||
gl.BindBufferBase(gl.UNIFORM_BUFFER, bindPointIndex, ub.Id)
|
||||
}
|
||||
|
||||
func addUniformBufferFieldsToArray(startAlignedOffset uint16, arrayToAddTo *[]UniformBufferField, fieldsToAdd []UniformBufferFieldInput) (totalSize uint32) {
|
||||
|
||||
if len(fieldsToAdd) == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
// This function is recursive so only size the array once
|
||||
if cap(*arrayToAddTo) == 0 {
|
||||
*arrayToAddTo = make([]UniformBufferField, 0, len(fieldsToAdd))
|
||||
}
|
||||
|
||||
var alignedOffset uint16 = 0
|
||||
fieldIdToTypeMap := make(map[uint16]ElementType, len(fieldsToAdd))
|
||||
|
||||
for i := 0; i < len(fieldsToAdd); i++ {
|
||||
|
||||
f := fieldsToAdd[i]
|
||||
if f.Count == 0 {
|
||||
f.Count = 1
|
||||
}
|
||||
|
||||
existingFieldType, ok := fieldIdToTypeMap[f.Id]
|
||||
assert.T(!ok, "Uniform buffer field id is reused within the same uniform buffer. FieldId=%d was first used on a field with type=%s and then used on a different field with type=%s\n", f.Id, existingFieldType.String(), f.Type.String())
|
||||
|
||||
// To understand this take an example. Say we have a total offset of 100 and we are adding a vec4.
|
||||
// Vec4s must be aligned to a 16 byte boundary but 100 is not (100 % 16 != 0).
|
||||
//
|
||||
// To fix this, we take the alignment error which is alignErr=100 % 16=4, but this is error to the nearest
|
||||
// boundary, which is below the offset.
|
||||
//
|
||||
// To get the nearest boundary larger than the offset we can:
|
||||
// offset + (boundary - alignErr) == 100 + (16 - 4) == 112; 112 % 16 == 0, meaning its a boundary
|
||||
//
|
||||
// Note that arrays of scalars/vectors are always aligned to 16 bytes, like a vec4
|
||||
var alignmentBoundary uint16 = 16
|
||||
if f.Count == 1 {
|
||||
alignmentBoundary = f.Type.GlStd140AlignmentBoundary()
|
||||
}
|
||||
|
||||
alignmentError := alignedOffset % alignmentBoundary
|
||||
if alignmentError != 0 {
|
||||
alignedOffset += alignmentBoundary - alignmentError
|
||||
}
|
||||
|
||||
newField := UniformBufferField{Id: f.Id, Type: f.Type, AlignedOffset: startAlignedOffset + alignedOffset, Count: f.Count}
|
||||
*arrayToAddTo = append(*arrayToAddTo, newField)
|
||||
|
||||
// Prepare aligned offset for the next field.
|
||||
//
|
||||
// Matrices are treated as an array of column vectors, where each column is a vec4,
|
||||
// that's why we have a multiplier depending on how many columns we have when calculating
|
||||
// the offset
|
||||
multiplier := uint16(1)
|
||||
if f.Type == DataTypeMat2 {
|
||||
multiplier = 2
|
||||
} else if f.Type == DataTypeMat3 {
|
||||
multiplier = 3
|
||||
} else if f.Type == DataTypeMat4 {
|
||||
multiplier = 4
|
||||
}
|
||||
|
||||
if f.Type == DataTypeStruct {
|
||||
|
||||
subfieldsAlignedOffset := uint16(addUniformBufferFieldsToArray(startAlignedOffset+alignedOffset, arrayToAddTo, f.Subfields))
|
||||
|
||||
// Pad structs to 16 byte boundary
|
||||
subfieldsAlignmentError := subfieldsAlignedOffset % 16
|
||||
if subfieldsAlignmentError != 0 {
|
||||
subfieldsAlignedOffset += 16 - subfieldsAlignmentError
|
||||
}
|
||||
|
||||
alignedOffset += subfieldsAlignedOffset * f.Count
|
||||
|
||||
} else {
|
||||
alignedOffset = newField.AlignedOffset + alignmentBoundary*f.Count*multiplier - startAlignedOffset
|
||||
}
|
||||
}
|
||||
|
||||
return uint32(alignedOffset)
|
||||
}
|
||||
|
||||
func (ub *UniformBuffer) getField(fieldId uint16, fieldType ElementType) UniformBufferField {
|
||||
|
||||
for i := 0; i < len(ub.Fields); i++ {
|
||||
|
||||
f := ub.Fields[i]
|
||||
|
||||
if f.Id != fieldId {
|
||||
continue
|
||||
}
|
||||
|
||||
assert.T(f.Type == fieldType, "Uniform buffer field id is reused within the same uniform buffer. FieldId=%d was first used on a field with type=%v, but is now being used on a field with type=%v\n", fieldId, f.Type.String(), fieldType.String())
|
||||
|
||||
return f
|
||||
}
|
||||
|
||||
logging.ErrLog.Panicf("couldn't find uniform buffer field of id=%d and type=%s\n", fieldId, fieldType.String())
|
||||
return UniformBufferField{}
|
||||
}
|
||||
|
||||
func (ub *UniformBuffer) SetInt32(fieldId uint16, val int32) {
|
||||
|
||||
f := ub.getField(fieldId, DataTypeInt32)
|
||||
gl.BufferSubData(gl.UNIFORM_BUFFER, int(f.AlignedOffset), 4, gl.Ptr(&val))
|
||||
}
|
||||
|
||||
func (ub *UniformBuffer) SetUint32(fieldId uint16, val uint32) {
|
||||
|
||||
f := ub.getField(fieldId, DataTypeUint32)
|
||||
gl.BufferSubData(gl.UNIFORM_BUFFER, int(f.AlignedOffset), 4, gl.Ptr(&val))
|
||||
}
|
||||
|
||||
func (ub *UniformBuffer) SetFloat32(fieldId uint16, val float32) {
|
||||
|
||||
f := ub.getField(fieldId, DataTypeFloat32)
|
||||
gl.BufferSubData(gl.UNIFORM_BUFFER, int(f.AlignedOffset), 4, gl.Ptr(&val))
|
||||
}
|
||||
|
||||
func (ub *UniformBuffer) SetVec2(fieldId uint16, val *gglm.Vec2) {
|
||||
f := ub.getField(fieldId, DataTypeVec2)
|
||||
gl.BufferSubData(gl.UNIFORM_BUFFER, int(f.AlignedOffset), 4*2, gl.Ptr(&val.Data[0]))
|
||||
}
|
||||
|
||||
func (ub *UniformBuffer) SetVec3(fieldId uint16, val *gglm.Vec3) {
|
||||
f := ub.getField(fieldId, DataTypeVec3)
|
||||
gl.BufferSubData(gl.UNIFORM_BUFFER, int(f.AlignedOffset), 4*3, gl.Ptr(&val.Data[0]))
|
||||
}
|
||||
|
||||
func (ub *UniformBuffer) SetVec4(fieldId uint16, val *gglm.Vec4) {
|
||||
f := ub.getField(fieldId, DataTypeVec4)
|
||||
gl.BufferSubData(gl.UNIFORM_BUFFER, int(f.AlignedOffset), 4*4, gl.Ptr(&val.Data[0]))
|
||||
}
|
||||
|
||||
func (ub *UniformBuffer) SetMat2(fieldId uint16, val *gglm.Mat2) {
|
||||
f := ub.getField(fieldId, DataTypeMat2)
|
||||
gl.BufferSubData(gl.UNIFORM_BUFFER, int(f.AlignedOffset), 4*4, gl.Ptr(&val.Data[0][0]))
|
||||
}
|
||||
|
||||
func (ub *UniformBuffer) SetMat3(fieldId uint16, val *gglm.Mat3) {
|
||||
f := ub.getField(fieldId, DataTypeMat3)
|
||||
gl.BufferSubData(gl.UNIFORM_BUFFER, int(f.AlignedOffset), 4*9, gl.Ptr(&val.Data[0][0]))
|
||||
}
|
||||
|
||||
func (ub *UniformBuffer) SetMat4(fieldId uint16, val *gglm.Mat4) {
|
||||
f := ub.getField(fieldId, DataTypeMat4)
|
||||
gl.BufferSubData(gl.UNIFORM_BUFFER, int(f.AlignedOffset), 4*16, gl.Ptr(&val.Data[0][0]))
|
||||
}
|
||||
|
||||
func (ub *UniformBuffer) SetStruct(inputStruct any) {
|
||||
setStruct(ub.Fields, make([]byte, ub.Size), inputStruct, 1000_000, false)
|
||||
}
|
||||
|
||||
func setStruct(fields []UniformBufferField, buf []byte, inputStruct any, maxFieldsToConsume int, onlyBufWrite bool) (bytesWritten, fieldsConsumed int) {
|
||||
|
||||
if len(fields) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
structFieldIndex := 0
|
||||
// structFieldCount := structVal.NumField()
|
||||
for fieldIndex := 0; fieldIndex < len(fields) && fieldIndex < maxFieldsToConsume; fieldIndex++ {
|
||||
|
||||
ubField := &fields[fieldIndex]
|
||||
valField := structVal.Field(structFieldIndex)
|
||||
|
||||
fieldsConsumed++
|
||||
structFieldIndex++
|
||||
|
||||
kind := valField.Kind()
|
||||
if kind == reflect.Pointer {
|
||||
valField = valField.Elem()
|
||||
}
|
||||
|
||||
var elementType reflect.Type
|
||||
isArray := kind == reflect.Slice || kind == reflect.Array
|
||||
if isArray {
|
||||
elementType = valField.Type().Elem()
|
||||
} else {
|
||||
elementType = valField.Type()
|
||||
}
|
||||
|
||||
if isArray {
|
||||
assert.T(valField.Len() == int(ubField.Count), "ubo field of id=%d is an array/slice field of length=%d but got input of length=%d\n", ubField.Id, ubField.Count, valField.Len())
|
||||
}
|
||||
|
||||
typeMatches := false
|
||||
bytesWritten = int(ubField.AlignedOffset)
|
||||
|
||||
switch ubField.Type {
|
||||
|
||||
case DataTypeUint32:
|
||||
|
||||
typeMatches = elementType.Name() == "uint32"
|
||||
if typeMatches {
|
||||
|
||||
if isArray {
|
||||
Write32BitIntegerSliceToByteBufWithAlignment(buf, &bytesWritten, 16, valField.Slice(0, valField.Len()).Interface().([]uint32))
|
||||
} else {
|
||||
Write32BitIntegerToByteBuf(buf, &bytesWritten, uint32(valField.Uint()))
|
||||
}
|
||||
}
|
||||
|
||||
case DataTypeFloat32:
|
||||
|
||||
typeMatches = elementType.Name() == "float32"
|
||||
if typeMatches {
|
||||
|
||||
if isArray {
|
||||
WriteF32SliceToByteBufWithAlignment(buf, &bytesWritten, 16, valField.Slice(0, valField.Len()).Interface().([]float32))
|
||||
} else {
|
||||
WriteF32ToByteBuf(buf, &bytesWritten, float32(valField.Float()))
|
||||
}
|
||||
}
|
||||
|
||||
case DataTypeInt32:
|
||||
|
||||
typeMatches = elementType.Name() == "int32"
|
||||
if typeMatches {
|
||||
|
||||
if isArray {
|
||||
Write32BitIntegerSliceToByteBufWithAlignment(buf, &bytesWritten, 16, valField.Slice(0, valField.Len()).Interface().([]int32))
|
||||
} else {
|
||||
Write32BitIntegerToByteBuf(buf, &bytesWritten, uint32(valField.Int()))
|
||||
}
|
||||
}
|
||||
|
||||
case DataTypeVec2:
|
||||
|
||||
typeMatches = elementType.Name() == "Vec2"
|
||||
|
||||
if typeMatches {
|
||||
|
||||
if isArray {
|
||||
WriteVec2SliceToByteBufWithAlignment(buf, &bytesWritten, 16, valField.Slice(0, valField.Len()).Interface().([]gglm.Vec2))
|
||||
} else {
|
||||
v2 := valField.Interface().(gglm.Vec2)
|
||||
WriteF32SliceToByteBuf(buf, &bytesWritten, v2.Data[:])
|
||||
}
|
||||
}
|
||||
|
||||
case DataTypeVec3:
|
||||
|
||||
typeMatches = elementType.Name() == "Vec3"
|
||||
|
||||
if typeMatches {
|
||||
|
||||
if isArray {
|
||||
WriteVec3SliceToByteBufWithAlignment(buf, &bytesWritten, 16, valField.Slice(0, valField.Len()).Interface().([]gglm.Vec3))
|
||||
} else {
|
||||
v3 := valField.Interface().(gglm.Vec3)
|
||||
WriteF32SliceToByteBuf(buf, &bytesWritten, v3.Data[:])
|
||||
}
|
||||
}
|
||||
|
||||
case DataTypeVec4:
|
||||
|
||||
typeMatches = elementType.Name() == "Vec4"
|
||||
|
||||
if typeMatches {
|
||||
|
||||
if isArray {
|
||||
WriteVec4SliceToByteBufWithAlignment(buf, &bytesWritten, 16, valField.Slice(0, valField.Len()).Interface().([]gglm.Vec4))
|
||||
} else {
|
||||
v3 := valField.Interface().(gglm.Vec4)
|
||||
WriteF32SliceToByteBuf(buf, &bytesWritten, v3.Data[:])
|
||||
}
|
||||
}
|
||||
|
||||
case DataTypeMat2:
|
||||
|
||||
typeMatches = elementType.Name() == "Mat2"
|
||||
|
||||
if typeMatches {
|
||||
|
||||
if isArray {
|
||||
m2Arr := valField.Interface().([]gglm.Mat2)
|
||||
WriteMat2SliceToByteBufWithAlignment(buf, &bytesWritten, 16*2, m2Arr)
|
||||
} else {
|
||||
m := valField.Interface().(gglm.Mat2)
|
||||
WriteF32SliceToByteBuf(buf, &bytesWritten, m.Data[0][:])
|
||||
WriteF32SliceToByteBuf(buf, &bytesWritten, m.Data[1][:])
|
||||
}
|
||||
}
|
||||
|
||||
case DataTypeMat3:
|
||||
|
||||
typeMatches = elementType.Name() == "Mat3"
|
||||
|
||||
if typeMatches {
|
||||
|
||||
if isArray {
|
||||
m3Arr := valField.Interface().([]gglm.Mat3)
|
||||
WriteMat3SliceToByteBufWithAlignment(buf, &bytesWritten, 16*3, m3Arr)
|
||||
} else {
|
||||
m := valField.Interface().(gglm.Mat3)
|
||||
WriteF32SliceToByteBuf(buf, &bytesWritten, m.Data[0][:])
|
||||
WriteF32SliceToByteBuf(buf, &bytesWritten, m.Data[1][:])
|
||||
WriteF32SliceToByteBuf(buf, &bytesWritten, m.Data[2][:])
|
||||
}
|
||||
}
|
||||
|
||||
case DataTypeMat4:
|
||||
|
||||
typeMatches = elementType.Name() == "Mat4"
|
||||
|
||||
if typeMatches {
|
||||
|
||||
if isArray {
|
||||
m4Arr := valField.Interface().([]gglm.Mat4)
|
||||
WriteMat4SliceToByteBufWithAlignment(buf, &bytesWritten, 16*4, m4Arr)
|
||||
} else {
|
||||
m := valField.Interface().(gglm.Mat4)
|
||||
WriteF32SliceToByteBuf(buf, &bytesWritten, m.Data[0][:])
|
||||
WriteF32SliceToByteBuf(buf, &bytesWritten, m.Data[1][:])
|
||||
WriteF32SliceToByteBuf(buf, &bytesWritten, m.Data[2][:])
|
||||
WriteF32SliceToByteBuf(buf, &bytesWritten, m.Data[3][:])
|
||||
}
|
||||
}
|
||||
|
||||
case DataTypeStruct:
|
||||
typeMatches = kind == reflect.Struct
|
||||
|
||||
if typeMatches {
|
||||
|
||||
setStructBytesWritten, setStructFieldsConsumed := setStruct(fields[fieldIndex+1:], buf, valField.Interface(), valField.NumField(), true)
|
||||
|
||||
bytesWritten += setStructBytesWritten
|
||||
fieldIndex += setStructFieldsConsumed
|
||||
fieldsConsumed += setStructFieldsConsumed
|
||||
}
|
||||
|
||||
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 type %s\n", fieldIndex, ubField, valField.String())
|
||||
}
|
||||
}
|
||||
|
||||
if bytesWritten == 0 {
|
||||
return 0, fieldsConsumed
|
||||
}
|
||||
|
||||
if !onlyBufWrite {
|
||||
gl.BufferSubData(gl.UNIFORM_BUFFER, 0, bytesWritten, gl.Ptr(&buf[0]))
|
||||
}
|
||||
|
||||
return bytesWritten - int(fields[0].AlignedOffset), fieldsConsumed
|
||||
}
|
||||
|
||||
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 Write32BitIntegerSliceToByteBufWithAlignment[T uint32 | int32](buf []byte, startIndex *int, alignmentPerField int, vals []T) {
|
||||
|
||||
assert.T(*startIndex+len(vals)*alignmentPerField <= len(buf), "failed to write uint32/int32 with custom alignment=%d to buffer because the buffer doesn't have enough space. Start index=%d, Buffer length=%d, but needs %d bytes free", alignmentPerField, *startIndex, len(buf), len(vals)*alignmentPerField)
|
||||
|
||||
for i := 0; i < len(vals); i++ {
|
||||
|
||||
val := vals[i]
|
||||
|
||||
buf[*startIndex] = byte(val)
|
||||
buf[*startIndex+1] = byte(val >> 8)
|
||||
buf[*startIndex+2] = byte(val >> 16)
|
||||
buf[*startIndex+3] = byte(val >> 24)
|
||||
|
||||
*startIndex += alignmentPerField
|
||||
}
|
||||
}
|
||||
|
||||
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+len(vals)*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 WriteF32SliceToByteBufWithAlignment(buf []byte, startIndex *int, alignmentPerField int, vals []float32) {
|
||||
|
||||
assert.T(*startIndex+len(vals)*alignmentPerField <= len(buf), "failed to write slice of float32 with custom alignment=%d to buffer because the buffer doesn't have enough space. Start index=%d, Buffer length=%d, but needs %d bytes free", alignmentPerField, *startIndex, len(buf), len(vals)*alignmentPerField)
|
||||
|
||||
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 += alignmentPerField
|
||||
}
|
||||
}
|
||||
|
||||
func WriteVec2SliceToByteBufWithAlignment(buf []byte, startIndex *int, alignmentPerVector int, vals []gglm.Vec2) {
|
||||
|
||||
assert.T(*startIndex+len(vals)*alignmentPerVector <= len(buf), "failed to write slice of gglm.Vec2 with custom alignment=%d to buffer because the buffer doesn't have enough space. Start index=%d, Buffer length=%d, but needs %d bytes free", alignmentPerVector, *startIndex, len(buf), len(vals)*alignmentPerVector)
|
||||
|
||||
for i := 0; i < len(vals); i++ {
|
||||
|
||||
bitsX := math.Float32bits(vals[i].X())
|
||||
bitsY := math.Float32bits(vals[i].Y())
|
||||
|
||||
buf[*startIndex] = byte(bitsX)
|
||||
buf[*startIndex+1] = byte(bitsX >> 8)
|
||||
buf[*startIndex+2] = byte(bitsX >> 16)
|
||||
buf[*startIndex+3] = byte(bitsX >> 24)
|
||||
|
||||
buf[*startIndex+4] = byte(bitsY)
|
||||
buf[*startIndex+5] = byte(bitsY >> 8)
|
||||
buf[*startIndex+6] = byte(bitsY >> 16)
|
||||
buf[*startIndex+7] = byte(bitsY >> 24)
|
||||
|
||||
*startIndex += alignmentPerVector
|
||||
}
|
||||
}
|
||||
|
||||
func WriteVec3SliceToByteBufWithAlignment(buf []byte, startIndex *int, alignmentPerVector int, vals []gglm.Vec3) {
|
||||
|
||||
assert.T(*startIndex+len(vals)*alignmentPerVector <= len(buf), "failed to write slice of gglm.Vec3 with custom alignment=%d to buffer because the buffer doesn't have enough space. Start index=%d, Buffer length=%d, but needs %d bytes free", alignmentPerVector, *startIndex, len(buf), len(vals)*alignmentPerVector)
|
||||
|
||||
for i := 0; i < len(vals); i++ {
|
||||
|
||||
bitsX := math.Float32bits(vals[i].X())
|
||||
bitsY := math.Float32bits(vals[i].Y())
|
||||
bitsZ := math.Float32bits(vals[i].Z())
|
||||
|
||||
buf[*startIndex] = byte(bitsX)
|
||||
buf[*startIndex+1] = byte(bitsX >> 8)
|
||||
buf[*startIndex+2] = byte(bitsX >> 16)
|
||||
buf[*startIndex+3] = byte(bitsX >> 24)
|
||||
|
||||
buf[*startIndex+4] = byte(bitsY)
|
||||
buf[*startIndex+5] = byte(bitsY >> 8)
|
||||
buf[*startIndex+6] = byte(bitsY >> 16)
|
||||
buf[*startIndex+7] = byte(bitsY >> 24)
|
||||
|
||||
buf[*startIndex+8] = byte(bitsZ)
|
||||
buf[*startIndex+9] = byte(bitsZ >> 8)
|
||||
buf[*startIndex+10] = byte(bitsZ >> 16)
|
||||
buf[*startIndex+11] = byte(bitsZ >> 24)
|
||||
|
||||
*startIndex += alignmentPerVector
|
||||
}
|
||||
}
|
||||
|
||||
func WriteVec4SliceToByteBufWithAlignment(buf []byte, startIndex *int, alignmentPerVector int, vals []gglm.Vec4) {
|
||||
|
||||
assert.T(*startIndex+len(vals)*alignmentPerVector <= len(buf), "failed to write slice of gglm.Vec4 with custom alignment=%d to buffer because the buffer doesn't have enough space. Start index=%d, Buffer length=%d, but needs %d bytes free", alignmentPerVector, *startIndex, len(buf), len(vals)*alignmentPerVector)
|
||||
|
||||
for i := 0; i < len(vals); i++ {
|
||||
|
||||
bitsX := math.Float32bits(vals[i].X())
|
||||
bitsY := math.Float32bits(vals[i].Y())
|
||||
bitsZ := math.Float32bits(vals[i].Z())
|
||||
bitsW := math.Float32bits(vals[i].W())
|
||||
|
||||
buf[*startIndex] = byte(bitsX)
|
||||
buf[*startIndex+1] = byte(bitsX >> 8)
|
||||
buf[*startIndex+2] = byte(bitsX >> 16)
|
||||
buf[*startIndex+3] = byte(bitsX >> 24)
|
||||
|
||||
buf[*startIndex+4] = byte(bitsY)
|
||||
buf[*startIndex+5] = byte(bitsY >> 8)
|
||||
buf[*startIndex+6] = byte(bitsY >> 16)
|
||||
buf[*startIndex+7] = byte(bitsY >> 24)
|
||||
|
||||
buf[*startIndex+8] = byte(bitsZ)
|
||||
buf[*startIndex+9] = byte(bitsZ >> 8)
|
||||
buf[*startIndex+10] = byte(bitsZ >> 16)
|
||||
buf[*startIndex+11] = byte(bitsZ >> 24)
|
||||
|
||||
buf[*startIndex+12] = byte(bitsW)
|
||||
buf[*startIndex+13] = byte(bitsW >> 8)
|
||||
buf[*startIndex+14] = byte(bitsW >> 16)
|
||||
buf[*startIndex+15] = byte(bitsW >> 24)
|
||||
|
||||
*startIndex += alignmentPerVector
|
||||
}
|
||||
}
|
||||
|
||||
func WriteMat2SliceToByteBufWithAlignment(buf []byte, startIndex *int, alignmentPerMatrix int, vals []gglm.Mat2) {
|
||||
|
||||
assert.T(*startIndex+len(vals)*alignmentPerMatrix <= len(buf), "failed to write slice of gglm.Mat2 with custom alignment=%d to buffer because the buffer doesn't have enough space. Start index=%d, Buffer length=%d, but needs %d bytes free", alignmentPerMatrix, *startIndex, len(buf), len(vals)*alignmentPerMatrix)
|
||||
|
||||
for i := 0; i < len(vals); i++ {
|
||||
|
||||
m := &vals[i]
|
||||
|
||||
WriteVec2SliceToByteBufWithAlignment(
|
||||
buf,
|
||||
startIndex,
|
||||
16,
|
||||
[]gglm.Vec2{
|
||||
{Data: m.Data[0]},
|
||||
{Data: m.Data[1]},
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func WriteMat3SliceToByteBufWithAlignment(buf []byte, startIndex *int, alignmentPerMatrix int, vals []gglm.Mat3) {
|
||||
|
||||
assert.T(*startIndex+len(vals)*alignmentPerMatrix <= len(buf), "failed to write slice of gglm.Mat3 with custom alignment=%d to buffer because the buffer doesn't have enough space. Start index=%d, Buffer length=%d, but needs %d bytes free", alignmentPerMatrix, *startIndex, len(buf), len(vals)*alignmentPerMatrix)
|
||||
|
||||
for i := 0; i < len(vals); i++ {
|
||||
|
||||
m := &vals[i]
|
||||
|
||||
WriteVec3SliceToByteBufWithAlignment(
|
||||
buf,
|
||||
startIndex,
|
||||
16,
|
||||
[]gglm.Vec3{
|
||||
{Data: m.Data[0]},
|
||||
{Data: m.Data[1]},
|
||||
{Data: m.Data[2]},
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func WriteMat4SliceToByteBufWithAlignment(buf []byte, startIndex *int, alignmentPerMatrix int, vals []gglm.Mat4) {
|
||||
|
||||
assert.T(*startIndex+len(vals)*alignmentPerMatrix <= len(buf), "failed to write slice of gglm.Mat2 with custom alignment=%d to buffer because the buffer doesn't have enough space. Start index=%d, Buffer length=%d, but needs %d bytes free", alignmentPerMatrix, *startIndex, len(buf), len(vals)*alignmentPerMatrix)
|
||||
|
||||
for i := 0; i < len(vals); i++ {
|
||||
|
||||
m := &vals[i]
|
||||
|
||||
WriteVec4SliceToByteBufWithAlignment(
|
||||
buf,
|
||||
startIndex,
|
||||
16,
|
||||
[]gglm.Vec4{
|
||||
{Data: m.Data[0]},
|
||||
{Data: m.Data[1]},
|
||||
{Data: m.Data[2]},
|
||||
{Data: m.Data[3]},
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
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{}
|
||||
|
||||
ub.Size = addUniformBufferFieldsToArray(0, &ub.Fields, fields)
|
||||
|
||||
gl.GenBuffers(1, &ub.Id)
|
||||
if ub.Id == 0 {
|
||||
logging.ErrLog.Panicln("Failed to create OpenGL buffer for a uniform buffer")
|
||||
}
|
||||
|
||||
ub.Bind()
|
||||
gl.BufferData(gl.UNIFORM_BUFFER, int(ub.Size), gl.Ptr(nil), gl.STATIC_DRAW)
|
||||
ub.UnBind()
|
||||
|
||||
return ub
|
||||
}
|
||||
@ -55,7 +55,7 @@ func NewVertexBuffer(layout ...Element) VertexBuffer {
|
||||
|
||||
gl.GenBuffers(1, &vb.Id)
|
||||
if vb.Id == 0 {
|
||||
logging.ErrLog.Println("Failed to create OpenGL buffer")
|
||||
logging.ErrLog.Panicln("Failed to create OpenGL buffer")
|
||||
}
|
||||
|
||||
vb.SetLayout(layout...)
|
||||
|
||||
397
main.go
397
main.go
@ -3,6 +3,7 @@ package main
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"runtime/pprof"
|
||||
"strconv"
|
||||
@ -40,14 +41,14 @@ import (
|
||||
- HDR ✅
|
||||
- Fix bad point light acne ✅
|
||||
- UBO support
|
||||
- Cascaded shadow mapping
|
||||
- Skeletal animations
|
||||
- Cascaded shadow mapping
|
||||
- In some cases we DO want input even when captured by UI. We need two systems within input package, one filtered and one not✅
|
||||
- (?) Support OpenGL 4.1 and 4.6, and default to 4.6
|
||||
- Proper model loading (i.e. load model by reading all its meshes, textures, and so on together)
|
||||
- Renderer batching
|
||||
- Scene graph
|
||||
- Separate engine loop from rendering loop? or leave it to the user?
|
||||
- Abstract keys enum away from sdl?
|
||||
- (?) Separate engine loop from rendering loop
|
||||
- Frustum culling
|
||||
- Proper Asset loading system
|
||||
- Material system editor with fields automatically extracted from the shader
|
||||
@ -207,17 +208,38 @@ func (s *SpotLight) OuterCutoffCos() float32 {
|
||||
return gglm.Cos32(s.OuterCutoffRad)
|
||||
}
|
||||
|
||||
type GlobalMatricesUboData struct {
|
||||
CamPos gglm.Vec3
|
||||
ProjViewMat gglm.Mat4
|
||||
}
|
||||
|
||||
type DirLightUboData struct {
|
||||
Dir gglm.Vec3
|
||||
DiffuseColor gglm.Vec3
|
||||
SpecularColor gglm.Vec3
|
||||
Shadowmap int32
|
||||
}
|
||||
type LightsUboData struct {
|
||||
DirLight DirLightUboData
|
||||
}
|
||||
|
||||
const (
|
||||
UNSCALED_WINDOW_WIDTH = 1280
|
||||
UNSCALED_WINDOW_HEIGHT = 720
|
||||
|
||||
PROFILE_CPU = true
|
||||
PROFILE_MEM = true
|
||||
PROFILE_CPU = false
|
||||
PROFILE_MEM = false
|
||||
|
||||
FRAME_TIME_MS_SAMPLES = 10000
|
||||
)
|
||||
|
||||
var (
|
||||
globalMatricesUboData GlobalMatricesUboData
|
||||
globalMatricesUbo buffers.UniformBuffer
|
||||
|
||||
lightsUboData LightsUboData
|
||||
lightsUbo buffers.UniformBuffer
|
||||
|
||||
frameTimesMsIndex int = 0
|
||||
frameTimesMs []float32 = make([]float32, 0, FRAME_TIME_MS_SAMPLES)
|
||||
|
||||
@ -568,10 +590,7 @@ func (g *Game) Init() {
|
||||
whiteMat.SetUnifInt32("material.emission", int32(materials.TextureSlot_Emission))
|
||||
whiteMat.SetUnifVec3("ambientColor", &ambientColor)
|
||||
whiteMat.SetUnifFloat32("material.shininess", whiteMat.Shininess)
|
||||
whiteMat.SetUnifVec3("dirLight.dir", &dirLight.Dir)
|
||||
whiteMat.SetUnifVec3("dirLight.diffuseColor", &dirLight.DiffuseColor)
|
||||
whiteMat.SetUnifVec3("dirLight.specularColor", &dirLight.SpecularColor)
|
||||
whiteMat.SetUnifInt32("dirLight.shadowMap", int32(materials.TextureSlot_ShadowMap1))
|
||||
whiteMat.SetUnifInt32("dirLightShadowMap", int32(materials.TextureSlot_ShadowMap1))
|
||||
whiteMat.SetUnifInt32("pointLightCubeShadowMaps", int32(materials.TextureSlot_Cubemap_Array))
|
||||
whiteMat.SetUnifInt32("spotLightShadowMaps", int32(materials.TextureSlot_ShadowMap_Array1))
|
||||
|
||||
@ -586,10 +605,7 @@ func (g *Game) Init() {
|
||||
containerMat.SetUnifInt32("material.emission", int32(materials.TextureSlot_Emission))
|
||||
containerMat.SetUnifVec3("ambientColor", &ambientColor)
|
||||
containerMat.SetUnifFloat32("material.shininess", containerMat.Shininess)
|
||||
containerMat.SetUnifVec3("dirLight.dir", &dirLight.Dir)
|
||||
containerMat.SetUnifVec3("dirLight.diffuseColor", &dirLight.DiffuseColor)
|
||||
containerMat.SetUnifVec3("dirLight.specularColor", &dirLight.SpecularColor)
|
||||
containerMat.SetUnifInt32("dirLight.shadowMap", int32(materials.TextureSlot_ShadowMap1))
|
||||
containerMat.SetUnifInt32("dirLightShadowMap", int32(materials.TextureSlot_ShadowMap1))
|
||||
containerMat.SetUnifInt32("pointLightCubeShadowMaps", int32(materials.TextureSlot_Cubemap_Array))
|
||||
containerMat.SetUnifInt32("spotLightShadowMaps", int32(materials.TextureSlot_ShadowMap_Array1))
|
||||
|
||||
@ -604,10 +620,7 @@ func (g *Game) Init() {
|
||||
groundMat.SetUnifInt32("material.emission", int32(materials.TextureSlot_Emission))
|
||||
groundMat.SetUnifVec3("ambientColor", &ambientColor)
|
||||
groundMat.SetUnifFloat32("material.shininess", groundMat.Shininess)
|
||||
groundMat.SetUnifVec3("dirLight.dir", &dirLight.Dir)
|
||||
groundMat.SetUnifVec3("dirLight.diffuseColor", &dirLight.DiffuseColor)
|
||||
groundMat.SetUnifVec3("dirLight.specularColor", &dirLight.SpecularColor)
|
||||
groundMat.SetUnifInt32("dirLight.shadowMap", int32(materials.TextureSlot_ShadowMap1))
|
||||
groundMat.SetUnifInt32("dirLightShadowMap", int32(materials.TextureSlot_ShadowMap1))
|
||||
groundMat.SetUnifInt32("pointLightCubeShadowMaps", int32(materials.TextureSlot_Cubemap_Array))
|
||||
groundMat.SetUnifInt32("spotLightShadowMaps", int32(materials.TextureSlot_ShadowMap_Array1))
|
||||
|
||||
@ -621,10 +634,7 @@ func (g *Game) Init() {
|
||||
palleteMat.SetUnifInt32("material.emission", int32(materials.TextureSlot_Emission))
|
||||
palleteMat.SetUnifVec3("ambientColor", &ambientColor)
|
||||
palleteMat.SetUnifFloat32("material.shininess", palleteMat.Shininess)
|
||||
palleteMat.SetUnifVec3("dirLight.dir", &dirLight.Dir)
|
||||
palleteMat.SetUnifVec3("dirLight.diffuseColor", &dirLight.DiffuseColor)
|
||||
palleteMat.SetUnifVec3("dirLight.specularColor", &dirLight.SpecularColor)
|
||||
palleteMat.SetUnifInt32("dirLight.shadowMap", int32(materials.TextureSlot_ShadowMap1))
|
||||
palleteMat.SetUnifInt32("dirLightShadowMap", int32(materials.TextureSlot_ShadowMap1))
|
||||
palleteMat.SetUnifInt32("pointLightCubeShadowMaps", int32(materials.TextureSlot_Cubemap_Array))
|
||||
palleteMat.SetUnifInt32("spotLightShadowMaps", int32(materials.TextureSlot_ShadowMap_Array1))
|
||||
|
||||
@ -665,11 +675,282 @@ func (g *Game) Init() {
|
||||
g.initFbos()
|
||||
g.updateLights()
|
||||
|
||||
// Ubos
|
||||
g.initUbos()
|
||||
// testUbos()
|
||||
|
||||
// Initial camera update
|
||||
cam.Update()
|
||||
updateAllProjViewMats(cam.ProjMat, cam.ViewMat)
|
||||
}
|
||||
|
||||
func (g *Game) initUbos() {
|
||||
|
||||
globalMatricesUbo = buffers.NewUniformBuffer(
|
||||
[]buffers.UniformBufferFieldInput{
|
||||
{Id: 0, Type: buffers.DataTypeVec3},
|
||||
{Id: 1, Type: buffers.DataTypeMat4},
|
||||
},
|
||||
)
|
||||
|
||||
globalMatricesUbo.SetBindPoint(0)
|
||||
groundMat.SetUniformBlockBindingPoint("GlobalMatrices", 0)
|
||||
whiteMat.SetUniformBlockBindingPoint("GlobalMatrices", 0)
|
||||
containerMat.SetUniformBlockBindingPoint("GlobalMatrices", 0)
|
||||
palleteMat.SetUniformBlockBindingPoint("GlobalMatrices", 0)
|
||||
|
||||
lightsUbo = buffers.NewUniformBuffer(
|
||||
[]buffers.UniformBufferFieldInput{
|
||||
{Id: 0, Type: buffers.DataTypeStruct, Subfields: []buffers.UniformBufferFieldInput{
|
||||
{Id: 1, Type: buffers.DataTypeVec3},
|
||||
{Id: 2, Type: buffers.DataTypeVec3},
|
||||
{Id: 3, Type: buffers.DataTypeVec3},
|
||||
{Id: 4, Type: buffers.DataTypeInt32},
|
||||
}},
|
||||
},
|
||||
)
|
||||
|
||||
lightsUbo.SetBindPoint(1)
|
||||
groundMat.SetUniformBlockBindingPoint("Lights", 1)
|
||||
whiteMat.SetUniformBlockBindingPoint("Lights", 1)
|
||||
containerMat.SetUniformBlockBindingPoint("Lights", 1)
|
||||
palleteMat.SetUniformBlockBindingPoint("Lights", 1)
|
||||
}
|
||||
|
||||
func testUbos() {
|
||||
|
||||
xx := []int{1, 2, 3, 4}
|
||||
xx2 := [4]int{1, 2, 3, 4}
|
||||
fmt.Printf("XX: %v; Kind: %v; Elem Type: %v\n", reflect.ValueOf(xx), reflect.ValueOf(xx).Type().Kind(), reflect.ValueOf(xx).Type().Elem().Kind())
|
||||
fmt.Printf("XX: %v; Kind: %v; Elem Type: %v\n", reflect.ValueOf(xx2), reflect.ValueOf(xx).Kind(), reflect.ValueOf(xx).Type().Elem().Kind())
|
||||
|
||||
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.Bind()
|
||||
|
||||
println("!!!!!!!!!!!!! Id:", ubo.Id, "; Size:", ubo.Size)
|
||||
fmt.Printf("%+v\n", ubo.Fields)
|
||||
|
||||
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}}})
|
||||
|
||||
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())
|
||||
|
||||
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())
|
||||
|
||||
//
|
||||
// Ubo2
|
||||
//
|
||||
type TestUBO2 struct {
|
||||
F32 float32
|
||||
V3 gglm.Vec3
|
||||
F32Slice []float32
|
||||
I32 int32
|
||||
I32Slice []int32
|
||||
V3Slice []gglm.Vec3
|
||||
V4Slice []gglm.Vec4
|
||||
Mat2Slice []gglm.Mat2
|
||||
Mat3Slice []gglm.Mat3
|
||||
Mat4Slice []gglm.Mat4
|
||||
}
|
||||
|
||||
s2 := TestUBO2{
|
||||
F32: 1.5,
|
||||
V3: gglm.Vec3{Data: [3]float32{11, 22, 33}},
|
||||
F32Slice: []float32{-1, -2, -3, -4},
|
||||
I32: 55,
|
||||
I32Slice: []int32{41, 42, 43},
|
||||
V3Slice: []gglm.Vec3{gglm.NewVec3(1.1, 1.2, 1.3), gglm.NewVec3(2.1, 2.2, 2.3)},
|
||||
V4Slice: []gglm.Vec4{gglm.NewVec4(1.1, 1.2, 1.3, 1.4), gglm.NewVec4(2.1, 2.2, 2.3, 2.4)},
|
||||
Mat2Slice: []gglm.Mat2{gglm.NewMat2Diag(1.1), gglm.NewMat2Diag(2.1)},
|
||||
Mat3Slice: []gglm.Mat3{gglm.NewMat3Diag(3.1), gglm.NewMat3Diag(4.1)},
|
||||
Mat4Slice: []gglm.Mat4{gglm.NewMat4Diag(5.1), gglm.NewMat4Diag(6.1)},
|
||||
}
|
||||
|
||||
ubo2 := buffers.NewUniformBuffer([]buffers.UniformBufferFieldInput{
|
||||
{Id: 0, Type: buffers.DataTypeFloat32},
|
||||
{Id: 1, Type: buffers.DataTypeVec3},
|
||||
{Id: 2, Type: buffers.DataTypeFloat32, Count: 4},
|
||||
{Id: 3, Type: buffers.DataTypeInt32},
|
||||
{Id: 4, Type: buffers.DataTypeInt32, Count: 3},
|
||||
{Id: 5, Type: buffers.DataTypeVec3, Count: 2},
|
||||
{Id: 6, Type: buffers.DataTypeVec4, Count: 2},
|
||||
{Id: 7, Type: buffers.DataTypeMat2, Count: 2},
|
||||
{Id: 8, Type: buffers.DataTypeMat3, Count: 2},
|
||||
{Id: 9, Type: buffers.DataTypeMat4, Count: 2},
|
||||
})
|
||||
ubo2.Bind()
|
||||
|
||||
ubo2.SetStruct(s2)
|
||||
|
||||
var someInt32 int32
|
||||
fArr := [4 * 4]float32{}
|
||||
i32Arr := [3 * 4]int32{}
|
||||
vec3Slice := [2 * 4]float32{}
|
||||
vec4Slice := [2 * 4]float32{}
|
||||
mat2Slice := [2 * 2 * 4]float32{}
|
||||
mat3Slice := [2 * 3 * 4]float32{}
|
||||
mat4Slice := [2 * 4 * 4]float32{}
|
||||
gl.GetBufferSubData(gl.UNIFORM_BUFFER, 0, 4, gl.Ptr(&x))
|
||||
gl.GetBufferSubData(gl.UNIFORM_BUFFER, 16, 12, gl.Ptr(&v.Data[0]))
|
||||
gl.GetBufferSubData(gl.UNIFORM_BUFFER, 32, 16*4, gl.Ptr(&fArr[0]))
|
||||
gl.GetBufferSubData(gl.UNIFORM_BUFFER, 32+16*4, 4, gl.Ptr(&someInt32))
|
||||
gl.GetBufferSubData(gl.UNIFORM_BUFFER, 32+16*4+16, 16*3, gl.Ptr(&i32Arr[0]))
|
||||
gl.GetBufferSubData(gl.UNIFORM_BUFFER, 32+16*4+16+16*3, 16*2, gl.Ptr(&vec3Slice[0]))
|
||||
gl.GetBufferSubData(gl.UNIFORM_BUFFER, 32+16*4+16+16*3+16*2, 16*2, gl.Ptr(&vec4Slice[0]))
|
||||
gl.GetBufferSubData(gl.UNIFORM_BUFFER, 32+16*4+16+16*3+16*2+16*2, 2*16*2, gl.Ptr(&mat2Slice[0]))
|
||||
gl.GetBufferSubData(gl.UNIFORM_BUFFER, 32+16*4+16+16*3+16*2+16*2+2*16*2, 2*16*3, gl.Ptr(&mat3Slice[0]))
|
||||
gl.GetBufferSubData(gl.UNIFORM_BUFFER, 32+16*4+16+16*3+16*2+16*2+2*16*2+2*16*3, 2*16*4, gl.Ptr(&mat4Slice[0]))
|
||||
|
||||
fmt.Printf("f32=%f; v3=%s; f32Slice=%v; i32=%d; i32Arr=%v; v3Slice=%v; v4Slice=%v; mat2Slice=%v; mat3Slice=%v; mat4Slice=%v\n", x, v.String(), fArr, someInt32, i32Arr, vec3Slice, vec4Slice, mat2Slice, mat3Slice, mat4Slice)
|
||||
|
||||
//
|
||||
// Ubo3
|
||||
//
|
||||
type TestUBO3_Z struct {
|
||||
V int32
|
||||
}
|
||||
|
||||
type TestUBO3_Y struct {
|
||||
V TestUBO3_Z
|
||||
}
|
||||
|
||||
type TestUBO3_X struct {
|
||||
V TestUBO3_Y
|
||||
}
|
||||
|
||||
type TestUBO3_0 struct {
|
||||
X int32
|
||||
}
|
||||
|
||||
type TestUBO3_1 struct {
|
||||
F32 float32
|
||||
V3 gglm.Vec3
|
||||
Zero TestUBO3_0
|
||||
}
|
||||
|
||||
type TestUBO3_2 struct {
|
||||
F32 float32
|
||||
S TestUBO3_1
|
||||
XX int32
|
||||
Z2 TestUBO3_0
|
||||
XX2 int32
|
||||
Abcd TestUBO3_X
|
||||
}
|
||||
|
||||
ubo3 := buffers.NewUniformBuffer([]buffers.UniformBufferFieldInput{
|
||||
{Id: 0, Type: buffers.DataTypeFloat32}, // 04 00
|
||||
{Id: 1, Type: buffers.DataTypeStruct, Subfields: []buffers.UniformBufferFieldInput{ // 00 16
|
||||
{Id: 2, Type: buffers.DataTypeFloat32}, // 04 16
|
||||
{Id: 3, Type: buffers.DataTypeVec3}, // 16 32
|
||||
{Id: 4, Type: buffers.DataTypeStruct, Subfields: []buffers.UniformBufferFieldInput{ // 00 48
|
||||
{Id: 5, Type: buffers.DataTypeInt32}, // 04 48
|
||||
}},
|
||||
}},
|
||||
{Id: 6, Type: buffers.DataTypeInt32}, // 04 64
|
||||
{Id: 7, Type: buffers.DataTypeStruct, Subfields: []buffers.UniformBufferFieldInput{ // 00 80
|
||||
{Id: 8, Type: buffers.DataTypeInt32}, // 04 80
|
||||
}},
|
||||
{Id: 9, Type: buffers.DataTypeInt32}, // 04 96
|
||||
{Id: 10, Type: buffers.DataTypeStruct, Subfields: []buffers.UniformBufferFieldInput{ // 00 112
|
||||
{Id: 11, Type: buffers.DataTypeStruct, Subfields: []buffers.UniformBufferFieldInput{ // 00 112
|
||||
{Id: 12, Type: buffers.DataTypeStruct, Subfields: []buffers.UniformBufferFieldInput{ // 00 112
|
||||
{Id: 13, Type: buffers.DataTypeInt32}, // 04 112
|
||||
}},
|
||||
}},
|
||||
}},
|
||||
}) // 116
|
||||
ubo3.Bind()
|
||||
|
||||
ubo3.SetBindPoint(2)
|
||||
groundMat.SetUniformBlockBindingPoint("Test2", 2)
|
||||
|
||||
fmt.Printf("\n==UBO3 (id=%d)==\nSize=%d\nFields: %+v\n\n", ubo3.Id, ubo3.Size, ubo3.Fields)
|
||||
|
||||
s3 := TestUBO3_2{
|
||||
F32: 76.1,
|
||||
S: TestUBO3_1{
|
||||
F32: 89.9,
|
||||
V3: gglm.NewVec3(7.1, 7.2, 7.3),
|
||||
Zero: TestUBO3_0{
|
||||
X: 33,
|
||||
},
|
||||
},
|
||||
XX: 41,
|
||||
Z2: TestUBO3_0{
|
||||
X: 8,
|
||||
},
|
||||
XX2: 321,
|
||||
Abcd: TestUBO3_X{
|
||||
V: TestUBO3_Y{
|
||||
V: TestUBO3_Z{
|
||||
V: 9911,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
ubo3.SetStruct(s3)
|
||||
|
||||
ubo3F32 := float32(0.0)
|
||||
ubo3SF32 := float32(0.0)
|
||||
ubo3SV3 := gglm.Vec3{}
|
||||
ubo3SZeroX := 0
|
||||
ubo3Xx := 0
|
||||
ubo3SZ2X := 0
|
||||
ubo3Xx2 := 0
|
||||
ubo3AbcdV := 0
|
||||
gl.GetBufferSubData(gl.UNIFORM_BUFFER, 0, 4, gl.Ptr(&ubo3F32))
|
||||
gl.GetBufferSubData(gl.UNIFORM_BUFFER, 16, 4, gl.Ptr(&ubo3SF32))
|
||||
gl.GetBufferSubData(gl.UNIFORM_BUFFER, 32, 16, gl.Ptr(&ubo3SV3.Data[0]))
|
||||
gl.GetBufferSubData(gl.UNIFORM_BUFFER, 48, 4, gl.Ptr(&ubo3SZeroX))
|
||||
gl.GetBufferSubData(gl.UNIFORM_BUFFER, 64, 4, gl.Ptr(&ubo3Xx))
|
||||
gl.GetBufferSubData(gl.UNIFORM_BUFFER, 64, 4, gl.Ptr(&ubo3Xx))
|
||||
gl.GetBufferSubData(gl.UNIFORM_BUFFER, 80, 4, gl.Ptr(&ubo3SZ2X))
|
||||
gl.GetBufferSubData(gl.UNIFORM_BUFFER, 96, 4, gl.Ptr(&ubo3Xx2))
|
||||
gl.GetBufferSubData(gl.UNIFORM_BUFFER, 112, 4, gl.Ptr(&ubo3AbcdV))
|
||||
|
||||
fmt.Printf("ubo3_f32=%f\nubo3_s_f32=%f\nubo3_s_v3=%s\nubo3_s_zero_x=%d\nubo3_xx=%d\nubo3_z2_x=%d\nubo3_xx2=%d\nubo3_abcd_v=%d\n", ubo3F32, ubo3SF32, ubo3SV3.String(), ubo3SZeroX, ubo3Xx, ubo3SZ2X, ubo3Xx2, ubo3AbcdV)
|
||||
}
|
||||
|
||||
func (g *Game) initFbos() {
|
||||
|
||||
// @TODO: Resize window sized fbos on window resize
|
||||
@ -737,10 +1018,16 @@ func (g *Game) initFbos() {
|
||||
func (g *Game) updateLights() {
|
||||
|
||||
// Directional light
|
||||
whiteMat.ShadowMapTex1 = dirLightDepthMapFbo.Attachments[0].Id
|
||||
containerMat.ShadowMapTex1 = dirLightDepthMapFbo.Attachments[0].Id
|
||||
groundMat.ShadowMapTex1 = dirLightDepthMapFbo.Attachments[0].Id
|
||||
palleteMat.ShadowMapTex1 = dirLightDepthMapFbo.Attachments[0].Id
|
||||
lightsUboData.DirLight = DirLightUboData{
|
||||
Dir: dirLight.Dir,
|
||||
DiffuseColor: dirLight.DiffuseColor,
|
||||
SpecularColor: dirLight.SpecularColor,
|
||||
Shadowmap: int32(dirLightDepthMapFbo.Attachments[0].Id),
|
||||
}
|
||||
whiteMat.ShadowMapTex1 = uint32(lightsUboData.DirLight.Shadowmap)
|
||||
containerMat.ShadowMapTex1 = uint32(lightsUboData.DirLight.Shadowmap)
|
||||
groundMat.ShadowMapTex1 = uint32(lightsUboData.DirLight.Shadowmap)
|
||||
palleteMat.ShadowMapTex1 = uint32(lightsUboData.DirLight.Shadowmap)
|
||||
|
||||
// Point lights
|
||||
for i := 0; i < len(pointLights); i++ {
|
||||
@ -846,6 +1133,9 @@ func (g *Game) updateLights() {
|
||||
containerMat.ShadowMapTexArray1 = spotLightDepthMapFbo.Attachments[0].Id
|
||||
groundMat.ShadowMapTexArray1 = spotLightDepthMapFbo.Attachments[0].Id
|
||||
palleteMat.ShadowMapTexArray1 = spotLightDepthMapFbo.Attachments[0].Id
|
||||
|
||||
lightsUbo.Bind()
|
||||
lightsUbo.SetStruct(lightsUboData)
|
||||
}
|
||||
|
||||
func (g *Game) Update() {
|
||||
@ -857,6 +1147,9 @@ func (g *Game) Update() {
|
||||
g.updateCameraLookAround()
|
||||
g.updateCameraPos()
|
||||
|
||||
globalMatricesUboData.CamPos = cam.Pos
|
||||
updateAllProjViewMats(cam.ProjMat, cam.ViewMat)
|
||||
|
||||
g.showDebugWindow()
|
||||
}
|
||||
|
||||
@ -906,6 +1199,11 @@ func (g *Game) showDebugWindow() {
|
||||
|
||||
imgui.Spacing()
|
||||
|
||||
//
|
||||
// Lights
|
||||
//
|
||||
updateLights := false
|
||||
|
||||
// Ambient light
|
||||
imgui.Text("Ambient Light")
|
||||
|
||||
@ -924,30 +1222,29 @@ func (g *Game) showDebugWindow() {
|
||||
imgui.Checkbox("Render Directional Light Shadows", &renderDirLightShadows)
|
||||
|
||||
if imgui.DragFloat3("Direction", &dirLight.Dir.Data) {
|
||||
whiteMat.SetUnifVec3("dirLight.dir", &dirLight.Dir)
|
||||
containerMat.SetUnifVec3("dirLight.dir", &dirLight.Dir)
|
||||
groundMat.SetUnifVec3("dirLight.dir", &dirLight.Dir)
|
||||
palleteMat.SetUnifVec3("dirLight.dir", &dirLight.Dir)
|
||||
updateLights = true
|
||||
}
|
||||
|
||||
if imgui.ColorEdit3("Diffuse Color", &dirLight.DiffuseColor.Data) {
|
||||
whiteMat.SetUnifVec3("dirLight.diffuseColor", &dirLight.DiffuseColor)
|
||||
containerMat.SetUnifVec3("dirLight.diffuseColor", &dirLight.DiffuseColor)
|
||||
groundMat.SetUnifVec3("dirLight.diffuseColor", &dirLight.DiffuseColor)
|
||||
palleteMat.SetUnifVec3("dirLight.diffuseColor", &dirLight.DiffuseColor)
|
||||
updateLights = true
|
||||
}
|
||||
|
||||
if imgui.ColorEdit3("Specular Color", &dirLight.SpecularColor.Data) {
|
||||
whiteMat.SetUnifVec3("dirLight.specularColor", &dirLight.SpecularColor)
|
||||
containerMat.SetUnifVec3("dirLight.specularColor", &dirLight.SpecularColor)
|
||||
groundMat.SetUnifVec3("dirLight.specularColor", &dirLight.SpecularColor)
|
||||
palleteMat.SetUnifVec3("dirLight.specularColor", &dirLight.SpecularColor)
|
||||
updateLights = true
|
||||
}
|
||||
|
||||
imgui.DragFloat3("dPos", &dirLightPos.Data)
|
||||
imgui.DragFloat("dSize", &dirLightSize)
|
||||
imgui.DragFloat("dNear", &dirLightNear)
|
||||
imgui.DragFloat("dFar", &dirLightFar)
|
||||
if imgui.DragFloat3("dPos", &dirLightPos.Data) {
|
||||
updateLights = true
|
||||
}
|
||||
if imgui.DragFloat("dSize", &dirLightSize) {
|
||||
updateLights = true
|
||||
}
|
||||
if imgui.DragFloat("dNear", &dirLightNear) {
|
||||
updateLights = true
|
||||
}
|
||||
if imgui.DragFloat("dFar", &dirLightFar) {
|
||||
updateLights = true
|
||||
}
|
||||
|
||||
imgui.Spacing()
|
||||
|
||||
@ -1129,6 +1426,10 @@ func (g *Game) showDebugWindow() {
|
||||
imgui.EndListBox()
|
||||
}
|
||||
|
||||
if updateLights {
|
||||
g.updateLights()
|
||||
}
|
||||
|
||||
// Demo fbo
|
||||
imgui.Text("Demo Framebuffer")
|
||||
imgui.Checkbox("Show FBO##0", &renderToDemoFbo)
|
||||
@ -1176,8 +1477,6 @@ func (g *Game) updateCameraLookAround() {
|
||||
}
|
||||
|
||||
cam.UpdateRotation(pitch, yaw)
|
||||
|
||||
updateAllProjViewMats(cam.ProjMat, cam.ViewMat)
|
||||
}
|
||||
|
||||
func (g *Game) updateCameraPos() {
|
||||
@ -1211,7 +1510,6 @@ func (g *Game) updateCameraPos() {
|
||||
|
||||
if update {
|
||||
cam.Update()
|
||||
updateAllProjViewMats(cam.ProjMat, cam.ViewMat)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1226,10 +1524,8 @@ var (
|
||||
|
||||
func (g *Game) Render() {
|
||||
|
||||
whiteMat.SetUnifVec3("camPos", &cam.Pos)
|
||||
containerMat.SetUnifVec3("camPos", &cam.Pos)
|
||||
groundMat.SetUnifVec3("camPos", &cam.Pos)
|
||||
palleteMat.SetUnifVec3("camPos", &cam.Pos)
|
||||
globalMatricesUbo.Bind()
|
||||
globalMatricesUbo.SetStruct(globalMatricesUboData)
|
||||
|
||||
rotatingCubeTrMat1.Rotate(rotatingCubeSpeedDeg1*gglm.Deg2Rad*timing.DT(), 0, 1, 0)
|
||||
rotatingCubeTrMat2.Rotate(rotatingCubeSpeedDeg2*gglm.Deg2Rad*timing.DT(), 1, 1, 0)
|
||||
@ -1482,12 +1778,9 @@ func (g *Game) DeInit() {
|
||||
func updateAllProjViewMats(projMat, viewMat gglm.Mat4) {
|
||||
|
||||
projViewMat := *projMat.Clone().Mul(&viewMat)
|
||||
globalMatricesUboData.ProjViewMat = projViewMat
|
||||
|
||||
unlitMat.SetUnifMat4("projViewMat", &projViewMat)
|
||||
whiteMat.SetUnifMat4("projViewMat", &projViewMat)
|
||||
containerMat.SetUnifMat4("projViewMat", &projViewMat)
|
||||
groundMat.SetUnifMat4("projViewMat", &projViewMat)
|
||||
palleteMat.SetUnifMat4("projViewMat", &projViewMat)
|
||||
debugDepthMat.SetUnifMat4("projViewMat", &projViewMat)
|
||||
|
||||
// Update skybox projViewMat
|
||||
|
||||
@ -124,6 +124,21 @@ func (m *Material) UnBind() {
|
||||
gl.UseProgram(0)
|
||||
}
|
||||
|
||||
func (m *Material) SetUniformBlockBindingPoint(uniformBlockName string, bindPointIndex uint32) {
|
||||
|
||||
nullStr := gl.Str(uniformBlockName + "\x00")
|
||||
index := gl.GetUniformBlockIndex(m.ShaderProg.Id, nullStr)
|
||||
assert.T(
|
||||
index != gl.INVALID_INDEX,
|
||||
"SetUniformBlockBindingPoint for material=%s (matId=%d; shaderId=%d) failed because the uniform block=%s wasn't found",
|
||||
m.Name,
|
||||
m.Id,
|
||||
m.ShaderProg.Id,
|
||||
uniformBlockName,
|
||||
)
|
||||
gl.UniformBlockBinding(m.ShaderProg.Id, index, bindPointIndex)
|
||||
}
|
||||
|
||||
func (m *Material) GetAttribLoc(attribName string) int32 {
|
||||
|
||||
loc, ok := m.AttribLocs[attribName]
|
||||
|
||||
@ -14,22 +14,14 @@ layout(location=3) in vec2 vertUV0In;
|
||||
layout(location=4) in vec3 vertColorIn;
|
||||
|
||||
//
|
||||
// Uniforms
|
||||
// UBOs
|
||||
//
|
||||
uniform vec3 camPos;
|
||||
uniform mat4 modelMat;
|
||||
uniform mat3 normalMat;
|
||||
uniform mat4 projViewMat;
|
||||
uniform mat4 dirLightProjViewMat;
|
||||
uniform mat4 spotLightProjViewMats[NUM_SPOT_LIGHTS];
|
||||
|
||||
struct DirLight {
|
||||
vec3 dir;
|
||||
vec3 diffuseColor;
|
||||
vec3 specularColor;
|
||||
sampler2D shadowMap;
|
||||
};
|
||||
uniform DirLight dirLight;
|
||||
uniform sampler2D dirLightShadowMap;
|
||||
|
||||
struct PointLight {
|
||||
vec3 pos;
|
||||
@ -41,7 +33,6 @@ struct PointLight {
|
||||
float nearPlane;
|
||||
float farPlane;
|
||||
};
|
||||
uniform PointLight pointLights[NUM_POINT_LIGHTS];
|
||||
|
||||
struct SpotLight {
|
||||
vec3 pos;
|
||||
@ -51,7 +42,24 @@ struct SpotLight {
|
||||
float innerCutoff;
|
||||
float outerCutoff;
|
||||
};
|
||||
|
||||
layout (std140) uniform GlobalMatrices {
|
||||
vec3 camPos;
|
||||
mat4 projViewMat;
|
||||
};
|
||||
|
||||
layout (std140) uniform Lights {
|
||||
DirLight dirLight;
|
||||
};
|
||||
|
||||
//
|
||||
// Uniforms
|
||||
//
|
||||
uniform PointLight pointLights[NUM_POINT_LIGHTS];
|
||||
uniform SpotLight spotLights[NUM_SPOT_LIGHTS];
|
||||
uniform mat4 modelMat;
|
||||
uniform mat4 dirLightProjViewMat;
|
||||
uniform mat4 spotLightProjViewMats[NUM_SPOT_LIGHTS];
|
||||
|
||||
//
|
||||
// Outputs
|
||||
@ -70,6 +78,16 @@ out vec3 tangentSpotLightPositions[NUM_SPOT_LIGHTS];
|
||||
out vec3 tangentSpotLightDirections[NUM_SPOT_LIGHTS];
|
||||
out vec3 tangentPointLightPositions[NUM_POINT_LIGHTS];
|
||||
|
||||
struct Test1 {
|
||||
float ff;
|
||||
vec3 v3;
|
||||
};
|
||||
|
||||
layout (std140) uniform Test2 {
|
||||
float f1;
|
||||
Test1 s;
|
||||
};
|
||||
|
||||
void main()
|
||||
{
|
||||
vertUV0 = vertUV0In;
|
||||
@ -155,9 +173,8 @@ struct DirLight {
|
||||
vec3 dir;
|
||||
vec3 diffuseColor;
|
||||
vec3 specularColor;
|
||||
sampler2D shadowMap;
|
||||
};
|
||||
uniform DirLight dirLight;
|
||||
uniform sampler2D dirLightShadowMap;
|
||||
|
||||
struct PointLight {
|
||||
vec3 pos;
|
||||
@ -183,6 +200,15 @@ struct SpotLight {
|
||||
uniform SpotLight spotLights[NUM_SPOT_LIGHTS];
|
||||
uniform sampler2DArray spotLightShadowMaps;
|
||||
|
||||
layout (std140) uniform GlobalMatrices {
|
||||
vec3 camPos;
|
||||
mat4 projViewMat;
|
||||
};
|
||||
|
||||
layout (std140) uniform Lights {
|
||||
DirLight dirLight;
|
||||
};
|
||||
|
||||
uniform vec3 ambientColor = vec3(0.2, 0.2, 0.2);
|
||||
|
||||
//
|
||||
@ -250,7 +276,7 @@ vec3 CalcDirLight()
|
||||
vec3 finalSpecular = specularAmount * dirLight.specularColor * specularTexColor.rgb;
|
||||
|
||||
// Shadow
|
||||
float shadow = CalcDirShadow(dirLight.shadowMap, lightDir);
|
||||
float shadow = CalcDirShadow(dirLightShadowMap, lightDir);
|
||||
|
||||
return (finalDiffuse + finalSpecular) * (1 - shadow);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user