[jasper/world/studio] Make WorldEditor able to animate BG
All checks were successful
Build / build (push) Successful in 3m17s

This commit is contained in:
Gary Talent 2024-06-01 15:43:38 -05:00
parent e008416d08
commit cab71a5fcf
6 changed files with 69 additions and 16 deletions

View File

@ -16,16 +16,28 @@ namespace ncore = nostalgia::core;
class World { class World {
private: private:
struct PaletteTracker {
keel::AssetRef<ncore::CompactPalette> pal;
int page{};
};
ox::Vector<PaletteTracker, 10> m_palettes;
ncore::Context &m_nctx; ncore::Context &m_nctx;
ox::Vector<keel::AssetRef<ncore::CompactPalette>, 10> m_palettes;
WorldStatic const&m_worldStatic; WorldStatic const&m_worldStatic;
#ifndef OX_OS_BareMetal
turbine::TimeMs m_prevUpdateTime{};
turbine::TimeMs m_nextUpdateTime{};
#endif
public: public:
explicit World(ncore::Context &nctx, WorldStatic const&worldStatic) noexcept; explicit World(ncore::Context &nctx, WorldStatic const&worldStatic) noexcept;
ox::Error setupDisplay() noexcept; ox::Error setupDisplay() noexcept;
ox::Result<int> update() const noexcept; ox::Result<int> update() noexcept;
#ifndef OX_OS_BareMetal
ox::Result<int> editorModeUpdate() noexcept;
#endif
private: private:
void setupLayer(uint_t lyr, uint_t cbb) const noexcept; void setupLayer(uint_t lyr, uint_t cbb) const noexcept;

View File

@ -251,11 +251,19 @@ void WorldEditorImGui::drawPropEditor() noexcept {
void WorldEditorImGui::drawMenu() noexcept { void WorldEditorImGui::drawMenu() noexcept {
ig::IDStackItem const idStackItem("Menu"); ig::IDStackItem const idStackItem("Menu");
if (ig::PushButton("Resize")) { if (ImGui::Button("Resize")) {
m_sizeEditor.show = true; m_sizeEditor.show = true;
m_sizeEditor.columns = m_doc.columns; m_sizeEditor.columns = m_doc.columns;
m_sizeEditor.rows = m_doc.rows; 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 { void WorldEditorImGui::drawResources() noexcept {

View File

@ -34,9 +34,11 @@ void WorldEditorView::draw(ox::Size const&targetSz) noexcept {
glutils::resizeInitFrameBuffer(m_frameBuffer, ncore::gl::drawSize(m_scale)); glutils::resizeInitFrameBuffer(m_frameBuffer, ncore::gl::drawSize(m_scale));
} }
glutils::FrameBufferBind const frameBufferBind(m_frameBuffer); glutils::FrameBufferBind const frameBufferBind(m_frameBuffer);
auto const wakeUp = m_world.update(); if (m_animateWorld) {
if (wakeUp.ok()) { auto const wakeUp = m_world.editorModeUpdate();
turbine::setRefreshWithin(m_sctx.tctx, wakeUp.value); if (wakeUp.ok()) {
turbine::setRefreshWithin(m_sctx.tctx, wakeUp.value);
}
} }
ncore::gl::draw(*m_cctx, m_scale); ncore::gl::draw(*m_cctx, m_scale);
m_highlighter.draw(); m_highlighter.draw();

View File

@ -32,6 +32,7 @@ class WorldEditorView {
ox::Size m_scaleSz = ncore::gl::drawSize(m_scale); ox::Size m_scaleSz = ncore::gl::drawSize(m_scale);
ox::Optional<studio::Selection> m_selection; ox::Optional<studio::Selection> m_selection;
MapTileHighlighter m_highlighter; MapTileHighlighter m_highlighter;
bool m_animateWorld{};
public: public:
WorldEditorView(studio::StudioContext &ctx, WorldStatic const&worldStatic); WorldEditorView(studio::StudioContext &ctx, WorldStatic const&worldStatic);
@ -44,6 +45,11 @@ class WorldEditorView {
void setSelection(studio::Selection const&sel) noexcept; void setSelection(studio::Selection const&sel) noexcept;
[[nodiscard]]
bool animate() const noexcept { return m_animateWorld; }
void setAnimate(bool animate) noexcept { m_animateWorld = animate; }
[[nodiscard]] [[nodiscard]]
glutils::FrameBuffer const&framebuffer() const noexcept; glutils::FrameBuffer const&framebuffer() const noexcept;

View File

@ -12,8 +12,7 @@ namespace jasper::world {
World::World(ncore::Context &nctx, WorldStatic const&worldStatic) noexcept: World::World(ncore::Context &nctx, WorldStatic const&worldStatic) noexcept:
m_nctx(nctx), m_nctx(nctx),
m_worldStatic(worldStatic) { m_worldStatic(worldStatic) {}
}
ox::Error World::setupDisplay() noexcept { ox::Error World::setupDisplay() noexcept {
if (m_worldStatic.palettes.empty()) { if (m_worldStatic.palettes.empty()) {
@ -22,8 +21,8 @@ ox::Error World::setupDisplay() noexcept {
m_palettes.clear(); m_palettes.clear();
for (auto i = 0u; auto const&pal : m_worldStatic.palettes) { for (auto i = 0u; auto const&pal : m_worldStatic.palettes) {
auto &palRef = m_palettes.emplace_back(); auto &palRef = m_palettes.emplace_back();
oxReturnError(readObj<ncore::CompactPalette>(keelCtx(m_nctx), pal.palette).moveTo(palRef)); oxReturnError(readObj<ncore::CompactPalette>(keelCtx(m_nctx), pal.palette).moveTo(palRef.pal));
oxReturnError(ncore::loadBgPalette(m_nctx, i, *palRef)); oxReturnError(ncore::loadBgPalette(m_nctx, i, *palRef.pal));
++i; ++i;
} }
oxReturnError(ncore::loadBgTileSheet(m_nctx, 0, m_worldStatic.tilesheets)); oxReturnError(ncore::loadBgTileSheet(m_nctx, 0, m_worldStatic.tilesheets));
@ -68,17 +67,44 @@ void World::setupLayer(
} }
} }
ox::Result<int> World::update() const noexcept { ox::Result<int> World::update() noexcept {
auto const time = ticksMs(turbineCtx(m_nctx)); 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) { for (size_t i = 0; auto const&pal : m_palettes) {
auto const interval = m_worldStatic.palettes[i].intervalMs; 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<int>(time % interval)); expiresIn = ox::min(expiresIn, static_cast<int>(time % interval));
oxReturnError(ncore::loadBgPalette(m_nctx, i, *pal, static_cast<size_t>(page))); oxReturnError(ncore::loadBgPalette(m_nctx, i, *pal.pal, static_cast<size_t>(page)));
++i; ++i;
} }
return expiresIn; return expiresIn;
} }
#ifndef OX_OS_BareMetal
ox::Result<int> 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<int>(pal.pal->pages.size());
oxReturnError(ncore::loadBgPalette(m_nctx, i, *pal.pal, static_cast<size_t>(page)));
updated = updated || update;
expiresIn = ox::min<turbine::TimeMs>(expiresIn, interval);
++i;
}
if (updated) {
m_prevUpdateTime = time;
}
m_nextUpdateTime = time + expiresIn;
}
return static_cast<int>(m_nextUpdateTime - time);
}
#endif
} }

View File

@ -25,10 +25,9 @@ ox::Error run(turbine::Context &tctx, ox::StringView, ox::SpanView<ox::String> a
oxReturnError(world.setupDisplay()); oxReturnError(world.setupDisplay());
turbine::setApplicationData(tctx, &world); turbine::setApplicationData(tctx, &world);
setUpdateHandler(tctx, [](turbine::Context &tctx) -> int { setUpdateHandler(tctx, [](turbine::Context &tctx) -> int {
auto const&world = *applicationData<world::World>(tctx); auto &world = *applicationData<world::World>(tctx);
auto [sleepTime, err] = world.update(); auto [sleepTime, err] = world.update();
if (err) { if (err) {
oxDebugf("error: {}", toStr(err));
oxLogError(err); oxLogError(err);
} }
return 0; return 0;