141 lines
4.8 KiB
Go
141 lines
4.8 KiB
Go
package camera
|
|
|
|
import (
|
|
"aego/core/mathx"
|
|
"aego/scene"
|
|
"aego/script/abi"
|
|
"aego/script/bind"
|
|
)
|
|
|
|
type Blend uint64
|
|
|
|
func blendOf(k uint64) Blend {
|
|
return Blend(k)
|
|
}
|
|
|
|
func (b Blend) key() uint64 {
|
|
return uint64(b)
|
|
}
|
|
|
|
func live(c *bind.Ctx) *Service {
|
|
if c.World == nil {
|
|
return nil
|
|
}
|
|
return Of(c.World)
|
|
}
|
|
|
|
func need(c *bind.Ctx) *Service {
|
|
s := live(c)
|
|
if s == nil {
|
|
c.Fail("cameras run only during Play")
|
|
}
|
|
return s
|
|
}
|
|
|
|
func installScript(m *bind.Module) {
|
|
bind.Struct[Pose](m, "Pose", bind.Doc("Pose is a camera position in world units, a rotation in radians and a zoom in pixels per unit."))
|
|
bind.Handle(m, "Blend", true, blendOf, Blend.key,
|
|
bind.Doc("Blend is a running blend between virtual cameras. yield b waits until it ends; a nil blend is done."))
|
|
|
|
bind.Func0(m, "Active", func(c *bind.Ctx) scene.NodeHandle {
|
|
if s := live(c); s != nil {
|
|
return s.Active("")
|
|
}
|
|
return scene.NodeHandle{}
|
|
}, bind.Doc("Active returns the virtual camera that drives the main output, or nil."))
|
|
bind.Func1(m, "ActiveOn", func(c *bind.Ctx, output string) scene.NodeHandle {
|
|
if s := live(c); s != nil {
|
|
return s.Active(output)
|
|
}
|
|
return scene.NodeHandle{}
|
|
}, bind.Doc("ActiveOn returns the virtual camera that drives the named output."), bind.Params("output"))
|
|
bind.Func2(m, "BlendTo", func(c *bind.Ctx, vc scene.NodeHandle, sec float32) Blend {
|
|
s := need(c)
|
|
if s == nil {
|
|
return 0
|
|
}
|
|
k, err := s.BlendTo(vc, sec, false)
|
|
if err != nil {
|
|
c.Fail(err.Error())
|
|
}
|
|
return Blend(k)
|
|
}, bind.Doc("BlendTo makes vc active over priorities and blends to it; seconds 0 uses its Blend Time. Release hands control back to priorities."),
|
|
bind.Params("camera", "seconds"), bind.Example("yield camera.BlendTo(BossCam, 1.5)"))
|
|
bind.Proc1(m, "Cut", func(c *bind.Ctx, vc scene.NodeHandle) {
|
|
if s := need(c); s != nil {
|
|
if _, err := s.BlendTo(vc, 0, true); err != nil {
|
|
c.Fail(err.Error())
|
|
}
|
|
}
|
|
}, bind.Doc("Cut makes vc active at once, without a blend."), bind.Params("camera"))
|
|
bind.Func1(m, "Release", func(c *bind.Ctx, sec float32) Blend {
|
|
if s := live(c); s != nil {
|
|
return Blend(s.Release("", sec))
|
|
}
|
|
return 0
|
|
}, bind.Doc("Release ends BlendTo or Cut on the main output; priorities decide again, blending over seconds or the camera's Blend Time."),
|
|
bind.Params("seconds"))
|
|
bind.Proc1(m, "Shake", func(c *bind.Ctx, t float32) {
|
|
if s := live(c); s != nil {
|
|
s.Shake("", t)
|
|
}
|
|
}, bind.Doc("Shake adds trauma to the main output; shake grows with trauma, which is capped at 1 and fades over time."),
|
|
bind.Params("trauma"), bind.Example("camera.Shake(0.4)"))
|
|
bind.Proc2(m, "ShakeOn", func(c *bind.Ctx, output string, t float32) {
|
|
if s := live(c); s != nil {
|
|
s.Shake(output, t)
|
|
}
|
|
}, bind.Doc("ShakeOn adds trauma to the named output."), bind.Params("output", "trauma"))
|
|
bind.Func0(m, "Trauma", func(c *bind.Ctx) float32 {
|
|
if s := live(c); s != nil {
|
|
return s.Trauma("")
|
|
}
|
|
return 0
|
|
}, bind.Doc("Trauma returns the current trauma of the main output, 0 to 1."))
|
|
bind.Func0(m, "LogicalPose", func(c *bind.Ctx) Pose {
|
|
if s := live(c); s != nil {
|
|
return s.Logical("")
|
|
}
|
|
return Pose{}
|
|
}, bind.Doc("LogicalPose returns the pose of the main output without shake and pixel snapping."))
|
|
bind.Func0(m, "RenderPose", func(c *bind.Ctx) Pose {
|
|
if s := live(c); s != nil {
|
|
return s.Render("")
|
|
}
|
|
return Pose{}
|
|
}, bind.Doc("RenderPose returns the pose the main output was drawn with in the last frame."))
|
|
bind.Func1(m, "ScreenToWorld", func(c *bind.Ctx, p mathx.Vec2) mathx.Vec2 {
|
|
if s := live(c); s != nil {
|
|
if v, ok := s.View(""); ok {
|
|
return v.ScreenToWorld(p)
|
|
}
|
|
}
|
|
return p
|
|
}, bind.Doc("ScreenToWorld converts output pixels to world units with the last drawn view of the main output."), bind.Params("point"))
|
|
bind.Func1(m, "WorldToScreen", func(c *bind.Ctx, p mathx.Vec2) mathx.Vec2 {
|
|
if s := live(c); s != nil {
|
|
if v, ok := s.View(""); ok {
|
|
return v.WorldToScreen(p)
|
|
}
|
|
}
|
|
return p
|
|
}, bind.Doc("WorldToScreen converts world units to output pixels with the last drawn view of the main output."), bind.Params("point"))
|
|
|
|
hm := m.Registry().HandleMethods(KindBlend)
|
|
bind.Func1(hm, "Done", func(c *bind.Ctx, b Blend) bool {
|
|
s := live(c)
|
|
return s == nil || s.BlendDone(uint64(b))
|
|
}, bind.Doc("Done reports whether the blend ended, was replaced or is nil."))
|
|
bind.Func1(hm, "Running", func(c *bind.Ctx, b Blend) bool {
|
|
s := live(c)
|
|
return s != nil && !s.BlendDone(uint64(b))
|
|
}, bind.Doc("Running is the opposite of Done."))
|
|
bind.Proc1(hm, "Stop", func(c *bind.Ctx, b Blend) {
|
|
if s := live(c); s != nil {
|
|
s.StopBlend(uint64(b))
|
|
}
|
|
}, bind.Doc("Stop ends the blend at the target camera."))
|
|
bind.Signal(hm, "Completed", []abi.TypeRef{abi.T(abi.Bool)}, bind.Params("finished"),
|
|
bind.Doc("Completed runs once when the blend ends: finished is false after Stop or when another camera became active first."))
|
|
}
|