Files
aego/app/edit/shots.go
T

156 lines
4.0 KiB
Go

package edit
import (
"fmt"
"image"
"image/png"
"os"
"path/filepath"
"aego/editor/core/command"
"aego/editor/core/context"
"aego/editor/core/workspace"
"aego/editor/panels/gameview"
"aego/editor/shell"
)
// EnvShots makes the editor write the documentation screenshots to this directory and exit.
const EnvShots = "AEGO_SHOTS"
type shot struct {
name string
frames int
inset int
bottom int
setup func(s *Session) error
}
func (s *Session) shots(dir string) error {
defer s.Close()
if err := os.MkdirAll(dir, 0o755); err != nil {
return err
}
if !s.Step() {
return fmt.Errorf("the editor quit")
}
ctx := s.App.Context()
scene := func() { ctx.Open(context.At("scenes/main.aescene", 1, 1)) }
frameAll := func() error {
if err := ctx.Commands.Run(command.EditSelectAll); err != nil {
return err
}
if err := ctx.Commands.Run(command.SceneFrame); err != nil {
return err
}
for i := 0; i < 30; i++ {
s.Step()
}
return nil
}
list := []shot{
{name: "editor", frames: 240, setup: func(s *Session) error {
scene()
s.App.Workspace().Show(workspace.Inspector)
if err := frameAll(); err != nil {
return err
}
return selectNamed(ctx, "Player")
}},
{name: "tags", frames: 60, setup: func(s *Session) error {
return selectNamed(ctx, "Player")
}},
{name: "prefab", frames: 60, setup: func(s *Session) error {
return selectNamed(ctx, "EnemyLeft")
}},
{name: "settings-input", frames: 60, setup: func(s *Session) error {
ctx.Open(context.SettingsAt("input"))
return nil
}},
{name: "settings-physics", frames: 60, setup: func(s *Session) error {
ctx.Open(context.SettingsAt("physics"))
return nil
}},
{name: "script", frames: 90, setup: func(s *Session) error {
ctx.Open(context.At("scripts/player/player.aes", 1, 1))
return nil
}},
{name: "workspace-programming", frames: 60, setup: func(s *Session) error {
s.App.Workspace().Switch(workspace.Programming)
return nil
}},
{name: "play", frames: 150, setup: func(s *Session) error {
s.App.Workspace().Switch(workspace.Design)
scene()
return ctx.Commands.Run(command.PlayStart)
}},
{name: "physics-debug", frames: 30, setup: func(s *Session) error {
ctx.Overlay.Set("physics.debug.contacts", true)
return ctx.Commands.Run(gameview.CommandOverlays)
}},
{name: "demo", frames: 60, inset: 2, bottom: 28, setup: func(s *Session) error {
for _, f := range []string{"physics.debug", "physics.debug.shapes", "physics.debug.contacts", "physics.debug.joints"} {
ctx.Overlay.Set(f, false)
}
return ctx.Commands.Run(shell.CommandFullscreenPlay)
}},
{name: "prefab-mode", frames: 120, setup: func(s *Session) error {
if err := ctx.Commands.Run(command.PlayStop); err != nil {
return err
}
id, ok := s.Pipeline.Lookup("prefabs/enemy.aeprefab")
if !ok {
return fmt.Errorf("no prefabs/enemy.aeprefab")
}
return s.App.Prefabs().Open(id)
}},
}
for _, sh := range list {
if err := sh.setup(s); err != nil {
return fmt.Errorf("%s: %w", sh.name, err)
}
if err := s.capture(sh, filepath.Join(dir, sh.name+".png")); err != nil {
return fmt.Errorf("%s: %w", sh.name, err)
}
}
return nil
}
func selectNamed(ctx *context.Editor, name string) error {
sc := ctx.Scene()
if sc == nil {
return fmt.Errorf("no scene is open")
}
h := sc.Find(sc.Root(), name)
if !sc.IsAlive(h) {
return fmt.Errorf("the scene has no node %q", name)
}
ctx.Select(sc.ID(h))
return nil
}
func (s *Session) capture(sh shot, path string) error {
for i := 0; i < sh.frames; i++ {
if !s.Step() {
return fmt.Errorf("the editor quit")
}
}
var img *image.RGBA
var err error
s.Engine.CaptureFrame(func(got *image.RGBA, e error) { img, err = got, e })
s.Step()
if err != nil {
return err
}
if img == nil {
return fmt.Errorf("no frame was presented")
}
b := img.Bounds()
crop := img.SubImage(image.Rect(b.Min.X+sh.inset, b.Min.Y+sh.inset, b.Max.X-sh.inset, b.Max.Y-sh.inset-sh.bottom))
f, err := os.Create(path)
if err != nil {
return err
}
defer f.Close()
return png.Encode(f, crop)
}