[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 {
private:
struct PaletteTracker {
keel::AssetRef<ncore::CompactPalette> pal;
int page{};
};
ox::Vector<PaletteTracker, 10> m_palettes;
ncore::Context &m_nctx;
ox::Vector<keel::AssetRef<ncore::CompactPalette>, 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<int> update() const noexcept;
ox::Result<int> update() noexcept;
#ifndef OX_OS_BareMetal
ox::Result<int> editorModeUpdate() noexcept;
#endif
private:
void setupLayer(uint_t lyr, uint_t cbb) const noexcept;

View File

@ -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 {

View File

@ -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();

View File

@ -32,6 +32,7 @@ class WorldEditorView {
ox::Size m_scaleSz = ncore::gl::drawSize(m_scale);
ox::Optional<studio::Selection> 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;

View File

@ -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<ncore::CompactPalette>(keelCtx(m_nctx), pal.palette).moveTo(palRef));
oxReturnError(ncore::loadBgPalette(m_nctx, i, *palRef));
oxReturnError(readObj<ncore::CompactPalette>(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<int> World::update() const noexcept {
ox::Result<int> 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<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;
}
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());
turbine::setApplicationData(tctx, &world);
setUpdateHandler(tctx, [](turbine::Context &tctx) -> int {
auto const&world = *applicationData<world::World>(tctx);
auto &world = *applicationData<world::World>(tctx);
auto [sleepTime, err] = world.update();
if (err) {
oxDebugf("error: {}", toStr(err));
oxLogError(err);
}
return 0;