diff --git a/src/jasper/modules/world/include/jasper/world/world.hpp b/src/jasper/modules/world/include/jasper/world/world.hpp index be60892..e9aaef5 100644 --- a/src/jasper/modules/world/include/jasper/world/world.hpp +++ b/src/jasper/modules/world/include/jasper/world/world.hpp @@ -14,13 +14,16 @@ namespace ncore = nostalgia::core; class World { private: + struct ObjState { + uint16_t objIdx{}; + uint16_t frame{}; + turbine::TimeMs nextUpdateTime{}; + }; ncore::Context &m_nctx; WorldStatic const&m_worldStatic; ox::Vector, 32> m_tilesheets; -#ifndef OX_OS_BareMetal - //turbine::TimeMs m_prevUpdateTime{}; - turbine::TimeMs m_nextUpdateTime{}; -#endif + ox::Vector m_objStates; + turbine::TimeMs m_currentTicks{}; public: explicit World(ncore::Context &nctx, WorldStatic const&worldStatic) noexcept; @@ -29,16 +32,14 @@ class World { ox::Result update() noexcept; -#ifndef OX_OS_BareMetal - ox::Result editorModeUpdate() noexcept; -#endif - void setupTiles() noexcept; - void setupTile(uint32_t lyr, uint32_t x, uint32_t y) const noexcept; + void setupTile(uint32_t lyr, uint32_t x, uint32_t y) noexcept; private: - void setupLayer(uint_t lyr, uint_t cbb) const noexcept; + turbine::TimeMs updateObj(ObjState &state) noexcept; + + void setupLayer(uint_t lyr, uint_t cbb) noexcept; }; diff --git a/src/jasper/modules/world/include/jasper/world/worldstatic.hpp b/src/jasper/modules/world/include/jasper/world/worldstatic.hpp index 12289d5..a85597b 100644 --- a/src/jasper/modules/world/include/jasper/world/worldstatic.hpp +++ b/src/jasper/modules/world/include/jasper/world/worldstatic.hpp @@ -91,6 +91,7 @@ struct ObjTileRefSet { uint8_t tileCnt{}; // each successive frame will use tileIdx[i] + tileCnt * frameNo for the tileIdx uint8_t frames{}; + uint16_t intervalMs{}; }; OX_MODEL_BEGIN(ObjTileRefSet) @@ -101,6 +102,7 @@ OX_MODEL_BEGIN(ObjTileRefSet) OX_MODEL_FIELD(tilesheetId) OX_MODEL_FIELD(tileCnt) OX_MODEL_FIELD(frames) + OX_MODEL_FIELD(intervalMs) OX_MODEL_END() [[nodiscard]] diff --git a/src/jasper/modules/world/src/studio/worldeditor/worldeditorview.cpp b/src/jasper/modules/world/src/studio/worldeditor/worldeditorview.cpp index 1ac1dca..0209e67 100644 --- a/src/jasper/modules/world/src/studio/worldeditor/worldeditorview.cpp +++ b/src/jasper/modules/world/src/studio/worldeditor/worldeditorview.cpp @@ -17,7 +17,7 @@ WorldEditorView::WorldEditorView(studio::StudioContext &sctx, WorldStatic const& ox::Error WorldEditorView::setupTile( uint32_t const lyr, uint32_t const x, - uint32_t const y) const noexcept { + uint32_t const y) noexcept { m_world.setupTile(lyr, x, y); return {}; } @@ -46,7 +46,7 @@ void WorldEditorView::draw(ox::Size const&targetSz) noexcept { } glutils::FrameBufferBind const frameBufferBind(m_frameBuffer); if (m_animateWorld) { - auto const wakeUp = m_world.editorModeUpdate(); + auto const wakeUp = m_world.update(); if (wakeUp.ok()) { turbine::setRefreshWithin(m_sctx.tctx, wakeUp.value); } diff --git a/src/jasper/modules/world/src/studio/worldeditor/worldeditorview.hpp b/src/jasper/modules/world/src/studio/worldeditor/worldeditorview.hpp index 665f49b..4fe8ce9 100644 --- a/src/jasper/modules/world/src/studio/worldeditor/worldeditorview.hpp +++ b/src/jasper/modules/world/src/studio/worldeditor/worldeditorview.hpp @@ -37,7 +37,7 @@ class WorldEditorView: public ox::SignalHandler { public: WorldEditorView(studio::StudioContext &ctx, WorldStatic const&worldStatic); - ox::Error setupTile(uint32_t lyr, uint32_t x, uint32_t y) const noexcept; + ox::Error setupTile(uint32_t lyr, uint32_t x, uint32_t y) noexcept; void setupTiles() noexcept; diff --git a/src/jasper/modules/world/src/world.cpp b/src/jasper/modules/world/src/world.cpp index f6043f0..020c432 100644 --- a/src/jasper/modules/world/src/world.cpp +++ b/src/jasper/modules/world/src/world.cpp @@ -10,6 +10,11 @@ namespace jasper::world { +[[nodiscard]] +static bool isUpdatingObj(ObjTileRefSet const&obj) noexcept { + return obj.frames > 1; +} + World::World(ncore::Context &nctx, WorldStatic const&worldStatic) noexcept: m_nctx(nctx), m_worldStatic(worldStatic) {} @@ -46,7 +51,17 @@ ox::Error World::setupDisplay() noexcept { return {}; } +ox::Result World::update() noexcept { + turbine::TimeMs nextUpdateTime = ox::MaxValue; + m_currentTicks = ticksMs(turbineCtx(m_nctx)); + for (auto &state : m_objStates) { + nextUpdateTime = ox::min(nextUpdateTime, updateObj(state)); + } + return static_cast(nextUpdateTime - m_currentTicks); +} + void World::setupTiles() noexcept { + m_currentTicks = ticksMs(turbineCtx(m_nctx)); ncore::setBgStatus(m_nctx, 0); // disable all backgrounds for (auto layerNo = 0u; auto const&layer : m_worldStatic.map) { setupLayer(layerNo, layer.cbb); @@ -57,7 +72,7 @@ void World::setupTiles() noexcept { void World::setupTile( uint32_t const lyr, uint32_t const x, - uint32_t const y) const noexcept { + uint32_t const y) noexcept { auto &t = tile(m_worldStatic, lyr, x, y); auto const tx = static_cast(x) * 2; auto const ty = static_cast(y) * 2; @@ -78,11 +93,37 @@ void World::setupTile( .tileIdx = static_cast(obj.cbbIdx + 3), .palBank = obj.palBank, }); + if (isUpdatingObj(obj)) { + m_objStates.emplace_back(ObjState{ + .objIdx = t.objIdxRefSet, + .frame = 0, + .nextUpdateTime = m_currentTicks + obj.intervalMs, + }); + } +} + +turbine::TimeMs World::updateObj(ObjState &state) noexcept { + if (state.nextUpdateTime <= m_currentTicks) { + auto &obj = m_worldStatic.objTileRefSets[state.objIdx]; + ++state.frame; + if (state.frame >= obj.frames) { + state.frame = 0; + } + std::ignore = ncore::loadBgTileSheet( + m_nctx, + obj.cbb, + *m_tilesheets[obj.tilesheetId], + obj.cbbIdx, + static_cast(obj.tilesheetIdx + state.frame * static_cast(obj.tileCnt)), + obj.tileCnt); + state.nextUpdateTime = m_currentTicks + obj.intervalMs; + } + return state.nextUpdateTime; } void World::setupLayer( uint_t const lyr, - uint_t const cbb) const noexcept { + uint_t const cbb) noexcept { ncore::clearBg(m_nctx, lyr); ncore::setBgStatus(m_nctx, lyr, true); ncore::setBgCbb(m_nctx, lyr, cbb); @@ -95,20 +136,4 @@ void World::setupLayer( } } -ox::Result World::update() noexcept { - int expiresIn = 60'000; - 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; - m_nextUpdateTime = time + expiresIn; - } - return static_cast(m_nextUpdateTime - time); -} -#endif - } diff --git a/src/jasper/modules/world/src/worldstatic.cpp b/src/jasper/modules/world/src/worldstatic.cpp index 73c26fd..a24a282 100644 --- a/src/jasper/modules/world/src/worldstatic.cpp +++ b/src/jasper/modules/world/src/worldstatic.cpp @@ -167,6 +167,7 @@ ox::Result WorldStaticLoader::setupTileResrc(DocObjRef const&docObjRef) .tilesheetId = tsIdx, .tileCnt = subsheetTileCnt(*subsheet), .frames = obj->frames, + .intervalMs = obj->intervalMs, }); m_cbbIt += refSet.tileCnt; m_resourcesChanged = true; diff --git a/src/jasper/player/app.cpp b/src/jasper/player/app.cpp index a4a0786..0d0ced4 100644 --- a/src/jasper/player/app.cpp +++ b/src/jasper/player/app.cpp @@ -43,11 +43,11 @@ ox::Error run( } setUpdateHandler(*tctx, [](turbine::Context &tctx) -> int { auto &world = *applicationData(tctx); - auto [sleepTime, err] = world.update(); + auto const [sleepTime, err] = world.update(); if (err) { oxLogError(err); } - return 0; + return sleepTime; }); OX_RETURN_ERROR(turbine::run(*tctx)); oxOut("Exiting...\n");