Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions lib/include/chomper/engine.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ class Engine : public IDebugInspector, public klib::Pinned {
return m_debugStats;
}

[[nodiscard]] le::AssetLoader createAssetLoader() const {
return m_context->create_asset_loader(&getDataLoader());
}

void run();

void setVsync(le::Vsync vsync);
Expand Down
11 changes: 11 additions & 0 deletions lib/include/chomper/manifest/asset_manifest.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#pragma once
#include <string>
#include <vector>

namespace chomper {
struct AssetManifest {
std::vector<std::string> textures{};
std::vector<std::string> audio{};
std::vector<std::string> fonts{};
};
} // namespace chomper
62 changes: 62 additions & 0 deletions lib/include/chomper/manifest/manifest_loader.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#pragma once
#include "chomper/manifest/asset_manifest.hpp"
#include "chomper/resources.hpp"
#include <klib/log.hpp>
#include <le2d/asset/asset.hpp>
#include <le2d/asset/asset_loader.hpp>
#include <future>
#include <memory>
#include <span>

namespace chomper {
class ManifestLoader {
public:
struct Progress;

explicit ManifestLoader(le::AssetLoader asset_loader);

void startLoad(AssetManifest const& manifest);

Progress update();
Progress getProgress() const;
Comment thread
karnkaul marked this conversation as resolved.
Outdated

void transferTo(Resources& out);

private:
struct Asset {
std::string uri{};
std::unique_ptr<le::IAsset> asset{};
};

template <std::derived_from<le::IAsset> AssetTypeT>
void startLoads(std::span<std::string const> uris);

klib::TypedLogger<ManifestLoader> m_log{};

le::AssetLoader m_asset_loader{};

std::vector<std::future<Asset>> m_loading{}; // assets being loaded.
std::vector<Asset> m_loaded{}; // loaded assets.
};

struct ManifestLoader::Progress {
[[nodiscard]] constexpr std::int64_t getTotal() const {
return remaining + loaded;
}

[[nodiscard]] constexpr float normalized() const {
auto const total = getTotal();
if (total == 0) {
return 0.0f;
}
return float(loaded) / float(total);
}

[[nodiscard]] constexpr bool isLoading() const {
return remaining > 0;
}

std::int64_t remaining{};
std::int64_t loaded{};
};
} // namespace chomper
37 changes: 29 additions & 8 deletions lib/include/chomper/resources.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once
#include "chomper/debug_inspector.hpp"
#include <djson/string_table.hpp>
#include <klib/log.hpp>
#include <le2d/asset/asset.hpp>
#include <le2d/asset/asset_loader.hpp>
#include <le2d/resource/font.hpp>
Expand All @@ -13,18 +14,16 @@ class Resources : public IDebugInspector {
public:
explicit Resources(le::AssetLoader assetLoader);

void store(std::string uri, std::unique_ptr<le::IAsset> asset);

template <std::derived_from<le::IAsset> AssetTypeT>
[[nodiscard]] AssetTypeT* load(std::string_view const uri) {
auto it = m_assets.find(uri);
if (it == m_assets.end()) {
auto ret = m_assetLoader.load<AssetTypeT>(uri);
if (!ret) {
return {};
}
it = m_assets.insert_or_assign(std::string{uri}, std::move(ret)).first;
if (it != m_assets.end()) {
return dynamic_cast<AssetTypeT*>(it->second.get());
}
KLIB_ASSERT(it != m_assets.end());
return dynamic_cast<AssetTypeT*>(it->second.get());
m_log.warn("loading {} at runtime: {}", klib::demangled_name<AssetTypeT>(), uri);
return reload<AssetTypeT>(uri);
}

template <std::derived_from<le::IAsset> AssetTypeT>
Expand All @@ -35,6 +34,26 @@ class Resources : public IDebugInspector {
throw std::runtime_error{std::format("Failed to load required {}: {}", klib::demangled_name<AssetTypeT>(), uri)};
}

template <std::derived_from<le::IAsset> AssetTypeT>
[[nodiscard]] AssetTypeT* reload(std::string_view const uri) {
auto asset = m_assetLoader.load<AssetTypeT>(uri);
if (!asset) {
m_log.warn("failed to load {}: {}", klib::demangled_name<AssetTypeT>(), uri);
return {};
}
auto* ret = asset.get();
m_assets.insert_or_assign(std::string{uri}, std::move(asset));
return ret;
}

template <std::derived_from<le::IAsset> AssetTypeT>
[[nodiscard]] AssetTypeT& reloadRequired(std::string_view const uri) {
if (auto* ret = reload<AssetTypeT>(uri)) {
return *ret;
}
throw std::runtime_error{std::format("Failed to load required {}: {}", klib::demangled_name<AssetTypeT>(), uri)};
}

[[nodiscard]] le::IFont& getMainFont() const {
return *m_mainFont;
}
Expand All @@ -52,6 +71,8 @@ class Resources : public IDebugInspector {
// IDebugInspector
void debugInspect() final;

klib::TypedLogger<Resources> m_log{};

le::AssetLoader m_assetLoader{};
dj::StringTable<std::unique_ptr<le::IAsset>> m_assets{};

Expand Down
10 changes: 8 additions & 2 deletions lib/include/chomper/runtimes/entrypoint.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#pragma once
#include "chomper/engine.hpp"
#include "chomper/manifest/manifest_loader.hpp"
#include "chomper/runtime.hpp"
#include "chomper/ui/progress_bar.hpp"
#include <le2d/drawable/text.hpp>

namespace chomper::runtime {
Expand All @@ -12,11 +14,15 @@ class Entrypoint : public IRuntime {
void tick(kvf::Seconds dt) final;
void render(le::IRenderer& renderer) const final;

void swingMainText(kvf::Seconds dt);
void setupMainText();
void setupProgressBar();

gsl::not_null<Engine*> m_engine;

ManifestLoader m_manifestLoader;

le::drawable::Text m_mainText{};
kvf::Seconds m_elapsed{};
ui::ProgressBar m_progressBar{};
float m_progress{};
};
} // namespace chomper::runtime
22 changes: 22 additions & 0 deletions lib/include/chomper/runtimes/main_menu.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#pragma once
#include "chomper/engine.hpp"
#include "chomper/runtime.hpp"
#include <le2d/drawable/text.hpp>

namespace chomper::runtime {
class MainMenu : public IRuntime {
public:
explicit MainMenu(gsl::not_null<Engine*> engine);

private:
void tick(kvf::Seconds dt) final;
void render(le::IRenderer& renderer) const final;

void swingMainText(kvf::Seconds dt);

gsl::not_null<Engine*> m_engine;

le::drawable::Text m_mainText{};
kvf::Seconds m_elapsed{};
};
} // namespace chomper::runtime
1 change: 1 addition & 0 deletions lib/include/chomper/theme.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@

namespace chomper::theme {
constexpr auto clearColor_v = kvf::Color{glm::vec4{.34f, .54f, .2f, 1.f}};
constexpr auto snakeBodyColor_v = kvf::Color(glm::vec4{0.f, 0.6f, 1.f, 1.f});
} // namespace chomper::theme
17 changes: 17 additions & 0 deletions lib/include/chomper/ui/progress_bar.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#pragma once
#include <le2d/drawable/shape.hpp>

namespace chomper::ui {
class ProgressBar {
public:
void setProgress(float value);

void draw(le::IRenderer& renderer) const {
quad.draw(renderer);
}

le::drawable::Quad quad{};

glm::vec2 targetSize{300.0f, 50.0f};
};
} // namespace chomper::ui
4 changes: 2 additions & 2 deletions lib/src/engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ void Engine::debugInspect() {
ImGui::Separator();
if (ImGui::Button("restart")) {
m_log.info("restarting");
m_context->wait_idle();
setNextRuntime(&createEntrypoint);
}
}
Expand Down Expand Up @@ -137,8 +138,7 @@ void Engine::createContext(CreateInfo const& createInfo) {
}

void Engine::createResources() {
auto assetLoader = m_context->create_asset_loader(m_dataLoader.get());
m_resources = std::make_unique<Resources>(std::move(assetLoader));
m_resources = std::make_unique<Resources>(createAssetLoader());
}

void Engine::inspectStats() {
Expand Down
72 changes: 72 additions & 0 deletions lib/src/manifest/manifest_loader.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#include "chomper/manifest/manifest_loader.hpp"
#include <klib/assert.hpp>
#include <le2d/resource/audio_buffer.hpp>
#include <le2d/resource/font.hpp>
#include <le2d/resource/texture.hpp>

namespace chomper {
ManifestLoader::ManifestLoader(le::AssetLoader asset_loader) : m_asset_loader(std::move(asset_loader)) {}

void ManifestLoader::startLoad(AssetManifest const& assetManifest) {
// call startLoads<AssetType>() for each field in the manifest.
startLoads<le::ITexture>(assetManifest.textures);
startLoads<le::IAudioBuffer>(assetManifest.audio);
startLoads<le::IFont>(assetManifest.fonts);
}

auto ManifestLoader::getProgress() const -> Progress {
return Progress{
.remaining = std::int64_t(m_loading.size()),
.loaded = std::int64_t(m_loaded.size()),
};
}

auto ManifestLoader::update() -> Progress {
auto const isReady = [this](std::future<Asset>& future) {
// should only have futures from std::async().
KLIB_ASSERT(future.valid());

if (future.wait_for(0s) == std::future_status::ready) { // if future is ready,
m_loaded.push_back(future.get()); // store loaded asset, and
return true; // erase corresponding future.
}
return false; // else do nothing.
};
std::erase_if(m_loading, isReady);
return getProgress();
}

void ManifestLoader::transferTo(Resources& out) {
// block until all pending loads have been completed.
for (auto& future : m_loading) {
m_loaded.push_back(future.get());
}
m_loading.clear();

// transfer valid loaded assets to out.
auto count = std::int64_t{};
for (auto& asset : m_loaded) {
if (!asset.asset) {
continue;
}
out.store(std::move(asset.uri), std::move(asset.asset));
++count;
}
m_loaded.clear();

m_log.info("{} asset(s) transferred to {}", count, klib::demangled_name(out));
}

template <std::derived_from<le::IAsset> AssetTypeT>
void ManifestLoader::startLoads(std::span<std::string const> uris) {
for (auto const& uri : uris) {
if (uri.empty()) {
continue;
}
auto const loadAsset = [this, uri] {
return Asset{.uri = std::move(uri), .asset = m_asset_loader.load<AssetTypeT>(uri)};
};
m_loading.push_back(std::async(loadAsset));
}
}
} // namespace chomper
9 changes: 8 additions & 1 deletion lib/src/resources.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,14 @@
#include <klib/fixed_string.hpp>

namespace chomper {
Resources::Resources(le::AssetLoader assetLoader) : m_assetLoader(std::move(assetLoader)), m_mainFont(&loadRequired<le::IFont>("fonts/main.ttf")) {}
Resources::Resources(le::AssetLoader assetLoader) : m_assetLoader(std::move(assetLoader)), m_mainFont(&reloadRequired<le::IFont>("fonts/main.ttf")) {}

void Resources::store(std::string uri, std::unique_ptr<le::IAsset> asset) {
if (uri.empty() || !asset) {
return;
}
m_assets.insert_or_assign(std::move(uri), std::move(asset));
}

bool Resources::unload(std::string_view const uri) {
auto const it = m_assets.find(uri);
Expand Down
Loading