Files

184 lines
4.8 KiB
Go

package editor
import (
"aego/core/errs"
"aego/core/ids"
"aego/core/log"
"aego/core/mathx"
"aego/editor/core/command"
"aego/editor/core/context"
"aego/editor/core/history"
"aego/editor/ext"
"aego/editor/ext/inspect"
"aego/modules/physics"
"aego/modules/physics/components"
"aego/modules/physics/settings"
"aego/modules/physics/systems"
"aego/schema"
)
const (
CmdDebug = "physics.debug"
FlagShapes = "physics.debug.shapes"
FlagContacts = "physics.debug.contacts"
FlagAABBs = "physics.debug.aabbs"
FlagJoints = "physics.debug.joints"
FlagIslands = "physics.debug.islands"
FlagBroad = "physics.debug.broadphase"
CmdSettings = "physics.settings"
PageID = settings.ID
Category = "Physics"
layerForces = "forces"
partBase = 32
)
type issueKey struct {
node ids.NodeID
comp string
}
type plugin struct {
ed *context.Editor
types [components.KindCount]*schema.TypeDescriptor
body *schema.TypeDescriptor
distance *schema.TypeDescriptor
revolute *schema.TypeDescriptor
index map[issueKey]string
rev uint64
tx *history.Transaction
col components.Collider
pts []mathx.Vec2
focus string
}
func lookup(sr *schema.Registry, name string) (*schema.TypeDescriptor, error) {
td, ok := sr.ByName(name)
if !ok {
return nil, errs.New(errs.SchemaUnknownType, "physics component is not registered", log.F("type", name))
}
return td, nil
}
func newPlugin(ed *context.Editor, sr *schema.Registry) (*plugin, error) {
p := &plugin{ed: ed, index: map[issueKey]string{}}
var err error
for k := components.Kind(0); k < components.KindCount; k++ {
if p.types[k], err = lookup(sr, components.Names[k]); err != nil {
return nil, err
}
}
if p.body, err = lookup(sr, components.NameBody); err != nil {
return nil, err
}
if p.distance, err = lookup(sr, components.NameDistance); err != nil {
return nil, err
}
if p.revolute, err = lookup(sr, components.NameRevolute); err != nil {
return nil, err
}
return p, nil
}
func Hook(e *ext.Registry) error {
p, err := newPlugin(e.Editor(), e.Schema())
if err != nil {
return err
}
for k := components.Kind(0); k < components.KindCount; k++ {
name := components.Names[k]
if err := e.Gizmo(name, &colliderGizmo{p: p, kind: k, td: p.types[k]}); err != nil {
return err
}
if err := e.Bounds(name, bounds(k)); err != nil {
return err
}
if err := e.Inspector(name, inspect.CustomFunc(p.colliderInspector(k))); err != nil {
return err
}
}
if err := e.Gizmo(components.NameDistance, &jointGizmo{p: p, td: p.distance}); err != nil {
return err
}
if err := e.Gizmo(components.NameRevolute, &jointGizmo{p: p, td: p.revolute, revolute: true}); err != nil {
return err
}
if err := e.Inspector(components.NameBody, inspect.CustomFunc(p.bodyInspector)); err != nil {
return err
}
e.GameOverlay(p.overlay)
for _, l := range []struct {
id, title string
fn func(*context.VectorSink)
}{
{"velocity", "Velocity", p.velocity},
{"angular", "Angular Velocity", p.angular},
{layerForces, "Forces", p.forces},
{"contacts", "Contact Impulses", p.contacts},
{"gravity", "Gravity", p.gravity},
} {
if err := e.Vectors(l.id, l.title, l.fn); err != nil {
return err
}
}
if err := e.SettingsPage(settings.ID, p.settingsPage, "Gravity", "Substeps", "Velocity Iterations", "Relax Iterations", "Contact Hertz", "Contact Damping Ratio", "Contact Push Velocity", "Restitution Threshold", "Linear Slop", "Sleep Linear", "Sleep Angular", "Sleep Time", "Layers", "Collision Matrix"); err != nil {
return err
}
e.Profiler("Physics", true, p.profile)
if p.ed != nil {
o := &p.ed.Overlay
o.Set(CmdDebug, true)
o.Set(FlagShapes, true)
o.Set(FlagJoints, true)
}
return p.commands(e)
}
func (p *plugin) commands(e *ext.Registry) error {
o := &p.ed.Overlay
toggle := func(id, name string, order int) command.Desc {
return command.Desc{
ID: id, Name: name, Category: Category, Order: order,
Checked: func() bool { return o.On(id) },
Run: func() error {
o.Toggle(id)
return nil
},
}
}
list := []command.Desc{
toggle(CmdDebug, "Debug Overlay", 100),
toggle(FlagShapes, "Shapes", 200),
toggle(FlagContacts, "Contacts", 210),
toggle(FlagAABBs, "AABBs", 220),
toggle(FlagJoints, "Joints", 230),
toggle(FlagIslands, "Islands", 240),
toggle(FlagBroad, "Broadphase Tree", 250),
{ID: CmdSettings, Name: "Physics Settings…", Category: Category, Order: 900, Run: func() error {
if p.ed.ShowSettings != nil {
p.ed.ShowSettings(PageID)
}
return nil
}},
}
for _, d := range list {
if err := e.Command(d); err != nil {
return err
}
}
return nil
}
func (p *plugin) sim() *systems.Sim {
if p.ed == nil || p.ed.Docs == nil {
return nil
}
return physics.SimOf(p.ed.Docs.ActiveWorld())
}
func (p *plugin) playSim() *systems.Sim {
if p.ed == nil {
return nil
}
return physics.SimOf(p.ed.PlayWorld())
}