Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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();
[[nodiscard]] Progress getProgress() const;

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