diff --git a/src/jasper/modules/world/include/jasper/world/world.hpp b/src/jasper/modules/world/include/jasper/world/world.hpp index 5463733..4fd59f6 100644 --- a/src/jasper/modules/world/include/jasper/world/world.hpp +++ b/src/jasper/modules/world/include/jasper/world/world.hpp @@ -16,16 +16,28 @@ namespace ncore = nostalgia::core; class World { private: + struct PaletteTracker { + keel::AssetRef pal; + int page{}; + }; + ox::Vector m_palettes; ncore::Context &m_nctx; - ox::Vector, 10> m_palettes; WorldStatic const&m_worldStatic; +#ifndef OX_OS_BareMetal + turbine::TimeMs m_prevUpdateTime{}; + turbine::TimeMs m_nextUpdateTime{}; +#endif public: explicit World(ncore::Context &nctx, WorldStatic const&worldStatic) noexcept; ox::Error setupDisplay() noexcept; - ox::Result update() const noexcept; + ox::Result update() noexcept; + +#ifndef OX_OS_BareMetal + ox::Result editorModeUpdate() noexcept; +#endif private: void setupLayer(uint_t lyr, uint_t cbb) const noexcept; diff --git a/src/jasper/modules/world/src/studio/worldeditor/worldeditor-imgui.cpp b/src/jasper/modules/world/src/studio/worldeditor/worldeditor-imgui.cpp index afe3851..ae322bd 100644 --- a/src/jasper/modules/world/src/studio/worldeditor/worldeditor-imgui.cpp +++ b/src/jasper/modules/world/src/studio/worldeditor/worldeditor-imgui.cpp @@ -251,11 +251,19 @@ void WorldEditorImGui::drawPropEditor() noexcept { void WorldEditorImGui::drawMenu() noexcept { ig::IDStackItem const idStackItem("Menu"); - if (ig::PushButton("Resize")) { + if (ImGui::Button("Resize")) { m_sizeEditor.show = true; m_sizeEditor.columns = m_doc.columns; m_sizeEditor.rows = m_doc.rows; } + ImGui::SameLine(); + { + bool animate = m_view.animate(); + if (ImGui::Checkbox("Animate", &animate) && !animate) { + oxLogError(m_view.setupWorld()); + } + m_view.setAnimate(animate); + } } void WorldEditorImGui::drawResources() noexcept { diff --git a/src/jasper/modules/world/src/studio/worldeditor/worldeditorview.cpp b/src/jasper/modules/world/src/studio/worldeditor/worldeditorview.cpp index 2147fb0..c2e373c 100644 --- a/src/jasper/modules/world/src/studio/worldeditor/worldeditorview.cpp +++ b/src/jasper/modules/world/src/studio/worldeditor/worldeditorview.cpp @@ -34,9 +34,11 @@ void WorldEditorView::draw(ox::Size const&targetSz) noexcept { glutils::resizeInitFrameBuffer(m_frameBuffer, ncore::gl::drawSize(m_scale)); } glutils::FrameBufferBind const frameBufferBind(m_frameBuffer); - auto const wakeUp = m_world.update(); - if (wakeUp.ok()) { - turbine::setRefreshWithin(m_sctx.tctx, wakeUp.value); + if (m_animateWorld) { + auto const wakeUp = m_world.editorModeUpdate(); + if (wakeUp.ok()) { + turbine::setRefreshWithin(m_sctx.tctx, wakeUp.value); + } } ncore::gl::draw(*m_cctx, m_scale); m_highlighter.draw(); diff --git a/src/jasper/modules/world/src/studio/worldeditor/worldeditorview.hpp b/src/jasper/modules/world/src/studio/worldeditor/worldeditorview.hpp index bc1f122..dad40cb 100644 --- a/src/jasper/modules/world/src/studio/worldeditor/worldeditorview.hpp +++ b/src/jasper/modules/world/src/studio/worldeditor/worldeditorview.hpp @@ -32,6 +32,7 @@ class WorldEditorView { ox::Size m_scaleSz = ncore::gl::drawSize(m_scale); ox::Optional m_selection; MapTileHighlighter m_highlighter; + bool m_animateWorld{}; public: WorldEditorView(studio::StudioContext &ctx, WorldStatic const&worldStatic); @@ -44,6 +45,11 @@ class WorldEditorView { void setSelection(studio::Selection const&sel) noexcept; + [[nodiscard]] + bool animate() const noexcept { return m_animateWorld; } + + void setAnimate(bool animate) noexcept { m_animateWorld = animate; } + [[nodiscard]] glutils::FrameBuffer const&framebuffer() const noexcept; diff --git a/src/jasper/modules/world/src/world.cpp b/src/jasper/modules/world/src/world.cpp index fde93a7..16ed7b3 100644 --- a/src/jasper/modules/world/src/world.cpp +++ b/src/jasper/modules/world/src/world.cpp @@ -12,8 +12,7 @@ namespace jasper::world { World::World(ncore::Context &nctx, WorldStatic const&worldStatic) noexcept: m_nctx(nctx), - m_worldStatic(worldStatic) { -} + m_worldStatic(worldStatic) {} ox::Error World::setupDisplay() noexcept { if (m_worldStatic.palettes.empty()) { @@ -22,8 +21,8 @@ ox::Error World::setupDisplay() noexcept { m_palettes.clear(); for (auto i = 0u; auto const&pal : m_worldStatic.palettes) { auto &palRef = m_palettes.emplace_back(); - oxReturnError(readObj(keelCtx(m_nctx), pal.palette).moveTo(palRef)); - oxReturnError(ncore::loadBgPalette(m_nctx, i, *palRef)); + oxReturnError(readObj(keelCtx(m_nctx), pal.palette).moveTo(palRef.pal)); + oxReturnError(ncore::loadBgPalette(m_nctx, i, *palRef.pal)); ++i; } oxReturnError(ncore::loadBgTileSheet(m_nctx, 0, m_worldStatic.tilesheets)); @@ -68,17 +67,44 @@ void World::setupLayer( } } -ox::Result World::update() const noexcept { +ox::Result World::update() noexcept { auto const time = ticksMs(turbineCtx(m_nctx)); - int expiresIn = 30 * 1000; + int expiresIn = 60'000; for (size_t i = 0; auto const&pal : m_palettes) { auto const interval = m_worldStatic.palettes[i].intervalMs; - auto const page = (time / interval) % pal->pages.size(); + auto const page = (time / interval) % pal.pal->pages.size(); expiresIn = ox::min(expiresIn, static_cast(time % interval)); - oxReturnError(ncore::loadBgPalette(m_nctx, i, *pal, static_cast(page))); + oxReturnError(ncore::loadBgPalette(m_nctx, i, *pal.pal, static_cast(page))); ++i; } return expiresIn; } +#ifndef OX_OS_BareMetal +ox::Result World::editorModeUpdate() noexcept { + auto const time = ticksMs(turbineCtx(m_nctx)); + if (time >= m_nextUpdateTime) { + turbine::TimeMs expiresIn = 60'000; + bool updated = false; + auto const elapsedSincePrev = time - m_prevUpdateTime; + for (size_t i = 0; auto &pal: m_palettes) { + auto const interval = m_worldStatic.palettes[i].intervalMs; + auto &page = pal.page; + auto const update = (elapsedSincePrev >= interval); + page += update * 1; + page %= static_cast(pal.pal->pages.size()); + oxReturnError(ncore::loadBgPalette(m_nctx, i, *pal.pal, static_cast(page))); + updated = updated || update; + expiresIn = ox::min(expiresIn, interval); + ++i; + } + if (updated) { + m_prevUpdateTime = time; + } + m_nextUpdateTime = time + expiresIn; + } + return static_cast(m_nextUpdateTime - time); +} +#endif + } diff --git a/src/jasper/player/app.cpp b/src/jasper/player/app.cpp index 36c3a02..c463ab5 100644 --- a/src/jasper/player/app.cpp +++ b/src/jasper/player/app.cpp @@ -25,10 +25,9 @@ ox::Error run(turbine::Context &tctx, ox::StringView, ox::SpanView a oxReturnError(world.setupDisplay()); turbine::setApplicationData(tctx, &world); setUpdateHandler(tctx, [](turbine::Context &tctx) -> int { - auto const&world = *applicationData(tctx); + auto &world = *applicationData(tctx); auto [sleepTime, err] = world.update(); if (err) { - oxDebugf("error: {}", toStr(err)); oxLogError(err); } return 0;