#define FSM_DEBUG 1 #include "sound.hpp" #include "ai.hpp" #include "animation.hpp" #include #include "shaders.hpp" #include "backend.hpp" #include "events.hpp" #include "constants.hpp" #include "gui/event_router.hpp" #include "constants.hpp" #include #include "gui/event_router.hpp" #include "gui/guecstra.hpp" #include "animate2.hpp" using namespace std::chrono_literals; bool YES_SYNC=true; namespace animator { struct UI { guecs::UI $ui; void init(const std::string& sprite_name) { $ui.position(0,0, SCREEN_WIDTH, SCREEN_HEIGHT); $ui.layout( "[play|*%=(300,400)viewer|_|_]" "[stop|_|_|_]" "[next|_|_|_]" "[prev|_|_|_]"); for(auto& [name, cell] : $ui.cells()) { auto comp = $ui.entity(name); if(name == "viewer") { $ui.set(comp, { sprite_name, 0, false}); } else { $ui.set(comp, {}); $ui.set(comp, {guecs::to_wstring(name)}); $ui.set(comp, {}); $ui.set(comp, {[](auto){ fmt::println("I don't know what to do here."); }}); } } $ui.init(); } void render(sf::RenderWindow& window) { $ui.render(window); } bool mouse(float x, float y, guecs::Modifiers mods) { return $ui.mouse(x, y, mods); } std::shared_ptr get_sprite() { auto viewer = $ui.entity("viewer"); return $ui.get(viewer).sprite; } }; enum class State { START=__LINE__, ANIMATE=__LINE__, END=__LINE__, }; struct FSM : public DeadSimpleFSM { UI $ui; gui::routing::Router $router; sf::RenderWindow $window{sf::VideoMode({SCREEN_WIDTH, SCREEN_HEIGHT}), "Animation Crafting Tool"}; void init(const std::string &sprite_name) { $ui.init(sprite_name); if(YES_SYNC) { $window.setVerticalSyncEnabled(VSYNC); if(FRAME_LIMIT) $window.setFramerateLimit(FRAME_LIMIT); } $window.setPosition({0,0}); } void event(game::Event ev, std::any data={}) { switch($state) { FSM_STATE(State, START, ev); FSM_STATE(State, ANIMATE, ev); FSM_STATE(State, END, ev); } } void START(game::Event ev) { switch(ev) { case game::Event::TICK: state(State::ANIMATE); break; default: state(State::START); } } void ANIMATE(game::Event ev) { switch(ev) { case game::Event::TICK: // stuff break; default: state(State::START); } } void END(game::Event ev) { } void handle_keyboard_mouse() { while(const auto ev = $window.pollEvent()) { using enum game::Event; auto gui_ev = $router.process_event(ev); auto mouse_pos = $window.mapPixelToCoords($router.position); switch(gui_ev) { case MOUSE_CLICK: $ui.mouse(mouse_pos.x, mouse_pos.y, guecs::NO_MODS); break; case MOUSE_MOVE: $ui.mouse(mouse_pos.x, mouse_pos.y, {1 << guecs::ModBit::hover}); break; case QUIT: state(State::END); default: break; // ignored } } } void render() { $window.clear(); $ui.render($window); $window.display(); } bool active() { return !in_state(State::END); } }; } animate2::Sheet sheet{ .width{720*2}, .height{720}, .frame_width{720}, .frame_height{720}, }; animate2::Sequence sequence{ .frames{0,1}, .durations{800ms, 200ms} }; animate2::Transform scale_tr{ .min_x{0.6f}, .min_y{0.6f}, .max_x{0.8f}, .max_y{0.8f}, .simple{false}, .flipped{false}, .ease_rate{4.0f}, .scaled{true}, .toggled{false}, .looped{false}, .easing = ease2::in_out_back, .motion = ease2::move_rush, }; animate2::Transform move_tr{ .min_x{-20.0f}, .min_y{-20.0f}, .max_x{20.0f}, .max_y{20.0f}, .simple{false}, .flipped{false}, .ease_rate{2.5f}, .scaled{true}, .toggled{false}, .looped{true}, .easing = ease2::normal_dist, .motion = ease2::move_shake, }; int main(int argc, char* argv[]) { shaders::init(); components::init(); sfml::Backend backend; guecs::init(&backend); ai::init("ai"); animation::init(); dbc::check(argc == 2, "USAGE: animator "); std::string sprite_name{argv[1]}; sound::mute(true); sound::play("ambient_1", true); animator::FSM main; main.init(argv[1]); animate2::Animate2 anim{sheet, sequence, scale_tr}; anim.play(); auto sprite = main.$ui.get_sprite(); // need to keep these aroung auto pos = sprite->getPosition(); auto scale = sprite->getScale(); while(main.active()) { auto [ticks, alpha] = anim.commit(); for(int i = 0; i < ticks; i++) { main.event(game::Event::TICK, {}); if(anim.playing) { anim.update(); anim.apply(*sprite); anim.motion(*sprite, pos, scale); } } main.render(); main.handle_keyboard_mouse(); } return 0; }