From acadf3ca312a216f179fb5c90eb84912a5fb68e2 Mon Sep 17 00:00:00 2001 From: "Zed A. Shaw" Date: Thu, 15 Jan 2026 14:06:30 -0500 Subject: [PATCH] Started a TDD for the new animation system. --- Makefile | 4 +- tests/animation.cpp | 111 ++++++++++++++++++++++++++++++++++++++++++ tests/ansi_parser.cpp | 77 ----------------------------- 3 files changed, 113 insertions(+), 79 deletions(-) delete mode 100644 tests/ansi_parser.cpp diff --git a/Makefile b/Makefile index af938f2..6a047a6 100644 --- a/Makefile +++ b/Makefile @@ -37,7 +37,7 @@ tracy_build: meson compile -j 10 -C builddir test: build - ./builddir/runtests -d yes + ./builddir/runtests -d yes "[animation-new]" run: build test ifeq '$(OS)' 'Windows_NT' @@ -60,7 +60,7 @@ clean: meson compile --clean -C builddir debug_test: build - gdb --nx -x .gdbinit --ex run --ex bt --ex q --args builddir/runtests -e + gdb --nx -x .gdbinit --ex run --ex bt --ex q --args builddir/runtests -e "[animation-new]" win_installer: powershell 'start "C:\Program Files (x86)\solicus\InstallForge\bin\ifbuilderenvx86.exe" scripts\win_installer.ifp' diff --git a/tests/animation.cpp b/tests/animation.cpp index 42a4df2..9d197d8 100644 --- a/tests/animation.cpp +++ b/tests/animation.cpp @@ -1,12 +1,123 @@ #include #include "animation.hpp" +#include "textures.hpp" #include "dinkyecs.hpp" #include "config.hpp" #include +#include using namespace components; using namespace textures; +struct Sheet { + std::string texture_name; + int width; + int height; + int frame_width; + int frame_height; +}; + +struct Sequence { + size_t current_frame; + float subframe; + std::vector frames; + std::vector durations; +}; + +struct Transform { + // how to know when a transform ends? + float min_x = 1.0f; + float min_y = 1.0f; + float max_x = 1.0f; + float max_y = 1.0f; + bool simple = true; + bool flipped = false; + float ease_rate = 0.5f; + bool scaled = false; + bool stationary = false; + // these can handled by the onLoop, same as ganim8 does it + bool toggled = false; + bool looped = false; + + std::shared_ptr shader = nullptr; + // change to using a callback function for these + ease::Style easing = ease::IN_OUT_BACK; + ease::Motion motion = ease::RUSH; +}; + +/* Gets the number of times it looped, and returns if it should stop. */ +using OnLoopHandler = std::function; + +class Animate2 { + public: + Sheet& $sheet; + Sequence $sequence; + Transform $transform; + std::shared_ptr $sprite = nullptr; + std::shared_ptr $texture = nullptr; + + Animate2(Sheet sheet, Sequence seq, Transform trans) : + $sheet(sheet), $sequence(seq), $transform(trans) + { + auto st = textures::get_sprite($sheet.texture_name); + $sprite = st.sprite; + $texture = st.texture; + } + + OnLoopHandler onLoop = nullptr; +}; + + +/* + * Animation is a Sheet + Sequence + Transform. + * + * A Sheet is just a grid of images with a predefined size for each cell. Arbitrary sized cells not supported. + * + * A Sequence is a list of Sheet cells _in any order_. See https://github.com/yottahmd/ganim8-lib. Sequences have a timing element for the cells, possibly a list of durations or a single duration. + * + * A Transform is combinations of scale and/or position easing/motion, shader effects, and things like if it's looped or toggled. + * + * I like the ganim8 onLoop concept, just a callback that says what to do when the animation has looped. + */ +TEST_CASE("new animation system", "[animation-new]") { + textures::init(); + + Sheet sheet{ + .texture_name{"rat_king_boss"}, + .width{720*2}, + .height{720}, + .frame_width{720}, + .frame_height{720}, + }; + + Sequence sequence{ + .current_frame{0}, + .subframe{0.0f}, + .frames{0,1}, + .durations{0.1f,0.1f}, + }; + + Transform transform{ + .min_x{1.0f}, + .min_y{1.0f}, + .max_x{1.0f}, + .max_y{1.0f}, + .simple{true}, + .flipped{false}, + .ease_rate{0.5f}, + .scaled{false}, + .stationary{false}, + .toggled{false}, + .looped{false}, + }; + + Animate2 anim{sheet, sequence, transform}; + anim.onLoop = [](int loop_count) -> bool { + return loop_count < 2; + }; +} + + TEST_CASE("animation easing tests", "[animation]") { Animation anim; diff --git a/tests/ansi_parser.cpp b/tests/ansi_parser.cpp deleted file mode 100644 index 1c7a1b9..0000000 --- a/tests/ansi_parser.cpp +++ /dev/null @@ -1,77 +0,0 @@ -#include -#include -#include -#include "ansi_parser.hpp" -#include -#include - -#include "ftxui/dom/elements.hpp" // for text, bgcolor, color, vbox, hbox, separator, operator|, Elements, Element, Fit, border -#include "ftxui/dom/node.hpp" // for Render -#include "ftxui/screen/color.hpp" // for Color, Color::Black, Color::Blue, Color::BlueLight, Color::Cyan, Color::CyanLight, Color::Default, Color::GrayDark, Color::GrayLight, Color::Green, Color::GreenLight, Color::Magenta, Color::MagentaLight, Color::Red, Color::RedLight, Color::White, Color::Yellow, Color::YellowLight, Color::Palette256, ftxui -#include // for ColorInfo -#include // for Full, Screen -#include // for Full, Screen -#include // for ColorSupport, Color, Palette16, Palette256, TrueColor -#include "render.hpp" - -using namespace fmt; -using namespace ftxui; - -std::string generate_colors() { - SFMLRender::init_terminal(); - - REQUIRE(ftxui::Terminal::ColorSupport() == ftxui::Terminal::Color::TrueColor); - - const int max_value = 255; - const int value_increment = 8; - const int hue_increment = 6; - int saturation = max_value; - Elements array; - int count = 0; - - for (int value = 0; value < max_value; value += 2 * value_increment) { - Elements line; - for (int hue = 0; hue < max_value; hue += hue_increment) { - line.push_back( - text("#") // - | ftxui::color(Color::HSV(hue, saturation, value)) // - | ftxui::bgcolor(Color::HSV(hue, saturation, value + value_increment))); - count++; - } - array.push_back(hbox(std::move(line))); - } - - auto true_color_display = vbox({ - vbox(std::move(array)), - }); - - auto document = vbox({hbox({ - true_color_display, - })}); - - auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document)); - Render(screen, document); - return screen.ToString(); -} - -TEST_CASE("test out ragel parser", "[gui]") { - SFMLRender::init_terminal(); - sf::Color default_fg(0,0,0); - sf::Color default_bg(100,100,100); - - // this sets the Truecolor so need to do it first - ANSIParser ansi(default_fg, default_bg); - std::wstring_convert> $converter; - std::string colors = generate_colors(); - std::wstring colors_utf = $converter.from_bytes(colors); - - bool good = ansi.parse(colors_utf, - [&](sf::Color color[[maybe_unused]], sf::Color bgcolor[[maybe_unused]]){ - }, - [&](wchar_t ch) { - bool correct_char = ch == '#' || ch == ' ' || ch == '\n' || ch == '\r'; - REQUIRE(correct_char); - }); - - REQUIRE(good); -}