zworld/engine/object/mesh/mesh.go

150 lines
3.3 KiB
Go
Raw Normal View History

2024-01-14 22:56:06 +08:00
package mesh
import (
"zworld/engine/object"
"zworld/engine/renderapi/material"
"zworld/engine/renderapi/texture"
"zworld/engine/renderapi/vertex"
"zworld/plugins/math/shape"
"zworld/plugins/math/vec3"
)
func init() {
object.Register[*Static](Deserialize)
}
type Mesh interface {
object.Component
Primitive() vertex.Primitive
CastShadows() bool
Material() *material.Def
MaterialID() material.ID
Texture(texture.Slot) texture.Ref
// Bounding sphere used for view frustum culling
BoundingSphere() shape.Sphere
// returns the VertexData property
// this is kinda ugly - but other components might need to subscribe to changes ?
Mesh() *object.Property[vertex.Mesh]
}
// mesh base
type Static struct {
object.Component
primitive vertex.Primitive
shadows bool
mat *material.Def
matId material.ID
textures map[texture.Slot]texture.Ref
// bounding radius
center vec3.T
radius float32
VertexData object.Property[vertex.Mesh]
}
// New creates a new mesh component
func New(mat *material.Def) *Static {
return NewPrimitiveMesh(vertex.Triangles, mat)
}
// NewLines creates a new line mesh component
func NewLines() *Static {
return NewPrimitiveMesh(vertex.Lines, nil)
}
// NewPrimitiveMesh creates a new mesh composed of a given GL primitive
func NewPrimitiveMesh(primitive vertex.Primitive, mat *material.Def) *Static {
m := object.NewComponent(&Static{
mat: mat,
matId: material.Hash(mat),
textures: make(map[texture.Slot]texture.Ref),
primitive: primitive,
shadows: true,
VertexData: object.NewProperty[vertex.Mesh](nil),
})
m.VertexData.OnChange.Subscribe(func(data vertex.Mesh) {
// refresh bounding sphere
min := data.Min()
max := data.Max()
m.center = max.Sub(min).Scaled(0.5)
m.radius = m.center.Length()
})
return m
}
//func (m *Static) Name() string {
//return "Mesh"
//}
func (m *Static) Primitive() vertex.Primitive { return m.primitive }
func (m *Static) Mesh() *object.Property[vertex.Mesh] { return &m.VertexData }
func (m *Static) Texture(slot texture.Slot) texture.Ref {
return m.textures[slot]
}
func (m *Static) SetTexture(slot texture.Slot, ref texture.Ref) {
m.textures[slot] = ref
}
func (m *Static) CastShadows() bool {
return m.primitive == vertex.Triangles && m.shadows && !m.mat.Transparent
}
func (m *Static) SetShadows(shadows bool) {
m.shadows = shadows
}
func (m *Static) Material() *material.Def {
return m.mat
}
func (m *Static) MaterialID() material.ID {
return m.matId
}
func (m *Static) BoundingSphere() shape.Sphere {
return shape.Sphere{
Center: m.Transform().WorldPosition().Add(m.center),
Radius: m.radius,
}
}
type MeshState struct {
object.ComponentState
Primitive vertex.Primitive
Material material.Def
}
func (m *Static) State() MeshState {
return MeshState{
// send help
ComponentState: object.NewComponentState(m.Component),
Primitive: m.primitive,
Material: *m.Material(),
}
}
func (m *Static) Serialize(enc object.Encoder) error {
return enc.Encode(m.State())
}
func Deserialize(dec object.Decoder) (object.Component, error) {
var state MeshState
if err := dec.Decode(&state); err != nil {
return nil, err
}
obj := NewPrimitiveMesh(state.Primitive, &state.Material)
obj.Component = state.ComponentState.New()
return obj, nil
}